问题:为什么镜像这么大?#

1
2
3
$ docker images
REPOSITORY    TAG       SIZE
my-python-app latest    1.2GB  # 太大了!

优化策略#

1. 选择合适的基础镜像#

1
2
3
4
5
6
7
8
# ❌ 不推荐:完整版镜像
FROM python:3.11          # 约 1GB

# ✅ 推荐:slim 版本
FROM python:3.11-slim     # 约 150MB

# ✅ 更推荐:alpine 版本
FROM python:3.11-alpine   # 约 50MB

2. 多阶段构建#

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
# === 构建阶段 ===
FROM golang:1.21 AS builder

WORKDIR /app
COPY go.mod go.sum ./
RUN go mod download

COPY . .
RUN CGO_ENABLED=0 go build -o /app/server

# === 运行阶段 ===
FROM alpine:3.18

COPY --from=builder /app/server /server
EXPOSE 8080
CMD ["/server"]

效果

  • 构建镜像:~800MB
  • 最终镜像:~15MB ✓

3. 合并 RUN 指令#

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
# ❌ 不推荐:多个 RUN
RUN apt-get update
RUN apt-get install -y curl
RUN apt-get clean

# ✅ 推荐:合并 RUN
RUN apt-get update \
    && apt-get install -y --no-install-recommends curl \
    && apt-get clean \
    && rm -rf /var/lib/apt/lists/*

4. 利用构建缓存#

1
2
3
4
5
6
# ✅ 依赖文件单独 COPY
COPY requirements.txt .
RUN pip install -r requirements.txt

# 源代码后 COPY(经常变动)
COPY . .

5. 使用 .dockerignore#

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
# .dockerignore
.git
.gitignore
node_modules
__pycache__
*.pyc
.env
.vscode
*.md
tests/
docs/

Python 项目最佳实践#

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
FROM python:3.11-slim AS builder

WORKDIR /app

# 安装编译依赖
RUN apt-get update && apt-get install -y --no-install-recommends \
    build-essential \
    && rm -rf /var/lib/apt/lists/*

# 创建虚拟环境
RUN python -m venv /opt/venv
ENV PATH="/opt/venv/bin:$PATH"

# 安装依赖
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt

# === 最终镜像 ===
FROM python:3.11-slim

# 复制虚拟环境
COPY --from=builder /opt/venv /opt/venv
ENV PATH="/opt/venv/bin:$PATH"

WORKDIR /app
COPY . .

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

EXPOSE 8000
CMD ["python", "main.py"]

Node.js 项目最佳实践#

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
FROM node:20-alpine AS builder

WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production

# === 最终镜像 ===
FROM node:20-alpine

WORKDIR /app
COPY --from=builder /app/node_modules ./node_modules
COPY . .

USER node
EXPOSE 3000
CMD ["node", "server.js"]

镜像分析工具#

dive#

1
2
3
4
5
# 安装
brew install dive

# 分析镜像
dive my-python-app:latest
┌─────────────────────────────────────────┐
│ Layer Details                           │
├─────────────────────────────────────────┤
│ Size: 156 MB                            │
│ Command: RUN pip install -r req.txt     │
│                                         │
│ Potential wasted space: 23 MB           │
│ - /root/.cache/pip (23 MB)              │
└─────────────────────────────────────────┘

docker history#

1
2
3
4
$ docker history my-app:latest --no-trunc
IMAGE          CREATED        SIZE      COMMAND
abc123         2 hours ago    156MB     pip install...
def456         2 hours ago    50MB      apt-get install...

优化效果对比#

优化前                    优化后
────────────────────────────────────────
FROM python:3.11         FROM python:3.11-slim
多个 RUN 指令            合并 RUN 指令
无 .dockerignore         有 .dockerignore
单阶段构建               多阶段构建
────────────────────────────────────────
1.2 GB                   120 MB  (↓90%)

检查清单#

1
2
3
4
5
6
7
□ 使用 slim/alpine 基础镜像
□ 使用多阶段构建
□ 合并 RUN 指令
□ 清理缓存和临时文件
□ 添加 .dockerignore
□ 使用 dive 分析镜像层
□ 以非 root 用户运行
1
2
$ docker images | awk '{print $1, $7}'
my-app 120MB  # 目标达成!