Dockerfile 指令详解¶
FROM¶
Docker hub 中 99% 镜像都是从 FROM scratch 为基础构建的
必需指令:一个有效的 Dockerfile 必须以 FROM 指令开头(唯一例外是 ARG 可以出现在它之前)。
多次使用:一个 Dockerfile 中可以出现多个 FROM 指令,用于创建多个镜像或实现多阶段构建。
语法格式¶
FROM 指令有三种基本格式:
FROM [--platform=<platform>] <image> [AS <name>]FROM [--platform=<platform>] <image>[:<tag>] [AS <name>](最常见)FROM [--platform=<platform>] <image>[@<digest>] [AS <name>]
参数解释:
<image>: (必需) 指定基础镜像的名称。可以是官方镜像(如 ubuntu)、私有仓库镜像(如my-registry.com/app)或本地镜像。[:<tag>]: (可选) 指定镜像的标签。如果省略,构建器默认使用:latest标签。- 示例:
FROM alpine:3.18
- 示例:
[@<digest>]: (可选) 使用镜像的摘要(Digest)来指定一个绝对固定的版本,这比标签更精确。- 示例:
FROM alpine@sha256:...(一长串哈希值)
- 示例:
[AS <name>]: (可选) 为当前构建阶段命名。这个名字可以在后续的多阶段构建中被其他指令(如COPY --from=<name>)引用。- 示例:
FROM node:18 AS builder-stage
- 示例:
选项(Flag):
[--platform=<platform>]: (可选) 当引用的基础镜像是多平台镜像(如官方 python 镜像同时支持 linux/amd64 和 linux/arm64)时,使用此选项来强制指定构建平台。
- 示例:
FROM --platform=linux/arm64 alpine - 常与全局构建参数一起使用,例如
--platform=$BUILDPLATFORM或--platform=$TARGETPLATFORM。
与 ARG 指令的交互¶
这是 FROM 指令的一个复杂但强大的特性。
-
在 FROM 之前声明的 ARG:这些 ARG 位于==构建阶段之外==,只能在 FROM 指令本身中使用
-
在阶段内使用外部 ARG 的默认值:如果需要在阶段内部使用之前声明的 ARG 的默认值,需要在阶段内重新声明一个同名的 ARG(可以不带值)
RUN¶
两种形式¶
1. Shell 形式(最常用)¶
RUN <command> ...
- 命令在
shell(默认/bin/sh -c)中执行。 -
支持使用
\换行和 Heredoc 语法来编写多行命令。
2. Exec 形式¶
RUN ["executable", "param1", "param2"]
- 直接执行命令,不调用 shell。
- 注意:不会自动进行环境变量替换。需要变量替换时,应显式调用 shell:
RUN ["sh", "-c", "echo $HOME"]。
主要选项 (--mount)¶
-
type=cache - 缓存目录(用于加速构建)¶
用途:为包管理器(apt, npm, go mod)等创建缓存目录,内容在多次构建间持久化。
| Docker | |
|---|---|
id:可选缓存标识符,用于识别不同的缓存,默认为target路径。target,dst,destination:挂载路径ro,readonly:设置为只读sharing:默认共享模式。可以被多个写入器使用。locked暂停第二写入器,确保并发构建顺序访问缓存;private为每个构建创建独立缓存。from:要用作缓存挂载基础的构建阶段、上下文或映像名称。默认为空目录source:from挂载的子路径,默认为根目录mode:新缓存目录的文件模式为八进制,默认0755uid:缓存目录用户ID,默认0gid:缓存目录组ID,默认0
-
type=bind - 绑定挂载(从其他阶段或上下文复制文件¶
用途:将文件或目录从构建上下文或其他构建阶段挂载到当前指令中
| Docker | |
|---|---|
target,dst,destination:挂载路径source:from中的源路径。默认为from的根目录from:源代码根的构建阶段、上下文或映像名称。默认为构建上下文rw,readwrite:允许在挂载上写。写入的数据将被丢弃
-
type=secret - 挂载敏感信息¶
用途:在构建时安全地访问密码、密钥等,避免将其固化到最终镜像中
| Docker | |
|---|---|
构建时需传递密钥:docker build --secret id=my_key,src=./id_rsa
-
type=ssh - 挂载 SSH 代理¶
用途:在构建过程中使用 SSH 密钥(例如克隆私有仓库)
构建时需传递 SSH agent:docker build --ssh default=$SSH_AUTH_SOCK .
建议¶
- 绝大多数情况下,使用 Shell 形式 和
--mount=type=cache就足以应对大多数场景。 - 使用
secret和ssh来安全地处理敏感信息。 - 使用
--network=none来创建可复现的、隔离的构建环境
CMD¶
作用:指定从镜像启动容器时默认执行的命令。在构建阶段 (docker build) 不执行。
语法形式¶
Exec 形式(推荐)¶
CMD ["executable", "param1", "param2"]
Exec 形式(作为 ENTRYPOINT 的参数)¶
CMD ["param1", "param2"] # 必须与 ENTRYPOINT 搭配使用
Shell 形式¶
CMD command param1 param2
关键特性¶
- 唯一性:一个 Dockerfile 中只能有一个生效的 CMD 指令,最后一个会覆盖之前的。
- 默认值:CMD 提供的是容器的默认命令和参数。
- 覆盖性:用户在执行
docker run [IMAGE] [NEW_COMMAND]时,[NEW_COMMAND]会完全覆盖 Dockerfile 中的 CMD。 - 与 ENTRYPOINT 的关系:
- ENTRYPOINT 定义固定的可执行文件。
- CMD 定义传递给 ENTRYPOINT 的默认参数。
- 两者结合时,应都使用 Exec 形式。
- docker run 传入的参数会覆盖 CMD 的内容,但不会覆盖 ENTRYPOINT
示例¶
| Docker | |
|---|---|
LABEL¶
作用:为镜像添加键值对形式的元数据(如作者、版本、描述等)
语法¶
LABEL <key>=<value> [<key>=<value> ...]
关键特性¶
- 多标签:一个镜像可以有多个标签。可以在一个指令中写多个,也可以用多个指令。
- 换行:值中包含空格或需要换行时,使用引号和反斜杠
\。 - 继承与覆盖:基础镜像的标签会被继承。如果标签键重复,后设置的值会覆盖先前的值。
- 查看:使用
docker image inspect --format='{{json .Config.Labels}}' [IMAGE]查看所有标签。
示例¶
EXPOSE¶
作用:声明容器在运行时将监听哪些网络端口和协议(TCP/UDP)。它本身并不发布端口
EXPOSE <port>[/<protocol>] [<port>[/<protocol>]...] # 协议默认为 tcp
关键特性¶
- 文档功能:它主要作为镜像作者和使用者之间的文档说明,告知哪些端口需要被映射。
- 自动映射:使用
docker run -P时,Docker 会自动随机映射所有 EXPOSE 声明的端口到主机的高端口。 - 手动映射:使用
docker run -p <host-port>:<container-port>/<protocol>可以手动指定映射。 - 协议:可以指定 tcp 或 udp。如需同时监听,必须声明两次。
示例¶
| Docker | |
|---|---|
ENV¶
作用:设置环境变量,该变量在构建阶段和最终的容器运行时都有效。
语法(推荐)¶
ENV <key>=<value> [<key>=<value> ...]
关键特性¶
- 持久化:使用 ENV 设置的环境变量会被持久化到最终的镜像中,容器运行时也能看到。
- 作用范围:在构建阶段,它对其后所有指令都有效。在运行时,所有从该镜像启动的容器内部都存在这些变量。
- 值中的空格:如果值包含空格,需要用引号括起或用反斜杠
\转义。 - 查看与覆盖:使用
docker inspect查看;使用docker run --env <key>=<value>在运行时覆盖。 - 潜在问题:滥用 ENV 可能导致镜像包含不必要的或敏感的环境变量(如
DEBIAN_FRONTEND=noninteractive)。
替代方案¶
如果环境变量仅在构建阶段需要,不应保留到最终镜像中,应使用:
单条命令前设置:
RUN DEBIAN_FRONTEND=noninteractive apt-get update && apt-get install -y ...
使用 ARG 指令(不会持久化到镜像):
示例¶
| Docker | |
|---|---|
ADD¶
基本语法¶
可用选项¶
--keep-git-dir(v1.1+) - 保留 Git 目录--checksum(v1.6+) - 验证远程资源校验码--chown- 设置文件所有权--chmod(v1.2+) - 设置文件权限--link(v1.4+) - 创建硬链接--exclude(v1.7-labs) - 排除特定文件
功能说明¶
ADD 指令从 <src> 复制文件/目录到镜像文件系统的 <dest> 路径,支持:
- 构建上下文中的本地文件
- 远程 URL
- Git 仓库
源类型处理¶
- 本地文件/目录:内容复制到目标位置
- 本地 tar 归档:自动解压到目标位置
- 远程 URL:下载文件到目标位置
- Git 仓库:克隆到目标位置
示例¶
目标路径规则¶
- 以
/开头:绝对路径 - 不以
/开头:相对于工作目录 - 尾随斜线影响行为:
ADD file /dir:将file放在/目录命名为dirADD file /dir/:结果则是/dir/file
注意事项¶
- 通过 stdin 传递 Dockerfile 时无构建上下文
- URL 文件不支持身份验证
- Git 仓库需可从构建上下文访问
- 使用 SSH 密钥需通过
--ssh标志传递
COPY¶
基本语法¶
可用选项¶
-
--from- 从构建阶段、命名上下文或镜像复制 -
--chown- 设置文件所有权 -
--chmod(v1.2+) - 设置文件权限 -
--link(v1.4+) - 创建硬链接优化层缓存COPY --link /foo /bar优势:
- 层独立性:文件保持在自己的独立层
- 缓存重用:前层变更不影响COPY层
- 性能提升:支持直接推送到注册表而不拉取基础层
-
--parents(v1.7-labs) - 保留源文件父目录结构 -
--exclude(v1.7-labs) - 排除特定文件Docker 满足 Go 的 filepath.Match 规则
功能说明¶
COPY 指令从 <src> 复制文件/目录到镜像文件系统的 <dest> 路径,支持:
- 构建上下文中的本地文件
- 构建阶段(多阶段构建)
- 命名上下文
- 其他镜像
示例¶
| Docker | |
|---|---|
目标路径规则¶
-
以
/开头:绝对路径 -
不以
/开头:相对于工作目录 -
尾随斜线影响行为:
ADD file /dir:将file放在/目录命名为dirADD file /dir/:结果则是/dir/file
注意事项¶
- 无构建上下文时:通过stdin传递Dockerfile时,只能使用
--from选项 - 权限默认值:从Git仓库复制的文件权限为644,可执行文件为755
- Linux专用:
--chown和--chmod仅适用于Linux容器 - 冲突处理:目录复制会合并内容,文件冲突时以源文件为准
最佳实践¶
- 明确指定目标路径的尾随斜线以避免混淆
- 在多阶段构建中使用
--from减少最终镜像大小 - 考虑使用
--link优化构建缓存和层管理 - 使用
--chown和--chmod确保正确的文件权限 - 不需要ADD的特殊功能(自动解压、远程URL下载)时优先使用COPY
ENTRYPOINT¶
ENTRYPOINT 允许将容器配置为可执行文件,定义容器启动时运行的主命令
基本语法形式¶
1. Exec 形式(推荐)¶
ENTRYPOINT ["executable", "param1", "param2"]
2. Shell 形式¶
ENTRYPOINT command param1 param2
关键特性¶
命令行参数处理¶
- Exec 形式:
docker run <image>的参数会追加到 ENTRYPOINT 参数后面 - Shell 形式:会忽略 CMD 和
docker run的命令行参数
信号处理¶
- Exec 形式: executable 作为 PID 1,能正确接收 Unix 信号(如 SIGTERM)
- Shell 形式: executable 作为
/bin/sh -c的子命令,无法接收信号
覆盖规则¶
- 只有最后一个 ENTRYPOINT 指令生效
- 可以使用
docker run --entrypoint标志覆盖 ENTRYPOINT
Exec 形式示例¶
| Docker | |
|---|---|
Shell 形式正确用法¶
ENTRYPOINT 与 CMD 交互规则¶
| ENTRYPOINT | CMD | 最终执行的命令 |
|---|---|---|
| 未设置 | 未设置 | 错误,不允许 |
| 未设置 | CMD ["exec_cmd", "p1_cmd"] |
exec_cmd p1_cmd |
| 未设置 | CMD exec_cmd p1_cmd |
/bin/sh -c exec_cmd p1_cmd |
ENTRYPOINT exec_entry p1_entry |
未设置 |
/bin/sh -c exec_entry p1_entry |
ENTRYPOINT exec_entry p1_entry |
CMD ["exec_cmd", "p1_cmd"] |
/bin/sh -c exec_entry p1_entry |
ENTRYPOINT exec_entry p1_entry |
CMD exec_cmd p1_cmd |
/bin/sh -c exec_entry p1_entry |
ENTRYPOINT ["exec_entry", "p1_entry"] |
未设置 |
exec_entry p1_entry |
ENTRYPOINT ["exec_entry", "p1_entry"] |
CMD ["exec_cmd", "p1_cmd"] |
exec_entry p1_entry exec_cmd p1_cmd |
ENTRYPOINT ["exec_entry", "p1_entry"] |
CMD exec_cmd p1_cmd |
exec_entry p1_entry /bin/sh -c exec_cmd p1_cmd |
重要注意事项¶
- 至少指定一个:Dockerfile 应至少指定 CMD 或 ENTRYPOINT 中的一个
- 可执行容器:ENTRYPOINT 应在将容器用作可执行文件时定义
- 默认参数:CMD 应为 ENTRYPOINT 命令定义默认参数
- 基础镜像覆盖:设置 ENTRYPOINT 会重置来自基础镜像的 CMD
最佳实践¶
- 优先使用 Exec 形式:确保正确的信号处理
- 使用 exec 命令:在 shell 脚本中确保进程替换和信号传递
- 明确分工:
ENTRYPOINT:定义主命令CMD:定义默认参数
- 测试信号处理:确保
docker stop能正常停止容器
VOLUME¶
基本语法¶
重要注意事项¶
-
Windows容器:卷目标必须是:
- 不存在或空的目录
- 非C:驱动器
-
BuildKit差异:
- 传统构建器:VOLUME声明后的数据变更会被丢弃
- BuildKit:保留数据变更
-
JSON格式:必须使用双引号
- 主机目录:不能在Dockerfile中指定主机目录,必须在运行时指定
USER¶
基本语法¶
功能说明¶
- 设置当前阶段后续指令的默认用户和组
- 用于RUN指令和运行时(
ENTRYPOINT、CMD)
注意事项¶
- 如果用户没有主组,将使用root组运行
- Windows必须先创建非内置账户
WORKDIR¶
基本语法¶
WORKDIR /path/to/workdir
功能说明¶
- 设置后续
RUN、CMD、ENTRYPOINT、COPY、ADD指令的工作目录 - 如果目录不存在会自动创建
- 支持多次使用,路径会相对累积
示例¶
| Docker | |
|---|---|
最佳实践¶
- 始终明确设置WORKDIR,避免在未知目录中操作
ARG¶
基本语法¶
ARG <name>[=<default value>]
功能说明
- 定义构建时用户可传递的变量
- 通过
docker build --build-arg <varname>=<value>传递
示例¶
作用域规则¶
- 从声明行开始生效
- 在多个阶段使用时,每个阶段都需要重新声明
- 环境变量(ENV)会覆盖同名的ARG变量
预定义的ARG变量¶
代理相关(自动排除在history外):
平台相关ARG变量(BuildKit)¶
| Bash | |
|---|---|
BuildKit内置构建参数¶
| Bash | |
|---|---|
缓存影响¶
- ARG变量不会持久化到镜像中
- 改变ARG值会导致缓存失效(在第一次使用时)
- 预定义ARG变量免缓存,除非在Dockerfile中声明
安全警告¶
不要使用ARG传递敏感信息(密码、API令牌等),因为它们会出现在:
docker history输出中- 公开仓库的溯源证明中
使用 RUN --mount=type=secret 安全地处理秘密信息。
ONBUILD¶
功能说明¶
ONBUILD 指令添加一个触发器指令,在当前镜像作为其他构建的基础时执行。触发器在下游构建的上下文中执行,就像插入在下游 Dockerfile 的 FROM 指令之后
使用场景¶
- 构建作为其他镜像基础的可重用镜像
- 应用构建环境或可定制的守护进程
示例¶
| Docker | |
|---|---|
限制¶
- 不允许链式
ONBUILD ONBUILD - 不能触发
FROM或MAINTAINER指令 - 触发器执行后会被清除,不会继承到"孙子"构建
STOPSIGNAL¶
语法¶
STOPSIGNAL signal
功能说明¶
设置发送给容器以退出的系统调用信号,可以是信号名(如 SIGKILL )或数字(如 9 )。默认为 SIGTERM。
示例¶
运行时覆盖¶
docker run --stop-signal SIGKILL myimage
HEALTHCHECK¶
语法形式¶
选项参数¶
| Bash | |
|---|---|
退出状态码¶
0: 成功 - 容器健康1: 失败 - 容器不健康2: 保留 - 不要使用
示例¶
| Docker | |
|---|---|
调试信息¶
健康检查命令的输出(stdout/stderr)会存储在健康状态中,可通过 docker inspect 查询(最多存储4096字节)
SHELL¶
语法¶
SHELL ["executable", "parameters"]
默认值¶
- Linux:
["/bin/sh", "-c"] - Windows:
["cmd", "/S", "/C"]
示例¶
| Docker | |
|---|---|
影响范围¶
影响后续使用shell形式的指令:
RUNCMDENTRYPOINT
Here-Documents¶
多行文本输入
基本语法¶
示例¶
| Docker | |
|---|---|
COPY指令中使用¶
变量扩展规则¶
- 默认:构建时扩展变量
- 使用引号分隔符:运行时扩展变量
- 支持制表符去除(使用
<<-)