Dockerfile文件指令

    Dockerfile 文件类似于一个配置文件,Docker 可以通过读取其中的指令来自动构建镜像,官网地址: https://docs.docker.com/engine/reference/builder/。   
    Dockerfile的内容格式如下:
        # comment
        # INSTRUCTION arguments
    虽然 Dockerfile 并不区分大小写,不过按照惯例,一般指令都大写,以与参数部分区分。
    类似于 shell 脚本开头中的“#!/bin/bash”写法,Dockerfile 开头也可有相应的解析指令,其格式如下:
        # directive=value   (注:不允许跨行)
    目前官网上列出的解析指令仅有“escape”,是用来自定义转义字符的,默认是“\”。
    下面开始介绍 Dockerfile 文件中各个指令的用法。
    * FROM
    格式:
        FROM image[:tag] 或者 FROM image@digest
    关于 FROM 指令,需要注意以下几点:
    (1) FROM 为随后的指令设置了一个基础镜像,所以必须在 Dockerfile 的第一个非注释行。
    (2) FROM 可以出现多次,以便创建多个镜像。
    (3) 当忽略掉 tag 或 digest 时,默认会以 latest 来代替。
    * RUN
    RUN 指令可用来在当前镜像中执行任意命令,并把执行结果传给 Dockerfile 中的下一步。RUN 指令的格式为:
        RUN command  或者  RUN ["executable", "param1", "param2"]
    其中,前一种属于“shell”形式,运行命令的 shell 在 Linux 上默认是“/bin/sh -c”,在 Windows 上默认是“cmd /S /C”。运行 shell 是可以通过命令改变的,比如:
        RUN /bin/bash -c 'echo $HOME'
    后一种属于“exec”形式(它会被解析成 JSON 数组,所以必须用双引号),它可以避免整理 shell 字符串,使用了一个没有包含指定运行 shell 的基础镜像来运行命令。它也可以通过类似下面的命令来使用不同的运行 shell:
        RUN ["/bin/bash", "-c", "echo $HOME"]
    另外,在“exec”形式中是不会调用命令 shell 的,所以运行 RUN ["echo", "$HOME"]不会对 $HOME 进行变量替换(除非使用类似 RUN ["sh", "-c", "echo $HOME"] 来直接执行shell),因为执行环境变量扩展是 shell 而非 docker 的工作。除此之外,对反斜杠“\”进行转移也是必须的,尤其是在 Windows 类系统上。
    RUN 的缓存不会自动失效,除非使用了类似“docker build --no-cache”的命令或使用了 ADD 指令(见下面 ADD 指令部分)。
    * CMD
    CMD 指令设置了启动镜像后默认要运行的命令,它有以下三种形式:
        CMD ["executable", "param1", "param2"]     # exec 形式,推荐
        CMD ["param1", "param2"]         # 默认作为 ENTRYPOINT 指令的参数
        CMD command param1 param2        # shell 形式
    在一个 Dockerfile 文件中只能有一个 CMD 指令。如果有多个,则只有最后一个生效。
    如果用户在运行“docker run”命令时含有参数,则会覆盖掉 CMD 设置的默认对应参数。
    * LABEL
    LABEL 指令可以为一个镜像创建元数据信息。其格式为:
        LABEL key1=value1 key2=value2 ...
    其中,当 key 或 value 中含有空格时,应该用引号引起来。另外,LABEL 也支持使用转义符来进行跨行定义。
    * EXPOSE
    EXPOSE 指令用于向 Docker 表明容器运行时要监听的网络端口。其格式为:
        EXPOSE port [port ...]
    注意,外部主机是无法访问容器中的端口的,必须使用“docker run”命令的“-p”或“-P”来指定映射端口。
    * ENV
    该指令可用来设置环境变量。格式为:
        ENV key value
        ENV key=value ...
    当一个容器在镜像中运行时,它的环境变量就会一直存在。用户可以使用命令“docker inspect”来查看环境变量信息,还可使用“docker run --env key=value”来修改。然而,变量持续存在也会带来一些副作用。比如,在 Debian 类的基镜像中使用设置“ENV DEBIAN_FRONTEND noninteractive”就可能造成“apt-get”命令的混乱。要为单个命令设置值,可以使用“RUN key=value command”的形式。
    * ADD
    ADD 指令可用于复制本地或远程的文件或目录(包括元数据)到镜像中。格式如下:
        ADD src1 src2 ... dest
        ADD ["src1", ..., "dest"]    # 路径中含有空格时
    当指定多个 src(包括含有通配符的情况) 时,必须相对于要构建的上下文原目录。
    dest 是一个绝对路径或是相对于 WORKDIR 的路径。所有新创建的文件的 UID 和 GID 都是 0。当 src 是一个远程地址时,目标文件的权限将会为 600。
    如果镜像是通过传递 Dockerfile 文件给标准输入中“docker build”命令构建而成,此种情况是没有构建上下文的,这就要求 Dockerfile 中只能含有一个 URL 类的 ADD 指令。另外,也可传递压缩文件给“docker build”,不过要求 Dockerfile 位于压缩包中的根目录下,然后剩余的内容就会被当作构建的上下文。
    ADD 指令不支持文件权限认证,所以当远程文件受权限保护时,应先用“RUN wget”或者“RUN curl”之类的工具认证掉相应的权限。
    当 src 的内容变动时,第一个解析到的 ADD 指令会使随后指令的缓存失效,其中就包括了 RUN 指令。
    另外,ADD 遵循下面这些规则:
    (1) src 路径要在要构建的上下文中,不能使用类似于“ADD ../something dest”的写法,因为“docker build”的第一步就是发送构建上下文目录给 docker 后台进程。
    (2) 如果 src 是一个远程地址,并且 dest 没有以“/”结尾,那么远程文件就会先被下下来,然后再复制到 dest;否则就直接复制到 dest 目录下。
    (3) 当 src 是本地压缩文件时,复制之前会先被解压,而远程压缩文件则不会。
    (4) 如果 src 是一个其它类型的文件,它就会与它的元数据一起被单独复制。此时,如果 dest 以“/”结尾,它就会被当成是目录,然后把 src 的内容写到 dest/base(src) 中。
    (5) 当指定多个 src (包括使用通配符的情况)时,dest 必须是已“/”结尾的目录。
    (6) 如果 dest 没有以“/”结尾,那它就会被当成是普通文件,然后 src 的内容就会直接写到 dest 中。
    (7) 当 dest 不存在时,它就会被递归创建。
    * COPY
    格式:
        COPY src1 src2 ... dest
        COPY ["src1", ..., "dest"]        # 路径中含有空格时
    COPY 和 ADD 都可以复制 src 的内容到 dest,区别是 COPY 不能复制远程文件,然后其余的规则和限制都一样。
    * ENTRYPOINT
    ENTRYPOINT 可将容器配置成可执行文件的形式。格式如下:
        ENTRYPOINT ["executable", "param1", "param2"]   # exec 形式,推荐
        ENTRYPOINT command param1 param2       # shell 形式
    “docker run image”后的命令行参数会被添加到“exec”形式的 ENTRYPOINT 中,并且会覆盖掉所有 CMD 指定的参数。比如,“docker run image -d”就会把“-d”传给ENTRYPOINT。可以使用“docker run --entrypoint”来覆盖 ENTRYPOINT 指令。
    ENTRYPOINT 的“shell”形式会阻止 CMD 和 run 命令行参数的执行,但缺点是会被当成“/bin/sh -c”的子命令,这就意味着容器的 PID 1 将不是该可执行文件,并且也不能接收 UNIX 信号,因此也就不能接收到来自“docker stop container”的 SIGTERM 信号(但 stop 会在超时后被迫发送一个 SIGKILL 信号来强制停止)。要想它能正确处理信号和作为 PID 1,需要在命令前加上“exec”,比如,“ENTRYPOINT exec top -b”。
    另外,也只有最后一个 ENTRYPOINT 会生效。
    ENTRYPOINT 和 CMD 都定义了容器运行时要执行的命令,它们的相互关系如下:
    (1) Dockerfile 至少要指定一个 CMD 或 ENTRYPOINT。
    (2) 当要把容器当成可执行文件时,应该定义 ENTRYPOINT。
    (3) CMD 应该用来为 ENTRYPOINT 定义额外的默认参数,或要在容器中执行即席命令时使用。
    (4) CMD 会被运行容器时指定的替代参数覆盖。
    下表显示了指定不同的 ENTRYPOINT 和 CMD 组合时实际执行的命令情况:

    * VOLUME
    该指令可用来创建具有指定名字的挂载点,还可用来保存本地主机或其它容器的外部挂载卷。格式为:
        VOLUME ["/data", ...]
        VOLUME /data ...
    “docker run”命令会初始化新创建的挂载点,并保留解析到 VOLUME 之前已存在或生成的数据。
    关于 VOLUME 需要注意以下几点:
    (1) 当使用 Windows 类容器时,挂载点必须是 a) 不存在或者空目录 b) 不为系统驱动盘 C: 的驱动盘 两者之一。
    (2) 在挂载点被声明后又被随后的构建步骤改变的数据不会生效。
    (3) 挂载点与主机相关,是在容器运行时声明的。这是为了保持镜像的可移植性,因为一个给定的主机在别的主机上不一定可用。因此,不能在 Dockerfile 中挂载一个主机目录(即挂载点)。VOLUME 也不支持指定一个 host-dir 参数,你必须在创建或运行容器时指定挂载点。
    * USER
    该指令可用来设置运行镜像和执行随后的 RUN、CMD 及 ENTRYPOINT 等指令时的用户名和UID。格式为:
        USER daemon
    * WORKDIR
    该指令可为随后执行的 RUN 和 CMD 等命令设置工作目录(不存在则创建)。格式为:
        WORKDIR /path/to/workdir
    WORKDIR 可以指定多次,如果其中含有相对路径,则是相对于其上一个 WORKDIR 而言的。另外,WORKDIR 只能处理使用 ENV 明确设置的环境变量。
    * ARG
    ARG 指令定义了“docker build --build-arg varname=value”需要的变量,同时该选项设置的值又会反过来影响 Dockerfile 中的 ARG 定义的对应变量的值。格式为:
        ARG varname[=defaultValue]
    ARG 指令可被使用多次,以定义多个变量。
    注意,应该避免使用该指令与“--build-arg”来合作接收敏感信息,因为任意该镜像的用户都可使用“docker history”命令来查看所有构建时的变量值。
    ARG 和 ENV 指令定义的变量都可被 RUN 指令使用。ENV 定义的环境变量会覆盖掉之前 ARG定义的同名变量的值(包括“--build-arg”传进来的命令行参数值)。两者结合可产生有用的交互,比如下面这个 Dockerfile 文件:
