📜 详解 Dockerfile 各个指令与参数
Dockerfile
是构建镜像的核心配置文件,它由一系列 Docker 指令(Instruction) 组成。每个指令对应一个镜像层(Layer),并定义了如何打包应用、安装依赖、设置环境等操作。
本文将详细讲解每个 Dockerfile 指令的语法、参数、使用场景及最佳实践。
🧱 一、基础结构
# 注释说明
INSTRUCTION arguments
- 每条指令生成一个只读镜像层(Layer)
- 多条指令之间顺序很重要,会影响缓存和最终镜像大小
📘 二、常用指令详解
1. FROM
—— 设置基础镜像
FROM [--platform=<platform>] <image> [AS <name>]
示例:
FROM golang:1.22 AS builder
FROM alpine:3.20
参数 | 说明 |
---|---|
--platform | 指定平台架构,如 linux/amd64 , linux/arm64 |
AS <name> | 为当前阶段命名,用于多阶段构建 |
📌 注意: FROM
必须是 Dockerfile 中第一条有效指令。
2. RUN
—— 在镜像中执行命令
RUN <command>
RUN ["executable", "param1", "param2"]
示例:
RUN apt-get update && apt-get install -y curl
RUN ["go", "build", "-o", "/app"]
类型 | 说明 |
---|---|
Shell 形式 | 默认使用 /bin/sh -c 执行 |
Exec 形式 | 推荐形式,兼容性更好 |
📌 最佳实践:
- 将多个命令合并减少层数
- 清理临时文件以减小镜像体积
3. CMD
—— 容器启动默认命令
CMD ["executable","param1","param2"]
CMD command param1 param2
CMD ["param1","param2"] # 提供给 ENTRYPOINT 的默认参数
示例:
CMD ["/app"]
CMD ["nginx", "-g", "daemon off;"]
📌 注意:
CMD
可被运行时传入的命令覆盖- 一个 Dockerfile 中只能有一个有效的
CMD
4. ENTRYPOINT
—— 容器入口点
ENTRYPOINT ["executable", "param1", ...]
ENTRYPOINT command param1 ...
示例:
ENTRYPOINT ["/app"]
ENTRYPOINT ["echo", "Hello"]
CMD ["World"]
📌 区别于 CMD:
ENTRYPOINT
不会被运行时命令覆盖,除非使用--entrypoint
CMD
可作为ENTRYPOINT
的默认参数
5. COPY
—— 从主机复制文件到容器
COPY [--chown=<user>:<group>] <src>... <dest>
示例:
COPY . /app
COPY main.go /app/
COPY config/app.yaml /etc/app/
参数 | 说明 |
---|---|
--chown | 设置目标文件的拥有者(适用于 Linux 用户) |
📌 推荐用法:
- 优先使用
COPY
而不是ADD
,避免自动解压 tar 包带来的不确定性
6. ADD
—— 更强大的复制功能(慎用)
ADD [--chown=<user>:<group>] <src>... <dest>
示例:
ADD app.tar.gz /app/
ADD https://example.com/file.txt /tmp/
📌 说明:
- 支持远程 URL 下载 & 自动解压压缩包
- 一般不推荐使用,除非你确实需要自动解压功能
7. WORKDIR
—— 设置工作目录
WORKDIR /path/to/workdir
示例:
WORKDIR /app
COPY . .
RUN go build -o /app/app
📌 说明:
- 后续所有
RUN
,CMD
,COPY
等指令都在此路径下执行 - 如果目录不存在会自动创建
8. EXPOSE
—— 声明容器监听端口
EXPOSE <port>[/<proto>] [<port>[/<proto>]...]
示例:
EXPOSE 80/tcp
EXPOSE 8080/udp 8000
📌 说明:
- 仅作文档用途,不会真正打开端口
- 实际运行容器时需通过
-p
映射端口
9. ENV
—— 设置环境变量
ENV <key>=<value> ...
示例:
ENV PORT=8080
ENV DEBUG=true LOG_LEVEL=info
📌 说明:
- 可在后续指令中使用
${VAR}
替换 - 也可以通过
docker run -e KEY=VALUE
覆盖
10. ARG
—— 构建参数
ARG <name>[=<default value>]
示例:
ARG VERSION=dev
RUN echo "Build version: ${VERSION}"
构建时传递参数:
docker build --build-arg VERSION=1.0.0 -t myapp .
📌 说明:
ARG
仅在构建阶段可见- 和
ENV
不同,不会出现在最终镜像中(除非显式写入)
11. LABEL
—— 添加元数据
LABEL maintainer="[email protected]"
LABEL com.example.version="1.0"
📌 用途:
- 标注作者、版本、项目信息等
- 可用于 CI/CD 工具识别镜像来源
12. ONBUILD
—— 子镜像自动触发的指令(较少使用)
ONBUILD RUN make /app
📌 说明:
- 当当前镜像作为其他镜像的基础镜像时,这些指令会被触发执行
- 使用频率较低,但可用于构建模板镜像
13. STOPSIGNAL
—— 指定终止信号
STOPSIGNAL signal
示例:
STOPSIGNAL SIGINT
📌 说明:
- 控制容器收到
docker stop
时发送什么信号 - 默认是
SIGTERM
14. HEALTHCHECK
—— 容器健康检查
HEALTHCHECK [OPTIONS] CMD command
示例:
HEALTHCHECK --interval=5s --timeout=3s CMD curl -f http://localhost:8080/health || exit 1
参数 | 说明 |
---|---|
--interval | 检查间隔时间 |
--timeout | 单次检查超时时间 |
--start-period | 初期等待时间 |
--retries | 失败多少次判定为不健康 |
📌 作用:
- 检测服务是否可用
- 配合编排工具(如 Kubernetes)使用更佳
15. SHELL
—— 指定 Shell 解析方式
SHELL ["executable", "parameters"]
示例:
SHELL ["powershell", "-Command"]
RUN echo Hello from PowerShell
📌 说明:
- 修改默认 Shell(默认是
/bin/sh -c
) - 适用于 Windows 容器或自定义脚本环境
🧪 三、完整示例(多阶段 + distroless)
# 构建阶段
FROM golang:1.22 AS builder
ARG VERSION=dev
WORKDIR /app
COPY . .
RUN CGO_ENABLED=0 go build -ldflags "-X main.Version=${VERSION}" -o /server
# 运行阶段
FROM gcr.io/distroless/static-debian12
COPY --from=builder /server /server
EXPOSE 8080
ENV PORT=8080
CMD ["/server"]
✅ 四、最佳实践总结
实践 | 说明 |
---|---|
使用多阶段构建 | 减小镜像体积 |
使用 distroless 或 scratch | 更安全、轻量 |
尽量关闭 CGO | 减少动态依赖 |
合并 RUN 操作 | 减少分层数量 |
编写 .dockerignore | 排除无用文件 |
使用 LABEL 记录元数据 | 方便追踪与管理 |
设置 HEALTHCHECK | 提高可观测性 |
📚 五、参考资料
- Dockerfile 官方文档:https://docs.docker.com/engine/reference/builder/
- Distroless GitHub:https://github.com/GoogleContainerTools/distroless
- 多阶段构建指南:https://docs.docker.com/build/building/multi-stage/
💬 六、定制你的专属 Dockerfile
如果你能提供以下信息,我可以为你定制一份专属的 Dockerfile:
- 项目类型(CLI 工具、Web API、定时任务等)
- 是否需要挂载配置文件或日志目录
- 是否连接数据库或其他外部服务
- 是否有特殊依赖或构建流程
欢迎留言或私信 😊
📌 七、结语
掌握 Dockerfile
的编写,是实现容器化部署的第一步。理解每条指令的作用和参数含义,可以帮助你构建出更加高效、安全、可维护的容器镜像。