Dockerfile指令

Dockerfile中有许多指令,详细且全面的介绍参考官方文档

FROM

指令格式:

FROM <image> [AS <name>]

或者

FROM <image>[:<tag>] [AS <name>]

或者

FROM <image>[@<digest>] [AS <name>]

FROM指令设置一个基础镜像,让后面的指令可以在一个镜像中运行,可以是任何在镜像库中存在的镜像,一般作为是Dockerfile的第一条指令

  • ARG是唯一可以放在FROM之前的指令
  • FROM可以在同一个Dockerfile里面出现多次
  • tagdigest参数不是必填的,如果不填默认是 latest 也就是最后的版本
了解FROM和ARG的交互方式

FROM指令可以使用在FROM之前声明的任何ARG变量

ARG  CODE_VERSION=latest
FROM base:${CODE_VERSION}
CMD  /code/run-app

FROM extras:${CODE_VERSION}
CMD  /code/run-extras

FROM之前声明的变量如果想在FROM之后再次被其他指令使用需要重新声明

ARG VERSION=latest
FROM busybox:$VERSION
ARG VERSION
RUN echo $VERSION > image_version

RUN

RUN指令用于指定镜像被构建时要运行的命令。有两种格式:

RUN <command>  (shell格式,命令在shell中执行)


RUN ["executable", "param1", "param2"] (exec格式)

可以用反斜杠\表示换行

RUN /bin/bash -c 'source $HOME/.bashrc; \
echo $HOME'

等同于

RUN /bin/bash -c 'source $HOME/.bashrc; echo $HOME'

CMD

CMD指令用于指定一个容器启动时要运行的命令。有三种格式:

CMD ["executable","param1","param2"] (exec格式,首选)


CMD ["param1","param2"] (as default parameters to ENTRYPOINT)


CMD command param1 param2 (shell格式)

如docker run命令可以覆盖CMD指令,如果在Dockerfile文件中指定了CMD指令,而同时在docker run命令行中指定了要运行的命令,命令行的命令会覆盖Dockerfile中的CMD指令。

LABEL

给镜像指定标签

LABEL "com.example.vendor"="ACME Incorporated"
LABEL com.example.label-with-value="foo"
LABEL version="1.0"
LABEL description="This text illustrates \
that label-values can span multiple lines."

可以写在一行

LABEL multi.label1="value1" multi.label2="value2" other="value3"


LABEL multi.label1="value1" \
      multi.label2="value2" \
      other="value3"

可以使用 docker inspect 命令查看这些标签

MAINTAINER (deprecated)

指定作者信息,指令格式:

MAINTAINER <name>

官方推荐使用LABEL指令添加作者信息而不是使用MAINTAINER指令,这样就可以使用docker inspect命令查看这些信息

LABEL maintainer="SvenDowideit@home.org.au"

EXPOSE

开放容器内的端口给外部,可以指定端口是在TCP还是UDP上侦听,如果未指定协议,则默认值为TCP。 这个指令只是开放容器内部端口给外部,并不能指定宿主的映射端口,如果需要配置映射关系需要在 docker run-p 指定端口映射关系。指令格式

EXPOSE <port> [<port>/<protocol>...]

例如开放容器内80的TCP和UDP,格式是一行,当然也可以写成两行

EXPOSE 80/tcp
EXPOSE 80/udp

ENV

ENV指令用来在镜像构建过程中设置环境变量,后续的RUN可以使用它所创建的环境变量。 指令格式:

ENV <key> <value>
ENV <key>=<value> ...

新建一个Dockerfile添加如下内容

FROM ubuntu
ENV env varible

生成镜像,运行容器,会看到声明的环境变量

[root@Charlie env]# docker build -t test/env .
···
[root@Charlie env]# docker run -it test/env /bin/bash
root@3a27a7e4598f:/# env
···
env=varible
···

如果在 docker run -e 指定了某个环境变量值,就会覆盖Dockerfile中原先的配置值

[root@Charlie env]# docker run -it -e "env=run_command" test/env /bin/bash
root@0cf1a2954574:/# env
···
env=run_command
···

ADD

是将宿主机文件复制到镜像中,指令格式:

ADD [--chown=<user>:<group>] <src>... <dest>


ADD [--chown=<user>:<group>] ["<src>",... "<dest>"]

<dest>路径的填写可以是容器内的绝对路径,也可以是相对于工作目录的相对路径; <src>可以是一个本地文件或者是一个本地压缩文件,还可以是一个url; 如果把<src>写成一个url,那么ADD就类似于wget命令。 例如将构建目录下的 test.txt 文件复制到镜像中 /usr/local/test.txt 文件

ADD test.txt /usr/local/test.txt

文件源也可以使用url的格式,例如下载最新的wordpress压缩包 latest.zip/usr/local命名为wordpress.zip

ADD https://wordpress.org/latest.zip /usr/local/wordpress.zip

如果将本地归档文件(tar archive),合法的归档文件(gzip、bzip2、xz)指向到文件夹,Docker会自动解压,下面会将latest.tar.gz文件自动解压到镜像的/usr/local/wordpress/目录下

ADD latest.tar.gz /usr/local/wordpress/

COPY

是将宿主机文件复制到镜像中,与ADD功能相同,区别是ADD可以使用url下载远程服务器的文件复制到镜像中,ADD还可以自动解压某些压缩包,这两个功能COPY都不可以。指令格式:

