@[toc]
Dockerfile指令详解
FROM
格式:FROM <image>或FROM <image>:<tag>
FROM指令的功能是为后面的指令提供基础镜像,因此,Dockerfile必须以FROM指令作为第一条非注释指令。我们可以根据需要,选择任何有效的镜像作为基础镜像。
可以在一个Dockerfile文件中,使用多个 FROM 指令,来构建多个镜像。每个镜像构建完成之后,Docker会打印出该镜像的ID。如果 FROM 指令中没有指定镜像的tag,则默认tag是 latest 。如果镜像不存在,则报错退出。
MAINTAINER
格式:MAINTAINER <name> <Email>
用来指定维护该Dockerfile的作者信息。
ENV
ENV指令有两种格式:ENV <key> <value>
ENV <key1>=<value1> <key2>=<value2>
ENV指令用来在镜像创建出来的容器中声明环境变量,被声明的环境变量可被后面的特定指令,例如:ENV、ADD、COPY、WORKDIR、EXPOSE、VOLUME、USER使用。其他指令引用格式为:$variableName或${variableName}。可以使用斜杠 \ 来转义环境变量,例如:$test或者\${test},这样二者将会被分别转换为$test和${test}字符串,而不是环境变量所保存的值。这里要注意,ONBUILD指令不支持环境替换。
WORKDIR
格式:WORKDIR <工作目录路径>
该指令用于指定当前的工作目录,使用该命令后,接下来每一层的工作目录都会切换到指定的目录(除非重新使用 WORKDIR 切换)。
WORKDIR 的路径始终使用绝对路径。这可以保证指令的准确和可靠。 同时,使用 WORKDIR 来替代RUN cd ... && do-something 这样难以维护的指令。
COPY
格式:COPY <src> <dest>
COPY 指令复制本机上的 文件或目录到镜像的 路径下。若或以反斜杠/结尾则说明其指向的是目录,否则指向文件。
可以是多个文件或目录,但必须是上下文根目录中的相对路径。不能使用形如 COPY ../filename /filename这样的指令。此外,支持使用通配符指向所有匹配通配符的文件或目录,例如,COPY iam* /opt/表示添加所有以 iam 开头的文件到目录/opt/中。
可以是文件或目录,但必须是镜像中的绝对路径或者相对于WORKDIR的相对路径。 若是一个文件,则的内容会被复制到中;否则指向的文件或目录中的内容会被复制到目录中。当指定多个源时,必须是目录。如果在镜像中不存在,则会被自动创建。
ADD
格式:ADD <src> <dest>
ADD与COPY指令具有相似的功能,都支持复制本地文件到镜像的功能。但ADD指令还支持其他功能。在 ADD 指令中,可以是一个网络文件的下载地址, 比如 ADD http://example.com/iamctl.yaml /会在镜像中创建文件/iamctl.yaml。
还可以是一个压缩归档文件,该文件在复制到容器时会被解压提取,例如ADD iam.tar.xz /。但是若URL中的文件为归档文件,则不会被解压提取。
在编写Dockerfile时,推荐使用COPY,因为COPY只支持本地文件,它比 ADD 更加透明。
RUN
RUN指令有两种格式:RUN <command> (shell格式)
RUN ["executable", "param1", "param2"] (exec格式,推荐使用)
RUN指令会在前一条命令创建出的镜像的基础上创建一个容器,并在容器中运行命令,在命令结束运行后提交容器为新镜像,新镜像被Dockerfile中的下一条指令使用。
当使用shell格式时,命令通过/bin/sh -c运行。当使用exec格式时,命令是直接运行的,即不通过shell来运行命令。这里要注意,exec格式中的参数会以 JSON 数组的格式被Docker解析,所以参数必须使用双引号而不是单引号。
因为exec格式不会在shell中执行,所以环境变量不会被替换。比如,执行RUN ["echo", "$USER"]指令时,$USER不会做变量替换。如果希望运行shell程序,指令可以写成 RUN ["/bin/bash", "-c", "echo", "$USER"]。
CMD
CMD指令有3种格式:CMD <command> (shell格式)
CMD ["executable", "param1", "param2"] (exec格式,推荐使用)
CMD ["param1", "param2"] (为ENTRYPOINT指令提供参数)
CMD指令提供容器运行时的默认命令或参数,一个Dockerfile中可以有多条CMD指令,但只有最后一条CMD指令有效。CMD ["param1", "param2"]格式用来跟ENTRYPOINT指令配合使用,CMD指令中的参数会添加到ENTRYPOINT指令中。当使用shell和exec格式时,命令在容器中的运行方式与RUN指令相同。如果在执行docker run 时指定了命令行参数,则会覆盖CMD指令中的命令。
ENTRYPOINT
ENTRYPOINT指令有两种格式:ENTRYPOINT <command> (shell格式)
ENTRYPOINT ["executable", "param1", "param2"] (exec格式,推荐格式)
ENTRYPOINT指令和CMD指令类似,都可以让容器在每次启动时执行指定的命令,但二者又有不同。ENTRYPOINT只能是命令 ,而CMD可以是参数,也可以是指令。另外,docker run命令行参数可以覆盖CMD,但不能覆盖ENTRYPOINT。
当使用Shell格式时,ENTRYPOINT指令会忽略任何CMD指令和docker run命令的参数,并且会运行在bin/sh -c中。
推荐使用exec格式。使用exec格式时,docker run传入的命令行参数会覆盖CMD指令的内容并且追加到ENTRYPOINT指令的参数中。
一个Dockerfile中可以有多条ENTRYPOINT指令,但只有最后一条ENTRYPOINT指令有效。
ONBUILD
格式:ONBUILD [INSTRUCTION]
ONBUILD 指令后面跟的是其它指令,例如 RUN , COPY 等。这些指令,在当前镜像构建时不会被执行,当以当前镜像为基础镜像,构建下一级镜像时才会被执行。
这里要注意,使用包含ONBUILD指令的Dockerfile,构建的镜像应该打上特殊的标签,比如:python:3.0-onbuild。另外,在ONBUILD指令中使用ADD或COPY指令时要特别注意。假如新的构建过程的上下文中缺失了被添加的资源,则新的构建过程会失败。我们可以通过给ONBUILD镜像添加特殊标签,来提示编写Dockerfile的开发人员要特别注意。
VOLUME
VOLUME指令有两种格式:VOLUMN ["<路径1>", "路径2"...]
VOLUMN <路径>
为了防止容器内的重要数据因为容器重启而丢失,且避免容器不断变大,应该将容器内的某些目录挂载到宿主机上。在Dockerfile中,我们可以通过 VOLUME 指令事先将某些目录挂载为匿名卷,这样在执行docker run时,如果没有指定 -v 选项,则默认会将VOLUMN指定的目录挂载为匿名卷 。
EXPOSE
格式:EXPOSE <端口1> [<端口2> ...]
EXPOSE指定了该镜像生成容器时提供服务的端口(默认对外不暴露端口),可以配合docker run -P使用,也可以配合docker run --net=host使用。
LABEL
格式:LABEL <key>=<value> <key>=<value> <key>=<value> ...
LABEL 指令用来给镜像添加一些元数据(metadata)。
USER
格式:USER <用户名>[:<用户组>]
USER指令设定一个用户或者用户ID,在执行RUN、CMD、ENTRYPOINT等指令时指定以那个用户得身份去执行。如果容器中的服务不需要以特权身份来运行,则可以使用 USER 指令,切换到非root用户,以此来增加安全性。
ARG
格式:ARG <参数名>[=<默认值>]
与ENV作用一致,但作用域不相同。通过ARG指定的环境变量仅在docker build的过程中有效,构建好的镜像内不存在此变量。虽然构建好的镜像内不存在此变量,但是使用docker history可以查看到。所以,敏感数据不建议使用ARG。
可以在docker build时用--build-arg <参数名>=<值>来覆盖ARG指定的参数值 。
HEALTHCHECK
HEALTHCHECK指令有两种格式:HEALTHCHECK [选项] CMD <命令>:设置检查容器健康状况的命令
HEALTHCHECK NONE:用来屏蔽掉已有的健康检查指令。
定时检测容器进程是否健康,可以设置检查的时间间隔、超时时间、重试次数、以及用于判断是否健康的指令。其中,CMD指定的<命令>的返回值决定了该次健康检查是否成功:0 成功;1 失败;2 保留。
HEALTHCHECK支持下列指令:--interval=<时间间隔>:设置健康检查的时间间隔,默认是 30s。
--timeout=<超时时长>:设置单次健康检查的超时时间,默认是 30s。
--retries=<重试次数>:如果健康检查失败,重试多少次,默认是 3 次。如果连续 3 次健康检查都失败,容器的 STATUS 就会显示 unhealthy。
例如:
FROM nginx
RUN apt-get update && apt-get install -y curl && rm -rf /var/lib/apt/list*
HEALTHCHECK --interval=5s --timeout=3s\
CMD curl -fs http://localhost/ || exit 1
上面的Dockerfile中,使用curl -fs http://localhost/ || exit 1作为健康检查命令 ,每5秒检查一次容器是否健康,如果健康检查命令超过3秒没响应就视为检查失败。
STOPSIGNAL
格式:STOPSIGNAL signal
STOPSIGNAL指令指定了容器退出时,发送给容器的系统调用信号。