Skip to main content
☘️ Septvean's Documents
Toggle Dark/Light/Auto mode Toggle Dark/Light/Auto mode Toggle Dark/Light/Auto mode Back to homepage

Dockerfile 详解

一、Dockerfile 是什么(一句话本质)

Dockerfile 是一份“构建镜像的声明式脚本”,每一条指令都会生成一个新的镜像层(layer)。

关键词:

  • 声明式
  • 分层
  • 可复现

二、镜像分层原理(理解 Dockerfile 的核心)

1. 每条指令 = 一个 Layer

FROM ubuntu
RUN apt update
RUN apt install -y nginx

等价于:

Layer 1: ubuntu 基础镜像
Layer 2: apt update
Layer 3: 安装 nginx

📌 Layer 只读、可复用、可缓存

2. 为什么顺序非常重要?

COPY . /app
RUN pip install -r requirements.txt

❌ 每次代码变更 -> 重新装依赖

✅ 正确顺序:

COPY requirements.txt .
RUN pip install -r requirements.txt
COPY . /app

三、Dockerfile 构建流程(How)

docker build
解析 Dockerfile
从 FROM 拉基础镜像
按顺序执行指令
每条指令生成 layer
最终镜像

📌 构建是 单线程、有缓存的

四、Dockerfile 指令全解(核心)

1. FROM(必须是第一条)

FROM python:3.12-slim
  • 定义基础镜像
  • 多阶段构建中可多次使用

📌 所有镜像最终都基于某个 FROM

2. RUN(构建时执行)

RUN apt update && apt install -y curl
  • 在构建阶段执行
  • 结果写入镜像层

最佳实践

RUN apt update \
    && apt install -y curl \
    && rm -rf /var/lib/apt/lists/*

📌 减小镜像体积

3. COPY vs ADD(高频)

COPY(推荐)

COPY app /app

ADD(慎用)

ADD app.tar.gz /app

ADD 额外功能:

  • 自动解压
  • 支持 URL

📌 90% 场景用 COPY

4. WORKDIR(强烈推荐)

WORKDIR /app
  • 自动创建目录
  • 替代 cd

5. CMD(容器启动命令)

CMD ["nginx", "-g", "daemon off;"]
  • 运行时执行
  • 只能有一个
  • 可被 docker run 覆盖

6. ENTRYPOINT(入口点)

ENTRYPOINT ["python", "app.py"]
  • 不易被覆盖
  • 常用于固定启动逻辑

📌 CMD 是 ENTRYPOINT 的默认参数

7. CMD vs ENTRYPOINT

场景 推荐
固定主程序 ENTRYPOINT
可覆盖参数 CMD
二者结合 最佳实践
ENTRYPOINT ["python", "app.py"]
CMD ["--help"]

8. ENV(环境变量)

ENV APP_ENV=prod

📌 构建期 & 运行期可用

9. ARG(构建参数)

ARG VERSION
  • 只在 build 阶段有效
  • 不进最终镜像

📌 敏感信息不要用 ARG

10. EXPOSE(声明端口)

EXPOSE 8080

📌 只是文档性质

📌 不会自动映射端口

11. VOLUME(声明挂载点)

VOLUME /data

📌 会影响镜像可控性 📌 生产中慎用

12. USER(安全)

USER app

📌 强烈建议不用 root 跑应用

五、多阶段构建(现代 Dockerfile 核心)

示例:前端构建 + 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
  • ✅ 构建环境 ≠ 运行环境
  • ✅ 镜像更小
  • ✅ 更安全

六、.dockerignore(极其重要)

node_modules
.git
dist

📌 不忽略:

  • 构建慢
  • 镜像大
  • 缓存失效

七、镜像体积优化技巧(实战)

技巧 效果
slim / alpine ↓ 70%
合并 RUN ↓ layer
删除缓存 ↓ 体积
多阶段构建 ↓↓↓

八、Dockerfile 常见反模式(必避)

  • ❌ 一个 RUN 一个命令
  • ❌ 用 ADD 代替 COPY
  • ❌ 不写 WORKDIR
  • ❌ 用 root 跑服务
  • ❌ 在镜像里放源码 + node_modules
  • ❌ CMD 用 shell 形式(PID 1 问题)

九、Dockerfile 与运行时的边界(关键理解)

阶段 Dockerfile
构建 RUN / COPY
运行 CMD / ENTRYPOINT
配置 ENV
参数 docker run

📌 Dockerfile 不负责:

  • 服务依赖
  • 多容器通信

十、高频问答

Q:为什么 RUN 会产生 layer?

因为 Docker 使用 UnionFS 分层文件系统

Q:CMD 能写多个吗?

❌ 只能一个,后者覆盖前者

Q:为什么 alpine 有坑?

  • musl libc
  • DNS / timezone / glibc 兼容性

Q:Dockerfile 是 shell 脚本吗?

❌ 不是,是构建指令声明

十一、一个“标准生产级 Dockerfile 模板”

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 = 镜像构建说明书

每条指令 = 一个不可变层

顺序和缓存决定一切