2026年7月28日
2026年7月28日
Dockerコンテナの自動再起動とWatchdog設定|restartポリシーとヘルスチェックで「固まった」コンテナを戻す
Dockerのコンテナを自動で立ち直らせる仕組みは2段階あります。プロセスが終了したときに起動し直すのが --restart ポリシー、プロセスは生きているのに応答しない「固まった」状態を見つけるのが HEALTHCHECK です。ただし、単体のコンテナ(docker run やDocker Compose)では、ヘルスチェックが unhealthy になっても自動では再起動されません。この記事では、restartポリシーの選び方を確認したうえで、ヘルスチェックの結果をもとに再起動するWatchdog(監視して再起動する仕組み)をsystemdのタイマーで組む方法と、再起動の繰り返しに気づくための確認方法を説明します。
前提はLinux上のDocker Engine安定版とDocker Compose v2(2026年10月現在)です。
「終了」と「応答なし」は別の問題
コンテナが止まる原因は大きく2つに分かれます。
- メインのプロセスが終了した(エラーで落ちた、メモリ不足で強制終了された、ホストが再起動した)。
- プロセスは動いているが仕事をしていない(PHP-FPMのワーカーが詰まった、デッドロック、外部APIの待ちで応答しない)。
1はrestartポリシーで対応できます。2はDockerから見ると「正常に動いているコンテナ」なので、restartポリシーは何もしません。ここを見分けないと「自動再起動を設定したのにサイトが止まったまま」という状態になります。
restartポリシーを選ぶ
| ポリシー | 動き |
|---|---|
no |
再起動しない(既定値) |
on-failure[:回数] |
終了コードが0以外のときだけ再起動。回数で上限を付けられる |
always |
終了理由に関係なく再起動。手動で止めた場合も、Dockerデーモンの再起動時には起動し直す |
unless-stopped |
always とほぼ同じだが、手動で止めたコンテナはデーモン再起動後も止まったまま |
Webサーバーやデータベースのように常に動いていてほしいサービスには unless-stopped が扱いやすい選択です。メンテナンスで止めたコンテナが、サーバー再起動のたびに勝手に起動してくる、ということがありません。一度だけ実行するバッチ処理には on-failure:3 のように上限付きにしておくと、失敗し続けるジョブが無限に回るのを防げます。
docker run -d --name web --restart unless-stopped nginx:stable
# 作成済みのコンテナのポリシーを変更
docker update --restart unless-stopped web
Composeでは restart: unless-stopped と書きます。deploy.restart_policy はSwarmモード向けの書き方なので、通常の docker compose up では restart を使うのが基本です。
再起動の間隔は、失敗が続くと少しずつ長くなる仕組みになっています。また、起動直後にすぐ落ちるコンテナは、短時間で再起動を繰り返さないよう扱いが調整されます(細かい挙動はバージョンで変わることがあります)。
ホストの再起動後にも戻るようにする
restartポリシーが働くのは、Dockerデーモンが動いているときだけです。サーバー起動時にDocker自体が起動するよう設定されているか確認します。
sudo systemctl enable --now docker
systemctl is-enabled docker
Dockerデーモンの更新や再起動のたびにコンテナが止まるのを避けたい場合は、/etc/docker/daemon.json に "live-restore": true を設定すると、デーモンが止まっている間もコンテナを動かし続けられます。Swarmモードとは併用できないので注意してください。設定変更の前には daemon.json のバックアップを取り、検証用のサーバーで試してから本番に反映します。
ヘルスチェックで「応答なし」を検出する
DockerfileかComposeでヘルスチェックを定義すると、コンテナの状態が starting、healthy、unhealthy のいずれかで表示されるようになります。WordPressの例です。
services:
wordpress:
image: wordpress:php8.3-apache
restart: unless-stopped
labels:
watchdog: "true"
healthcheck:
test: ["CMD-SHELL", "curl -fsS -o /dev/null http://localhost/wp-login.php || exit 1"]
interval: 30s
timeout: 5s
retries: 3
start_period: 60s
ポイントは次のとおりです。
- 確認するURLは、PHPとデータベースまで通るページにします。静的ファイルだけを見ると、PHP-FPMが詰まっていても healthy になります。
timeoutを短めにしておくと、応答が極端に遅い状態も検出できます。start_periodは起動直後の猶予です。初回起動でデータベースの準備に時間がかかる場合は長めにします。- コマンドはコンテナの中で実行されるため、
curlが入っていないイメージでは使えません。入っているかはdocker exec <コンテナ名> which curlで確かめます。
状態は次のコマンドで確認できます。
docker ps --format 'table {{.Names}}\t{{.Status}}'
docker inspect --format '{{json .State.Health}}' wordpress-wordpress-1
State.Health.Log には直近のチェック結果と出力が残るので、なぜ unhealthy になったかはここを読みます。
unhealthyなら再起動するWatchdogを作る
単体のコンテナでは unhealthy になっても再起動されないため、外から見張って再起動する仕組みを足します。ここでは追加のソフトを入れず、シェルスクリプトとsystemdのタイマーで作ります。対象は watchdog=true のラベルを付けたコンテナだけに絞ります。
#!/bin/sh
# /usr/local/bin/docker-watchdog.sh
set -eu
for name in $(docker ps --filter "label=watchdog=true" --filter "health=unhealthy" --format '{{.Names}}'); do
logger -t docker-watchdog "unhealthy: ${name} を再起動します"
docker restart -t 30 "${name}"
done
# /etc/systemd/system/docker-watchdog.service
[Unit]
Description=Restart unhealthy Docker containers
Requires=docker.service
After=docker.service
[Service]
Type=oneshot
ExecStart=/usr/local/bin/docker-watchdog.sh
# /etc/systemd/system/docker-watchdog.timer
[Unit]
Description=Run docker-watchdog every minute
[Timer]
OnBootSec=2min
OnUnitActiveSec=1min
[Install]
WantedBy=timers.target
sudo chmod 755 /usr/local/bin/docker-watchdog.sh
sudo systemctl daemon-reload
sudo systemctl enable --now docker-watchdog.timer
journalctl -t docker-watchdog --since today
ラベルで対象を絞るのは、データベースのように再起動の影響が大きいコンテナを巻き込まないためです。データベースが unhealthy になる場合は、再起動より先にディスク容量やログを確認したほうが安全です。
コンテナ内のDockerソケット(/var/run/docker.sock)をマウントして同じことを行う、既製のWatchdog用コンテナもあります。手軽ですが、Dockerソケットにアクセスできるコンテナはホスト全体を操作できる権限を持つことになります。使う場合は、配布元とメンテナンス状況を確認し、信頼できるイメージかを見極めてからにします。
Swarmモードのサービスであれば、unhealthy になったタスクは自動で入れ替えられるため、このWatchdogは不要です。
再起動の繰り返しに気づく
自動再起動は、原因を隠してしまう面もあります。再起動が続いていないかは定期的に確認します。
docker inspect --format '{{.Name}} 再起動回数={{.RestartCount}} 終了コード={{.State.ExitCode}} OOM={{.State.OOMKilled}}' $(docker ps -aq)
docker events --filter type=container --since 1h
- 終了コード137は強制終了(SIGKILL)で、
OOMKilled=trueならメモリ上限に達したことが原因です。上限を見直すか、メモリの使い方を調べます。 - 再起動回数が増え続けている場合は、
docker logs --tail 100 <コンテナ名>で落ちる直前のログを確認します。 - 外部の死活監視サービスでサイトのURLを監視し、再起動しても戻らない場合に通知が届くようにしておくと、Watchdogが効かない障害にも気づけます。
ホスト自体が固まる問題は、コンテナ側の設定では対処できません。その場合は、ホスティング事業者の監視・自動復旧機能や、systemdのハードウェアWatchdog連携(RuntimeWatchdogSec など)を検討します。
まとめ
- restartポリシーは「プロセスが終了したとき」だけ働く。常駐サービスは
unless-stopped、バッチは回数付きのon-failureが扱いやすい。 - サーバー再起動後に戻すには、Dockerデーモン自体の自動起動を有効にしておく。
- 「固まった」状態はヘルスチェックで検出する。確認先はPHPとデータベースまで通るURLにする。
- 単体のコンテナは unhealthy でも再起動されないので、ラベルで対象を絞ったWatchdogを外から動かす。
- 再起動回数・終了コード・OOMを定期的に確認し、外部監視も組み合わせる。