起動順と環境を切り替える - depends_on / profiles
`depends_on` でサービスの起動順を制御し、`profiles` で dev / prod など環境ごとの有効化を切り替える。ただし起動順だけではアプリの準備完了を保証できないので healthcheck との組み合わせが必要になる。
概念図
構文
実例
healthcheck と depends_on.condition の組み合わせ
services:
db:
image: postgres:16
healthcheck:
test: ["CMD-SHELL", "pg_isready -U postgres"]
interval: 5s
timeout: 3s
retries: 10
api:
build: ./api
depends_on:
db:
condition: service_healthyprofiles で dev 専用 / prod 専用のサービスを切り替える
services:
app:
image: myapp
mailhog:
image: mailhog/mailhog
profiles: ["dev"]
metrics:
image: prom/prometheus
profiles: ["prod", "observability"]depends_on の長所と限界
depends_on は「A の起動を B より先にしてほしい」という指定をコンテナ起動順に反映させる。
書き方には短い形式と長い形式の 2 種類があり、待機の基準が異なる。
- 短い形式(配列): 依存先のコンテナプロセスが起動した時点で「依存満たし」とみなされる。アプリケーション側の準備完了(DB ならクエリを受け付けられる状態)までは待たない
- 長い形式(
condition指定):condition: service_started/service_healthy/service_completed_successfullyで待機条件を選べる。healthcheck と組み合わせると「受け付け可能になった」まで待てる
短い形式だけでは、Postgres が listen する前に API が接続試行して失敗する、という古典的な問題は解決しない。
解決策はアプリ側にリトライを実装するか、後述の healthcheck と condition: service_healthy を併用するかの二択になる。
いずれにしてもコンテナが「起動した」ことと「受け付け可能になった」ことは別物として扱う必要がある。
healthcheck と組み合わせる
depends_on を長い形式で書き、condition: service_healthy を指定すると、依存先の healthcheck が pass するまで起動を待機するようになる。
healthcheck はサービス自身の Dockerfile または compose.yml で定義し、pg_isready や curl -f localhost/health など「準備完了のシグナル」として信頼できるコマンドを選ぶ。
interval を短くしすぎると CI で DB に過剰な接続負荷をかけるので、5 秒程度が目安になる。
retries と start_period を組み合わせると、マイグレーション中など起動に時間がかかるサービスにも対応できる。
healthcheck 自体が不安定だと全体が立ち上がらなくなるため、healthcheck コマンドは十分にテストしてから採用する。
services:
db:
image: postgres:16
healthcheck:
test: ["CMD-SHELL", "pg_isready -U postgres"]
interval: 5s
retries: 10
start_period: 20s
api:
build: ./api
depends_on:
db:
condition: service_healthyprofiles で dev / prod を切り替える
profiles は「通常は起動しないが、特定のプロファイルを指定したときだけ起動する」サービスを宣言する仕組み。
たとえば開発時にしか使わない MailHog や DynamoDB Local、本番監視系の Prometheus などに付けておくと、docker compose --profile dev up のように明示的に起動対象を切り替えられる。
どのプロファイルにも属さないサービスは常に起動対象になる。
環境ごとに別の compose.yml を用意する代わりに 1 ファイルで切り替えたいときに有効で、後述の override ファイルと目的が重なるが、「サービスの有無」を切り替えたい場合は profiles、「既存サービスの設定だけ差し替えたい」場合は override ファイルと使い分けるのがわかりやすい。
services:
app:
image: myapp
mailhog:
image: mailhog/mailhog
profiles: ["dev"]
# docker compose up -> app だけ / only app
# docker compose --profile dev up -> app + mailhog