docker官方文档Dockerfile reference的笔记。
参考 https://github.com/qianlei90/Blog/issues/35
FROM
。#
开头的是注释,行内的#
都被当做参数,并且不支持续行。解析指令也以#
开头,形式如下:
# directive=value1
# directive=value2
FROM ImageName
解析指令是可选的,虽然不区分大小写,但还是约定使用小写。
解析指令会影响到Dockerfile的解析逻辑,并且不会生成图层,也不会在构建时显示。解析指令只能出现在Dockerfile头部,并且一条解析指令只能出现一次。如果碰到注释、Dockerfile指令或空行,接下来出现的解析指令都无效,被当做注释处理。不支持续行。
根据文档当前只有一个解析指令:escape。(我猜如果有必要可能会在之后的版本中增加新的解析指令吧)
escape用来设置转义或续行字符,这在Windows中很有用:
COPY testfile.txt c:\\
RUN dir c:\
会被docker解析成: COPY teestfile.txt c:\RUN dir c:
,下面的例子就可以正常执行。
# escape=`
COPY testfile.txt c:\RUN dir c:\
在Dockerfile中,使用env
指令来定义环境变量。环境变量有两种形式:$variable_name
和${variable_name}
,推荐使用后者,因为:
${foo}_bar
,前者就无法做到word
除了字符串外也支持环境变量,进行递归替换${variable:-word}
:如果variable
不存在,则使用word
${varialbe:+word}
:如果variable
存在,则使用word
,如果variable
不存在,则使用空字符串
支持这些指令:ADD
,COPY
,ENV
,EXPOSE
,LABEL
,USER
,WORKDIR
,VOLUME
,STOPSIGNAL
和1.4版本之后的ONBUILD
注意
在整个指令行中只使用一个值,参考下面这个例子:
ENV abc=hello
ENV abc=bye def=$abc
ENV ghi=$abc
最后abc=bye, def=hello, ghi=bye
几个注意点:
/bin/sh -c
)运行可执行文件,exec格式的是直接执行可执行文件。如果exec格式的要在某个shell中执行,要这么写:["/bin/bash", "-c", "echo hello"]
。shell可以使用SHELL
指令来更改。\\
)来换行。"
而不是单引号'
。RUN ["echo", "$HOME"]
不会将$HOME
展开,如果需要展开变量,可以这样使用:RUN ["sh", "-c", "echo $HOME"]
如果以docker build - < somefile
这种方式来构建镜像的,则没有上下文,ADD
只能使用远程文件URL而COPY
不能使用。如果以docker build - < archive.tar.gz
,则会在压缩包的根目录中寻找Dockerfile,压缩包的根目录当做上下文。
如果远程文件是需要登录才能访问的,应该使用RUN wget
或RUN curl
,而不是直接使用ADD
或COPY
。
使用ADD
或COPY
远程文件的,会赋予文件600权限,并且HTTP Last-Modified
时间就是文件的最后修改时间。最后修改时间被改变,docker不会认为文件被改变,docker只会检查文件内容。
构建的镜像继承自某个base image。格式:
FROM
FROM :
FROM @
FROM
指令必须是Dockerfile的第一个指令,可以使用多次来构建多个镜像,以最后一个镜像的ID为输出值。
tag
和digest
是可选的,如果不提供则使用latest
。
在镜像的构建过程中执行特定的命令,并生成一个中间镜像。格式:
RUN :shell格式
RUN ["executable", "param1", "param2"]:exec格式
指定容器运行时的默认参数,如果出现多次以最后一次为准。格式:
CMD ["executable", "param1", "param2"]:exec格式
CMD command param1 param2:shell格式
CMD ["param1", "param2"]:省略可执行文件的exec格式,这种写法使CMD中的参数当做ENTRYPOINT的默认参数,此时ENTRYPOINT也应该是exec格式
具体与ENTRYPOINT
的组合使用,参考ENTRYPOINT
。
注意
与RUN
指令的区别:RUN
在构建的时候执行,并生成一个新的镜像,CMD
在容器运行的时候执行,在构建时不进行任何操作。
给构建的镜像打标签。格式:
LABEL = = = ...
如果base image中也有标签,则继承,如果是同名标签,则覆盖。
为了减少图层数量,尽量将标签写在一个LABEL
指令中去,如:
LABEL multi.label1="value1" \
multi.label2="value2" \
other="value3"
为构建的镜像设置作者信息。格式:
MAINTAINER
LABEL
比MAINTAINER
更灵活,推荐使用LABEL
,弃用MAINTAINER
。
为构建的镜像设置监听端口,使容器在运行时监听。格式:
EXPOSE [...]
EXPOSE
指令并不会让容器监听host的端口,如果需要,需要在docker run
时使用-p
、-P
参数来发布容器端口到host的某个端口上。
在构建的镜像中设置环境变量,在后续的Dockerfile指令中可以直接使用,也可以固化在镜像里,在容器运行时仍然有效。格式:
ENV :把第一个空格之后的所有值都当做的值,无法在一行内设定多个环境变量。
ENV = ...:可以设置多个环境变量,如果中存在空格,需要转义或用引号"括起来。
docker推荐使用第二种,因为可以在一行中写多个环境变量,减少图层。如下:
ENV myName="John Doe" \
myDog=Rex\ The\ Dog \
myCat=fluffy
注意
docker run --env =
。ENV
可能会对后续的Dockerfile指令造成影响,如果只需要对一条指令设置环境变量,可以使用这种方式:RUN =
在构建镜像时,复制上下文中的文件到镜像内,格式:
ADD ...
ADD ["",... ""]
可以是文件、目录,也可以是文件URL。可以使用模糊匹配(wildcards,类似shell的匹配),可以指定多个
,必须是在上下文目录和子目录中,无法添加../a.txt
这样的文件。如果
是个目录,则复制的是目录下的所有内容,但不包括该目录。如果
是个可被docker识别的压缩包,docker会以tar -x
的方式解压后将内容复制到
。
可以是绝对路径,也可以是相对WORKDIR
目录的相对路径。
所有文件的UID和GID都是0。
注意
如果docker发现文件内容被改变,则接下来的指令都不会再使用缓存。
关于复制文件时需要处理的/
,基本跟正常的copy一致,具体参考ADD
指令。
与ADD
类似,只不过ADD
是将上下文内的文件复制到镜像内,COPY
是在镜像内的复制。格式与ADD
一致。
注意
如果
不存在,COPY
指令会自动创建所有目录,包括子目录
指定镜像的执行程序,只有最后一条ENTRYPOINT
指令有效。格式:
ENTRYPOINT :shell格式,因为嵌套在shell中,PID不再为1,也接受不到Unix信号,即在docker stop 时收不到SIGTERM信号,需要手动写脚本使用exec或gosu命令处理。
ENTRYPOINT ["", "", ""]:exec格式,PID为1
官方文档有两个例子:Exec form ENTRYPOINT example和Shell form ENTRYPOINT example。
CMD
和ENTRYPOINT
至少得使用一个。ENTRYPOINT
应该被当做docker的可执行程序,CMD
应该被当做ENTRYPOINT
的默认参数。
docker run
会把之后的参数传递给ENTRYPOINT
,覆盖CMD
指定的参数。可以用docker run --entrypoint
来重置默认的ENTRYPOINT
。
关于ENTRYPOINT
和CMD
的交互,用一个官方表格可以说明:
No ENTRYPOINTENTRYPOINT exec_entry p1_entryENTRYPOINT [“exec_entry”, “p1_entry”]No CMDerror, not allowed/bin/sh -c exec_entry p1_entryexec_entry p1_entryCMD [“exec_cmd”, “p1_cmd”]exec_cmd p1_cmd/bin/sh -c exec_entry p1_entryexec_entry p1_entry exec_cmd p1_cmdCMD [“p1_cmd”, “p2_cmd”]p1_cmd p2_cmd/bin/sh -c exec_entry p1_entryexec_entry p1_entry p1_cmd p2_cmdCMD exec_cmd p1_cmdCMD exec_cmd p1_cmd/bin/sh -c exec_entry p1_entryexec_entry p1_entry /bin/sh -c exec_cmd p1_cmd
指定镜像内的目录为数据卷。格式:
VOLUME ["/var/log"]
VOLUME /var/log /var/db
在容器运行的时候,docker会把镜像中的数据卷的内容复制到容器的数据卷中去。
如果在接下来的Dockerfile指令中,修改了数据卷中的内容,则修改无效。
为接下来的Dockerfile指令指定用户。格式:
USER daemon
收影响的指令有:RUN
、CMD
、ENTRYPOINT
。
为接下来的Dockerfile指令指定当前工作目录,可多次使用,如果使用的是相对路径,则相对的是上一个工作目录,类似shell中的cd命令。格式:
WORKDIR /path/to/workdir
收影响的指令有:RUN
、CMD
、ENTRYPOINT
、COPY
和ADD
。
指定了用户在docker build --build-arg
时可以使用的参数。格式:
ARG [=]
构建参数在定义的时候生效而不是在使用的时候。如下面第三行开始的user才是用户构建参数传递过来的user:
FROM busybox
USER ${user:-some_user}
ARG user
USER $user
后续的ENV
指令会覆盖同名的构建参数,正常用法如下:
FROM ubuntuARG CONT_IMG_VERENV CONT_IMG_VER ${CONT_IMG_VER:-v1.0.0}RUN echo $CONT_IMG_VER
docker内置了一批构建参数,可以不用在Dockerfile中声明:HTTP_PROXY
、http_proxy
、HTTPS_PROXY
、https_proxy
、FTP_PROXY
、ftp_proxy
、NO_PROXY
、no_proxy
注意
在使用构建参数(而不是在构建参数定义的时候)的指令中,如果构建参数的值发生了变化,会导致该指令发生变化,会重新寻找缓存。
向镜像中添加一个触发器,当以该镜像为base image再次构建新的镜像时,会触发执行其中的指令。格式:
ONBUILD [INSTRUCTION]
比如我们生成的镜像是用来部署Python代码的,但是因为有多个项目可能会复用该镜像。所以一个合适的方式是:
[...]
# 在下一次以此镜像为base image的构建中,执行ADD . /app/src,将项目代目添加到新镜像中去
ONBUILD ADD . /app/src# 并且build Python代码
ONBUILD RUN /usr/local/bin/python-build --dir /app/src
[...]
注意
ONBUILD
只会继承给子节点的镜像,不会再继承给孙子节点。
ONBUILD ONBUILD
或者ONBUILD FROM
或者ONBUILD MAINTAINER
是不允许的。
触发系统信号。格式:
STOPSIGNAL signal
增加自定义的心跳检测功能,多次使用只有最后一次有效。格式:
HEALTHCHECK [OPTION] CMD :通过在容器内运行command来检查心跳
HEALTHCHECK NONE:取消从base image继承来的心跳检测
可选的OPTION
:
--interval=DURATION
:检测间隔,默认30秒
--timeout=DURATION
:命令超时时间,默认30秒
--retries=N
:连续N次失败后标记为不健康,默认3次
可以是shell脚本,也可以是exec格式的json数组。
docker以
的退出状态码来区分容器是否健康,这一点同shell一致:
0:命令返回成功,容器健康
1:命令返回失败,容器不健康
2:保留状态码,不要使用
举例:每5分钟检测本地网页是否可访问,超时设为3秒:
HEALTHCHECK --interval=5m --timeout=3s \
CMD curl -f http://localhost/ || exit 1
可以使用docker inspect
命令来查看健康状态。
更改后续的Dockerfile指令中所使用的shell。默认的shell是["bin/sh", "-c"]
。可多次使用,每次都只改变后续指令。格式:
SHELL ["executable", "parameters"]
深入Dockerfile(一): 语法指南
docker官方文档Dockerfile reference的笔记。
参考 https://github.com/qianlei90/Blog/issues/35
FROM
。#
开头的是注释,行内的#
都被当做参数,并且不支持续行。解析指令也以#
开头,形式如下:
# directive=value1
# directive=value2
FROM ImageName
解析指令是可选的,虽然不区分大小写,但还是约定使用小写。
解析指令会影响到Dockerfile的解析逻辑,并且不会生成图层,也不会在构建时显示。解析指令只能出现在Dockerfile头部,并且一条解析指令只能出现一次。如果碰到注释、Dockerfile指令或空行,接下来出现的解析指令都无效,被当做注释处理。不支持续行。
根据文档当前只有一个解析指令:escape。(我猜如果有必要可能会在之后的版本中增加新的解析指令吧)
escape用来设置转义或续行字符,这在Windows中很有用:
COPY testfile.txt c:\\
RUN dir c:\
会被docker解析成: COPY teestfile.txt c:\RUN dir c:
,下面的例子就可以正常执行。
# escape=`
COPY testfile.txt c:\RUN dir c:\
在Dockerfile中,使用env
指令来定义环境变量。环境变量有两种形式:$variable_name
和${variable_name}
,推荐使用后者,因为:
${foo}_bar
,前者就无法做到word
除了字符串外也支持环境变量,进行递归替换${variable:-word}
:如果variable
不存在,则使用word
${varialbe:+word}
:如果variable
存在,则使用word
,如果variable
不存在,则使用空字符串
支持这些指令:ADD
,COPY
,ENV
,EXPOSE
,LABEL
,USER
,WORKDIR
,VOLUME
,STOPSIGNAL
和1.4版本之后的ONBUILD
注意
在整个指令行中只使用一个值,参考下面这个例子:
ENV abc=hello
ENV abc=bye def=$abc
ENV ghi=$abc
最后abc=bye, def=hello, ghi=bye
几个注意点:
/bin/sh -c
)运行可执行文件,exec格式的是直接执行可执行文件。如果exec格式的要在某个shell中执行,要这么写:["/bin/bash", "-c", "echo hello"]
。shell可以使用SHELL
指令来更改。\\
)来换行。"
而不是单引号'
。RUN ["echo", "$HOME"]
不会将$HOME
展开,如果需要展开变量,可以这样使用:RUN ["sh", "-c", "echo $HOME"]
如果以docker build - < somefile
这种方式来构建镜像的,则没有上下文,ADD
只能使用远程文件URL而COPY
不能使用。如果以docker build - < archive.tar.gz
,则会在压缩包的根目录中寻找Dockerfile,压缩包的根目录当做上下文。
如果远程文件是需要登录才能访问的,应该使用RUN wget
或RUN curl
,而不是直接使用ADD
或COPY
。
使用ADD
或COPY
远程文件的,会赋予文件600权限,并且HTTP Last-Modified
时间就是文件的最后修改时间。最后修改时间被改变,docker不会认为文件被改变,docker只会检查文件内容。
构建的镜像继承自某个base image。格式:
FROM
FROM :
FROM @
FROM
指令必须是Dockerfile的第一个指令,可以使用多次来构建多个镜像,以最后一个镜像的ID为输出值。
tag
和digest
是可选的,如果不提供则使用latest
。
在镜像的构建过程中执行特定的命令,并生成一个中间镜像。格式:
RUN :shell格式
RUN ["executable", "param1", "param2"]:exec格式
指定容器运行时的默认参数,如果出现多次以最后一次为准。格式:
CMD ["executable", "param1", "param2"]:exec格式
CMD command param1 param2:shell格式
CMD ["param1", "param2"]:省略可执行文件的exec格式,这种写法使CMD中的参数当做ENTRYPOINT的默认参数,此时ENTRYPOINT也应该是exec格式
具体与ENTRYPOINT
的组合使用,参考ENTRYPOINT
。
注意
与RUN
指令的区别:RUN
在构建的时候执行,并生成一个新的镜像,CMD
在容器运行的时候执行,在构建时不进行任何操作。
给构建的镜像打标签。格式:
LABEL = = = ...
如果base image中也有标签,则继承,如果是同名标签,则覆盖。
为了减少图层数量,尽量将标签写在一个LABEL
指令中去,如:
LABEL multi.label1="value1" \
multi.label2="value2" \
other="value3"
为构建的镜像设置作者信息。格式:
MAINTAINER
LABEL
比MAINTAINER
更灵活,推荐使用LABEL
,弃用MAINTAINER
。
为构建的镜像设置监听端口,使容器在运行时监听。格式:
EXPOSE [...]
EXPOSE
指令并不会让容器监听host的端口,如果需要,需要在docker run
时使用-p
、-P
参数来发布容器端口到host的某个端口上。
在构建的镜像中设置环境变量,在后续的Dockerfile指令中可以直接使用,也可以固化在镜像里,在容器运行时仍然有效。格式:
ENV :把第一个空格之后的所有值都当做的值,无法在一行内设定多个环境变量。
ENV = ...:可以设置多个环境变量,如果中存在空格,需要转义或用引号"括起来。
docker推荐使用第二种,因为可以在一行中写多个环境变量,减少图层。如下:
ENV myName="John Doe" \
myDog=Rex\ The\ Dog \
myCat=fluffy
注意
docker run --env =
。ENV
可能会对后续的Dockerfile指令造成影响,如果只需要对一条指令设置环境变量,可以使用这种方式:RUN =
在构建镜像时,复制上下文中的文件到镜像内,格式:
ADD ...
ADD ["",... ""]
可以是文件、目录,也可以是文件URL。可以使用模糊匹配(wildcards,类似shell的匹配),可以指定多个
,必须是在上下文目录和子目录中,无法添加../a.txt
这样的文件。如果
是个目录,则复制的是目录下的所有内容,但不包括该目录。如果
是个可被docker识别的压缩包,docker会以tar -x
的方式解压后将内容复制到
。
可以是绝对路径,也可以是相对WORKDIR
目录的相对路径。
所有文件的UID和GID都是0。
注意
如果docker发现文件内容被改变,则接下来的指令都不会再使用缓存。
关于复制文件时需要处理的/
,基本跟正常的copy一致,具体参考ADD
指令。
与ADD
类似,只不过ADD
是将上下文内的文件复制到镜像内,COPY
是在镜像内的复制。格式与ADD
一致。
注意
如果
不存在,COPY
指令会自动创建所有目录,包括子目录
指定镜像的执行程序,只有最后一条ENTRYPOINT
指令有效。格式:
ENTRYPOINT :shell格式,因为嵌套在shell中,PID不再为1,也接受不到Unix信号,即在docker stop 时收不到SIGTERM信号,需要手动写脚本使用exec或gosu命令处理。
ENTRYPOINT ["", "", ""]:exec格式,PID为1
官方文档有两个例子:Exec form ENTRYPOINT example和Shell form ENTRYPOINT example。
CMD
和ENTRYPOINT
至少得使用一个。ENTRYPOINT
应该被当做docker的可执行程序,CMD
应该被当做ENTRYPOINT
的默认参数。
docker run
会把之后的参数传递给ENTRYPOINT
,覆盖CMD
指定的参数。可以用docker run --entrypoint
来重置默认的ENTRYPOINT
。
指定镜像内的目录为数据卷。格式:
VOLUME ["/var/log"]
VOLUME /var/log /var/db
在容器运行的时候,docker会把镜像中的数据卷的内容复制到容器的数据卷中去。
如果在接下来的Dockerfile指令中,修改了数据卷中的内容,则修改无效。
为接下来的Dockerfile指令指定用户。格式:
USER daemon
收影响的指令有:RUN
、CMD
、ENTRYPOINT
。
为接下来的Dockerfile指令指定当前工作目录,可多次使用,如果使用的是相对路径,则相对的是上一个工作目录,类似shell中的cd命令。格式:
WORKDIR /path/to/workdir
收影响的指令有:RUN
、CMD
、ENTRYPOINT
、COPY
和ADD
。
指定了用户在docker build --build-arg
时可以使用的参数。格式:
ARG [=]
构建参数在定义的时候生效而不是在使用的时候。如下面第三行开始的user才是用户构建参数传递过来的user:
FROM busybox
USER ${user:-some_user}
ARG user
USER $user
后续的ENV
指令会覆盖同名的构建参数,正常用法如下:
FROM ubuntuARG CONT_IMG_VERENV CONT_IMG_VER ${CONT_IMG_VER:-v1.0.0}RUN echo $CONT_IMG_VER
docker内置了一批构建参数,可以不用在Dockerfile中声明:HTTP_PROXY
、http_proxy
、HTTPS_PROXY
、https_proxy
、FTP_PROXY
、ftp_proxy
、NO_PROXY
、no_proxy
注意
在使用构建参数(而不是在构建参数定义的时候)的指令中,如果构建参数的值发生了变化,会导致该指令发生变化,会重新寻找缓存。
向镜像中添加一个触发器,当以该镜像为base image再次构建新的镜像时,会触发执行其中的指令。格式:
ONBUILD [INSTRUCTION]
比如我们生成的镜像是用来部署Python代码的,但是因为有多个项目可能会复用该镜像。所以一个合适的方式是:
[...]
# 在下一次以此镜像为base image的构建中,执行ADD . /app/src,将项目代目添加到新镜像中去
ONBUILD ADD . /app/src# 并且build Python代码
ONBUILD RUN /usr/local/bin/python-build --dir /app/src
[...]
注意
ONBUILD
只会继承给子节点的镜像,不会再继承给孙子节点。
ONBUILD ONBUILD
或者ONBUILD FROM
或者ONBUILD MAINTAINER
是不允许的。
触发系统信号。格式:
STOPSIGNAL signal
增加自定义的心跳检测功能,多次使用只有最后一次有效。格式:
HEALTHCHECK [OPTION] CMD :通过在容器内运行command来检查心跳
HEALTHCHECK NONE:取消从base image继承来的心跳检测
可选的OPTION
:
--interval=DURATION
:检测间隔,默认30秒
--timeout=DURATION
:命令超时时间,默认30秒
--retries=N
:连续N次失败后标记为不健康,默认3次
可以是shell脚本,也可以是exec格式的json数组。
docker以
的退出状态码来区分容器是否健康,这一点同shell一致:
0:命令返回成功,容器健康
1:命令返回失败,容器不健康
2:保留状态码,不要使用
举例:每5分钟检测本地网页是否可访问,超时设为3秒:
HEALTHCHECK --interval=5m --timeout=3s \
CMD curl -f http://localhost/ || exit 1
可以使用docker inspect
命令来查看健康状态。
更改后续的Dockerfile指令中所使用的shell。默认的shell是["bin/sh", "-c"]
。可多次使用,每次都只改变后续指令。格式:
SHELL ["executable", "parameters"]