章节里写着「完整的文件如下」,仓库里配套的实际文件却已经和正文对不上。 这类漂移比正文里的笔误更隐蔽——读者按目录跑起来的是另一份东西。 - `11_compose/demo/django/Dockerfile` 用的是 `ENV PYTHONUNBUFFERED 1` 这种 空格旧写法,而 7.6 节写着绝对规则:「已被官方弃用……`docker buildx build --check` 会直接把它标出来。**一律用等号**」。这是全仓唯一一处违反(已扫过 全部 md 与 11 个 Dockerfile)。同文件还有三处与 11.6 节不符:`FROM python:3` (章节是 3.12-slim)、`pip install` 缺 `--no-cache-dir`(章节专门列表讲了 它的作用)、requirements 用 psycopg2 而章节表格写着「推荐使用 psycopg 3」。 按 11.6 同步,现与章节代码块逐字节一致。 - `07_dockerfile/multistage_example/laravel/Dockerfile` 与 7.18 节差三处, 两处有实质后果:`chmod -R 777 storage`(章节是 `chown www-data` + `775`) —— 而 18.5 节正拿 `777` 当"全员读写权限"的风险范例;以及 `COPY composer.json` 漏掉了 `composer.lock`,正好破坏该章论证的可复现性。第三处 nginx 标签 1.30 与全书 20 处 1.28 不一致(且章节自己的注释就推荐 1.28-alpine)。 同步后与章节仅差章节独有的那行说明性注释。 - `11_compose/demo/wordpress/docker-compose.yml` 的 wordpress 服务**完全没有 `volumes:`**,而 11.8 节专门加粗警告过「`volumes` 配置很重要!没有它,每次 容器重启数据都会丢失」并声明了 `wp_data`。该 demo 恰好演示了章节警告的那个 故障。另外还缺 `wp_net`、两个 container_name、`WORDPRESS_DB_NAME` 与 `uploads.ini` 挂载。按章节同步,并补上章节 11.8.3 已给出内容的 `uploads.ini` (否则挂载会指向不存在的文件)。同步后 YAML 实测可解析,volumes 为 db_data + wp_data。 `secrets/` 目录未补:它被 .gitignore 有意排除,demo 的 README 就是教读者 自己创建的,属于设计而非缺失。
第七章 Dockerfile 指令详解
什么是 Dockerfile
Dockerfile 是一个文本文件,其内包含了一条条的 指令 (Instruction),每一条指令构建一层,因此每一条指令的内容,就是描述该层应当如何构建。
在第四章中,我们通过 docker commit 学习了镜像的构成。但是,手动 commit 只能作为临时修补,并不适合作为生产环境镜像的构建方式。
使用 Dockerfile 构建镜像有以下优势:
- 自动化:可以通过
docker build命令自动构建镜像。 - 可重复性:由于 Dockerfile 是文本文件,可以确保每次构建的结果一致。
- 版本控制:Dockerfile 可以纳入版本控制系统(如 Git),便于追踪变更。
- 透明性:任何人都可以通过阅读 Dockerfile 了解镜像的构建过程。
Dockerfile 编写哲学
在深入每个指令的细节之前,笔者想强调一个至关重要的原则:Dockerfile 不是脚本,而是镜像的“设计图”。这个区别决定了你如何思考每条指令的作用。
相比编写 Bash 脚本的思维(“按顺序执行这些命令”),Dockerfile 的思维应该是(“这一层镜像应该如何构建,下一层如何分层”)。这个思维转变会影响你的决策:
- 合并命令:一个
RUN apt-get update && apt-get install ...应该写在一起,而不是分开成多个RUN指令,因为它们是同一个“层”的逻辑 - 选择合适的指令:
COPYvsADD、CMDvsENTRYPOINT这些选择不是随意的,而是根据镜像分层的语义来决定的 - 优化镜像大小:最后才清理缓存、删除临时文件,让这些“瘦身”操作在同一层完成
这个章节将详细介绍各个指令。在学习指令语法时,请始终思考:“这个指令为什么要以这样的方式工作?如果我是 Docker,我应该如何设计它?”
Dockerfile 基本结构
Dockerfile 一般分为四部分:基础镜像信息、维护者信息、镜像操作指令和容器启动时执行指令。
可运行 docker buildx build --check 校验的完整 Dockerfile 示例与配套 index.html 保存在仓库中。它使用 scratch,因此结构检查不会解析远程基础镜像元数据。下面的围栏与该文件由测试强制保持一致。
FROM scratch
COPY index.html /index.html
指令详解
本章将详细讲解 Dockerfile 中的各个指令:
- RUN 执行命令
- COPY 复制文件
- ADD 更高级的复制文件
- CMD 容器启动命令
- ENTRYPOINT 入口点
- ENV 设置环境变量
- ARG 构建参数
- VOLUME 定义匿名卷
- EXPOSE 暴露端口
- WORKDIR 指定工作目录
- USER 指定当前用户
- HEALTHCHECK 健康检查
- ONBUILD 为他人作嫁衣裳
- LABEL 为镜像添加元数据
- SHELL 指令
高级特性
本章还将介绍 Dockerfile 的高级特性:
参考与最佳实践
此外,我们还将介绍 Dockerfile 的最佳实践和常见问题。
使用 Dockerfile 构建镜像
构建镜像的基本命令格式为:
docker build [选项] <上下文路径/URL/->
例如,在 Dockerfile 所在目录执行:
docker build -t my-image:1.0 .
关于版本号最佳实践
本章中的 Dockerfile 示例使用的基础镜像标签遵循以下原则:
- 通用标签(如
ubuntu:24.04、alpine、nginx):保持原样,无需修改 - 基础镜像版本号(如
node:22、python:3.12):使用主或次版本号而非完整版本号(patch),这样可以自动获取最新的补丁版本,确保获得安全更新 - 避免:不建议使用
latest标签和完整的 patch 版本号(如20.10.0)作为基础镜像,因为这会导致构建的不可重现性或安全风险
读者在使用这些示例时,应根据实际生产环境需求选择合适的版本号。
更多关于 docker build 的用法,我们在实战中会结合具体指令进行演示。