1. 选择合适的基础镜像#
1
2
3
4
5
6
7
8
9
10
|
# ❌ 太大
FROM ubuntu:22.04 # ~77MB
FROM python:3.11 # ~1GB
# ✅ 推荐
FROM python:3.11-alpine # ~50MB
FROM python:3.11-slim # ~130MB
# ✅ 最小
FROM gcr.io/distroless/python3 # ~20MB
|
| 基础镜像 |
大小 |
ubuntu:22.04 |
~77MB |
python:3.11 |
~1GB |
python:3.11-alpine |
~50MB |
distroless |
~20MB |
2. 使用多阶段构建#
最有效的优化手段:编译阶段用大镜像,运行阶段只复制产物。
1
2
3
4
5
6
7
8
9
10
11
|
# 阶段 1:编译
FROM golang:1.21 AS builder
WORKDIR /app
COPY . .
RUN go build -o myapp
# 阶段 2:运行
FROM alpine:3.18
WORKDIR /app
COPY --from=builder /app/myapp .
CMD ["./myapp"]
|
Go 应用从 ~1GB 缩小到 ~15MB。
3. 合并 RUN 指令#
1
2
3
4
5
6
7
8
9
10
11
12
|
# ❌ 多个层
RUN apt-get update
RUN apt-get install -y curl
RUN apt-get install -y wget
RUN rm -rf /var/lib/apt/lists/*
# ✅ 合并为一个层
RUN apt-get update && \
apt-get install -y --no-install-recommends \
curl \
wget && \
rm -rf /var/lib/apt/lists/*
|
4. 清理构建缓存#
1
2
3
4
5
6
7
8
9
|
# Python - 禁用 pip 缓存
RUN pip install --no-cache-dir -r requirements.txt
# Node.js - 清理 npm 缓存
RUN npm ci --only=production && \
npm cache clean --force
# Go - 去除调试信息
RUN go build -ldflags="-s -w" -o myapp
|
5. 使用 .dockerignore#
1
2
3
4
5
6
7
8
9
10
11
|
# .dockerignore
.git
node_modules
*.md
.env
.vscode
__pycache__
*.pyc
dist
build
coverage
|
1
2
|
# 检查上下文大小
docker build --no-cache -t test . 2>&1 | grep "Sending build context"
|
6. 只安装必要的包#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
# ❌ 运行镜像里装了编译工具
FROM ubuntu:22.04
RUN apt-get install -y build-essential gcc make cmake
COPY . .
RUN make && make install
CMD ["./myapp"]
# ✅ 编译和运行分离
FROM ubuntu:22.04 AS builder
RUN apt-get install -y build-essential gcc make
COPY . .
RUN make && make install
FROM ubuntu:22.04
COPY --from=builder /app/myapp .
CMD ["./myapp"]
|
7. 使用 –no-install-recommends#
1
2
3
4
5
|
# ❌ 安装了所有推荐包
RUN apt-get install -y curl
# ✅ 只装必须的包(减少约 50% 依赖)
RUN apt-get install -y --no-install-recommends curl
|
8. 压缩静态资源#
1
2
3
4
5
6
7
8
9
10
11
|
# 压缩 JavaScript
RUN uglifyjs app.js -o app.min.js
# 压缩 CSS
RUN cssnano app.css app.min.css
# 压缩图片
RUN find . -name "*.png" -exec optipng {} \;
# Go 二进制去除调试信息
RUN go build -ldflags="-s -w" -o myapp
|
9. 使用 Squash 合并层#
1
2
|
# 合并所有层为一层,去除中间层的重复文件
docker build --squash -t myapp:slim .
|
需要在 /etc/docker/daemon.json 中启用 experimental 功能。
10. 分析镜像层#
1
2
3
4
5
6
7
|
# 使用 dive 工具分析每层大小和内容
docker run --rm -it \
-v /var/run/docker.sock:/var/run/docker.sock \
wagoodman/dive myapp:latest
# 或使用 docker history
docker history myapp:latest
|
实战案例:Python 应用#
1
2
3
4
5
6
|
# ❌ 优化前(1.2GB)
FROM python:3.11
WORKDIR /app
COPY . .
RUN pip install -r requirements.txt
CMD ["python", "app.py"]
|
1
2
3
4
5
6
7
8
9
10
11
12
|
# ✅ 优化后(150MB,缩小 87%)
FROM python:3.11-slim AS builder
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir --user -r requirements.txt
FROM python:3.11-slim
WORKDIR /app
COPY --from=builder /root/.local /root/.local
COPY . .
ENV PATH=/root/.local/bin:$PATH
CMD ["python", "app.py"]
|
实战案例:Node.js 应用#
1
2
3
4
5
6
|
# ❌ 优化前(1.1GB)
FROM node:18
WORKDIR /app
COPY . .
RUN npm install
CMD ["node", "server.js"]
|
1
2
3
4
5
6
7
8
9
10
11
12
|
# ✅ 优化后(180MB,缩小 84%)
FROM node:18-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production
FROM node:18-alpine
WORKDIR /app
COPY --from=builder /app/node_modules ./node_modules
COPY . .
USER node
CMD ["node", "server.js"]
|
推荐工具#
| 工具 |
用途 |
dive |
分析镜像每层内容和大小 |
docker-slim |
自动精简镜像 |
hadolint |
Dockerfile 静态检查 |
trivy |
镜像安全扫描 |