jimyag's Blog

Dockerfile 关键字以及部分关键字的区别

本文基于 Docker 官方 Dockerfile 参考 整理所有关键字,并说明几组容易混淆的指令之间的区别。

指令一览

Dockerfile 支持以下指令(按字母序):

指令说明
ADD添加本地或远程文件、目录(含 URL、压缩包自动解压)
ARG声明构建期变量
CMD指定容器默认要运行的命令或参数
COPY从构建上下文复制文件、目录到镜像
ENTRYPOINT指定容器默认的可执行程序
ENV设置环境变量(写入镜像,运行时可用)
EXPOSE声明容器监听的端口
FROM从基础镜像开始新的构建阶段
HEALTHCHECK配置容器健康检查
LABEL为镜像添加元数据
MAINTAINER指定镜像作者(已废弃,建议用 LABEL)
ONBUILD当本镜像被作为基础镜像使用时触发的指令
RUN在构建时执行命令,产生新层
SHELL设置 RUN、CMD、ENTRYPOINT 使用的默认 shell
STOPSIGNAL设置容器退出时发送的系统信号
USER设置后续指令及运行时的用户/组
VOLUME声明挂载点
WORKDIR设置工作目录

约定上指令用大写,便于与参数区分;指令本身不区分大小写。Dockerfile 必须由 FROM 开头(前面只能有解析器指令、注释和全局 ARG),指令按顺序执行。

解析器指令(Parser directives)

解析器指令写在文件最上方,形式为 # directive=value,不参与构建层。每条指令只能出现一次,且必须出现在任何普通注释或构建指令之前。

  • syntax:指定使用的 Dockerfile 语法版本,例如 # syntax=docker/dockerfile:1 使用最新稳定语法。
  • escape:设置转义符,默认 \;在 Windows 下可设为 ` 避免与路径中的 \ 冲突。
  • check:控制构建检查行为,如 # check=skip=JSONArgsRecommended 跳过指定检查,# check=error=true 让检查失败时构建失败。

Shell 形式与 Exec 形式

RUNCMDENTRYPOINT 都有两种写法:

  • Shell 形式:INSTRUCTION command param1 param2,通过 shell 执行,支持变量替换、多行续行等。
  • Exec 形式:INSTRUCTION ["executable","param1","param2"],按 JSON 数组解析,直接执行可执行文件,不经过 shell,因此不会自动做变量替换(若需要可显式写 ["sh","-c","echo $HOME"])。

Exec 形式中需用双引号,且反斜杠要转义(Windows 路径需写 \\)。

部分关键字的区别

ADD 和 COPY

  • ADD:源可以是「构建上下文中的路径」或「URL」;若源是本地 tar 等归档,会自动解压到目标;行为较多,语义相对复杂。ADD 不支持 --from
  • COPY:只从构建上下文复制本地文件/目录,不解压、不拉 URL;支持 COPY --from=<阶段名|镜像>,可从命名构建阶段或外部镜像复制,多阶段构建时常用。语义单一,可预期性更好。

需要从构建上下文复制文件时,优先用 COPY;要从上一阶段或其它镜像复制时只能用 COPY –from=…;只有需要 URL 或自动解压归档时再用 ADD。

CMD 和 ENTRYPOINT

  • CMD:定义容器默认的「命令或参数」。若 Dockerfile 中有多条 CMD,仅最后一条生效。docker run 末尾若带了参数,会覆盖整条 CMD。
  • ENTRYPOINT:定义容器启动时「固定执行的可执行程序」。docker run 末尾的参数会作为参数传给 ENTRYPOINT,而不是替换 ENTRYPOINT。

常见用法:用 ENTRYPOINT 指定程序(如 ENTRYPOINT ["/app/server"]),用 CMD 提供默认参数(如 CMD ["--port","8080"]);运行时可覆盖 CMD,而 ENTRYPOINT 一般不变(除非用 --entrypoint)。

ARG 和 ENV

  • ARG:仅构建期有效,用于 docker build 时传入或 Dockerfile 内默认值;不会写入最终镜像,容器运行时无法使用。
  • ENV:在构建期和运行期都有效,会写入镜像;容器内可通过环境变量访问。

FROM 之前的 ARG 只能用于 FROM 的镜像名/标签等;若要在阶段内再次使用该 ARG 的默认值,需在阶段内再写一行不带值的 ARG 变量名

环境变量替换

在 Dockerfile 中可用 $var${var} 引用已通过 ENV 定义的变量;部分指令(如 WORKDIRCOPYADDENVEXPOSE 等)由构建器做替换。RUNCMDENTRYPOINT 若用 shell 形式,变量替换由 shell 完成;若用 exec 形式且未通过 shell,则不会做变量替换。

.dockerignore

.gitignore 类似,.dockerignore 可排除构建上下文中不需要的文件,减小上下文体积并避免敏感文件被 COPY/ADD 进镜像。

参考链接:

#Docker #Dockerfile