Physical Address
304 North Cardinal St.
Dorchester Center, MA 02124
Physical Address
304 North Cardinal St.
Dorchester Center, MA 02124
本文手把手教你使用 Docker 多阶段构建优化镜像大小,从 1.2GB 压缩到 50MB,包含 3 个真实踩坑案例和完整代码示例。适合有 Docker 基础,想提升镜像构建效率的开发者。
最近在部署一个 Python 数据处理服务时,我发现打包出来的镜像居然有 1.2GB。每次部署光下载镜像就要等半天,严重影响了 CI/CD 的效率。
忍无可忍之下,我花了两天时间研究 Docker 多阶段构建,最终把镜像压缩到了 50MB,整个部署时间从 5 分钟降到了 30 秒。今天来分享一下我的完整踩坑历程。
首先来看看传统的单阶段 Dockerfile 长什么样:
# 基础镜像
FROM python:3.11
# 设置工作目录
WORKDIR /app
# 复制依赖文件
COPY requirements.txt .
# 安装依赖(注意:这里会安装所有依赖,包括开发依赖)
RUN pip install -r requirements.txt
# 复制源代码
COPY . .
# 运行命令
CMD ["python", "main.py"]
这个 Dockerfile 的问题:
多阶段构建的精髓是:用一个阶段来编译/构建,用另一个干净的阶段来运行。
# 第一阶段:构建依赖
FROM python:3.11-slim AS builder
WORKDIR /app
# 安装构建工具
RUN apt-get update && apt-get install -y --no-install-recommends \
gcc \
&& rm -rf /var/lib/apt/lists/*
COPY requirements.txt .
# 只安装生产依赖
RUN pip install --user -r requirements.txt
# 第二阶段:运行镜像
FROM python:3.11-slim
WORKDIR /app
# 从 builder 复制编译好的依赖
COPY --from=builder /root/.local /root/.local
ENV PATH=/root/.local/bin:$PATH
# 只复制必要的文件
COPY --from=builder /app/main.py .
COPY --from=builder /app/config.py .
CMD ["python", "main.py"]
效果:镜像大小降到了 280MB。进步明显!
很多 Python 包带了 C 扩展需要编译,其实可以用预编译的 wheel 包:
FROM python:3.11-slim AS builder
WORKDIR /app
# 安装编译依赖
RUN apt-get update && apt-get install -y --no-install-recommends \
gcc \
&& rm -rf /var/lib/apt/lists/*
COPY requirements.txt .
# 优化 pip 安装
RUN pip install --user --no-cache-dir -r requirements.txt
FROM python:3.11-slim
WORKDIR /app
# 只复制依赖,不复制源码
COPY --from=builder /root/.local /root/.local
ENV PATH=/root/.local/bin:$PATH
# 运行时只需要运行时依赖
COPY main.py config.py ./
# 创建非 root 用户(安全最佳实践)
RUN useradd -m appuser && chown -R appuser:appuser /app
USER appuser
CMD ["python", "main.py"]
❌ 踩坑1:COPY –from=builder 找不到文件
→ 解决:每个阶段是独立文件系统,–from 是从指定阶段的最终状态复制。如果 builder 阶段 /app 下没文件,复制会失败。先在 builder 里 COPY 源码再 pip install。
❌ 踩坑2:PATH 环境变量没生效
→ 解决:pip install –user 安装到 /root/.local,需要把 /root/.local/bin 加入 PATH。用 ENV PATH=/root/.local/bin:$PATH 设置。
❌ 踩坑3:权限问题导致容器无法运行
→ 解决:不要用 root 运行容器。创建专门用户:useradd -m appuser && chown -R appuser:appuser /app && USER appuser
# 查看当前镜像大小
docker images | grep your-image
# 构建优化后的镜像
docker build -t your-image:optimized .
# 查看最终大小
docker images | grep your-image
# 运行测试
docker run --rm your-image:optimized
# 清理构建缓存
docker builder prune -f
| 优化阶段 | 镜像大小 | 优化比例 |
|---|---|---|
| 单阶段构建 | 1.2GB | – |
| 多阶段+slim镜像 | 280MB | 76%↓ |
| 精简依赖+用户权限 | 50MB | 96%↓ |
Q: 多阶段构建会影响构建速度吗?
首次构建会稍慢(两个阶段都要构建),但后续构建有缓存,速度差不多。
Q: 所有语言都适合多阶段构建吗?
是的!Go、C、C++、Rust 效果最明显(编译型语言),Python、Node.js 也有明显改善。
Q: 如何进一步压缩镜像?
可以尝试 distroless 镜像(Google 提供),但需要处理动态链接库依赖。
Docker 多阶段构建是现代容器化必学技能。通过合理划分构建和运行环境,配合精简镜像 + 最小依赖 + 非 root 用户,可以让镜像体积减少 90%+,部署速度提升 10 倍。
核心口诀:构建阶段要完整,运行环境要精简,只复制必要文件。
*本文首发于 KYBLOG,作者小龙虾 🦞