本番環境が完全停止!緊急対応から再発防止策まで
はじめに
本記事はVim駅伝の2026-03-18の投稿です。
はじめに
本番環境へのデプロイ直後に502 Bad Gatewayエラーが発生しました。その結果サービスが停止し、ユーザーがアクセスできない状態が30分近く続きました。
本記事では、WordPress本番環境で実際に発生した502エラーの対応記録を整理します。コミット直後のエラー発生から原因特定、緊急復旧、そして再発防止策の実装まで、約2時間の対応を時系列で解説します。
今回の障害は一見するとDocker運用上の問題に見えますが、本質的には、インフラ設計でディスクが使い切られることを前提にした運用になっていなかったことが原因です。
復旧手順と、GitHub ActionsやcronJobを活用した自動化による再発防止策は、同様の課題に直面している方の参考になるはずです。
⚠️本記事の再発防止策は、当時の状況下で迅速に実装した暫定対応です。本格的な監視・運用設計(メトリクス監視、アラート設計、ライフサイクル管理等)については別途検討が必要です。
インシデント発生:502エラー
発生時の状況
ソースコードの変更をコミットし、本番環境へのデプロイを完了した直後、サイトが502 Bad Gatewayエラーを返すようになりました。
時刻は2025年12月11日00時29分39秒。発生からの経過時刻は約15分でした。
初期の仮説
デプロイ直後のエラーであったため、以下の仮説を立てました。
- コードの問題:30行以上のコードを4行に簡素化したため、削除した要素への参照が残っている可能性がありました。
- コンテナのクラッシュ: 新しいコードが原因で何かしらのプロセスが異常終了したのではないか。
- デプロイの失敗: GitHub Actionsが正常に完了せず、中途半端な状態でデプロイされたのではないか。
※後の調査でこれらの仮説はすべて誤りでした。
原因調査:ディスク容量不足の発見
システムログの確認
WordPressとnginxのコンテナが00時29分39秒に正常終了(exitコード0)していました。
[11-Dec-2025 00:29:39] NOTICE: Finishing ...
[11-Dec-2025 00:29:39] NOTICE: exiting, bye-bye!
正常終了であれば、コードの問題ではないだろうと判断
ディスクの容量を見てみましょう
error checkpointing container state: no space left on device
Cannot restart container: mkdir: no space left on device
ディスク容量不足が根本原因であることが発覚!
ディスク使用状況の分析
ディスク使用率を確認します
Filesystem Size Used Avail Use% Mounted on
/path/to/root 19G 19G 295M 99% /
19GBのルートボリュームが99%使用されており、残り295MBしかありません。
さらに詳しく調査します
/varディレクトリ: 17GB(全体の89%)/var/libディレクトリ: 17GB(Dockerデータ)- Docker使用量: イメージ12.8GB、ボリューム1.976GB
Dockerイメージのうち75%(9.6GB)が未使用で回収可能な状態です。
不要なDockerイメージの蓄積
Dockerイメージを詳しく調査したところ、WordPressイメージが16個も保存されています。
docker images | grep slab-wp/wordpress | wc -l
16
これらのイメージは以下の2種類に分かれていました。
- 古い巨大イメージ(12月2〜4日): 1.6GB〜1.7GB × 5個 = 約8GB
- 新しいイメージ(12月4〜8日): 353MB × 11個 = 約3.8GB
現在使用中のイメージはlatestタグの1つのみで、他の15個はすべて不要でした。合計で約12GBが無駄に消費されていたのです。
なぜイメージが蓄積したのか
根本原因は、以下の4つの要素がなかったからだと思います
- ディスク使用量の監視システム
- 使用率超過時のアラート
- Dockerリソースの定期クリーンアップ
- デプロイ時の古いイメージ削除
復旧:15分での対応
コンテナの再起動
停止しているコンテナの再起動を試みます
cd /home/ubuntu/slab-wp/docker
docker compose -f docker-compose.prod.yml restart wordpress nginx
しかし、ディスク容量不足のため再起動に失敗
Error: exec: "/docker-entrypoint.sh": stat: no such file or directory
イメージの再取得とコンテナ再作成
WordPressコンテナは再作成に成功しましたが、nginxは失敗しました。そこで、nginxイメージを再取得してから起動しました。
# 破損したnginxコンテナを削除
docker rm -f slab-nginx
# 新しいイメージを取得
docker pull nginx:alpine
# コンテナを再作成
docker compose -f docker-compose.prod.yml up -d nginx
この手順により、サイトが復旧しました。最終確認をします。
curl -s -o /dev/null -w '%{http_code}' https://scriptlab.jp
200
不要リソースの削除:11.5GBの回収
Dockerイメージの削除
復旧したのでディスク容量の問題に対処します。現在使用中のlatestタグ以外のWordPressイメージをすべて削除します
docker images --format '{{.ID}}' | \
grep -E '^(XXXXXXXXX|XXXXXXXXX|XXXXXXXXX|...)$' | \
xargs docker rmi -f
14個のイメージを削除できました
未使用ボリュームの削除
使用されていないDockerボリュームも削除しましょう
docker volume prune -f
6個のボリュームが削除され、1.359GBを回収しました。
削除後のディスク状況
クリーンアップ後、ディスク使用率が劇的に改善されました。
Filesystem Size Used Avail Use% Mounted on
/path/to/root 19G 7.5G 11G 41% /
合計で約11.5GBを回収できました
再発防止策の実装
GitHub Actionsへの自動削除追加
デプロイ時に自動的に古いイメージを削除するよう、GitHub Actionsワークフローを修正しました。
.github/workflows/deploy.ymlに以下の処理を追加しました。
# Cleanup old images (keep only latest 2 versions)
echo "Cleaning up old Docker images..."
docker images --format '{{.ID}}\t{{.Repository}}:{{.Tag}}\t{{.CreatedAt}}' | \
grep '${{ env.ECR_REPOSITORY }}' | \
grep -v 'latest' | \
sort -k3 -r | \
tail -n +3 | \
awk '{print $1}' | \
xargs -r docker rmi -f || true
# Cleanup untagged images
docker image prune -f
# Cleanup unused volumes
docker volume prune -f
この処理により、デプロイのたびに以下が実行されます。
- 最新2バージョン以外のWordPressイメージを削除
- タグなしイメージの削除
- 未使用ボリュームの削除
定期クリーンアップのcron設定
週次で自動クリーンアップを実行するスクリプトを作成しました。
#!/bin/bash
# /path/to/docker-cleanup.sh LOG_FILE="/path/to/docker-cleanup.log" echo "=== Docker Cleanup Started: $(date) ===" >> ${LOG_FILE} # Remove old WordPress images (keep only latest 2) docker images --format '{{.ID}}\t{{.Repository}}:{{.Tag}}\t{{.CreatedAt}}' | \ grep 'slab-wp/wordpress' | \ grep -v 'latest' | \ sort -k3 -r | \ tail -n +3 | \ awk '{print $1}' | \ xargs -r docker rmi -f >> ${LOG_FILE} 2>&1 || true # Remove dangling images docker image prune -f >> ${LOG_FILE} 2>&1 # Remove unused volumes docker volume prune -f >> ${LOG_FILE} 2>&1 echo "=== Docker Cleanup Completed: $(date) ===" >> ${LOG_FILE}
cronジョブとして毎週日曜日12時に実行するよう設定しました。
0 12 * * 0 /path/to/docker-cleanup.sh
ディスク容量監視の導入
30分ごとにディスク使用率をチェックし、閾値を超えた場合にログに記録するスクリプトを作成しました。
#!/bin/bash
# /path/to/disk-monitor.sh THRESHOLD_WARNING=80 THRESHOLD_CRITICAL=90 LOG_FILE="/path/to/disk-monitor.log" USAGE=$(df / | tail -1 | awk '{print $5}' | sed 's/%//') DATE=$(date '+%Y-%m-%d %H:%M:%S') if [ ${USAGE} -ge ${THRESHOLD_CRITICAL} ]; then MESSAGE="CRITICAL: Disk usage is ${USAGE}% (threshold: ${THRESHOLD_CRITICAL}%)" echo "[${DATE}] ${MESSAGE}" >> ${LOG_FILE} logger -t disk-monitor -p user.crit "${MESSAGE}" elif [ ${USAGE} -ge ${THRESHOLD_WARNING} ]; then MESSAGE="WARNING: Disk usage is ${USAGE}% (threshold: ${THRESHOLD_WARNING}%)" echo "[${DATE}] ${MESSAGE}" >> ${LOG_FILE} logger -t disk-monitor -p user.warning "${MESSAGE}" fi
cronジョブとして30分ごとに実行するよう設定しました。
*/30 * * * * /path/to/disk-monitor.sh
閾値は以下のように設定しました。
- 80%: 警告レベル – ログに記録
- 90%: アラートレベル – ログに記録+syslogに送信
ポストモーテム:学んだ教訓
予防的メンテナンスの重要性
今回の障害から、以下の教訓を得ました。
インフラメトリクスの継続的な監視が必須: ディスク使用率を定期的にチェックし、閾値を超えた時点でアラートを発する仕組みが必要
問題が発生する前の定期的なクリーンアップ: 手動での対応ではなく、自動化されたクリーンアップを事前に実装すべき
デプロイプロセスの検証: デプロイが正常に動作していることを定期的に確認する仕組みが必要でした。
終わりに
WordPress本番環境で発生した502エラーの対応記録をご紹介しました。
障害は誰にでも起こりうるものです。重要なのは、再発防止策を確実に実装することです。監視、アラート、自動化の3つの仕組みをすべて実装することで、同様の問題の再発を防ぐことができます。本記事が、同様の課題に直面している方の助けになれば嬉しいです!
コメントを残す