COPY [--chown=<user>:<group>] <src>... <dest>


COPY [--chown=<user>:<group>] ["<src>",... "<dest>"] (this form is required for paths containing whitespace)

ENTRYPOINT

CMD指令用于指定一个容器启动时要运行的命令。指令格式:

ENTRYPOINT ["executable", "param1", "param2"] (exec格式,首选)


ENTRYPOINT command param1 param2 (shell格式)

CMD功能类似,只能写一条,如果写了多条,只有最后一条生效,上文提到在运行docker run命令行时如果指定了要运行的命令会覆盖Dockerfile中的CMD指令,差异就在这里ENTRYPOINT指令是无法被docker run命令行指定的指令覆盖的。 如果在Dockerfile中同时写了ENTRYPOINTCMD,它们两个会互相覆盖,谁在最后谁生效。 ENTRYPOINTCMD不同组合的执行情况(这里展示效果不好可以直接去官网查看):

No ENTRYPOINT

ENTRYPOINT exec_entry p1_entry

ENTRYPOINT [“exec_entry”, “p1_entry”]

No CMD

error, not allowed

/bin/sh -c exec_entry p1_entry

exec_entry p1_entry

CMD [“exec_cmd”, “p1_cmd”]

exec_cmd p1_cmd

/bin/sh -c exec_entry p1_entry

exec_entry p1_entry exec_cmd p1_cmd

CMD [“p1_cmd”, “p2_cmd”]

p1_cmd p2_cmd

/bin/sh -c exec_entry p1_entry

exec_entry p1_entry p1_cmd p2_cmd

CMD exec_cmd p1_cmd

/bin/sh -c exec_cmd p1_cmd

/bin/sh -c exec_entry p1_entry

exec_entry p1_entry /bin/sh -c exec_cmd p1_cmd

VOLUME

VOLUME指令相当于创建一个挂载点,保存数据到容器挂载的这个文件夹。指令格式:

VOLUME ["/data"]

参数可以是个Json串,

VOLUME ["/var/log/"]

或者一个或多个值

VOLUME /var/log
VOLUME /var/log /var/db

当容器中的数据需要持久化的时候需要使用这个命令。

USER

设置启动容器的用户名(或者UID)和用户组(或者GID)来运行Dockerfile里面RUN, CMD and ENTRYPOINT 指令。指令格式:

USER <user>[:<group>]


USER <UID>[:<GID>]

WORKDIR

WORKDIR指令设置RUN, CMD, ENTRYPOINT, COPYADD指令的工作目录,如果设置的工作目录不存在会自动创建。指令格式:

WORKDIR /path/to/workdir

WORKDIR指令可以设置多次,下面例子的pwd命令执行结果是 /a/b/c

WORKDIR /a
WORKDIR b
WORKDIR c
RUN pwd

WORKDIR指令还可以解析ENV指令设置的环境变量,下面例子pwd命令执行结果是/path/$DIRNAME

ENV DIRPATH /path
WORKDIR $DIRPATH/$DIRNAME
RUN pwd

ARG

ARG指令设置变量,指令格式:

ARG <name>[=<default value>]

在docker build创建镜像的时候,使用 --build-arg <varname>=<value>来指定参数,如果用户在build镜像时指定了一个参数没有定义在Dockerfile种,那么将有一个Warning

[Warning] One or more build-args [foo] were not consumed.

一个Dockerfile文件中可以有一个或者多个ARG定义的变量,如下的例子ARG定义的参数都是可用的

FROM busybox
ARG user1
ARG buildno
···

也可以给变量设置一个默认值

FROM busybox
ARG user1=someuser
ARG buildno=1
···

ONBUILD

当一个Dockerfile文件中使用了ONBUILD指令,生成了镜像A,这个镜像A中是不执行ONBUILD指令的内容的,但是如果镜像B是以镜像A作为基础镜像时,镜像B中就会执行这个ONBUILD指令。指令格式:

ONBUILD [INSTRUCTION]

STOPSIGNAL

STOPSIGNAL命令是的作用是当容器退出时给系统发送什么样的指令。指令格式:

STOPSIGNAL signal

HEALTHCHECK

指令格式:

HEALTHCHECK [OPTIONS] CMD command (通过在容器内运行命令检查容器健康状况)


HEALTHCHECK NONE (在基础镜像中取消健康检查)

HEALTHCHECK命令只能出现一次,如果出现了多次,只有最后一个生效。 CMD后面可以接以下选项:

  • –interval=DURATION (default: 30s)
  • –timeout=DURATION (default: 30s)
  • –start-period=DURATION (default: 0s)
  • –retries=N (default: 3)

返回值:

  • 0: success - 表示容器是健康的
  • 1: unhealthy - 表示容器已经不能工作了
  • 2: reserved - 保留值

如下例子:健康检查命令是:curl -f http://localhost/ || exit 1;两次检查的间隔时间是5秒;命令超时时间为3秒。

HEALTHCHECK --interval=5m --timeout=3s CMD curl -f http://localhost/ || exit 1

SHELL

指令格式:

SHELL ["executable", "parameters"]

SHELL指令允许覆盖用于shell形式的命令的默认shell 。Linux上的默认shell是["/bin/sh", “-c”],而在Windows上[“cmd”, “/S”, “/C”]。 SHELL指令必须以JSON格式写入Dockerfile; SHELL指令可以多次出现。每条SHELL指令都会覆盖所有先前的SHELL指令,并影响所有后续指令。