Docker Composeで、DB(PostgreSQL)の準備ができてからアプリを起動する方法です。depends_on を短く書いただけでは接続に失敗することを、DBの初期化をわざと遅くして再現し、healthcheck と condition: service_healthy で待つようにしました。start_period と start_interval で待ち時間がどう変わるかと、docker compose ps の表示も確かめています。
結論
DBのサービスに healthcheck を書き、アプリの depends_on を condition: service_healthy にします。PostgreSQLでは pg_isready に -h 127.0.0.1 をつけ、TCPで接続を受け付けているかを確かめます。起動の直後だけ短い間隔で確かめたいときは、start_period と start_interval を一緒に書きます。
name: tb-healthcheck
services:
db:
image: postgres:18.6@sha256:e3d24f6906d0760bf4da0dae872415391ededefad23fd471c47dc53b0ddf3c42
environment:
POSTGRES_USER: app
POSTGRES_PASSWORD: not-a-real-password
POSTGRES_DB: app
volumes:
- ./initdb:/docker-entrypoint-initdb.d:ro
healthcheck:
test: ["CMD-SHELL", "pg_isready -h 127.0.0.1 -U app -d app || exit 1"]
interval: 10s
timeout: 5s
retries: 5
start_period: 30s
start_interval: 1s
app:
build: ./app
image: tb-healthcheck-app
environment:
DATABASE_URL: postgresql://app:not-a-real-password@db:5432/app
depends_on:
db:
condition: service_healthy
DBの初期化に10秒以上かかるようにして、書き方ごとに比べた結果です。時間は、dbのコンテナが起動してからappのコンテナが起動するまでで、docker inspect の起動時刻から計算しました。
| 書き方 | 結果 | appが起動するまで |
|---|---|---|
短い書き方の depends_on | 接続に失敗(Connection refused) | 約0.1秒 |
healthcheck(interval: 10s)と service_healthy | 接続できた | 約20.6秒 |
上に start_period: 30s と start_interval: 1s を追加 | 接続できた | 約11.7秒 |
start_interval だけを追加 | docker compose up がエラーで止まった | – |
interval: 1s、retries: 3、start_period なし | dbがunhealthyになり、docker compose up が失敗 | appは起動しない |
pg_isready に -h をつけない | healthyになったが、接続に失敗 | – |
動作確認した環境
- Docker Engine 29.7.2、Docker Compose 5.5.1(Windows 11 の Docker Desktop 4.90.0、Linuxコンテナ、x86_64)
- DB:
postgres:18.6(PostgreSQL 18.6。digestで固定) - アプリ:
python:3.15.2-slim(digestで固定)と psycopg 3.3.8 - 確認日: 2026年11月9日
start_interval は新しい項目なので、版に注意が必要です。Composeのリファレンスには、interval、timeout、start_period、start_interval の時間の書き方が Docker Compose 2.20.2 からと書かれています。ただ、Composeのリリースノートでは、start_interval に対応したのは 2.24.0 です。Dockerfileのリファレンスによると、Docker Engine 25.0 以降も必要です。この記事では Compose 5.5.1 と Engine 29.7.2 で確かめました。古い版では、この記事のとおりに動かない場合があります。
この記事は、MacとWindowsの両方の読者を対象にしています。使うのは docker compose と docker inspect のコマンドだけで、composeのファイルもOSによりません。この記事のコマンドは、Claude(AI)が実行して確認しました。本文の出力は、Windows 11 のGit Bashから上から順に実行した結果です。PowerShell 7 で実行した結果は、最後の章にまとめました。Macでは確認していません。
準備
次のようなフォルダを作ります。compose.yaml は、冒頭の「結論」のファイルです。ほかのcomposeのファイルは、章ごとに載せます。
.
├── app/
│ ├── Dockerfile
│ └── app.py
├── initdb/
│ └── 01-slow-init.sql
└── compose.yaml
アプリは、起動したときに1回だけDBへ接続し、失敗したら終了するPythonのプログラムです。起動時にDBへ接続するアプリの代わりです。app/app.py です。
import os
import sys
from datetime import datetime
import psycopg
def now():
return datetime.now().strftime("%H:%M:%S")
print(f"{now()} app: connecting to db", flush=True)
try:
with psycopg.connect(os.environ["DATABASE_URL"], connect_timeout=3) as conn:
version = conn.execute("SHOW server_version").fetchone()[0]
print(f"{now()} app: connected (PostgreSQL {version})", flush=True)
except psycopg.OperationalError as e:
print(f"{now()} app: {e}", flush=True)
sys.exit(1)
app/Dockerfile です。
FROM python:3.15.2-slim@sha256:65a65fc7b30b06cb6df4930fd4650697cb23f4c2698ab81fc87e4b031bc36928
RUN pip install --no-cache-dir "psycopg[binary]==3.3.8"
WORKDIR /app
COPY app.py .
CMD ["python", "app.py"]
DBの準備に時間がかかる状況は、初期化のSQLで再現します。PostgreSQLの公式イメージは、データのディレクトリが空のとき(初回の起動)だけ、/docker-entrypoint-initdb.d のSQLを実行します。テーブルの作成やデータの投入に時間がかかる代わりに、10秒待つだけのSQLを置きました。initdb/01-slow-init.sql です。
-- 初回の初期化に時間がかかる状況を再現する(10秒待つ)
SELECT pg_sleep(10);
この記事のcomposeのファイルには、どれも先頭に name: tb-healthcheck を書いています。コンテナ名は tb-healthcheck-db-1 と tb-healthcheck-app-1 になります。アプリのイメージは、どのファイルからも tb-healthcheck-app という名前で使うので、最初に1回だけ作ります(出力は省略)。
$ docker compose build
各章の最後には、docker compose -f <ファイル> down -v でコンテナを消しています。-v をつけるのは、PostgreSQLのデータが入る匿名ボリュームも消して、次の章でも初回の起動(初期化のSQLが動く状態)にするためです。
短い書き方のdepends_onでは、接続に失敗する
まず、depends_on にサービス名だけを書きます。compose.short.yaml です。
name: tb-healthcheck
services:
db:
image: postgres:18.6@sha256:e3d24f6906d0760bf4da0dae872415391ededefad23fd471c47dc53b0ddf3c42
environment:
POSTGRES_USER: app
POSTGRES_PASSWORD: not-a-real-password
POSTGRES_DB: app
volumes:
- ./initdb:/docker-entrypoint-initdb.d:ro
app:
build: ./app
image: tb-healthcheck-app
environment:
DATABASE_URL: postgresql://app:not-a-real-password@db:5432/app
depends_on:
- db
起動して、3秒ほど後に状態とアプリのログを見ました。docker compose ps は、表示する列を名前と状態にしぼっています。
$ docker compose -f compose.short.yaml up -d
Network tb-healthcheck_default Creating
Network tb-healthcheck_default Creating
Network tb-healthcheck_default Created
Network tb-healthcheck_default Created
Container tb-healthcheck-db-1 Creating
Container tb-healthcheck-db-1 Created
Container tb-healthcheck-app-1 Creating
Container tb-healthcheck-app-1 Created
Container tb-healthcheck-db-1 Starting
Container tb-healthcheck-db-1 Started
Container tb-healthcheck-app-1 Starting
Container tb-healthcheck-app-1 Started
$ docker compose -f compose.short.yaml ps -a --format "table {{.Name}}\t{{.Status}}"
NAME STATUS
tb-healthcheck-app-1 Exited (1) 4 seconds ago
tb-healthcheck-db-1 Up 4 seconds
$ docker compose -f compose.short.yaml logs app
app-1 | 00:24:31 app: connecting to db
app-1 | 00:24:31 app: connection failed: connection to server at "172.20.0.2", port 5432 failed: Connection refused
app-1 | Is the server running on that host and accepting TCP/IP connections?
dbのコンテナの起動を待ってからappが起動しましたが、そのときPostgreSQLはまだ5432番ポートで接続を受け付けておらず、接続は拒否されました(Connection refused)。appのコンテナは終了コード1で止まっています(時刻はコンテナの中のUTCです)。
12秒ほど後にdbのログの最後を見ると、5432番ポートで接続を受け付ける状態になっていました。appは、この前に一度だけ接続しようとして終わっています。
$ docker compose -f compose.short.yaml logs db | tail -n 3
db-1 | 2026-11-09 00:24:41.742 UTC [1] LOG: listening on Unix socket "/var/run/postgresql/.s.PGSQL.5432"
db-1 | 2026-11-09 00:24:41.747 UTC [77] LOG: database system was shut down at 2026-11-09 00:24:41 UTC
db-1 | 2026-11-09 00:24:41.751 UTC [1] LOG: database system is ready to accept connections
$ docker compose -f compose.short.yaml down -v
Composeのリファレンスでも、短い書き方では、依存するサービスが「healthy」になるのを待たないと説明されています。待つのはコンテナの起動までで、中のDBが接続を受け付けられるかどうかは見ていません。
WindowsのPowerShellには tail がないので、docker compose -f compose.short.yaml logs db --tail 3 と書きます(最後の章で実行しました)。
healthcheckとcondition: service_healthyで待つ
dbに healthcheck を書き、appの depends_on を長い書き方にして condition: service_healthy を指定します。compose.healthy.yaml の、compose.short.yaml と違うところです(ほかは同じです)。
services:
db:
# image、environment、volumes は compose.short.yaml と同じ
healthcheck:
test: ["CMD-SHELL", "pg_isready -h 127.0.0.1 -U app -d app || exit 1"]
interval: 10s
timeout: 5s
retries: 5
app:
# build、image、environment は compose.short.yaml と同じ
depends_on:
db:
condition: service_healthy
pg_isready は、PostgreSQLが接続を受け付けているかを確かめるコマンドで、PostgreSQLのイメージに入っています。公式ドキュメントによると、受け付けていれば0、起動中などで拒否していれば1、応答がなければ2を返します。Dockerのリファレンスでは、healthcheckのコマンドの終了コードは0が正常、1が異常で、2は予約(使わない)とされているので、|| exit 1 で失敗を1にそろえました。-h 127.0.0.1 をつける理由は、後の「ハマった点」の章で説明します。
なお、PostgreSQLの公式ドキュメントによると、pg_isready は正しいユーザー名、パスワード、DB名がなくてもサーバーの状態を返します。アプリのユーザーで認証できるか、必要なテーブルがあるかまでは確かめていません。
docker compose ps のhealthの表示を見るため、先にdbだけを起動してから、全体を起動しました。
$ docker compose -f compose.healthy.yaml up -d db
Network tb-healthcheck_default Creating
Network tb-healthcheck_default Creating
Network tb-healthcheck_default Created
Network tb-healthcheck_default Created
Container tb-healthcheck-db-1 Creating
Container tb-healthcheck-db-1 Created
Container tb-healthcheck-db-1 Starting
Container tb-healthcheck-db-1 Started
$ docker compose -f compose.healthy.yaml ps -a --format "table {{.Name}}\t{{.Status}}"
NAME STATUS
tb-healthcheck-db-1 Up Less than a second (health: starting)
$ docker compose -f compose.healthy.yaml up -d
Container tb-healthcheck-db-1 Running
Container tb-healthcheck-app-1 Creating
Container tb-healthcheck-app-1 Created
Container tb-healthcheck-db-1 Waiting
Container tb-healthcheck-db-1 Healthy
Container tb-healthcheck-app-1 Starting
Container tb-healthcheck-app-1 Started
$ docker compose -f compose.healthy.yaml ps -a --format "table {{.Name}}\t{{.Status}}"
NAME STATUS
tb-healthcheck-app-1 Exited (0) Less than a second ago
tb-healthcheck-db-1 Up 21 seconds (healthy)
$ docker compose -f compose.healthy.yaml logs app
app-1 | 00:25:12 app: connecting to db
app-1 | 00:25:12 app: connected (PostgreSQL 18.6 (Debian 18.6-1.pgdg13+2))
起動の直後は (health: starting) と表示され、docker compose up -d はdbを Waiting にして待ちました。Healthy になってからappが起動し、接続できました。appは接続を確かめたら終わるプログラムなので、Exited (0) は正常に終わったことを表しています。
ただし、待ち時間が長めです。起動時刻と、healthcheckの記録を docker inspect で見ました。
$ docker inspect -f '{{.Name}} {{.State.StartedAt}}' tb-healthcheck-db-1 tb-healthcheck-app-1
/tb-healthcheck-db-1 2026-11-09T00:24:51.865434279Z
/tb-healthcheck-app-1 2026-11-09T00:25:12.490641488Z
$ docker inspect -f '{{range .State.Health.Log}}{{.Start}} exit={{.ExitCode}} {{.Output}}{{end}}' tb-healthcheck-db-1
2026-11-09 00:25:01.990653321 +0000 UTC exit=1 127.0.0.1:5432 - no response
2026-11-09 00:25:12.036197238 +0000 UTC exit=0 127.0.0.1:5432 - accepting connections
$ docker compose -f compose.healthy.yaml down -v
最初のチェックは、dbの起動から約10秒後で、まだ応答がありませんでした(no response)。次のチェックはその10秒後で、ここで成功しました。appの起動は、dbの起動から約20.6秒後です。Dockerのリファレンスのとおり、healthcheckは起動から interval の秒数がたってから初めて実行され、その後も interval ごとに実行されます。次の章では、同じ条件のDBに、起動から約11.7秒後に接続できています。この章では、それより9秒ほど長く待ったことになります。
start_periodとstart_intervalで、起動の直後だけ短い間隔で確かめる
interval を短くすれば早く気づけますが、起動した後もずっと短い間隔でチェックが続きます。起動の直後だけ短くするのが start_period と start_interval です。Dockerのリファレンスでは、次のように説明されています。
start_period: 起動に時間がかかるコンテナのための猶予の時間。この間の失敗は、retriesの回数に数えない。この間にチェックが成功すると、起動したものとして扱い、それ以降の失敗は数える。start_interval:start_periodの間のチェックの間隔。
冒頭の compose.yaml は、compose.healthy.yaml に start_period: 30s と start_interval: 1s を足したものです。-f をつけないと compose.yaml が使われます。
$ docker compose up -d
Network tb-healthcheck_default Creating
Network tb-healthcheck_default Creating
Network tb-healthcheck_default Created
Network tb-healthcheck_default Created
Container tb-healthcheck-db-1 Creating
Container tb-healthcheck-db-1 Created
Container tb-healthcheck-app-1 Creating
Container tb-healthcheck-app-1 Created
Container tb-healthcheck-db-1 Starting
Container tb-healthcheck-db-1 Started
Container tb-healthcheck-db-1 Waiting
Container tb-healthcheck-db-1 Healthy
Container tb-healthcheck-app-1 Starting
Container tb-healthcheck-app-1 Started
$ docker compose logs app
app-1 | 00:25:29 app: connecting to db
app-1 | 00:25:29 app: connected (PostgreSQL 18.6 (Debian 18.6-1.pgdg13+2))
$ docker inspect -f '{{.Name}} {{.State.StartedAt}}' tb-healthcheck-db-1 tb-healthcheck-app-1
/tb-healthcheck-db-1 2026-11-09T00:25:17.905637681Z
/tb-healthcheck-app-1 2026-11-09T00:25:29.55634953Z
$ docker inspect -f '{{range .State.Health.Log}}{{.Start}} exit={{.ExitCode}} {{.Output}}{{end}}' tb-healthcheck-db-1
2026-11-09 00:25:25.301411232 +0000 UTC exit=1 127.0.0.1:5432 - no response
2026-11-09 00:25:26.347277306 +0000 UTC exit=1 127.0.0.1:5432 - no response
2026-11-09 00:25:27.39185607 +0000 UTC exit=1 127.0.0.1:5432 - no response
2026-11-09 00:25:28.436881612 +0000 UTC exit=1 127.0.0.1:5432 - no response
2026-11-09 00:25:29.484178663 +0000 UTC exit=0 127.0.0.1:5432 - accepting connections
$ docker compose -f compose.yaml down -v
チェックは約1秒ごとに実行され、appはdbの起動から約11.7秒後に起動しました(前の章では約20.6秒)。docker inspect の記録には、最後の5件だけが表示されていて、それより前の失敗は表示されていません。
この設定では、起動から30秒以内で、まだhealthyになっていない間は、約1秒ごとにチェックします。PowerShellでの確認(最後の章)では、healthyになってから5秒待っても、チェックの記録は増えませんでした。成功した後は、1秒ごとのチェックは続かないようです。リファレンスの説明では、30秒を過ぎても成功しなければ、そこからの失敗が数えられ、retries(5回)続けて失敗するとunhealthyになります(この場合は確かめていません)。start_period は、初回の起動にかかる時間より長めにしておきます。
start_intervalだけを書くと、Compose 5.5.1 ではエラーになった
start_period を書かずに start_interval: 1s だけを足した compose.start-interval-only.yaml では、docker compose up がエラーで止まりました。docker compose config の確認は通ります。
healthcheck:
test: ["CMD-SHELL", "pg_isready -h 127.0.0.1 -U app -d app || exit 1"]
interval: 10s
timeout: 5s
retries: 5
start_interval: 1s
$ docker compose -f compose.start-interval-only.yaml config -q
$ docker compose -f compose.start-interval-only.yaml up -d
Network tb-healthcheck_default Creating
Network tb-healthcheck_default Creating
Network tb-healthcheck_default Created
Network tb-healthcheck_default Created
Container tb-healthcheck-db-1 Creating
service:db:1 healthcheck.start_interval requires healthcheck.start_period to be set
Container tb-healthcheck-app-1 Creating
healthcheck.start_interval requires healthcheck.start_period to be set
$ docker compose -f compose.start-interval-only.yaml down -v
このエラーは、Docker Composeのソースコード(pkg/compose/convert.go)で、start_interval があって start_period がないときに返すものでした。Composeのリファレンスには、この制約は書かれていませんでした(2026年11月9日に確認)。start_period の既定値は0秒なので、start_interval だけでは効く期間がありません。start_interval を書くときは、start_period も書きます。
start_periodがないと、初期化の途中でunhealthyになる
反対に、start_period を書かずに interval: 1s、retries: 3 にした compose.no-start-period.yaml です。
healthcheck:
test: ["CMD-SHELL", "pg_isready -h 127.0.0.1 -U app -d app || exit 1"]
interval: 1s
timeout: 5s
retries: 3
$ docker compose -f compose.no-start-period.yaml up -d
Network tb-healthcheck_default Creating
Network tb-healthcheck_default Creating
Network tb-healthcheck_default Created
Network tb-healthcheck_default Created
Container tb-healthcheck-db-1 Creating
Container tb-healthcheck-db-1 Created
Container tb-healthcheck-app-1 Creating
Container tb-healthcheck-app-1 Created
Container tb-healthcheck-db-1 Starting
Container tb-healthcheck-db-1 Started
Container tb-healthcheck-db-1 Waiting
Container tb-healthcheck-db-1 Error dependency db failed to start
dependency failed to start: container tb-healthcheck-db-1 is unhealthy
$ docker compose -f compose.no-start-period.yaml ps -a --format "table {{.Name}}\t{{.Status}}"
NAME STATUS
tb-healthcheck-app-1 Created
tb-healthcheck-db-1 Up 5 seconds (unhealthy)
初期化の途中で3回続けて失敗したため、dbはunhealthyになり、docker compose up は失敗しました(終了コード1)。appのコンテナは作られただけで、起動していません。
15秒後にもう一度見ると、dbはhealthyに変わっていましたが、appは Created のままでした。dbがhealthyになった後も、appは起動されていませんでした。
$ docker compose -f compose.no-start-period.yaml ps -a --format "table {{.Name}}\t{{.Status}}"
NAME STATUS
tb-healthcheck-app-1 Created
tb-healthcheck-db-1 Up 21 seconds (healthy)
$ docker compose -f compose.no-start-period.yaml down -v
ハマった点: pg_isreadyに-hをつけないと、初期化の途中でhealthyになる
compose.yaml の pg_isready から -h 127.0.0.1 だけを外した compose.socket.yaml では、condition: service_healthy で待ったのに、appは接続に失敗しました。
healthcheck:
test: ["CMD-SHELL", "pg_isready -U app -d app || exit 1"]
interval: 10s
timeout: 5s
retries: 5
start_period: 30s
start_interval: 1s
$ docker compose -f compose.socket.yaml up -d
Network tb-healthcheck_default Creating
Network tb-healthcheck_default Creating
Network tb-healthcheck_default Created
Network tb-healthcheck_default Created
Container tb-healthcheck-db-1 Creating
Container tb-healthcheck-db-1 Created
Container tb-healthcheck-app-1 Creating
Container tb-healthcheck-app-1 Created
Container tb-healthcheck-db-1 Starting
Container tb-healthcheck-db-1 Started
Container tb-healthcheck-db-1 Waiting
Container tb-healthcheck-db-1 Healthy
Container tb-healthcheck-app-1 Starting
Container tb-healthcheck-app-1 Started
$ docker compose -f compose.socket.yaml logs app
app-1 | 00:26:04 app: connecting to db
app-1 | 00:26:04 app: connection failed: connection to server at "172.20.0.2", port 5432 failed: Connection refused
app-1 | Is the server running on that host and accepting TCP/IP connections?
$ docker inspect -f '{{range .State.Health.Log}}{{.Start}} exit={{.ExitCode}} {{.Output}}{{end}}' tb-healthcheck-db-1
2026-11-09 00:26:03.434352277 +0000 UTC exit=0 /var/run/postgresql:5432 - accepting connections
$ docker compose -f compose.socket.yaml logs db | grep -E 'listening|ready to accept'
db-1 | 2026-11-09 00:26:02.893 UTC [54] LOG: listening on Unix socket "/var/run/postgresql/.s.PGSQL.5432"
db-1 | 2026-11-09 00:26:02.900 UTC [54] LOG: database system is ready to accept connections
$ docker compose -f compose.socket.yaml down -v
-h をつけない pg_isready は、コンテナの中のUnixソケット(/var/run/postgresql)に接続して確かめ、成功していました。一方、その時点のdbのログには、Unixソケットで待ち受ける行しかなく、5432番ポート(TCP)で待ち受ける行はありません。
PostgreSQLの公式イメージは、初期化のSQLを実行する間、一時的なサーバーを起動します。イメージの説明によると、この一時的なサーバーはUnixソケットだけで待ち受けます。そのため、Unixソケットで確かめるとhealthyになりますが、別のコンテナからTCPでは接続できません。初期化が終わると、一時的なサーバーは止まり、TCPでも待ち受けるサーバーが起動します(1章のdbのログの database system was shut down の後の行)。
-h 127.0.0.1 をつけると、TCPで接続して確かめるので、一時的なサーバーの間は no response で失敗し、本来のサーバーが起動してから成功します。Composeの公式ドキュメントの起動順の例は -h なしの pg_isready ですが、初期化のSQLやスクリプトを使うときは、この違いに注意が必要です。
WindowsのPowerShellで実行する場合
Windows 11 のPowerShell 7.6 から、1章の compose.short.yaml、3章の compose.yaml、「ハマった点」の compose.socket.yaml を動かしました。ファイルの改行はCRLF(Windowsのエディタで保存したとき)にして試しています。docker compose build の後に実行した結果です。up -d の出力は本文と同じだったので省略しました。
PowerShellには tail と grep がないので、docker compose logs の --tail と、PowerShellの Select-String を使います。--format と -f の書き方(ダブルクォートとシングルクォート)は、Git Bashと同じです。
PS> docker compose -f compose.short.yaml up -d
PS> docker compose -f compose.short.yaml logs app
app-1 | 00:30:10 app: connecting to db
app-1 | 00:30:10 app: connection failed: connection to server at "172.19.0.2", port 5432 failed: Connection refused
app-1 | Is the server running on that host and accepting TCP/IP connections?
PS> docker compose -f compose.short.yaml logs db --tail 3
db-1 | 2026-11-09 00:30:20.562 UTC [1] LOG: listening on Unix socket "/var/run/postgresql/.s.PGSQL.5432"
db-1 | 2026-11-09 00:30:20.566 UTC [77] LOG: database system was shut down at 2026-11-09 00:30:20 UTC
db-1 | 2026-11-09 00:30:20.570 UTC [1] LOG: database system is ready to accept connections
PS> docker compose -f compose.short.yaml down -v
PS> docker compose up -d
PS> docker compose logs app
app-1 | 00:30:39 app: connecting to db
app-1 | 00:30:39 app: connected (PostgreSQL 18.6 (Debian 18.6-1.pgdg13+2))
PS> docker compose ps -a --format "table {{.Name}}\t{{.Status}}"
NAME STATUS
tb-healthcheck-app-1 Exited (0) Less than a second ago
tb-healthcheck-db-1 Up 12 seconds (healthy)
PS> docker inspect -f '{{.Name}} {{.State.StartedAt}}' tb-healthcheck-db-1 tb-healthcheck-app-1
/tb-healthcheck-db-1 2026-11-09T00:30:27.469334693Z
/tb-healthcheck-app-1 2026-11-09T00:30:39.113245614Z
PS> docker inspect -f '{{range .State.Health.Log}}{{.Start}} exit={{.ExitCode}} {{.Output}}{{end}}' tb-healthcheck-db-1
2026-11-09 00:30:34.863830949 +0000 UTC exit=1 127.0.0.1:5432 - no response
2026-11-09 00:30:35.904961417 +0000 UTC exit=1 127.0.0.1:5432 - no response
2026-11-09 00:30:36.948611706 +0000 UTC exit=1 127.0.0.1:5432 - no response
2026-11-09 00:30:37.993916946 +0000 UTC exit=1 127.0.0.1:5432 - no response
2026-11-09 00:30:39.037314997 +0000 UTC exit=0 127.0.0.1:5432 - accepting connections
PS> docker compose -f compose.yaml down -v
appはdbの起動から約11.6秒後に起動して接続できました。最後の docker inspect は、healthyになってから5秒待って、もう一度実行したものです。記録は増えていませんでした(1回目の出力は同じ5行だったので省略)。
PS> docker compose -f compose.socket.yaml up -d
PS> docker compose -f compose.socket.yaml logs app
app-1 | 00:30:49 app: connecting to db
app-1 | 00:30:49 app: connection failed: connection to server at "172.19.0.2", port 5432 failed: Connection refused
app-1 | Is the server running on that host and accepting TCP/IP connections?
PS> docker compose -f compose.socket.yaml logs db | Select-String 'listening|ready to accept'
db-1 | 2026-11-09 00:30:48.403 UTC [53] LOG: listening on Unix socket "/var/run/postgresql/.s.PGSQL.5432"
db-1 | 2026-11-09 00:30:48.413 UTC [53] LOG: database system is ready to accept connections
PS> docker compose -f compose.socket.yaml down -v
CRLFのファイルでも、ビルドと起動、結果はGit Bashのときと同じでした。Macのターミナルでは、本文の $ で始まるコマンド(tail と grep を含む)をそのまま使う想定ですが、確認はしていません。
参考
- Define services in Docker Compose | Docker Docs(
depends_on、healthcheck) - Release v2.24.0 · docker/compose(
start_intervalへの対応) - Control startup and shutdown order in Compose | Docker Docs
- Dockerfile reference: HEALTHCHECK | Docker Docs
- postgres – Official Image | Docker Hub(初期化のスクリプト、一時的なサーバー)
- PostgreSQL 18: pg_isready
- docker/compose v5.5.1: pkg/compose/convert.go(
start_intervalのエラー)

コメント