Dockerfile 详解
Dockerfile 是一份“构建镜像的声明式脚本”,每一条指令都会生成一个新的镜像层(layer)。
关键词:
- 声明式
- 分层
- 可复现
FROM ubuntu
RUN apt update
RUN apt install -y nginx
等价于:
Layer 1: ubuntu 基础镜像
Layer 2: apt update
Layer 3: 安装 nginx
📌 Layer 只读、可复用、可缓存
COPY . /app
RUN pip install -r requirements.txt
❌ 每次代码变更 -> 重新装依赖
✅ 正确顺序:
COPY requirements.txt .
RUN pip install -r requirements.txt
COPY . /app
docker build
↓
解析 Dockerfile
↓
从 FROM 拉基础镜像
↓
按顺序执行指令
↓
每条指令生成 layer
↓
最终镜像
📌 构建是 单线程、有缓存的
FROM python:3.12-slim
- 定义基础镜像
- 多阶段构建中可多次使用
📌 所有镜像最终都基于某个 FROM
RUN apt update && apt install -y curl
- 在构建阶段执行
- 结果写入镜像层
最佳实践
RUN apt update \
&& apt install -y curl \
&& rm -rf /var/lib/apt/lists/*
📌 减小镜像体积
COPY(推荐)
COPY app /app
ADD(慎用)
ADD app.tar.gz /app
ADD 额外功能:
- 自动解压
- 支持 URL
📌 90% 场景用 COPY
WORKDIR /app
- 自动创建目录
- 替代 cd
CMD ["nginx", "-g", "daemon off;"]
- 运行时执行
- 只能有一个
- 可被 docker run 覆盖
ENTRYPOINT ["python", "app.py"]
- 不易被覆盖
- 常用于固定启动逻辑
📌 CMD 是 ENTRYPOINT 的默认参数
| 场景 | 推荐 |
|---|---|
| 固定主程序 | ENTRYPOINT |
| 可覆盖参数 | CMD |
| 二者结合 | 最佳实践 |
ENTRYPOINT ["python", "app.py"]
CMD ["--help"]
ENV APP_ENV=prod
📌 构建期 & 运行期可用
ARG VERSION
- 只在 build 阶段有效
- 不进最终镜像
📌 敏感信息不要用 ARG
EXPOSE 8080
📌 只是文档性质
📌 不会自动映射端口
VOLUME /data
📌 会影响镜像可控性 📌 生产中慎用
USER app
📌 强烈建议不用 root 跑应用
示例:前端构建 + Nginx
FROM node:20 AS builder
WORKDIR /app
COPY package*.json ./
RUN npm install
COPY . .
RUN npm run build
FROM nginx:alpine
COPY --from=builder /app/dist /usr/share/nginx/html
- ✅ 构建环境 ≠ 运行环境
- ✅ 镜像更小
- ✅ 更安全
node_modules
.git
dist
📌 不忽略:
- 构建慢
- 镜像大
- 缓存失效
| 技巧 | 效果 |
|---|---|
| slim / alpine | ↓ 70% |
| 合并 RUN | ↓ layer |
| 删除缓存 | ↓ 体积 |
| 多阶段构建 | ↓↓↓ |
- ❌ 一个 RUN 一个命令
- ❌ 用 ADD 代替 COPY
- ❌ 不写 WORKDIR
- ❌ 用 root 跑服务
- ❌ 在镜像里放源码 + node_modules
- ❌ CMD 用 shell 形式(PID 1 问题)
| 阶段 | Dockerfile |
|---|---|
| 构建 | RUN / COPY |
| 运行 | CMD / ENTRYPOINT |
| 配置 | ENV |
| 参数 | docker run |
📌 Dockerfile 不负责:
- 服务依赖
- 多容器通信
因为 Docker 使用 UnionFS 分层文件系统
❌ 只能一个,后者覆盖前者
- musl libc
- DNS / timezone / glibc 兼容性
❌ 不是,是构建指令声明
FROM python:3.12-slim
WORKDIR /app
ENV PYTHONDONTWRITEBYTECODE=1 \
PYTHONUNBUFFERED=1
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY . .
RUN useradd -m appuser
USER appuser
EXPOSE 8000
CMD ["python", "main.py"]
Dockerfile = 镜像构建说明书
每条指令 = 一个不可变层
顺序和缓存决定一切