docker『Cannot Start Service』の原因と対処法
- 作成日 2025.11.13
- その他
Docker/Composeでサービスが起動できず停止・再試行を繰り返す状態。典型原因は「コンテナの実行失敗(ENTRYPOINT/CMD/権限)」「ポート競合」「ボリューム/バインドマウントの不整合」「依存サービス未起動」「リソース不足(メモリ/ディスク/ulimit)」「設定値の不正(環境変数・ネットワーク・デバイス)」など。まずエラーメッセージと直前ログを取り、構成・実行条件・外部要因の順に切り分ける。
目次
- 1. 最短切り分け(イベント/ログ/設定を同時に確認)
- 2. コンテナ自体が即終了(ENTRYPOINT/CMD/実行権限/依存ファイル)
- 3. ポート競合(すでに使用中 / 予約済み)
- 4. ボリューム/バインドマウントの失敗(パス/権限/SELinux)
- 5. 依存サービス未起動/未到達(depends_on/ヘルスチェック)
- 6. リソース不足(メモリ/OOM・ディスク/ENOSPC・ulimit)
- 7. 環境変数・設定ファイル不足(Exit 1の定番)
- 8. ネットワーク/名前解決/プロキシ(DNSやHTTP_PROXYの不整合)
- 9. 権限・セキュリティ(ユーザー/SELinux/AppArmor/Capability)
- 10. デバイス/GPU/特権が必要なサービス
- 11. Composeの構文・バージョン不整合(未知のフィールド/古いCompose)
- 12. Docker Desktop/WSL2/macOS/Windowsの特有ポイント
- 13. 最小再現テンプレ(「起動そのもの」を検証)
- 14. NG→OK 早見表(クイック修正)
- 15. チェックリスト(上から順に潰す)
最短切り分け(イベント/ログ/設定を同時に確認)
# 直近のエラーとイベント
docker compose ps
docker compose logs --no-color --tail=200 <service>
docker inspect <container_or_image> --format '{{json .State}}' | jq .
# 詳細デバッグ(Compose)
docker compose --verbose up <service>
# 単体で起動→ENTRYPOINT/CMD切り分け
docker compose run --rm --entrypoint sh <service>コンテナ自体が即終了(ENTRYPOINT/CMD/実行権限/依存ファイル)
# イメージのエントリ/コマンドを確認
docker image inspect <image>:<tag> --format '{{json .Config}}' | jq '.Entrypoint,.Cmd'
# exec形式CMDにする(シグナル伝播/引数処理が安定)
# docker-compose.yml(例)
services:
app:
image: node:20-alpine
command: ["node","server.js"] # ← exec形式
# shell形式だと"/bin/sh -c ..."経由
# 実行権限不足で126 → 実行ビット付与して再ビルド
RUN chmod +x /usr/local/bin/start.shポート競合(すでに使用中 / 予約済み)
# 競合確認(Linux/macOS)
lsof -iTCP -sTCP:LISTEN -nP | grep :8080 || true
# Composeのポート定義を見直し
services:
web:
image: nginx
ports:
- "8080:80" # ホスト8080が使用中なら他へ変更ボリューム/バインドマウントの失敗(パス/権限/SELinux)
# 典型:ソースが存在しない・権限不足で起動失敗
services:
app:
image: alpine
volumes:
- /abs/path/data:/app/data # ソースは事前に mkdir -p で用意
# SELinuxがある場合は :z/:Z を付ける(RHEL系)
volumes:
- /abs/path/data:/app/data:Z依存サービス未起動/未到達(depends_on/ヘルスチェック)
# healthcheck と depends_on のconditionsで待つ
services:
db:
image: postgres:16
healthcheck:
test: ["CMD-SHELL","pg_isready -U postgres"]
interval: 5s
timeout: 3s
retries: 10
app:
image: my/app:1.0
depends_on:
db:
condition: service_healthy
# 外部依存に対しては起動時スクリプトで待機(例:wait-for-it.sh)
command: ["sh","-lc","./wait-for-it.sh db:5432 -- ./start.sh"]
リソース不足(メモリ/OOM・ディスク/ENOSPC・ulimit)
# OOMKilledの有無
docker inspect <container> --format '{{json .State}}' | jq '.OOMKilled,.ExitCode'
# メモリ/スワップ制限を緩める
services:
app:
deploy:
resources:
limits:
memory: 1g
# ulimit不足(ファイル数)を増やす例
services:
app:
ulimits:
nofile:
soft: 65536
hard: 65536
# ディスク不足はまず掃除
docker system df -v
docker system prune -af --volumes環境変数・設定ファイル不足(Exit 1の定番)
# 必須変数をComposeで明示&デフォルト
services:
app:
environment:
- DB_HOST=${DB_HOST?set in .env}
- DB_USER=${DB_USER:-app}
# 起動前チェック用エントリスクリプト(例)
#!/bin/sh
set -eu
: "${DB_HOST:?required}"
exec /usr/local/bin/appネットワーク/名前解決/プロキシ(DNSやHTTP_PROXYの不整合)
# DNSサーバを明示(企業ネットワーク等)
services:
app:
dns:
- 8.8.8.8
- 1.1.1.1
# プロキシをアプリ/ベースイメージに合わせて設定
environment:
- HTTP_PROXY=http://proxy:8080
- NO_PROXY=localhost,127.0.0.1,db権限・セキュリティ(ユーザー/SELinux/AppArmor/Capability)
# 実行ユーザーを固定し、必要なファイル権限を準備
services:
app:
user: "1000:1000"
volumes:
- /abs/path/data:/app/data
# 一部機能でcapが必要な場合(最小限で)
cap_add:
- NET_ADMINデバイス/GPU/特権が必要なサービス
# GPUコンテナの例(NVIDIA)
services:
worker:
image: nvidia/cuda:12.3.2-runtime-ubuntu22.04
deploy:
resources:
reservations:
devices:
- capabilities: ["gpu"]
# デバイスマッピング
devices:
- /dev/ttyUSB0:/dev/ttyUSB0Composeの構文・バージョン不整合(未知のフィールド/古いCompose)
# バージョンと実装の差異を回避(compose-spec準拠)
docker compose version
docker compose config # 展開後の最終形を検証Docker Desktop/WSL2/macOS/Windowsの特有ポイント
# DesktopのFile Sharingにホストパスを追加(macOS/Windows)
# WSL2は /mnt/c/... か Linux側/home配下のパスを使う
# WSL再起動で改善することも
wsl --shutdown最小再現テンプレ(「起動そのもの」を検証)
# 同じイメージをシェルで起動 → 依存欠落/権限/PATHを確認
docker run --rm -it --entrypoint sh <image> -lc '
id && env | sort | sed -n "1,10p"
which app || exit 127
test -r /app/config.yml || exit 2
app --version || exit 1
'NG→OK 早見表(クイック修正)
# NG: shell形式CMDでシグナル/引数問題 → OK: exec形式
CMD ["node","server.js"]
# NG: ポート競合 → OK: ホスト側ポート変更 or 競合プロセス停止
ports: ["18080:8080"]
# NG: バインド元が存在しない → OK: 事前作成 & SELinuxは :z/:Z
volumes: ["/abs/path/data:/app/data:Z"]
# NG: 依存DB起動待ちなし → OK: healthcheck + depends_on.condition
depends_on: { db: { condition: service_healthy } }
# NG: OOM/ulimit不足 → OK: memory/ulimit を増やす
ulimits: { nofile: { soft: 65536, hard: 65536 } }
# NG: 必須ENV不足 → OK: .env と required記法
environment: ["DB_HOST=${DB_HOST?set}"]チェックリスト(上から順に潰す)
1) docker compose logs / –verbose で「直前に何が失敗したか」を読む
2) ENTRYPOINT/CMD/実行権限・依存ファイルの有無を確認
3) ポート競合を除去(lsof/netstat)し、portsマッピングを調整
4) バインド/ボリュームの存在・権限・SELinux/AppArmorを確認
5) depends_on + healthcheck で依存起動順を保証
6) メモリ/ディスク/ulimitの不足を解消
7) 環境変数・設定ファイル・プロキシ/DNSの整合を取る
8) Desktop/WSL2/macOS/Windows固有の共有設定・パスを見直す
9) それでも不明なら、同イメージをshで起動して最小再現
-
前の記事
docker『Container Exited with Code』の原因と対処法 2025.11.12
-
次の記事
docker『Exec Format Error』の原因と対処法 2025.11.14
コメントを書く