docker composeでnginxを動かすときはオリジンのコンテナがHealthyになっているかチェックすると良い

バックエンドとフロントエンドが分かれていたり、細かいルーティングを行うWebアプリケーションではローカルの開発環境でnginxをプロキシサーバとしてかますことが多いと思います。

しかし、docker compose upで立ち上げた初期はバックエンドのアプリケーションが起動中となりアクセスするとnginx側から502が返ってきてしまうことがよくあります*1。ローカル環境なので、開発体験の粋ではりますが、エンジニア以外がローカル環境を立ち上げた際に混乱のもとになりかねません。

この記事では、そのようなことが起こらないようにするためのdocker composeのhealthcheckを使用したWebアプリケーションの起動チェックについて解説していきます。

healthcheck とは

docker compose v2.1 で追加された機能の一つでtestで指定したコマンドを実行し成功したらhealtyとなる機能です。depends_on を使うことでhealtyになったら他のコンテナを起動するといったことができるようになります。

docs.docker.com

使い方

この記事では、docker composeでの使い方を解説します。DockerfileでもHEALTHCHECKがあるようですが、そちらの使い方は公式ドキュメントを参照してください。

まず、ヘルスチェックしたいコンテナに対して以下のように記述します。

healthcheck:
  test: "curl --fail http://localhost:8080 || exit 1"
  interval: 5s
  timeout: 30s
  retries: 5
  start_period: 30s
  • test
    • 実際にヘルスチェックで実行されるコマンドです。例ではcurlを使っていますが、alpineイメージだとデフォルトで入っていないのでRUN apk update && apk add --no-cache curlをすると良さそうです。
    • mysqlのヘルスチェックではmysqladmin pingなども使えます
  • interval
    • 前回のコマンドが0以外で終了した場合リトライをします。その間隔です。
    • また、初回のコマンド実行前にもintervalの秒数待つようです。
  • timeout
    • コマンド実行のタイムアウトです。
  • retries
    • リトライ回数です。
  • start_period
    • コンテナがスタートするまでの秒数です。パッケージのインストールなどで時間がかかることが予想される場合、この秒数を長くするといいかもしれません。
    • このperiodの範囲内ではtestのコマンドが実行されますが、失敗してもリトライ回数にカウントされません。しかし、成功したらHealthyとなります。

その後、ヘルスチェック後に起動したいコンテナに対してdepends_onを設定します。

depends_on:
  frontend:
    condition: service_healthy
  backend:
    condition: service_healthy

condition: service_healthy とすることで依存元のコンテナがHealthyになったタイミングで依存先のコンテナが立ち上がるようになります。

作成例

以下は、私の趣味で作っているプロダクトで実際に使っているcompose.yamlです。GoのバックエンドサーバーとNext.jsのフロントエンドサーバーがあり、nginxを通って配信されています。

この例では、GoとNext.jsの両コンテナにヘルスチェックを追加してnginxではservice_healthydepends_onをしています。これにより、両方のバックエンドサーバーが起動完了してからnginxが立ち上がるので502が返ってくることがなくなります。

github.com

参考文献

*1:特にNext.jsでApp Routerを使っている場合、ローカル環境立ち上げが遅いです。