← 返回资讯
赵一鸣
产品评测编辑
已审核

Docker 多阶段构建:把镜像从 1.2GB 压缩到 89MB

我们的 Node.js 应用镜像原来是 1.2GB,部署慢、存储贵。

Docker 多阶段构建:把镜像从 1.2GB 压缩到 89MB

Docker 多阶段构建:把镜像从 1.2GB 压缩到 89MB

我们的 Node.js 应用镜像原来是 1.2GB,部署慢、存储贵。

用多阶段构建优化后,镜像只有 89MB,部署速度提升 10 倍。

问题背景

原来的 Dockerfile

DOCKERFILE
# ❌ 单阶段构建
FROM node:20

WORKDIR /app

# 复制所有文件
COPY . .

# 安装所有依赖(包括 devDependencies)
RUN npm install

# 构建
RUN npm run build

# 启动
CMD ["node", "dist/index.js"]

问题:

镜像大小分析

BASH
$ docker images myapp
REPOSITORY   TAG       IMAGE ID       CREATED          SIZE
myapp        latest    abc123         2 minutes ago    1.2GB

$ docker history myapp
IMAGE          CREATED       SIZE
abc123         2 min ago     450MB    # node_modules
def456         2 min ago     380MB    # build tools
ghi789         2 min ago     220MB    # source code
jkl012         5 min ago     150MB    # base image

多阶段构建

优化后的 Dockerfile

DOCKERFILE
# ✅ 多阶段构建

# 阶段 1:构建阶段
FROM node:20-alpine AS builder

WORKDIR /app

# 只复制 package 文件(利用 Docker 缓存)
COPY package*.json ./

# 安装所有依赖(包括 devDependencies)
RUN npm ci

# 复制源代码
COPY . .

# 构建
RUN npm run build

# 阶段 2:生产阶段
FROM node:20-alpine AS production

WORKDIR /app

# 只复制 package 文件
COPY package*.json ./

# 只安装生产依赖
RUN npm ci --only=production && npm cache clean --force

# 从构建阶段复制构建产物
COPY --from=builder /app/dist ./dist

# 非 root 用户运行
RUN addgroup -g 1001 -S nodejs && \
    adduser -S nodejs -u 1001 && \
    chown -R nodejs:nodejs /app

USER nodejs

# 启动
CMD ["node", "dist/index.js"]

优化效果

BASH
$ docker images myapp
REPOSITORY   TAG       IMAGE ID       CREATED          SIZE
myapp        latest    xyz789         1 minute ago     89MB

从 1.2GB 降到 89MB,减少 93%。

进阶优化

优化 1:使用 distroless 基础镜像

DOCKERFILE
# 阶段 1:构建
FROM node:20-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build

# 阶段 2:生产(使用 distroless)
FROM gcr.io/distroless/nodejs20-debian12 AS production

WORKDIR /app

# 复制 node_modules
COPY --from=builder /app/node_modules ./node_modules

# 复制构建产物
COPY --from=builder /app/dist ./dist
COPY --from=builder /app/package.json ./

# 启动
CMD ["dist/index.js"]

distroless 镜像不包含 shell、包管理器等,更安全。

优化 2:分层缓存优化

DOCKERFILE
# 阶段 1:依赖安装(独立缓存层)
FROM node:20-alpine AS deps
WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production

# 阶段 2:构建
FROM node:20-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build

# 阶段 3:生产
FROM node:20-alpine AS production
WORKDIR /app

# 复制生产依赖(缓存友好)
COPY --from=deps /app/node_modules ./node_modules

# 复制构建产物
COPY --from=builder /app/dist ./dist
COPY package.json ./

USER node
CMD ["node", "dist/index.js"]

好处:

优化 3:多架构支持

DOCKERFILE
# 使用 buildx 构建多架构镜像
# docker buildx build --platform linux/amd64,linux/arm64 -t myapp .

FROM --platform=$BUILDPLATFORM node:20-alpine AS builder

ARG TARGETPLATFORM
ARG BUILDPLATFORM

WORKDIR /app

COPY package*.json ./
RUN npm ci

COPY . .

# 根据目标平台构建
RUN if [ "$TARGETPLATFORM" = "linux/arm64" ]; then \
      npm run build:arm64; \
    else \
      npm run build; \
    fi

FROM node:20-alpine AS production
WORKDIR /app

COPY --from=builder /app/dist ./dist
COPY --from=builder /app/node_modules ./node_modules
COPY package.json ./

USER node
CMD ["node", "dist/index.js"]

Python 项目示例

优化前

DOCKERFILE
# ❌ 单阶段
FROM python:3.12

WORKDIR /app

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

COPY . .

CMD ["python", "app.py"]

镜像大小:850MB

优化后

DOCKERFILE
# ✅ 多阶段

# 阶段 1:构建依赖
FROM python:3.12-slim AS builder

WORKDIR /app

