Dockerfile 编写进阶:从 Hello World 到生产镜像

135 阅读3分钟

开篇导读

你可能已经能用 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 有什么区别?

这两个指令都能指定容器启动后的执行命令,但作用不完全一样。

对比项ENTRYPOINTCMD
作用定义不可覆盖的启动命令定义默认参数(可被覆盖)
是否能被 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 镜像
  • 掌握了多阶段构建与调试技巧
  • 学会了高效、专业的生产级镜像优化方法