gitkadoの気まぐれ日記

島根在住エンジニアが何かに興味を持ったらブログを更新します

DockerComposeの起動順を制御する

開発環境でcompose.ymlを使用してると実行順を制御したくなることがある。
具体的にはDBコンテナよりAPIコンテナが先に起動するとmigrationなどがコケてつらい。

昔のワタシ

以下の公式ドキュメント(ja)にあるようにwait-for-xx.shを実行して制御していた。
※ サンプルの都合で昔はpostgresになっています

#!/bin/sh
# wait-for-postgres.sh

set -e

host="$1"
shift

until PGPASSWORD=$POSTGRES_PASSWORD psql -h "$host" -U "postgres" -c '\q'; do
  >&2 echo "Postgres is unavailable - sleeping"
  sleep 1
done

>&2 echo "Postgres is up - executing command"
exec "$@"
# compose.yml
version: "2"
services:
  web:
    build: .
    ports:
      - "80:8000"
    depends_on:
      - "db"
    command: ["./wait-for-postgres.sh", "db", "python", "app.py"]
  db:
    image: postgres

docs.docker.jp

最近のワタシ

healthcheckでDBコンテナのヘルスチェックを行ってからAPIコンテナが起動するようにdepends_onを設定しています。

# compose.yml
version: "3.9"
services:
  web:
    build: .
    ports:
      - "80:8000"
    depends_on:
      db:
        condition: service_healthy
    command: ["python", "app.py"]
  db:
    image: mysql
    environment:
      MYSQL_USER: myuser
      MYSQL_PASSWORD: mypassword
    healthcheck:
      test: mysqladmin ping -h 127.0.0.1 -u $$MYSQL_USER --password=$$MYSQL_PASSWORD
      start_period: 5s
      interval: 5s
      timeout: 5s
      retries: 55

docs.docker.com

メリット

  • ローカル固有の問題をcompose.yml内で完結できるのが良い(shell追加とか不要)
  • コンテナ間の依存関係がcompose.yml内で表現されているので分かりやすい
  • 起動順だけの話ならservice_healthy+healthcheckでなくservice_startedだけでいける

注意点

  • compose-specのversionが3.9である必要があります(2023/05/24時点の最新)
    • 試してないけど3.0 ~ 3.8ではdepends_onで使用するconditionが動作しなかったとか?

最後に

実は結構前から使えてたみたいだけど公式ドキュメント(ja)は更新されてない*1っぽくて気づけなかった。
Do not turn away from English documents!

*1:compose-specのversionが"2"ってのが何よりの証拠