1. 命令の順序を適切に配置する(キャッシュの活用)#
変更頻度の低い命令を前に、変更頻度の高い命令を後に配置します。あるレイヤーのキャッシュが無効になると、以降のすべてのレイヤーが再ビルドされます。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
# ❌ 错误:每次改代码都要重新装依赖
FROM node:18-alpine
WORKDIR /app
COPY . . # 代码经常变
RUN npm ci --production # 依赖很少变
CMD ["node", "server.js"]
# ✅ 正确:依赖变化时才重新安装
FROM node:18-alpine
WORKDIR /app
COPY package.json package-lock.json ./ # 依赖定义(很少变)
RUN npm ci --production # 安装依赖(很少变)
COPY . . # 代码(经常变)
CMD ["node", "server.js"]
|
1
2
|
# 检查缓存命中情况
docker build -t myapp . 2>&1 | grep -E "(CACHED|Using cache)"
|
2. .dockerignore でコンテキストを削減する#
docker build は .git や node_modules など不要なファイルを含むディレクトリ全体を Docker daemon に送信します。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
# .dockerignore
.git
.github
.vscode
.idea
node_modules
dist
build
*.md
*.log
.env
.env.local
.DS_Store
coverage
.nyc_output
|
1
2
3
4
|
# 检查上下文大小
docker build --no-cache -t test . 2>&1 | grep "Sending build context"
# 优化前:Sending build context to Docker daemon 1.2GB
# 优化后:Sending build context to Docker daemon 50MB
|
3. 軽量なベースイメージを使用する#
| ベースイメージ |
サイズ |
説明 |
ubuntu:22.04 |
~77MB |
完全な Ubuntu |
python:3.11 |
~1GB |
完全な Python を含む |
python:3.11-slim |
~130MB |
スリム版 |
python:3.11-alpine |
~50MB |
Alpine 版 |
1
2
3
4
5
6
7
8
|
# ❌ 太大
FROM python:3.11 # 1GB
# ✅ 推荐
FROM python:3.11-slim # 130MB
# ✅ 最小(注意 musl 兼容性问题)
FROM python:3.11-alpine # 50MB
|
Alpine は glibc ではなく musl を使用するため、一部のソフトウェアで互換性の問題が生じる可能性があります。問題に遭遇した場合は slim 版を選択してください。
4. RUN 命令を統合してレイヤー数を削減する#
各 RUN は新しいレイヤーを作成し、レイヤーが多いほどビルドが遅くなり、イメージも大きくなります。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
# ❌ 5 个层
RUN apt-get update
RUN apt-get install -y curl
RUN apt-get install -y wget
RUN apt-get clean
RUN rm -rf /var/lib/apt/lists/*
# ✅ 1 个层
RUN apt-get update && \
apt-get install -y --no-install-recommends \
curl \
wget && \
apt-get clean && \
rm -rf /var/lib/apt/lists/*
|
1
2
|
# 检查镜像层数
docker history myapp:latest
|
5. マルチステージビルドを使用する#
あるステージでビルドを行い、別のステージで実行し、必要なファイルだけをコピーします。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
# 阶段 1:构建
FROM golang:1.21-alpine AS builder
WORKDIR /app
COPY go.mod go.sum ./
RUN go mod download
COPY . .
RUN CGO_ENABLED=0 GOOS=linux go build -o app .
# 阶段 2:运行(只有 ~15MB)
FROM alpine:3.18
RUN apk --no-cache add ca-certificates
WORKDIR /root/
COPY --from=builder /app/app .
EXPOSE 8080
CMD ["./app"]
|
| 方式 |
イメージサイズ |
ビルド時間 |
| シングルステージ |
~1.2GB |
5 分 |
| マルチステージ |
~15MB |
2 分 |
6. BuildKit でビルドを高速化する#
BuildKit は並列ビルドと高度なキャッシュをサポートしています。
1
2
3
4
5
6
7
|
# 启用 BuildKit
export DOCKER_BUILDKIT=1
# 或在 /etc/docker/daemon.json 中永久配置
# {
# "features": { "buildkit": true }
# }
|
1
2
3
4
5
6
7
8
9
10
|
# 使用缓存挂载(BuildKit 特性)
# syntax=docker/dockerfile:1
FROM node:18-alpine
WORKDIR /app
COPY package.json package-lock.json ./
# 缓存挂载避免每次重新下载依赖
RUN --mount=type=cache,target=/root/.npm \
npm ci --production
COPY . .
CMD ["node", "server.js"]
|
1
2
|
# 检查 BuildKit 是否启用
docker build --progress=plain -t myapp . 2>&1 | head -5
|
7. キャッシュのインポート・エクスポートを使用する#
CI/CD では、キャッシュは毎回のビルド後に失われます。キャッシュのインポート・エクスポートを使うことで、ビルド間でキャッシュを保持できます。
1
2
3
4
5
6
7
8
9
10
11
|
# 导出到本地
docker build \
--cache-from type=local,src=/tmp/cache \
--cache-to type=local,dest=/tmp/cache \
-t myapp .
# 使用注册表作为缓存
docker build \
--cache-from type=registry,ref=myregistry/myapp:cache \
--cache-to type=registry,ref=myregistry/myapp:cache,mode=max \
-t myapp .
|
1
2
3
4
5
6
7
8
9
|
# GitHub Actions 示例
- name: Build and push
uses: docker/build-push-action@v5
with:
context: .
push: true
tags: myapp:latest
cache-from: type=gha
cache-to: type=gha,mode=max
|
8. 依存関係の並列インストール#
1
2
3
4
5
6
7
8
9
10
11
12
|
# Node.js - npm ci 比 npm install 快
RUN npm ci --production
# Python - 禁用缓存
RUN pip install --no-cache-dir -r requirements.txt
# Go - 并行下载模块
RUN go mod download
# Rust - 使用 cargo-chef
COPY --from=chef /app/recipe.json recipe.json
RUN cargo chef cook --release --recipe-path recipe.json
|
9. ビルドキャッシュと一時ファイルのクリーンアップ#
同じ RUN 命令内でクリーンアップを行い、ファイルがレイヤーに残らないようにします。
1
2
3
4
5
6
7
8
9
10
11
12
|
# ✅ 正确:同一层中清理
RUN apt-get update && \
apt-get install -y --no-install-recommends build-essential && \
make && make install && \
apt-get purge -y --auto-remove build-essential && \
apt-get clean && \
rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*
# ❌ 错误:清理在另一层,文件仍然存在
RUN apt-get update && apt-get install -y build-essential
RUN make && make install
RUN apt-get clean # 太晚了!前面的层已经包含了文件
|
各言語のクリーンアップコマンド:
1
2
3
4
5
6
7
8
|
# Node.js
RUN npm ci --production && npm cache clean --force
# Python
RUN pip install --no-cache-dir -r requirements.txt
# Go
RUN go build -o app . && go clean -cache
|
10. 特定バージョンのタグを使用する#
1
2
3
4
5
6
7
8
|
# ❌ latest 可能变化,缓存不可预测
FROM node:latest
# ✅ 特定版本
FROM node:18.17.0-alpine3.18
# ✅ 更安全:使用 SHA256 摘要
FROM node:18.17.0-alpine3.18@sha256:abc123...
|
イメージレイヤーの詳細#
1
2
|
# 查看镜像层历史
docker history <image-name>
|
新しいレイヤーを作成する命令:FROM、RUN、COPY、ADD
新しいレイヤーを作成しない命令(メタデータのみ):CMD、ENTRYPOINT、ENV、EXPOSE、WORKDIR、USER、LABEL、ARG、VOLUME
1
2
3
4
5
6
7
8
9
10
11
|
# 这会创建 4 个层
FROM node:18-alpine # 层 1
RUN apk add --no-cache curl # 层 2
COPY package.json . # 层 3
RUN npm install # 层 4
# 这些指令不增加层
WORKDIR /app # 无层
ENV NODE_ENV=production # 无层
EXPOSE 3000 # 无层
CMD ["node", "server.js"] # 无层
|
最適化効果の比較#
1
2
3
4
5
6
7
8
9
|
# ❌ 优化前(8 分钟,1.2GB)
FROM ubuntu:22.04
RUN apt-get update
RUN apt-get install -y python3 python3-pip
RUN apt-get install -y build-essential
WORKDIR /app
COPY . .
RUN pip3 install -r requirements.txt
CMD ["python3", "app.py"]
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
# ✅ 优化后(1.5 分钟,150MB)
# syntax=docker/dockerfile:1
FROM python:3.11-slim AS builder
WORKDIR /app
COPY requirements.txt .
RUN --mount=type=cache,target=/root/.cache/pip \
pip install --no-cache-dir -r requirements.txt
FROM python:3.11-slim
WORKDIR /app
COPY --from=builder /usr/local/lib/python3.11/site-packages /usr/local/lib/python3.11/site-packages
COPY . .
EXPOSE 8000
CMD ["python", "app.py"]
|
| 指標 |
最適化前 |
最適化後 |
改善 |
| ビルド時間 |
8 分 |
1.5 分 |
81% ⬇️ |
| イメージサイズ |
1.2GB |
150MB |
87% ⬇️ |
| コンテキストサイズ |
500MB |
50MB |
90% ⬇️ |
| キャッシュヒット率 |
10% |
90% |
80% ⬆️ |
監視とデバッグ#
1
2
3
4
5
6
7
8
9
10
11
|
# 显示详细构建时间
time docker build -t myapp .
# BuildKit 详细进度
DOCKER_BUILDKIT=1 docker build --progress=plain -t myapp .
# 分析镜像层
docker history myapp:latest
# 使用 dive 工具深入分析
dive myapp:latest
|