FROM ubuntu
ARG CONT_IMG_VAR
ENV CONT_IMG_VAR ${CONT_IMG_VAR:-v1.0.0}
RUN echo $CONT_IMG_VAR

    不同于 ARG,ENV 定义的变量是持久化的,因此可像上面这个例子一样使用 ENV 来长期保存 ARG 接收到的命令行参数到最终镜像中。
    Docker 中已经预定义了以下这些 ARG 变量(包括它们的大写形式):
        http_proxy, https_proxy, ftp_proxy, no_proxy
    虽然 ARG 变量不能持久化,但如果跟以前构建时使用的值不一样时,也还是会影响构建缓存的。
    * ONBUILD
    ONBUILD 指令可为一个镜像添加触发器指令,当把该镜像作为另一构建过程的基时,就会执行这些触发器指令。格式为:
        ONBUILD INSTRUCTION
    ONBUILD 的工作方式是这样的:
    (1) 当解析到 ONBUILD 指令时,构建器就把这个触发器指令添加到当前正在构建的镜像的元数据中,而并不影响当前的构建过程。
    (2) 在构建末尾,触发器指令列表就被存到镜像元数据清单的“OnBuild”关键字之下,可使用“docker inspect”指令查看到。
    (3) 之后,可利用 FROM 指令把该镜像当成另一构建过程的基使用。在下游的构建器处理 FROM 指令时,就会按注册顺序依次执行这些触发器指令。任意一个指令执行出错都会造成构建过程的失败。
    (4) 构建成功后,触发器就会从最终镜像中移除,因此不能被孙子辈构建过程所继承。
    示例:
