docker compose up --wait の落とし穴
再現リポジトリ
問題
docker compose up --wait で下記を満たすとき、
どうあがいても exit code 1 になり、「docker compose の起動に失敗した」と見なされる。
- depends_on チェーンの最後に起動するサービスがバッチ系処理であり、実行時間が極端に短い。
解決
明示的に sleep 2 とかで待機するか、docker compose wait コマンドで明示的に待つしかないみたいです。
sleep 1 だと早すぎて失敗することがある。
背景
1. CI での ミドルウェア service の起動
マイクロサービス構成を docker-compose で一発起動できるように設定しています。
profile を利用し、テスト環境向けには DB や localstack のみを起動できるようにして、別 service で migration や init のスクリプトを流しています。(以後 init 系 service と呼びます)
Github Actions で docker compose up --wait で起動して、そのあと pnpm test で自動テストを流すようにしました。
2. init 系 service の起動を待たないことが発覚
上記の構成にして マイグレーションファイルが増えていくと、いくつかの結合テストが失敗するようになりました。
log を見ると「テーブルが無い」とのこと。
ローカルで試したところ、確かに失敗するタイミングがある。
ワンライナーで実行すると失敗するが、個別コマンドで実行すると成功する。
どうやら migration の実行完了前に 自動テストが流れている様子。
--wait は、どの service からも depends_on されていない終端 service の実行完了を待たない、ということのようです。
3. watcher の追加
Claude と相談し、init-watcher というサービスを追加しました。
これは init 系 service に depends_on し、それらの完了を待つだけのもの。
command: exit 0 のようにして、watch が終わったら即時終了するだけの薄い service です。
これで解決すると思われました。
4. --wait は 即時終了する service を適切に扱えない
この記事の主題です。
init-watcher が終了すると同時に docker-compose 自体が exit code 1 で終了するようになりました。
ただ、log には原因が全く出力されていません。
> docker compose up --wait
[+] Running 2/3
✔ Network docker-compose-wait-test_default Created 0.1s
✔ Container docker-compose-wait-test-base-service-1 Healthy 1.0s
⠇ Container docker-compose-wait-test-init-watcher-1 Waiting 0.9s
container docker-compose-wait-test-init-watcher-1 exited (0)
ここからは気合で調査しましたが、init-watcher の起動終了が早すぎるのが原因のようでした。
deepwiki と相談したところ、compose 自体が起動後に service の監視を始めるようで、このラグを考慮してある程度処理時間がないと落ちるとのことでした。
Discussion