下面列出了 Dockerfile 中最常用的指令,完整列表和说明可参看官方文档。
FROM
指定 base 镜像。
支持三种格式:
FROM
FROM :
FROM @
FROM指令必须指定,且需要在Dockerfile其他指令的前面。指定的基础指令可以是官方远程仓库中的,也可以是位于本地仓库。后续的指令都依赖于该指令指定的image。 在同一个Dockerfile中建立多个镜像时,可以使用多个FROM指令。
MAINTAINER
设置镜像的作者,可以是任意字符串。
格式:
MAINTAINER
示例:
MAINTAINER Jasper Xu
COPY
格式为:
COPY ...
COPY ["", ...""], shell中执行
复制本地的src到容器的dest, 和ADD指令相似,但是COPY不支持URL和压缩包。
将文件从 build context 复制到镜像。
COPY 支持两种形式:
COPY src dest
COPY ["src", "dest"]
注意:src 只能指定 build context 中的文件或目录。
ADD
与 COPY 类似,从 build context 复制文件到镜像。不同的是,如果 src 是归档文件(tar, zip, tgz, xz 等),文件会被自动解压到 dest。
格式:ADD ...
ADD ["", ...""]
从src目录复制文件到容器的dest目录,src可以是Dockerfile所在目录的相对路径,也可以是一个url,还可以是一个压缩包
注意事项:
1. src必须在构建的上下⽂内,不能使⽤例如: ADD ../some/something ,因为 docker build 命令⾸先会将上下⽂路径和其⼦⽬录发送到docker daemon
2. 如果src是⼀个URL,同时dest不以斜杠结尾,dest将会被视为⽂件,src对应内容⽂件将会被下载到dest
3. 如果src是⼀个URL,同时dest以斜杠结尾,dest将被视为⽬录,src对应内容将会被下载到dest⽬录
4. 如果src是⼀个⽬录,那么整个⽬录其下的内容将会被拷⻉,包括⽂件系统元数据
5. 如果⽂件是可识别的压缩包格式,则docker会⾃动解压
ENV设置环境变量,环境变量可被后面的指令使用
格式:ENV
ENV =
指定环境变量,会被后续的RUN指令使用,并在容器使用后可以通过docker inspect查看这个环境变量,也可以通过使用docker run --env =来修改环境变量
例如:
...
ENV MY_VERSION 1.3
RUN apt-get install -y mypackage=$MY_VERSION
...
EXPOSE
指定容器中的进程会监听某个端口,Docker 可以将该端口暴露出来。
格式:
EXPOSE [...] 为Docker容器设置对外的端口号,使用时可以-p选项或者-P选项。
映射⼀个端⼝的例子:
EXPOSE port1
相应的运⾏容器使⽤的命令docker run -p port1 image
也可以使⽤-P选项启动docker run -P image
映射多个端⼝示例EXPOSE port1 port2 port3
相应的运⾏容器使⽤的命令docker run -p port1 -p port2 -p port3 image
还可以指定需要映射到宿主机器上的某个端⼝号docker run -p host_port1:port1 -p host_port2:port2 -p host_port3:port3 image
注意:
#EXPOSE并不会让容器的端口访问到主机。要使其可访问,需要在docker run运行容器时通过-p来发布这些端口,或通过-P参数来发布EXPOSE导出的所有端口
#默认是TCP
VOLUME
将文件或目录声明为 volume。
格式为: VOLUME ["/data"]
格式:
VOLUME ["/path/to/dir"]
示例:
VOLUME ["/data"]
VOLUME ["/var/www", "/var/log/apache2", "/etc/apache2"
注:
一个卷可以存在于一个或多个容器的指定目录,该目录可以绕过联合文件系统,并具有以下功能:
卷可以容器间共享和重用
容器并不一定要和其它容器共享卷
修改卷后会立即生效
对卷的修改不会对镜像产生影响
卷会一直存在,直到没有任何容器在使用它
[root@localhost imgl]# vi Dockerfile
# Description: test image
FROM busybox:latest
LABEL maintainer "NAME "
COPY yum.repos.d /etc/yum.repos.d/
# ADD http://nginx.org/download/nginx-1.17.3.tar.gz /usr/local/src/
ADD nginx-1.17.3.tar.gz /usr/local/src/
VOLUME /data/mysql
注意:
容器使用的是AUFS,这种文件系统不能持久化数据,当容器关闭后,所有的更改都会丢失,所以当数据需要持久化时用这个命令。
一个卷可以存在于一个或多个容器的指定目录,该目录可以绕过联合文件系统
卷可以容器间共享和重用 可以关注参数 --volumes-from
容器并不一定要和其它容器共享卷
修改卷后会立即生效
对卷的修改不会对镜像产生影响卷会一直存在,直到没有任何容器在使用它
使容器中的⼀个⽬录具有持久化存储数据的功能,该⽬录可以被容器本身使⽤,也可以共享给其他容器
WORKDIR
为后面的 RUN, CMD, ENTRYPOINT, ADD 或 COPY 指令设置镜像中的当前工作目录。
格式为: WORKDIR /path/to/workdir
切换⽬录指令,类似于cd命令,对RUN、CMD、ENTRYPOINT⽣效。
注意:
通过WORKDIR设置工作目录后,Dockerfile中其后的命令RUN、CMD、ENTRYPOINT、ADD、COPY等命令都会在该目录下执行。在使用docker run运行容器时,可以通过-w参数覆盖构建时所设置的工作目录。
RUN
在容器中运行指定的命令。
支持两种格式:
RUN 在shell终端中运行命令,在Linux中默认是/bin/sh -c
RUN["executable", "param1", "param2"],使用exec执行,指定其他终端,例如:RUN["/bin/bash", "-c", "echo hello"],该方式会被转成json数组。
RUN用于在镜像容器中执行命令,其有以下两种命令执行方式:
shell执行
格式:
RUN
exec执行
格式:
RUN ["executable", "param1", "param2"]
示例:
RUN ["executable", "param1", "param2"]
RUN apk update
RUN ["/etc/execfile", "arg1", "arg1"]
注:
RUN指令创建的中间镜像会被缓存,并会在下次构建中使用。如果不想使用这些缓存镜像,可以在构建时指定--no-cache参数,如:docker build --no-cache
基于基础镜像执行,在操作时评估好基础镜像的能力
注意:json数组中,要使用双引号
CMD
容器启动时运行指定的命令。
Dockerfile 中可以有多个 CMD 指令,但只有最后一个生效。CMD 可以被 docker run 之后的参数替换。
CMD ["executable", "param1", "param2"], 推荐使用该方式
CMD ["param1", "param2"],为ENTRYPOINT指令提供预设参数
CMD command param1 param2 在SHELL中执行
CMD指令的主要目的是为执行容器提供默认值,每个Dockerfile只有一个CMD命令,如果指定了多个CMD命令,也只会有一条执行,如果启动容器的时候指定了运行的命令,则会覆盖掉CMD指定的命令。
格式:
CMD ["executable","param1","param2"] (执行可执行文件,优先)
CMD ["param1","param2"] (设置了ENTRYPOINT,则直接调用ENTRYPOINT添加参数)
CMD command param1 param2 (执行shell内部命令)
示例:
CMD echo "This is a test." | wc -
CMD ["/usr/bin/wc","--help"]
注:
CMD不同于RUN,CMD用于指定在容器启动时所要执行的命令,而RUN用于指定镜像构建时所要执行的命令。
ENTRYPOINT
设置容器启动时运行的命令。
格式为: ENTRYPOINT ["executable", "param1", "param2"]
ENTRYPOINT command param1 param2
指定Docker容器启动时执⾏的命令,Dockerfile 中可以有多个 ENTRYPOINT 指令,但只有最后一个生效。
CMD 或 docker run 之后的参数会被当做参数传递给 ENTRYPOINT
LABEL
格式为:LABEL = = = 为镜像添加元数据。
注意:
使用LABEL指定元数据时,一条LABEL指定可以指定一或多条元数据,指定多条元数据时不同元数据之间通过空格分隔。推荐将所有的元数据通过一条LABEL指令指定,以免生成过多的中间镜像。
LABEL会继承基础镜像种的LABEL,如遇到key相同,则值覆盖
USER
格式为: USER ⽤户名
设置启动容器的⽤户,默认是root⽤户
注:
使用USER指定用户后,Dockerfile中其后的命令RUN、CMD、ENTRYPOINT都将使用该用户。镜像构建完成后,通过docker run运行容器时,可以通过-u参数来覆盖所指定的用户。
ARG
格式为: ARG [=]
ARG指令定义⼀个变量。
注意:
如果用户在build镜像时指定了一个参数没有定义在Dockerfile中,那么将有一个Warning:[Warning] One or more build-args [foo] were not consumed
ARG定义的参数默认值,当build镜像时没有指定参数值,将会使用这个默认值
ONBUILD
格式为:ONBUILD [INSTRUCTION]
指定当前建⽴的镜像作为其他镜像的基础时,所执⾏的命令。
注意:
当所构建的镜像被用做其它镜像的基础镜像,该镜像中的触发器将会被钥触发只对当前镜像的子镜像生效。
比如当前镜像为A,在Dockerfile种添加:ONBUILD RUN ls -al 这个 ls -al 命令不会在A镜像构建或启动的时候执行,此时有一个镜像B是基于A镜像构建的,那么这个ls -al 命令会在B镜像构建的时候被执行。
STOPSIGNAL
该STOPSIGNAL指令设置将发送到容器的系统调用信号以退出。此信号可以是与内核的系统调用表中的位置匹配的有效无符号数,例如9,或SIGNAME格式的信号名,例如SIGKILL
HEALTHCHECK
HEALTHCHECK指令告诉Docker如何测试容器以检查它是否仍在工作。即使服务器进程仍在运行,这也可以检测到陷入无限循环且无法处理新连接的Web服务器等情况。
当容器指定了运行状况检查时,除了正常状态外,它还具有运行状况。这个状态最初是starting。每当健康检查通过时,它就会变成healthy(以前的状态)。经过一定数量的连续失败后,它就变成了unhealthy
HEALTHCHECKDockerfile中只能有一条指令。如果列出多个,则只有最后一个HEALTHCHECK生效
SHELL
SHELL指令允许覆盖用于shell形式的命令的默认shell 。Linux上的默认shell是["/bin/sh", “-c”],而在Windows上[“cmd”, “/S”, “/C”]。
SHELL指令必须以JSON格式写入Dockerfile
SHELL指令可以多次出现。每条SHELL指令都会覆盖所有先前的SHELL指令,并影响所有后续指令
2、RUN、CMD 和 ENTRYPOINT的区别
区别:
RUN 执行命令并创建新的镜像层,RUN 经常用于安装软件包。
CMD 设置容器启动后默认执行的命令及其参数,但 CMD 能够被 docker run 后面跟的命令行参数替换。
ENTRYPOINT 配置容器启动时运行的命令。
Shell 和 Exec 格式
我们可用两种方式指定 RUN、CMD 和 ENTRYPOINT 要运行的命令:Shell 格式和 Exec 格式,二者在使用上有细微的区别。
Shell 格式
例如:
RUN apt-get install python3
CMD echo "Hello world"
ENTRYPOINT echo "Hello world"
当指令执行时,shell 格式底层会调用 /bin/sh -c 。
例如下面的 Dockerfile 片段:
ENV name Cloud Man
ENTRYPOINT echo "Hello, $name"
执行 docker run 将输出:
Hello, Man
注意环境变量 name 已经被值 Cloud Man 替换。
下面来看 Exec 格式。
Exec 格式
["executable", "param1", "param2", ...]
例如:
RUN ["apt-get", "install", "python3"]
CMD ["/bin/echo", "Hello world"]
ENTRYPOINT ["/bin/echo", "Hello world"]
当指令执行时,会直接调用 ,不会被 shell 解析。
例如下面的 Dockerfile 片段:
ENV name Man
ENTRYPOINT ["/bin/echo", "Hello, $name"]
运行容器将输出:
Hello, $name
注意环境变量“name”没有被替换。
如果希望使用环境变量,照如下修改
ENV name Man
ENTRYPOINT ["/bin/sh", "-c", "echo Hello, $name"]
运行容器将输出:
Hello, Man
CMD 和 ENTRYPOINT 推荐使用 Exec 格式,因为指令可读性更强,更容易理解。RUN 则两种格式都可以。
RUN
RUN 指令通常用于安装应用和软件包。
RUN 在当前镜像的顶部执行命令,并通过创建新的镜像层。Dockerfile 中常常包含多个 RUN 指令。
RUN 有两种格式:
Shell 格式:RUN
Exec 格式:RUN ["executable", "param1", "param2"]
下面是使用 RUN 安装多个包的例子:
RUN apt-get update && apt-get install -y \
bzr \
cvs \
git \
mercurial \
subversion
注意:apt-get update 和 apt-get install 被放在一个 RUN 指令中执行,这样能够保证每次安装的是最新的包。如果 apt-get install 在单独的 RUN 中执行,则会使用 apt-get update 创建的镜像层,而这一层可能是很久以前缓存的。
CMD
CMD 指令允许用户指定容器的默认执行的命令。
此命令会在容器启动且 docker run 没有指定其他命令时运行。
如果 docker run 指定了其他命令,CMD 指定的默认命令将被忽略。
如果 Dockerfile 中有多个 CMD 指令,只有最后一个 CMD 有效。
CMD 有三种格式:
Exec 格式:CMD ["executable","param1","param2"]
这是 CMD 的推荐格式。
CMD ["param1","param2"] 为 ENTRYPOINT 提供额外的参数,此时 ENTRYPOINT 必须使用 Exec 格式。
Shell 格式:CMD command param1 param2
Exec 和 Shell 格式前面已经介绍过了。
第二种格式 CMD ["param1","param2"] 要与 Exec 格式 的 ENTRYPOINT 指令配合使用,其用途是为 ENTRYPOINT 设置默认的参数。我们将在后面讨论 ENTRYPOINT 时举例说明。
下面看看 CMD 是如何工作的。Dockerfile 片段如下:
CMD echo "Hello world"
运行容器 docker run -it [image] 将输出:
Hello world
但当后面加上一个命令,比如 docker run -it [image] /bin/bash,CMD 会被忽略掉,命令 bash 将被执行:
root@10a32dc7d3d3:/#
ENTRYPOINT
ENTRYPOINT 指令可让容器以应用程序或者服务的形式运行。
ENTRYPOINT 看上去与 CMD 很像,它们都可以指定要执行的命令及其参数。不同的地方在于 ENTRYPOINT 不会被忽略,一定会被执行,即使运行 docker run 时指定了其他命令。
ENTRYPOINT 有两种格式:
Exec 格式:ENTRYPOINT ["executable", "param1", "param2"] 这是 ENTRYPOINT 的推荐格式。
Shell 格式:ENTRYPOINT command param1 param2
在为 ENTRYPOINT 选择格式时必须小心,因为这两种格式的效果差别很大。
Exec 格式
ENTRYPOINT 的 Exec 格式用于设置要执行的命令及其参数,同时可通过 CMD 提供额外的参数。
ENTRYPOINT 中的参数始终会被使用,而 CMD 的额外参数可以在容器启动时动态替换掉。
比如下面的 Dockerfile 片段:
ENTRYPOINT ["/bin/echo", "Hello"]
CMD ["world"]
当容器通过 docker run -it [image] 启动时,输出为:
Hello world
而如果通过 docker run -it [image] Man 启动,则输出为:
Hello Man
Shell 格式
ENTRYPOINT 的 Shell 格式会忽略任何 CMD 或 docker run 提供的参数。
最佳实践
使用 RUN 指令安装应用和软件包,构建镜像。
如果 Docker 镜像的用途是运行应用程序或服务,比如运行一个 MySQL,应该优先使用 Exec 格式的 ENTRYPOINT 指令。CMD 可为 ENTRYPOINT 提供额外的默认参数,同时可利用 docker run 命令行替换默认参数。
如果想为容器设置默认的启动命令,可使用 CMD 指令。用户可在 docker run 命令行中替换此默认命令。
作者:junior1206