[...]
ONBUILD ADD . /app/src
ONBUILD RUN /usr/local/bin/python-build --dir /app/src
[...]

    注意:使用 ONBUILD ONBUILD 来链接 ONBUILD 是不允许的,ONBUILD 指令也不会触发 FROM 和 MAINTAINER 指令。
    * STOPSIGNAL
    STOPSIGNAL 指令设置了发送给容器以让其终止的信号。格式为:
        STOPSIGNAL signalNum/signalName
    * HEALTHCHECK
    该指令可用来测试一个容器是否正在工作。格式为:
        HEALTHCHECK [options] CMD command  # 运行容器中的命令来检测容器的健康状态
        HEALTHCHECK NONE  # 禁用继承自基础镜像的 HEALTHCHECK
    其中 CMD 前的 options 选项值有:
    (1) --interval=DURATION (default: 30s)
    (2) --timeout=DURATION (default: 30s)
    (3) --retries=N (default: 3)
    它可以检测出一个运行中的 Web 服务器是否出现异常导致不能处理新的连接这类的情况。
    当一个容器指定了一个 healthcheck 后,除了正常状态外,它还有一个“健康状态”,它初始时是“starting”。不管以前处于什么状态,只要现在通过了健康检查,它就被当作是“健康的”;而如果连续多次不通过,就被当作是“不健康的”。
    在一个 Dockerfile 中,只能存在一个 HEALTHCHECK 指令。
    在 CMD 后的命令可以是“shell”形式,也可以是“exec”形式。
    该指令的退出状态表面了容器的健康状态。可能的值有:
    (1) 0:成功(容器是“健康的”,随时可用)
    (2) 1:不健康的(容器不能正确地工作)
    (3) 2:保留
    下面是一个每隔 5 分钟检测一次某 Web 服务器能否在 3 秒内正确服务主页的示例:
