- Docker
docker compose healthcheck|depends_onの待ち方
depends_on を短い書き方(- db)にすると、Compose は db のコンテナが「動き始めた」ところで次を起動します。DB が接続を受け付けるまで待たせるには、db に healthcheck を書き、待つ側に condition: service_healthy を書きます。
services:
db:
image: postgres:18
environment:
POSTGRES_USER: app
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:?}
POSTGRES_DB: appdb
healthcheck:
test: ["CMD-SHELL", "pg_isready -h 127.0.0.1 -U $${POSTGRES_USER} -d $${POSTGRES_DB}"]
interval: 10s
timeout: 5s
retries: 5
start_period: 60s
start_interval: 1s
app:
build: .
depends_on:
db:
condition: service_healthy # db が healthy になるまで app を起動しない
| condition | 待つ側が起動するタイミング | 依存先に必要なもの |
|---|---|---|
service_started(短い書き方と同じ) |
依存先のコンテナが起動した後 | なし |
service_healthy |
依存先が healthy になった後 |
healthcheck(イメージ側の HEALTHCHECK でもよい) |
service_completed_successfully |
依存先が終了コード 0 で終わった後 | 終わるコマンド(マイグレーションなど) |
この記事で手元で確かめたことです。
| 確かめたこと | 結果 |
|---|---|
pg_isready に存在しないユーザー・DB を渡す |
終了コード 0(accepting connections)。認証や DB の有無は見ていない |
mysqladmin ping に誤ったパスワードを渡す |
終了コード 0。Access denied と表示されても成功扱い |
valkey-cli ping でパスワード未指定 |
終了コード 0。NOAUTH Authentication required. でも成功扱い |
$${POSTGRES_USER} と $POSTGRES_USER |
$$ は ${POSTGRES_USER} のままコンテナに渡る。$ だけだと手元の値で置き換えられ、未設定なら空になる |
| healthcheck の既定値 | interval 30s・timeout 30s・retries 3・start_period 0s・start_interval 5s(Docker Engine のソース) |
確認環境:compose ファイルは、Docker Compose v5.6.0 が使っている compose-go v2.16.1 を Go 1.24.7 で組み込んだ小さなプログラムで読み込み、正規化された結果とエラー文を確かめました。待ち合わせの動きは docker/compose v5.6.0 のソース(pkg/compose/service_containers.go)、healthcheck の既定値とタイミングは moby(Docker Engine)のソース(daemon/health.go)、仕様は compose-spec の原文と Docker のドキュメントで確かめています。ヘルスチェックのコマンドは Ubuntu 24.04 の apt で入れた PostgreSQL 16.15(pg_isready 16.15)、MySQL 8.0.46、Valkey 7.2.13(valkey-cli 7.2.4)を起動・停止して、成功・失敗時の終了コードを確かめました(確認日 2026年10月13日)。
本記事の内容は、ご自由にお使いください。
ご利用の際は、出典として本ページへのリンクを記載いただけますようお願いします。
(記載例)出典:株式会社RJC「docker compose healthcheck|depends_onの待ち方」
depends_on だけでは「準備完了」を待たない
Docker のドキュメントには「On startup, Compose does not wait until a container is "ready", only until it's running.」とあります。PostgreSQL や MySQL は、プロセスが動き始めてから接続を受け付けるまでに時間がかかります。その間にアプリが接続すると、Connection refused などで落ちます。
sequenceDiagram
participant C as docker compose up
participant DB as db コンテナ
participant A as app コンテナ
C->>DB: 起動
Note over DB: starting(ヘルスチェック待ち)
DB-->>C: healthcheck 成功 → healthy
C->>A: 起動(service_healthy を満たした)
Compose のソース(v5.6.0)では、待つ側のサービスを起動する前に、依存先のコンテナの状態を 0.5秒ごとに調べています。条件ごとの動きは次の通りです。
| 依存先の状態 | service_healthy |
service_completed_successfully |
|---|---|---|
starting |
待ち続ける | (状態を見ない) |
healthy |
次へ進む | (状態を見ない) |
unhealthy |
dependency failed to start: container <名前> is unhealthy で止まる |
(状態を見ない) |
| healthcheck が無い | container <名前> has no healthcheck configured で止まる |
(関係なし) |
| 終了コード 0 で終了 | container <名前> exited (0) で止まる |
次へ進む |
| 0 以外で終了 | container <名前> exited (1) などで止まる |
service "<名前>" didn't complete successfully: exit 1 で止まる |
service_healthy の依存先が先に終了すると、終了コードが 0 でも失敗になります。 終わるコマンド(マイグレーション・初期データ投入)を待つときは service_completed_successfully を使います。
短い書き方と長い書き方
services:
app:
depends_on: # 短い書き方:起動順だけ
- db
- cache
services:
app:
depends_on: # 長い書き方:条件・再起動・必須を指定できる
db:
condition: service_healthy
restart: true
cache:
condition: service_started
required: false
compose-go で短い書き方を読み込むと、condition: service_started と required: true が補われました。
| キー | 既定値 | 意味 |
|---|---|---|
condition |
service_started |
上の3つから選ぶ |
restart |
false |
true のとき、依存先が Compose の操作(docker compose restart など)で再起動・更新されたら、こちらも再起動する。コンテナが落ちて自動で再起動した場合は対象外 |
required |
true |
false のとき、依存先が無い・起動しないと警告だけ出して進む |
restart は Compose v2.17.0、required は v2.20.0 で入ったと compose-spec に書かれています。
required: false を使う場面
profiles で起動しないことがあるサービスに依存するときに使います。 compose-go で確かめた結果です。
services:
app:
image: myapp
depends_on:
worker:
condition: service_started
worker:
image: myapp
profiles: ["worker"] # --profile worker のときだけ起動
service "app" depends on undefined service "worker": invalid compose project
required: false を付けると、このエラーにならずに読み込めました。
healthcheck の項目と既定値
| 項目 | 既定値 | 意味 |
|---|---|---|
test |
(イメージの HEALTHCHECK) |
実行するコマンド。終了コード 0 で成功 |
interval |
30s |
チェックの間隔。1回目もこの時間が経ってから動く |
timeout |
30s |
1回のチェックの制限時間。超えると失敗として数える |
retries |
3 |
何回続けて失敗したら unhealthy にするか |
start_period |
0s |
起動直後の猶予。この間の失敗は数えない |
start_interval |
5s |
start_period の間のチェック間隔(Docker Engine 25.0 以降) |
disable |
false |
true でイメージの HEALTHCHECK を無効にする |
既定値は Docker Engine のソース(defaultProbeInterval = 30 * time.Second など)と Dockerfile リファレンスで同じ値でした。compose-spec には「It works in the same way, and has the same default values, as the HEALTHCHECK Dockerfile instruction」とあり、Compose で書かなかった項目はこの値になります。
時間は 10s・1m30s・500ms のように単位付きの文字列で書きます。interval: 10 と数字だけにすると、compose-go では次のエラーになりました。
validating compose.yaml: services.db.healthcheck.interval must be a string
1回目のチェックはいつ動くか
Engine のソースでは、start_period の間(状態が starting のとき)は start_interval で、それ以外は interval で次のチェックまで待ちます。既定のままだと、1回目のチェックは起動の 30秒後です。 service_healthy で待つ側も、少なくとも 30秒待たされます。
| 書き方 | 1回目のチェック | その後 |
|---|---|---|
| 何も書かない | 起動の 30秒後 | 30秒ごと |
interval: 10s |
起動の 10秒後 | 10秒ごと |
start_period: 60s |
起動の 5秒後(start_interval の既定値) | 成功するまで 5秒ごと、成功後は interval ごと |
start_period: 60s と start_interval: 1s |
起動の 1秒後 | 成功するまで 1秒ごと、成功後は interval ごと |
start_interval は start_period が 0 だと使われません。 起動を早く検知したいときは、2つを組み合わせます。
healthy・unhealthy の決まり方
| 状況 | 状態の変化 |
|---|---|
| 起動直後 | starting |
| チェックが1回成功 | healthy(どの状態からでも) |
start_period の間に失敗 |
数えない。starting のまま |
start_period の後に失敗 |
失敗の回数を1増やす。retries 回続くと unhealthy |
timeout を超えた |
失敗として数え、チェックのプロセスは止められる |
Dockerfile リファレンスには「if a health check succeeds during the start period, the container is considered started and all consecutive failures will be counted」とあります。1回成功した後は、start_period の間でも失敗を数えます。
終了コードは 0 が成功、それ以外はすべて失敗です。 リファレンスでは 1 を unhealthy、2 を予約済みとしていますが、Engine のソースでは 0 以外をまとめて失敗として扱っています。curl -f が返す 22 や 7 も失敗になります。|| exit 1 は、リファレンスの決まりに合わせて 1 にそろえる書き方です。
test の書き方
| 書き方 | 動き |
|---|---|
["CMD", "pg_isready", "-U", "app"] |
シェルを通さずに実行する。$VAR は展開されない |
["CMD-SHELL", "pg_isready -U $${POSTGRES_USER}"] |
/bin/sh -c で実行する。変数・パイプ・|| が使える |
pg_isready -U app(文字列) |
CMD-SHELL と同じ。compose-go で読むと CMD-SHELL に変わった |
["NONE"] または disable: true |
イメージの HEALTHCHECK を無効にする |
リストの1つ目が CMD・CMD-SHELL・NONE 以外だとエラーになります。 ["pg_isready"] と書くと compose-go では次のエラーでした。
healthcheck.test must start either by "CMD", "CMD-SHELL" or "NONE"
DB ごとのヘルスチェックのコマンド
apt の PostgreSQL 16.15・MySQL 8.0.46・Valkey 7.2.13 を起動・停止して、各コマンドの終了コードを確かめました。
PostgreSQL:pg_isready
| 状況 | 表示 | 終了コード |
|---|---|---|
| 接続を受け付けている | 127.0.0.1:55444 - accepting connections |
0 |
停止処理中(the database system is shutting down) |
rejecting connections |
1 |
| 起動していない | no response |
2 |
存在しないユーザー・DB を -U・-d で指定 |
accepting connections |
0 |
pg_isready はサーバーが接続を受け付けるかだけを見ます。 -U と -d を誤っても成功になりました。ユーザー・パスワード・DB まで確かめたいときは psql で SELECT 1 を実行します。
healthcheck:
# 接続を受け付けるか(軽い)
test: ["CMD-SHELL", "pg_isready -h 127.0.0.1 -U $${POSTGRES_USER} -d $${POSTGRES_DB}"]
healthcheck:
# ログインして SQL が通るか(認証と DB の有無まで確かめる)
test: ["CMD-SHELL", "PGPASSWORD=$${POSTGRES_PASSWORD} psql -h 127.0.0.1 -U $${POSTGRES_USER} -d $${POSTGRES_DB} -tAc 'SELECT 1'"]
-h 127.0.0.1 を付けて TCP で確かめます。 公式 postgres イメージの docker-entrypoint.sh は、初回(データが空のとき)に初期化用の一時サーバーを listen_addresses=''(TCP を開かない)で起動し、初期化が終わると止めて本番のサーバーを起動し直します。-h を付けないとソケットで一時サーバーに接続でき、初期化の途中で healthy になることがあります。
postgres:18 から、イメージの VOLUME は /var/lib/postgresql/data から /var/lib/postgresql に変わっています(イメージの Dockerfile のコメントより)。
MySQL:mysqladmin ping より mysql で SELECT 1
| コマンド | 状況 | 終了コード |
|---|---|---|
mysqladmin ping |
動いている(正しいパスワード) | 0(mysqld is alive) |
mysqladmin ping |
パスワード誤り(Access denied for user) |
0 |
mysqladmin ping |
存在しないユーザー | 0 |
mysqladmin ping |
起動していない(Can't connect to MySQL server) |
1 |
mysql -e 'SELECT 1' |
正しいパスワード | 0 |
mysql -e 'SELECT 1' |
パスワード誤り(ERROR 1045 (28000)) |
1 |
mysql -e 'SELECT 1' 存在しないDB |
ERROR 1044 (42000) |
1 |
mysqladmin ping は、サーバーが応答すればパスワードを誤っても 0 を返しました。 MySQL のマニュアルにも、ping の戻り値は「Access denied」のようなエラーでも 0 になると書かれています。 「サーバーが動いているか」の確認には使えますが、アプリのユーザーで接続できるかまでは分かりません。
services:
mysql:
image: mysql:8.4
environment:
MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD:?}
MYSQL_DATABASE: appdb
MYSQL_USER: app
MYSQL_PASSWORD: ${MYSQL_PASSWORD:?}
volumes:
- mysqldata:/var/lib/mysql
healthcheck:
test: ["CMD-SHELL", "mysql -h 127.0.0.1 -u\"$${MYSQL_USER}\" -p\"$${MYSQL_PASSWORD}\" -e 'SELECT 1' \"$${MYSQL_DATABASE}\""]
interval: 10s
timeout: 5s
retries: 5
start_period: 90s
start_interval: 2s
volumes:
mysqldata:
ここでも -h 127.0.0.1 を付けます。 公式 mysql イメージの docker-entrypoint.sh も、初期化用の一時サーバーを --skip-networking(TCP を開かない)で起動します。-h を省くと localhost 扱いでソケットに接続し、一時サーバーに対して成功することがあります。-p でパスワードを渡すと Using a password on the command line interface can be insecure. の警告が出ますが、終了コードには影響しませんでした。
Redis・Valkey:PONG を grep で確かめる
| コマンド | 状況 | 表示 | 終了コード |
|---|---|---|---|
valkey-cli ping |
動いている | PONG |
0 |
valkey-cli ping |
起動していない | Could not connect to Valkey at 127.0.0.1:63444: Connection refused |
1 |
valkey-cli ping |
パスワードが要るのに未指定 | NOAUTH Authentication required. |
0 |
valkey-cli -a 誤り ping |
パスワード誤り | AUTH failed: WRONGPASS ... と NOAUTH ... |
0 |
valkey-cli ping | grep -q PONG |
パスワード未指定 | (なし) | 1 |
REDISCLI_AUTH=... valkey-cli ping |
正しいパスワード | PONG |
0 |
valkey-cli はエラーの応答でも 0 を返しました。 PONG が返ったかを grep -q PONG で確かめると、認証の誤りも失敗として扱えます。パスワードは -a より環境変数 REDISCLI_AUTH で渡すと、Warning: Using a password with '-a' or '-u' option on the command line interface may not be safe. の警告も出ません。
services:
cache:
image: valkey/valkey:8
command: ["valkey-server", "--requirepass", "${VALKEY_PASSWORD:?}"]
environment:
REDISCLI_AUTH: ${VALKEY_PASSWORD:?}
healthcheck:
test: ["CMD-SHELL", "valkey-cli ping | grep -q PONG"]
interval: 10s
timeout: 3s
retries: 5
start_period: 10s
start_interval: 1s
redis イメージでは、valkey-cli を redis-cli に置き換えます。Valkey と Redis の作り方と接続コードは、関連記事「ElastiCacheの使い方|Valkey/Redisの作り方と接続コード」で扱っています。
Web アプリ:curl が無いイメージ
イメージに curl が入っているとは限りません。 公式 postgres イメージの Dockerfile は、gosu の取得に使った wget を最後に削除し、curl は入れていません。node や python のイメージでは、その言語でリクエストを送る書き方が使えます。手元で、200 と 503 を返す小さなサーバーに対して確かめた結果です。
| コマンド | 200 | 503 | サーバー停止 |
|---|---|---|---|
curl -fsS URL -o /dev/null |
0 | 22 | 7 |
curl -sS URL -o /dev/null(-f なし) |
0 | 0 | 7 |
wget -q --spider URL(BusyBox 1.36.1) |
0 | 1 | 1 |
node -e "fetch(URL).then(r=>process.exit(r.ok?0:1)).catch(()=>process.exit(1))"(Node.js 22.22.2) |
0 | 1 | 1 |
python3 -c "import urllib.request; urllib.request.urlopen(URL, timeout=3)" |
0 | 1 | 1 |
curl は -f を付けないと 503 でも 0 を返します。 alpine 系のイメージには BusyBox の wget が入っていることが多く、distroless のようにシェルも無いイメージでは、アプリ自身にヘルスチェック用のサブコマンドを持たせて CMD 形式で呼ぶ方法があります。
healthcheck:
test: ["CMD", "node", "-e", "fetch('http://127.0.0.1:3000/health').then(r=>process.exit(r.ok?0:1)).catch(()=>process.exit(1))"]
/health で何を返すか(DB まで見るか)の設計は、関連記事「ヘルスチェック設計|livenessとreadinessの違いと実装例」で扱っています。
コピペ用:DB・キャッシュ・マイグレーション・アプリ
PostgreSQL と Valkey が healthy になり、マイグレーションが終了コード 0 で終わってからアプリを起動する構成です。compose-go v2.16.1 でエラーなく読み込めることを確かめています。
services:
db:
image: postgres:18
environment:
POSTGRES_USER: app
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:?POSTGRES_PASSWORD を .env に書く}
POSTGRES_DB: appdb
volumes:
- pgdata:/var/lib/postgresql
healthcheck:
test: ["CMD-SHELL", "pg_isready -h 127.0.0.1 -U $${POSTGRES_USER} -d $${POSTGRES_DB}"]
interval: 10s
timeout: 5s
retries: 5
start_period: 60s
start_interval: 1s
cache:
image: valkey/valkey:8
command: ["valkey-server", "--requirepass", "${VALKEY_PASSWORD:?}"]
environment:
REDISCLI_AUTH: ${VALKEY_PASSWORD:?}
healthcheck:
test: ["CMD-SHELL", "valkey-cli ping | grep -q PONG"]
interval: 10s
timeout: 3s
retries: 5
start_period: 10s
start_interval: 1s
migrate:
build: .
command: ["npm", "run", "migrate"]
environment:
DATABASE_URL: postgres://app:${POSTGRES_PASSWORD}@db:5432/appdb
depends_on:
db:
condition: service_healthy
app:
build: .
ports:
- "3000:3000"
environment:
DATABASE_URL: postgres://app:${POSTGRES_PASSWORD}@db:5432/appdb
REDIS_URL: redis://:${VALKEY_PASSWORD}@cache:6379
depends_on:
db:
condition: service_healthy
restart: true
cache:
condition: service_healthy
migrate:
condition: service_completed_successfully
healthcheck:
test: ["CMD", "node", "-e", "fetch('http://127.0.0.1:3000/health').then(r=>process.exit(r.ok?0:1)).catch(()=>process.exit(1))"]
interval: 30s
timeout: 5s
retries: 3
start_period: 30s
start_interval: 2s
restart: unless-stopped
volumes:
pgdata:
# .env(Git に入れない)
POSTGRES_PASSWORD=change-me
VALKEY_PASSWORD=change-me
.env が無いときは、${VAR:?} の書き方により次のエラーで止まりました。空のパスワードで起動するのを防げます。
error while interpolating services.db.environment.POSTGRES_PASSWORD: required variable POSTGRES_PASSWORD is missing a value: POSTGRES_PASSWORD を .env に書く
起動と確かめ方
docker compose up -d --wait --wait-timeout 120 # healthy になるまで待って戻る(CI 向け)
docker compose ps # STATUS に (healthy) / (unhealthy) / (health: starting)
docker inspect --format '{{json .State.Health}}' <コンテナ名> # 直近のチェック結果と出力
docker compose config # 変数を展開した結果を見る
| オプション | 意味(docker/compose v5.6.0 のフラグの説明) |
|---|---|
--wait |
Wait for services to be running|healthy. Implies detached mode. |
--wait-timeout |
Maximum duration in seconds to wait for the project to be running|healthy。依存先を待つ時間にも使われ、超えると timeout waiting for dependencies |
--no-deps |
Don't start linked services。依存先を起動せず、待ちもしない |
--wait-timeout を付けないと、依存先が starting のままなら待ち続けます。 CI では時間の上限を付けておくと、止まったまま時間を使い切ることを防げます。docker inspect で見える出力は、Dockerfile リファレンスによると先頭の 4096 バイトまでで、記録は直近の5回分です(Engine のソースの maxLogEntries = 5)。
restart(再起動ポリシー)との関係
| 書く場所 | 何をするか |
|---|---|
サービスの restart: |
コンテナが終了したときに再起動するか(no・always・on-failure[:回数]・unless-stopped) |
depends_on の restart: true |
依存先が Compose の操作で再起動・更新されたら、こちらも再起動する |
healthcheck |
状態(healthy / unhealthy)を付けるだけ |
unhealthy になっても、コンテナは止まらず、再起動もされません。 Engine のソースでは、ヘルスチェックの結果は状態を書き換えてイベントを出すだけです。compose-spec の restart も「the policy that the platform applies on container termination」と、終了時の動きとして書かれています。unhealthy で入れ替えたいときは、オーケストレーター(Kubernetes の livenessProbe など)を使うか、アプリが自分で終了するようにします。
よくある誤り
| 症状 | 原因 | 直し方 |
|---|---|---|
The "POSTGRES_USER" variable is not set. Defaulting to a blank string. |
$POSTGRES_USER が Compose の変数展開で手元の値に置き換えられた |
コンテナ内の変数は $$ で書く($${POSTGRES_USER}) |
CMD 形式で $${VAR} が展開されない |
CMD はシェルを通さないので ${VAR} がそのまま渡る |
変数を使うときは CMD-SHELL |
ずっと unhealthy、ログに executable file not found |
イメージに curl などが無い |
wget・言語のランタイム・アプリのサブコマンドを使う |
["CMD", "pg_isready -U app"] が失敗する |
"pg_isready -U app" という名前のコマンドを探してしまう |
["CMD", "pg_isready", "-U", "app"] と分けるか CMD-SHELL |
| healthy なのにアプリが接続に失敗する | pg_isready・mysqladmin ping は認証を見ていない/初期化用の一時サーバーに成功した |
-h 127.0.0.1 を付ける。SELECT 1 で確かめる |
condition value must be one of ... |
service_healty などの綴り誤り |
3つの値から選ぶ |
services.db.healthcheck.interval must be a string |
interval: 10 |
10s と単位を付ける |
depends on undefined service |
サービス名の誤り、または profiles で外れた | 名前を直す。profiles なら required: false |
dependency cycle detected: a -> b -> a |
互いに depends_on している | 片方を外す |
dependency failed to start: container ... has no healthcheck configured |
service_healthy の依存先に healthcheck が無い |
依存先に healthcheck を書く |
| 毎回 30秒以上待たされる | interval の既定 30s。1回目も 30秒後 | start_period と start_interval を書く |
$ のエスケープの違いを、compose-go で読み込んで確かめた結果です(.env に POSTGRES_USER=app)。
| compose.yaml の書き方 | コンテナに渡る文字列 |
|---|---|
pg_isready -U $${POSTGRES_USER} |
pg_isready -U ${POSTGRES_USER}(コンテナの環境変数で展開) |
pg_isready -U $POSTGRES_USER(.env あり) |
pg_isready -U app(手元の .env の値) |
pg_isready -U $POSTGRES_USER(.env なし) |
pg_isready -U(空。警告が出る) |
$${...} は、コンテナの environment に設定した値を使います。 .env の値で置き換わる $ だけの書き方も動きますが、.env とコンテナの環境変数がずれると、チェックだけが別のユーザーで動きます。
compose.yaml の基本の書き方は関連記事「Docker Composeの使い方|compose.yamlの書き方と開発環境の作り方」、ネットワークとボリュームは「Docker network/volume使い方|種類比較表と実行ログで理解」で扱っています。イメージ側に HEALTHCHECK を書く場合の Dockerfile の書き方は、関連記事「Dockerfileの書き方|軽く・速く・安全なイメージを作るベストプラクティス」で扱っています。
よくある質問
Q. wait-for-it.sh や dockerize は要りますか?
A. Compose の service_healthy で、多くの「DB を待つ」用途は書けます。ただし Compose が待つのは、Compose がサービスを起動するときです。DB が途中で再起動したときのために、アプリ側にも再接続の処理(リトライと待ち時間)を入れておくと、起動順に頼らずに済みます。
Q. version: "3.8" は書く必要がありますか?
A. compose-spec では version は互換のためだけに残っている項目で、Compose は値を使いません。compose-go で version: "3.8" を読み込むと、次の警告が出ました。書かなくても、この記事の condition や start_interval は使えます。
the attribute `version` is obsolete, it will be ignored, please remove it to avoid potential confusion
Q. Dockerfile の HEALTHCHECK と compose の healthcheck の両方を書いたら?
A. compose-spec には「Your Compose file can override the values set in the Dockerfile.」とあり、compose の値が使われます。イメージの healthcheck を止めたいときは disable: true を書きます。
Q. GitHub Actions のサービスコンテナでも同じ書き方ですか?
A. GitHub Actions の services: では、options: --health-cmd "pg_isready" --health-interval 10s ... のように docker run のオプションで書きます。項目の意味と既定値はこの記事の表と同じです。
まとめ
- 短い
depends_onは起動順だけ。準備完了を待つには、依存先にhealthcheck、待つ側にcondition: service_healthy - マイグレーションなど終わるものは
service_completed_successfully(service_healthyだと終了で失敗になる) - 既定値は interval 30s・timeout 30s・retries 3・start_period 0s・start_interval 5s。1回目も 30秒後なので、
start_periodとstart_intervalで早める pg_isready・mysqladmin ping・valkey-cli pingは認証の誤りでも 0 を返した。SELECT 1やgrep -q PONGで確かめる- 公式イメージの初期化用一時サーバーを避けるため、
-h 127.0.0.1で TCP 接続して確かめる - コンテナ内の変数は
$$でエスケープし、CMD-SHELLで書く unhealthyになっても再起動はされない。CI ではup --wait --wait-timeout
参考・出典
確認日はいずれも 2026年10月13日です。
- Docker Docs「Control startup and shutdown order in Compose」:https://docs.docker.com/compose/how-tos/startup-order/
- Docker Docs「Dockerfile reference - HEALTHCHECK」:https://docs.docker.com/reference/dockerfile/#healthcheck
- Docker Docs「docker compose up」:https://docs.docker.com/reference/cli/docker/compose/up/
- compose-spec「Services top-level elements」(05-services.md):https://github.com/compose-spec/compose-spec/blob/main/05-services.md
- compose-spec/compose-go v2.16.1:https://github.com/compose-spec/compose-go
- docker/compose v5.6.0(pkg/compose/service_containers.go):https://github.com/docker/compose
- moby/moby(daemon/health.go):https://github.com/moby/moby/blob/master/daemon/health.go
- docker-library/postgres(docker-entrypoint.sh・Dockerfile):https://github.com/docker-library/postgres
- docker-library/mysql(docker-entrypoint.sh):https://github.com/docker-library/mysql
- PostgreSQL Documentation「pg_isready」:https://www.postgresql.org/docs/16/app-pg-isready.html
- MySQL 8.0 Reference Manual「mysqladmin」:https://dev.mysql.com/doc/refman/8.0/en/mysqladmin.html
本記事の内容は、ご自由にお使いください。
ご利用の際は、出典として本ページへのリンクを記載いただけますようお願いします。
(記載例)出典:株式会社RJC「docker compose healthcheck|depends_onの待ち方」
株式会社RJC ― SI事業・SES事業・AI駆動開発。RJCは一緒に成長を楽しめる会社です。
WE ARE HIRING
RJCで一緒に開発しながら、
成長を楽しみませんか?
RJCは、Web・モバイル・AIを活用した開発プロジェクトで、テックリードやPM・PMOも活躍するシステム開発会社です。会社を知る、待遇を確かめる、話を聞いてみる。気になるところ見てみてください!
- 127日年間休日
- 12時間平均残業時間
- 毎日ガチャ遊びココロも大切にする福利厚生。アマギフなどの賞品ラインナップ!
ほかにも、チケットレストラン、書籍読み放題、2年ごとの慰労報奨(休暇 or 金一封)、11期連続の黒字決算。