dockerfile是镜像的“构建蓝图”,每条指令生成一层只读镜像层;应合并run命令、前置不变内容、优先用copy、采用多阶段构建,并固定基础镜像、非root运行、排除敏感文件、声明健康检查。
dockerfile 不是脚本,而是镜像的“构建蓝图”——每条指令生成一层只读镜像层,层与层叠加构成最终镜像。写得好,构建快、体积小、安全可控;写得随意,ci卡顿、仓库臃肿、上线踩坑。
分层逻辑决定构建效率和镜像大小
镜像层不可变,且缓存依赖指令顺序。同一层中安装再删除的文件仍占用空间,比如:
- 错误写法:RUN apt-get update && apt-get install -y curl && apt-get clean && rm -rf /var/lib/apt/lists/* —— 这样写会把清理命令单独成层,上层残留大量缓存
- 正确写法:RUN apt-get update && apt-get install -y curl && rm -rf /var/lib/apt/lists/* —— 所有操作在单个 RUN 中完成,中间产物不落盘
不变内容尽量前置:基础镜像、系统依赖、语言运行时应靠前;易变内容如应用代码、配置文件靠后,利于复用缓存。
COPY 与 ADD 的明确分工
COPY 是首选,语义清晰、行为可预测;ADD 功能更强但容易引入意外行为(如自动解压 tar、支持 URL 下载),日常开发中多数场景只需 COPY。
- 复制单个文件或目录:用 COPY requirements.txt .
- 需要解压本地压缩包:才考虑 ADD app.tar.gz /app/
- 从远程 URL 下载并解压?不推荐——破坏构建可重现性,应改用 RUN curl + tar 显式控制
多阶段构建大幅精简生产镜像
编译型语言(Go、Rust、Java)或含构建工具链(Node.js、Python with C extensions)的应用,必须用多阶段构建剥离构建依赖。
- 第一阶段:FROM golang:1.23-alpine,COPY + go build 编译出二进制
- 第二阶段:FROM alpine:3.20,仅 COPY 上一阶段生成的二进制,不带任何 SDK、编译器、头文件
- 结果:镜像从 900MB → 12MB,无 shell、无包管理器、攻击面极小
安全与可维护性的硬性动作
生产环境 Dockerfile 必须包含以下四点:
- 固定基础镜像标签:FROM python:3.11-slim-bookworm,禁用 latest
- 非 root 用户运行:USER 1001,避免容器内提权风险
- 排除敏感文件:创建 .dockerignore,过滤 .git、.env、__pycache__、*.log
- 声明健康检查:HEALTHCHECK --interval=30s --timeout=3s CMD curl -f http://localhost:8000/health || exit 1











