开篇导读
你可能已经能用 docker run 拉取别人写好的镜像了,但有一个绕不过去的门槛:
如何编写属于你自己的 Dockerfile,构建专属镜像?
而这件事,恰恰决定了你能不能将项目真正容器化、部署上云、走向生产。
本讲将从最基础的 Hello World Dockerfile 入门,逐步引导你掌握构建生产级镜像的关键技巧,不再依赖别人打包,自己也能轻松构建容器世界的积木。
一、Dockerfile 是什么?
Dockerfile 是一个文本文件,包含了构建镜像所需的一系列指令和元数据。
简单说,它就是 Docker 构建镜像时的“配方”。
FROM nginx
COPY ./index.html /usr/share/nginx/html
你运行:
docker build -t my-nginx .
Docker 就会照着 Dockerfile 一步一步构建镜像,最终变成一个可以运行的容器。
二、Dockerfile 指令速查表
| 指令 | 说明 |
|---|---|
| FROM | 指定基础镜像(必须) |
| RUN | 执行命令(用于安装依赖) |
| COPY / ADD | 复制文件到镜像 |
| CMD / ENTRYPOINT | 容器启动时默认执行命令 |
| WORKDIR | 设置工作目录 |
| ENV | 设置环境变量 |
| EXPOSE | 声明暴露的端口 |
️三、Hello World Dockerfile 示例
让我们写一个最基础的 Dockerfile:
结构:
myapp/
├── Dockerfile
└── app.py
app.py:
print("Hello, Docker!")
Dockerfile:
FROM python:3.9-slim
COPY app.py /app.py
CMD ["python", "/app.py"]
构建并运行:
docker build -t hello-docker .
docker run hello-docker
输出:
Hello, Docker!
你完成了人生第一个镜像构建!
四、构建生产镜像的高级技巧
1️⃣ 多阶段构建(Multi-stage Build)
在生产环境中,我们希望:
- 构建依赖存在 → 但运行时镜像更小更干净!
# 第一阶段:构建
FROM node:18 AS build
WORKDIR /app
COPY . .
RUN npm install && npm run build
# 第二阶段:运行
FROM nginx:alpine
COPY --from=build /app/dist /usr/share/nginx/html
优势:
- 镜像体积小
- 更安全,攻击面小
- 构建过程更清晰可控
2️⃣ .dockerignore 优化构建上下文
类似 .gitignore,可避免无关文件进入构建上下文,提升构建速度。
示例:
node_modules
*.log
.git
3️⃣ 使用缓存提高构建效率
Docker 会尽可能重用前面构建步骤的缓存,因此合理安排 Dockerfile 的顺序非常关键:
✅ 推荐顺序:
COPY package.json ./
RUN npm install
COPY . .
- npm install 提前:改动频率低
- COPY . . 最后:改动频率高,触发最少重构
五、ENTRYPOINT vs CMD 有什么区别?
这两个指令都能指定容器启动后的执行命令,但作用不完全一样。
| 对比项 | ENTRYPOINT | CMD |
|---|---|---|
| 作用 | 定义不可覆盖的启动命令 | 定义默认参数(可被覆盖) |
| 是否能被 docker run 替代 | 否 | 是 |
| 推荐用法 | 做为主进程控制入口 | 提供默认参数 |
示例:
ENTRYPOINT ["nginx"]
CMD ["-g", "daemon off;"]
当你执行 docker run myimage 时,最终命令为:
nginx -g 'daemon off;'
六、构建最佳实践总结
✅ 使用轻量镜像(如 alpine):
FROM python:3.9-alpine
✅ 使用多阶段构建优化体积
✅ 用 .dockerignore 降低构建冗余
✅ 合理拆分 RUN 层,提升可维护性
✅ 写清楚 EXPOSE、CMD、ENTRYPOINT
✅ 镜像中不要存密钥和环境配置,用 ENV 配合外部注入
七、总结一下你学会了什么?
- 理解了 Dockerfile 的核心构建逻辑
- 能写出基本的 Hello World 镜像
- 掌握了多阶段构建与调试技巧
- 学会了高效、专业的生产级镜像优化方法