Dockerコンテナの無限再起動ループでお困りの方へ。メモリ不足、設定ミス、アプリケーションエラーなど主要原因と実践的な解決手順を詳しく解説します。
Dockerコンテナの再起動ループでお困りではありませんか?
「Dockerコンテナが勝手に再起動を繰り返して、サービスが安定しない...」「ログを見ても原因がよくわからない...」そんな悩みを抱えていませんか?
先日、あるクライアントから「LaravelアプリをDocker化したが、本番環境でコンテナが頻繁に再起動してしまう」という相談を受けました。調査の結果、メモリ不足とアプリケーション設定の組み合わせが原因で、適切な対処により安定稼働を実現できました。
Dockerコンテナの再起動ループは、Web開発において深刻な問題です。ユーザー体験の悪化、データの整合性問題、開発効率の低下など、様々な影響を及ぼします。しかし、原因を正しく特定し、適切な対処を行えば確実に解決できる問題でもあります。
本記事では、20年以上のWeb開発実績を持つ弊社が、実際の案件で遭遇した事例をもとに、コンテナ再起動問題の原因特定から解決まで、実践的な手順を詳しく解説します。
なぜDockerコンテナが再起動を繰り返すのか?
Dockerコンテナが無限に再起動する現象は、主に以下の原因で発生します。実際の案件での遭遇頻度も含めてご紹介します。
1. リソース不足(特にメモリ)
最も多い原因がメモリ不足です。Laravelアプリケーションの場合、Composerの依存関係解決やフレームワーク初期化で予想以上のメモリを消費します。コンテナに割り当てられたメモリ上限を超えると、Dockerがプロセスを強制終了し、再起動ポリシーにより自動的に再起動されます。
2. アプリケーション内のエラー
データベース接続エラー、設定ファイルの不備、Fatal Errorなどにより、アプリケーションが正常に起動できない場合も再起動ループの原因となります。特に環境変数の設定ミスが多く見られます。
3. Docker設定の問題
ヘルスチェックの設定が厳しすぎる、restart policyの設定ミス、ボリュームマウントの問題などが原因となることもあります。
4. 依存サービスとの接続問題
データベースやRedisなどの依存サービスが準備完了前にアプリケーションが起動を試みることで、接続失敗により再起動が発生することがあります。
段階的な原因特定と解決手順
実際の案件で効果的だった、段階的なトラブルシューティング手順をご紹介します。
ステップ1: ログの確認と状況把握
まずは現在の状況を正確に把握します:
# コンテナの状態確認
docker ps -a
# 再起動回数とステータス確認
docker stats --no-stream
# コンテナログの確認
docker logs -f [コンテナ名]
# システムログの確認(Linux)
dmesg | grep -i "killed process"
ある案件では、ログに「Killed」という表示が繰り返し出力されており、これがOOM Killerによるメモリ不足が原因であることが判明しました。
ステップ2: リソース使用量の監視
リアルタイムでのリソース消費を監視します:
# リソース使用量のリアルタイム監視
docker stats [コンテナ名]
# より詳細なメモリ使用量確認
docker exec [コンテナ名] cat /proc/meminfo
# プロセス別メモリ使用量
docker exec [コンテナ名] ps aux --sort=-%mem | head -10
ステップ3: アプリケーション固有の対処
Laravel アプリケーションの場合
# docker-compose.yml の設定例
version: '3.8'
services:
app:
build: .
deploy:
resources:
limits:
memory: 1G
reservations:
memory: 512M
environment:
- APP_ENV=production
- DB_CONNECTION=mysql
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost/health"]
interval: 30s
timeout: 10s
retries: 3
start_period: 40s
restart: unless-stopped
depends_on:
db:
condition: service_healthy
PHP設定の最適化
# php.ini の設定例
memory_limit = 512M
max_execution_time = 300
post_max_size = 50M
upload_max_filesize = 50M
max_input_vars = 3000
# OPcache設定(本番環境)
opcache.enable=1
opcache.memory_consumption=256
opcache.max_accelerated_files=20000
opcache.validate_timestamps=0
依存関係の待機処理
# Dockerfile内での依存関係待機
COPY wait-for-it.sh /usr/local/bin/
RUN chmod +x /usr/local/bin/wait-for-it.sh
# エントリーポイントで依存サービスを待機
ENTRYPOINT ["wait-for-it.sh", "db:3306", "--", "php-fpm"]
ステップ4: モニタリングの強化
再発防止のため、継続的なモニタリング環境を構築します:
# Prometheus メトリクス収集(docker-compose.yml に追加)
prometheus:
image: prom/prometheus
volumes:
- ./prometheus.yml:/etc/prometheus/prometheus.yml
ports:
- "9090:9090"
grafana:
image: grafana/grafana
ports:
- "3000:3000"
environment:
- GF_SECURITY_ADMIN_PASSWORD=admin
よくある失敗パターンと対処法
実際の案件で遭遇した失敗例とその対処法をご紹介します。
失敗例1: メモリ制限を緩くしすぎる
「メモリ不足なら制限を大きくすればいい」と考え、無制限に設定してしまうケースです。これは他のコンテナやホストシステムに影響を与える可能性があります。
対処法: 適切な制限値を段階的に設定し、実際の使用量を監視しながら調整する。
# 段階的なメモリ制限の設定例
deploy:
resources:
limits:
memory: 800M # 最大値
reservations:
memory: 400M # 最小保証値
失敗例2: ヘルスチェックの設定ミス
ヘルスチェックの間隔が短すぎる、またはタイムアウトが厳しすぎることで、正常なコンテナも異常と判定されてしまうケースです。
対処法: アプリケーションの起動時間を考慮した現実的な値を設定する。
healthcheck:
test: ["CMD", "php", "artisan", "tinker", "--execute=echo 'OK';"]
interval: 60s # 間隔を長めに
timeout: 30s # タイムアウトを十分に
retries: 3
start_period: 120s # 初回起動に十分な時間を確保
失敗例3: ログレベルの設定不備
本番環境でデバッグログが大量に出力され、ディスク容量やI/O負荷が原因で不安定になるケースです。
対処法: 環境に応じた適切なログ設定を行う。
# 本番環境用設定
APP_DEBUG=false
LOG_LEVEL=error
LOG_CHANNEL=stack
DB_SLOW_QUERY_LOG=false
失敗例4: 依存関係の起動順序を考慮していない
データベースが起動完了前にアプリケーションが接続を試み、接続失敗により再起動が発生するケースです。
対処法: depends_on と healthcheck を組み合わせて適切な起動順序を制御する。
まとめと次のステップ
Dockerコンテナの再起動ループ問題は、適切な手順で原因を特定し対処すれば確実に解決できます。重要なのは、症状だけでなく根本原因を突き止めることです。
弊社での対応事例では、適切な対処により99.9%の稼働率を実現し、1日あたり20回以上の再起動が0回まで改善されました。お客様からは「ようやく安心してサービスを運営できる」との声をいただいています。
すぐに実行すべき対処チェックリスト
もし「原因の特定が難しい」「対処方法がわからない」「安定した本番環境を構築したい」などのお悩みがございましたら、お気軽にご相談ください。20年以上のWeb開発実績を持つ弊社が、お客様の環境に最適な解決策をご提案いたします。
次回は、「Docker Composeでの複数サービス連携時のパフォーマンス最適化」について詳しく解説予定です。安定したコンテナ環境の構築と運用について、引き続きお役立ち情報をお届けします。