...
HEALTHCHECK --interval=5m --timeout=3s CMD curl -f http://localhost || exit 1
...

    为了帮助调试,任何命令输出的内容都被存到了健康状态之中,可使用“docker inspect”命令查看。
    当容器的健康状态改变时,就会产生一个带有新的状态的“health_status”事件。
    * SHELL
    该指令可用来覆盖“shell”形式的命令的默认执行 shell(Linux 上的默认 shell 是 ["/bin/sh", "-c"],Windows 上的是["cmd", "/S", "/C"])。格式为:
        SHELL ["executable", "param"]
    SHELL 指令可以出现多次。每个都会覆盖先前的 SHELL,然后被当作随后其它指令的执行 shell。示例:
FROM microsoft/windowsservercore

# Executed as cmd /S /C echo default
RUN echo default

# Executed as cmd /S /C powershell -command Write-Host default
RUN powershell -command Write-Host default

# Executed as powershell -command Write-Host hello (more efficient)
SHELL ["powershell", "-command"]
RUN Write-Host hello

# Executed as cmd /S /C echo hello (more efficient)
SHELL ["cmd", "/S"", "/C"]
RUN echo hello

    另外,SHELL 指令还可用来修改 shell 的操作方式。例如,在 Windows 上使用“SHELL cmd /S /C /V:ON|OFF”将会更改环境变量延迟扩展语法。

猜你喜欢

转载自aisxyz.iteye.com/blog/2378931