# 安装构建工具
RUN apt-get update && apt-get install -y \
    build-essential \
    && rm -rf /var/lib/apt/lists/*

COPY requirements.txt .

# 安装依赖到指定目录
RUN pip install --no-cache-dir --prefix=/install -r requirements.txt

# 阶段 2:生产
FROM python:3.12-slim AS production

WORKDIR /app

# 复制安装的依赖
COPY --from=builder /install /usr/local

# 只复制必要文件
COPY app.py .
COPY src/ ./src/

# 非 root 用户
RUN useradd -m -u 1001 appuser && chown -R appuser:appuser /app
USER appuser

CMD ["python", "app.py"]

镜像大小:180MB

Go 项目示例

优化前

DOCKERFILE
# ❌ 包含完整 Go 工具链
FROM golang:1.22

WORKDIR /app
COPY . .
RUN go build -o main .
CMD ["./main"]

镜像大小:1.1GB

优化后

DOCKERFILE
# ✅ 多阶段 + scratch

# 阶段 1:构建
FROM golang:1.22-alpine AS builder

WORKDIR /app

# 复制依赖文件
COPY go.mod go.sum ./
RUN go mod download

# 复制源代码
COPY . .

# 静态编译
RUN CGO_ENABLED=0 GOOS=linux go build -ldflags="-w -s" -o main .

# 阶段 2:最小镜像
FROM scratch AS production

# 复制 CA 证书(HTTPS 需要)
COPY --from=builder /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/

# 复制二进制
COPY --from=builder /app/main /main

# 复制配置
COPY --from=builder /app/config /config

# 非 root
USER 1001

ENTRYPOINT ["/main"]

镜像大小:12MB

最佳实践

1. 使用 .dockerignore

CODE
# .dockerignore
node_modules
npm-debug.log
.git
.gitignore
.env
.env.*
*.md
.vscode
.idea
coverage
.nyc_output
dist
build

2. 合理利用缓存

DOCKERFILE
# ✅ 好的缓存策略
COPY package*.json ./
RUN npm ci                    # 依赖不变时缓存

COPY tsconfig.json ./
COPY src/ ./src/
RUN npm run build             # 源代码变化时重新构建

# ❌ 差的缓存策略
COPY . .                      # 任何文件变化都重新安装依赖
RUN npm install

3. 安全实践

DOCKERFILE
# ✅ 安全实践

# 使用特定版本
FROM node:20.11.0-alpine3.19

# 非 root 用户
RUN addgroup -g 1001 -S nodejs && \
    adduser -S nodejs -u 1001
USER nodejs

# 只复制必要文件
COPY --from=builder /app/dist ./dist
COPY --from=builder /app/node_modules ./node_modules

# 健康检查
HEALTHCHECK --interval=30s --timeout=3s \
  CMD node -e "require('http').get('http://localhost:3000/health', (r) => {process.exit(r.statusCode === 200 ? 0 : 1)})"

4. 多环境构建

DOCKERFILE
# 使用构建参数
ARG NODE_ENV=production
ENV NODE_ENV=$NODE_ENV

# 根据环境安装依赖
RUN if [ "$NODE_ENV" = "development" ]; then \
      npm install; \
    else \
      npm ci --only=production; \
    fi

性能对比

| 项目类型 | 优化前 | 优化后 | 减少 |

|---------|--------|--------|------|

| Node.js | 1.2GB | 89MB | 93% |

| Python | 850MB | 180MB | 79% |

| Go | 1.1GB | 12MB | 99% |

总结

多阶段构建的核心原则:

1. 分离构建和运行环境

2. 只复制必要文件到生产镜像

3. 使用最小基础镜像

4. 合理利用 Docker 缓存

5. 非 root 用户运行

遵循这些原则,镜像大小可以减少 80-99%。


优化时间:2026年7月

项目类型:Node.js / Python / Go

镜像减少:80-99%

#Docker #多阶段构建 #容器优化 #DevOps

295
9859 阅读
5 评论
分享
链接已复制
编辑说明

本文由 MakeSense 编辑团队撰写并审核。文中引用的数据和观点均经过交叉验证,如有疏漏欢迎在评论区指正。最后更新:2026年07月10日 17:59

赵一鸣

产品评测编辑

前产品经理,现专注 AI 工具评测。实测过 30+ 款 AI 产品,擅长横向对比和用户体验分析。

读者评论 5

运营小陈 1周前
转发到团队群了,大家都觉得有参考价值。
回复 点赞 (4)
数据分析师 1周前
数据引用很扎实,建议补充一下近三个月的最新数据。
回复 点赞 (9)
产品经理阿杰 2天前
从产品角度看,这个方向确实有机会,但商业化路径还需要验证。
回复 点赞 (15)
张工 5天前
写得很实在,特别是实测对比那部分,跟我自己的使用感受一致。
回复 点赞 (12)
前端工程师 1周前
代码示例很清晰,直接用到项目里了。
回复 点赞 (6)