Docker: パフォーマンスチューニングとトラブルシューティング
最終更新:2026-08-26
本番環境のコンテナで問題が発生していませんか——CPU 使用率が高い、メモリがオーバーロードする、I/O が遅い。こうした状況には体系的なトラブルシューティングアプローチが必要です。
1. 学べること
- パフォーマンスボトルネックの特定方法
- 一般的な障害シナリオとその根本原因
- コンテナデバッグのツールチェーン
- ネットワーク遅延のトラブルシューティング
- ディスクスペース管理
2. 早朝のアラートの物語
(1) 悩み: API レイテンシが 50 ms から 5 s へ急増
本番環境の API レイテンシが 50 ms から 5 s へ急増し、ユーザーからの苦情が殺到しました。Alice は docker stats で原因を調べたところ、CPU 使用率はスパイクしていないものの、I/O 待機時間が極めて高く、コンテナが「固まっている」ように見えました。
(2) 体系的なトラブルシューティング
Alice は iostat を使ってログドライバがディスク I/O を限界まで使い切っていることを突き止め、ログドライバを切り替えて問題を解消しました。
BASH
# ステップ 1: リソース使用量を確認
docker stats --no-stream
# ステップ 2: ホストの I/O を確認
iostat -x 1 5
# ステップ 3: ボトルネックを特定
docker system df -v
(3) 効果: 5 秒 → 50 ミリ秒、復旧時間わずか 10 分
アラート発生から解決までわずか 10 分。「再起動してみる」という場当たり的な対応よりも、体系的なトラブルシューティングのほうが 100 倍効率的です。
3. パフォーマンストラブルシューティングの意思決定ツリー
(1) 4 つの主要なボトルネックと対応するツール
graph TB
START["パフォーマンス問題"] --> CPU{"CPU が高い?"}
CPU -->|はい| C1["docker stats<br/>top / htop"]
CPU -->|いいえ| MEM{"メモリ使用量が高い?"}
MEM -->|はい| M1["docker stats<br/>/proc/meminfo"]
MEM -->|いいえ| IO{"I/O 待機が高い?"}
IO -->|はい| I1["iostat -x<br/>docker system df"]
IO -->|いいえ| NET{"ネットワークが遅い?"}
NET -->|はい| N1["iperf / ping<br/>tcpdump"]
(2) 一般的なトラブルシューティングツール
| ツール | 機能 | 用途 |
|---|---|---|
docker stats |
コンテナのリソース使用量 | CPU / メモリ / I/O の概要 |
docker system df |
Docker のディスク使用量 | ディスクフルの調査 |
docker events |
コンテナイベントストリーム | OOM / 再起動 / 異常終了 |
docker logs |
コンテナログ | アプリケーションエラー |
docker inspect |
コンテナ設定 | ステータス / 終了コード / ネットワーク |
iostat |
ディスク I/O 統計 | I/O ボトルネック |
iperf |
ネットワーク帯域テスト | ネットワークボトルネック |
nsenter |
コンテナ名前空間への進入 | 高度なデバッグ |
4. CPU ボトルネックのトラブルシューティング
▶ サンプル: docker stats でリソースを監視 (難易度: ⭐)
BASH
# 全コンテナをリアルタイムで監視
docker stats
# ワンショットスナップショット
docker stats --no-stream
# カスタムフォーマット
docker stats --format "table {{.Name}}\t{{.CPUPerc}}\t{{.MemUsage}}\t{{.NetIO}}\t{{.BlockIO}}"
▶ サンプル: stress コンテナで CPU 負荷をシミュレート (難易度: ⭐⭐)
BASH
# stress を実行して CPU 負荷をシミュレート
docker run --rm --name stress-test \
--cpus=1 \
progrium/stress --cpu 1 --timeout 30s
# 別のターミナルで docker stats を使って監視
docker stats stress-test --no-stream
5. メモリボトルネックのトラブルシューティング
(1) よくあるメモリ問題
| 症状 | 終了コード | 原因 | 対策 |
|---|---|---|---|
| OOM Kill | 137 | --memory 上限を超過 |
上限を引き上げる、またはメモリ使用量を最適化 |
| メモリリーク | 徐々に増加 | アプリケーションのバグ | ヒープダンプの解析 |
| キャッシュ使用量が高い | 0 | ファイルシステムキャッシュ | 正常な動作 (回収可能) |
▶ サンプル: コンテナ OOM のシミュレーション (難易度: ⭐⭐⭐)
BASH
# 50 MB のメモリ制限でコンテナを起動
docker run -d --name oom-test \
--memory=50m \
--restart=on-failure:3 \
progrium/stress --vm 1 --vm-bytes 100M --timeout 10s
# OOM イベントを監視
docker events --filter event=oom --since 1m
# 終了コードを確認
docker inspect oom-test --format='ExitCode: {{.State.ExitCode}}, OOMKilled: {{.State.OOMKilled}}'
6. ディスク I/O ボトルネックのトラブルシューティング
▶ サンプル: docker system df でディスクを分析 (難易度: ⭐⭐)
BASH
# Docker のディスク使用量を表示
docker system df
# 詳細な内訳
docker system df -v
💻 出力:
TEXT
📖 参照専用
TYPE TOTAL ACTIVE SIZE RECLAIMABLE
Images 12 5 4.2GB 2.8GB (66%)
Containers 8 3 350MB 280MB (80%)
Local Volumes 5 3 1.2GB 500MB (41%)
Build Cache 45 0 800MB 800MB (100%)
▶ サンプル: ディスククリーンアップポリシー (難易度: ⭐⭐)
BASH
# 未使用のデータ (イメージ、コンテナ、ボリューム、ビルドキャッシュ) を削除
docker system prune
# より積極的: 未使用のイメージをすべて削除 (dangling だけでなく)
docker system prune -a
# ビルドキャッシュのみを削除
docker builder prune
# ボリュームを削除 (注意: データが削除されます)
docker volume prune
(1) ストレージドライバの比較
| ドライバ | パフォーマンス | 安定性 | 推奨 |
|---|---|---|---|
| overlay2 | 高 | ✅ 安定 | ✅ デフォルトで推奨 |
| aufs | 中 | ⚠️ 古いカーネル | ❌ 非推奨 |
| devicemapper | 低 | ⚠️ 設定が複雑 | ❌ 非推奨 |
| zfs | 中 | ✅ 安定 | 特定のシナリオ |
| btrfs | 中 | ⚠️ 不安定 | ❌ 非推奨 |
7. ネットワークトラブルシューティング
▶ サンプル: iperf によるネットワーク帯域テスト (難易度: ⭐⭐⭐)
BASH
# コンテナ内で iperf3 サーバーを起動
docker run -d --name iperf-server --network host networkstatic/iperf3 -s
# 別のコンテナから iperf3 クライアントを実行
docker run --rm --network host networkstatic/iperf3 -c localhost -t 10
# 異なるネットワーク上の 2 つのコンテナ間でテスト
docker run --rm --network app-net networkstatic/iperf3 -c db -t 5
▶ サンプル: Docker Events によるイベントトレース (難易度: ⭐⭐)
BASH
# コンテナライフサイクルイベントを監視
docker events --filter type=container
# 特定のイベントでフィルタ
docker events --filter event=oom --filter event=die --filter event=restart
# 時刻ベースのフィルタ
docker events --since "2024-01-15T03:00:00" --until "2024-01-15T04:00:00"
8. 高度なデバッグ: nsenter
▶ サンプル: nsenter でコンテナ名前空間に進入 (難易度: ⭐⭐⭐)
BASH
# コンテナのメイン PID を取得
PID=$(docker inspect --format='{{.State.Pid}}' myapp)
# コンテナのネットワーク名前空間に進入してデバッグ
nsenter -t $PID -n tcpdump -i eth0 -c 100 port 8080
# コンテナのプロセス名前空間に進入
nsenter -t $PID -p -m strace -p 1
💡 ヒント: nsenter は
docker exec より低いレベルで動作し、コンテナ内にシェルが不要で、コンテナの Linux 名前空間に直接進入します。scratch イメージや distroless イメージのデバッグに適しています。**
9. トラブルシューティングガイド: よくある問題と解決策
| 症状 | トラブルシューティングコマンド | よくある原因 | 解決策 |
|---|---|---|---|
| コンテナが頻繁に再起動する | docker ps -a + docker logs |
OOM / アプリクラッシュ | メモリ増設 / バグ修正 / 再起動ポリシー |
| ディスクスペースが満杯 | docker system df -v |
ログ / イメージ / ボリュームの蓄積 | docker system prune + ログローテーション |
| ネットワーク接続がタイムアウト | docker exec ping + nc |
ネットワーク設定エラー | ネットワーク / DNS / ポートを確認 |
| ビルドが遅い | docker build --progress=plain |
キャッシュの期限切れ | COPY の順序を調整 |
| コンテナ起動に失敗 | docker logs + docker inspect |
設定エラー / 依存関係の不足 | 設定を修正 / 依存関係を確認 |
| I/O 待機が高い | iostat -x |
ログドライバ / 大量書き込み | ログドライバを切り替え / 書き込みを最適化 |
10. 完全なサンプル: コンテナ OOM 問題のトラブルシューティングと解決
BASH
# ============================================
# 完全な手順: OOM 診断と修正
# カバー範囲: stats、events、logs、inspect、修正
# ============================================
# 1. 問題のあるコンテナをデプロイ
docker run -d \
--name leaky-app \
--memory=100m \
--restart=on-failure:5 \
-p 8080:8080 \
myapp:1.0
# 2. リソース使用量を監視
docker stats leaky-app --no-stream
# 3. メモリリークをシミュレート (OOM を発生させる)
docker exec leaky-app python -c "
import itertools
data = []
for i in itertools.count():
data.append('x' * 1024 * 1024) # 1 MB ずつ
if i % 10 == 0:
import time; time.sleep(0.1)
"
# 4. OOM イベントをキャプチャ
docker events --filter container=leaky-app --filter event=oom --since 1m
# 5. 終了コードと OOM ステータスを確認
docker inspect leaky-app --format='
ExitCode: {{.State.ExitCode}}
OOMKilled: {{.State.OOMKilled}}
Memory Limit: {{.HostConfig.Memory}}
'
# 6. アプリログでメモリパターンを確認
docker logs --tail 100 leaky-app 2>&1 | grep -i "memory\|alloc\|oom"
# 7. 対策: メモリ上限を引き上げる
docker stop leaky-app && docker rm leaky-app
docker run -d \
--name leaky-app \
--memory=512m \
--restart=on-failure:5 \
--log-opt max-size=10m \
--log-opt max-file=3 \
-p 8080:8080 \
myapp:1.0
# 8. 監視アラートを設定
docker events --filter event=oom | while read event; do
echo "ALERT: OOM detected at $(date)" >> /var/log/docker-alerts.log
done
❓ よくある質問
Q コンテナのパフォーマンス問題を階層的にトラブルシューティングするにはどうすればよいですか?
A 4 ステップのアプローチです。①
docker stats で CPU、メモリ、I/O の概要を確認。② 最も高い指標に応じて適切なツールを選択 (CPU → top、メモリ → smem、I/O → iostat、ネットワーク → iperf)。③ 具体的なコンテナまたはプロセスを特定。④ アプリケーションログを分析して根本原因を特定します。Q overlay2 と aufs のどちらが良いですか?
A overlay2 のほうが優れており、Docker のデフォルトかつ唯一の推奨ストレージドライバです。aufs は非推奨となり、Docker 24 以降ではサポートされていません。overlay2 はより高いパフォーマンス、よりシンプルな実装、よりアクティブなコミュニティサポートを提供します。
Q コンテナのディスクが満杯になったとき、どうやってスペースを確保しますか?
A
docker system df -v で最も容量を消費しているものを確認し、それに応じてクリーンアップします。① イメージ: docker image prune -a。② ビルドキャッシュ: docker builder prune。③ コンテナ: docker container prune。④ ボリューム: docker volume prune (注意: データが削除されるため慎重に)。⑤ すべて: docker system prune -a。Q コンテナの I/O が遅い問題をトラブルシューティングするには?
A ①
docker stats で BlockIO 列を確認。② ホストで iostat -x 1 を実行し、%util と await を確認。③ docker system df -v でストレージドライバの使用状況を確認。④ よくある原因: ログドライバがディスクを埋めている、overlay2 レイヤーが多すぎる、遅いディスクへの bind mount。Q コンテナのネットワークレイテンシをテストするには?
A iperf3 を使用します。サーバーコンテナで
iperf3 -s、クライアントコンテナで iperf3 -c server を実行し、スループットとレイテンシを測定します。コンテナ間でテストするには、それらが同じネットワーク上にあるか、--network host オプションを使用する必要があります。📖 まとめ
- パフォーマンストラブルシューティングの意思決定ツリー: CPU → メモリ → I/O → ネットワーク。階層的に切り分ける
docker statsでリアルタイム監視、docker system dfでディスク分析- OOM トラブルシューティング:
docker eventsとinspectで問題を検証し、メモリを引き上げるかアプリを修正 - ディスククリーンアップ:
docker system pruneで一键清理、ログローテーションで蓄積を防止 - overlay2 のみが推奨されるストレージドライバ
- nsenter: コンテナ名前空間に進入して高度なデバッグを行う
📝 練習問題
- 基礎問題 (難易度 ⭐):
stressコンテナを使って CPU 負荷をシミュレートし、docker statsで CPU 使用率の変化を監視してください。 - 応用問題 (難易度 ⭐⭐):
docker system df -vでディスク使用量を分析し、docker system prune -aでクリーンアップを実行、ディスクスペースの差を比較してください。 - 挑戦問題 (難易度: ⭐⭐⭐): iperf3 を使って 2 つのコンテナ間のネットワーク帯域をテストし、bridge ネットワークと host ネットワークのパフォーマンス差を比較してください。