Dockerコンテナが Restarting を繰り返す:logs・inspect・起動コマンドを見る順番

Photo: Wolfgang Weiser / Pexels
先に結論です。docker ps で Restarting が続くときは、コンテナの中で動くはずのプロセスがすぐ終わり、再起動ポリシー(restart: always や unless-stopped)がそれを起こし直している状態です。原因は Docker 本体ではなく、ほとんどが 中のアプリが起動直後に終了している理由 にあります。次の順番で見ると、闇雲に作り直すより早く原因に届きます。
docker logsでアプリ自身のエラーを読むdocker inspectで終了コードと OOM の有無を見る- 起動コマンド・マウント・環境変数を確認する
まず状態を確認する
docker ps -a
STATUS 列に Restarting (1) 10 seconds ago のように表示されます。カッコ内の数字は 直前に終了したときの終了コード です。この数字が原因の手がかりになるので、メモしておきます。
Docker Compose で動かしている場合は、次のコマンドでも同じ情報が見られます。
docker compose ps -a
手順1:docker logs でアプリのエラーを読む
いちばん情報が多いのはログです。再起動を繰り返していても、直前までのログは読めます。
docker logs --tail 50 <コンテナ名>
# Compose の場合
docker compose logs --tail 50 <サービス名>
見るのは最後の数行です。Permission denied、No such file or directory、connection refused、missing required environment variable のような一文が出ていれば、それがほぼ答えです。
ログが空のまま再起動している場合は、アプリが何も出力する前に終わっています。その場合は次の inspect に進みます。
手順2:docker inspect で終了コードを見る
docker inspect --format 'ExitCode={{.State.ExitCode}} OOMKilled={{.State.OOMKilled}} Restarts={{.RestartCount}} Error={{.State.Error}}' <コンテナ名>
終了コードは、一般に次のように読むとされています。
| 終了コード | よくある意味 | 次に見るところ |
|---|---|---|
| 0 | 正常終了した(常駐しないコマンドだった) | 起動コマンド |
| 1 | アプリが自分でエラー終了した | ログ・設定ファイル |
| 126 | コマンドに実行権限がない | スクリプトの権限 |
| 127 | コマンドが見つからない | command: の書き間違い |
| 137 | 強制終了(SIGKILL)。OOMKilled=true ならメモリ不足 | メモリ上限・ホストの空きメモリ |
| 139 | セグメンテーション違反 | イメージのアーキテクチャ・バージョン |
終了コード 0 で Restarting は見落としやすいパターンです。アプリは正常に終わっているのに、restart: always が付いているので起こし直され続けています。一度だけ実行するタスク用のイメージを常駐サービスとして書いてしまったときなどに起こります。
137 で OOMKilled=true なら、コンテナのメモリ上限(mem_limit など)か、ホスト全体のメモリが足りていません。free -h でホストの空きを確認し、上限を上げるか、同時に動かすコンテナを減らします。ミニPC で多くのサービスを動かしていて常にメモリが厳しいなら、増設できる機種であればメモリを足すのも手です。
手順3:起動コマンド・マウント・環境変数を見る
ログと終了コードで当たりがついたら、設定側を確認します。まず、Compose ファイルが意図どおりに解釈されているかを見ます。
docker compose config
変数の展開後の内容が表示されるので、.env の値が空になっていないか、パスがずれていないかを確認できます。
よくある原因と直し方
- 設定ファイルのはずがディレクトリになっている:バインドマウントでホスト側のパスが存在しないと、Docker はそこに空のディレクトリを作ります。
./config.yml:/app/config.ymlのつもりが、ホストにconfig.ymlという名前のフォルダができていたら、それが原因です。フォルダを消して、正しいファイルを置いてから起動し直します - 権限が足りない:マウントしたフォルダの所有者と、コンテナ内のユーザー(
PUID/PGIDなど)が合っていないと、書き込みで失敗して終了します。ls -lnでホスト側の UID・GID を確認します - 必須の環境変数がない:DB のパスワードや管理者ユーザー名を必須にしているイメージは多いです。イメージの説明ページで必須の変数を確認します
- 依存先が起動前に接続しに行っている:アプリが DB より先に起動して接続に失敗するケースです。
depends_onにcondition: service_healthyを付け、DB 側に healthcheck を書くと順番を待たせられます - アーキテクチャが違う:ラズパイ(arm64)で amd64 専用のイメージを動かすと
exec format errorで終わります。イメージが arm64 に対応しているか確認します
再起動ループを止めて中を調べる
再起動が速すぎて調べにくいときは、いったん再起動ポリシーを外します。
docker update --restart=no <コンテナ名>
そのうえで、起動コマンドを差し替えてシェルで入ると、マウントされたファイルや権限をコンテナの中から確認できます。
docker compose run --rm --entrypoint sh <サービス名>
中で ls -l や id を実行し、アプリが読むファイルが見えているか、書き込めるユーザーで動いているかを確かめます。原因を直したら、Compose ファイルの restart: は元のままなので、docker compose up -d --force-recreate <サービス名> で作り直せば元の再起動ポリシーに戻ります(docker update での変更は Compose からは差分として見えないため、--force-recreate を付けます)。
確認の順番まとめ
docker ps -aの STATUS で終了コードをメモしたdocker logs --tail 50で最後のエラーを読んだdocker inspectで ExitCode・OOMKilled を見たdocker compose configで展開後の設定を確認した- 必要なら再起動を止めて、シェルで中を確認した
まとめ
- Restarting は「中のプロセスがすぐ終わる」状態。Docker ではなくアプリ側の理由を探す
- 見る順番は logs → inspect の終了コード → 起動コマンド・マウント・環境変数
- 終了コード 0 は常駐しないコマンド、137 はメモリ不足を疑う
- 調べにくいときは
docker update --restart=noで止めて、シェルで中を確認する
運営者が作った Excel テンプレートを BOOTH で配布しています。IT 資産管理台帳(無料 Lite 版あり) / IT 資格の学習管理シート


