Docker 多阶段构建:把镜像体积砍掉八成的入门实战
为什么你的镜像越来越大?
刚接触 Docker 的同学常会遇到一个尴尬:一个简单的 Web 服务,打出来的镜像动不动就超过 1GB。原因很简单——构建时需要的编译器、依赖包和各种中间文件,全都被一股脑打包进了最终镜像。而实际运行阶段需要的,往往只是一个编译好的二进制文件,或者精简的语言运行时。
Docker 在 17.05 版本引入的多阶段构建(Multi-stage Build)正是为了解决这个问题:允许在一个 Dockerfile 里写多个 FROM 指令,前面的阶段负责构建,后面的阶段只复制构建产物,最终镜像里干干净净,不留一点构建垃圾。
核心语法:一个 Dockerfile,多个 FROM
第一阶段负责构建:
FROM golang:1.22 AS builder
WORKDIR /app
COPY . .
RUN go build -o server ./cmd/server
第二阶段负责运行:
FROM alpine:3.20
WORKDIR /app
COPY --from=builder /app/server .
EXPOSE 8080
CMD ["./server"]
关键点只有两个:第一,每个 FROM 都会开启一个全新的构建阶段,可以用 AS 给阶段起别名;第二,用 COPY --from=别名 把上一个阶段的产物复制过来,其余的构建依赖和中间文件会被自动丢弃。最终镜像只包含 alpine 基础系统加一个二进制文件,体积通常只有几十 MB。
实战:Python 项目同样适用
Python 项目没有编译环节,但一样可以用多阶段构建来隔离构建依赖。构建阶段用完整镜像安装依赖:
FROM python:3.12 AS builder
WORKDIR /app
COPY requirements.txt .
RUN pip install --user --no-cache-dir -r requirements.txt
运行阶段换成 slim 精简镜像:
FROM python:3.12-slim
WORKDIR /app
COPY --from=builder /root/.local /root/.local
COPY . .
ENV PATH=/root/.local/bin:$PATH
CMD ["python", "app.py"]
总体积能从近 1GB 降到 150MB 左右,部署和拉取速度都快了一大截。
三个实用小技巧
1. 善用层缓存:把不常变化的文件(如 requirements.txt、go.mod)先 COPY 并安装依赖,源代码放到最后 COPY,这样日常改代码不会触发依赖层重建,构建飞快。
2. 阶段命名见名知意:builder、tester、runner,阶段一多可读性优势非常明显。
3. 单独调试构建阶段:docker build --target builder -t myapp:debug . 可以只构建到指定阶段,排查构建问题时非常顺手。
小结
多阶段构建几乎没有额外的学习成本,却能同时改善镜像体积、安全性和构建速度。从今天起,试着给你的 Dockerfile 加上第二个 FROM 吧。
- 点赞
- 收藏
- 关注作者
评论(0)