1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

docekrコンテナの実行手順を制御するhealthcheckとは

Posted at

1. 前提条件

MySQL、Prisma、Docker-Compose を使用した環境で、データベースの起動遅延による接続エラーを防ぐ方法を解説します。

使用技術:

  • MySQL
  • Prisma
  • Docker-Compose

2. Healthcheck(ヘルスチェック)とは?

Healthcheck は、コンテナやサービスが 正常に動作しているか を自動で確認する仕組みです。
コンテナ環境では、アプリケーションが起動していても 実際に動作できる状態かどうか を保証する必要があります。
Healthcheck を使うことで、サービスの正常性を確認し、異常時に適切な対応(再起動・待機・通知など)を行うことができます。

Healthcheck の役割

コンテナの「起動完了」や「動作状態」を確認

  • 例: MySQL が起動していても、まだ接続を受け付けられない状態を防ぐ。

異常を検知して、コンテナを再起動

  • 例: アプリがハングした場合、Docker が自動で再起動できる。

他のサービスが「依存するコンテナの起動を待つ」制御ができる

  • 例: depends_on: service_healthy で、MySQL の起動を待ってからアプリを起動。

3. 問題の発生

Docker-Compose を使って MySQL とアプリケーションを始めて起動した際に、

Error: connect ECONNREFUSED 127.0.0.1:3306

または

PrismaClientInitializationError: Can't reach database server at `db:3306`

といったエラーが発生し、アプリケーションが MySQL に接続できない問題が発生。


4. エラーの原因

① MySQL の起動には時間がかかる

  • docker-compose updb コンテナがすぐに起動するが、MySQL サーバーが実際にリクエストを受け付けられるまでには時間がかかる。
  • アプリケーションが MySQL の起動完了を待たずに接続を試みると、エラーが発生。

depends_on では MySQL の起動完了を保証できない

  • depends_on を指定すると、アプリ (app) は MySQL (db) のコンテナが "起動" したことを確認してから起動する。
  • しかし、"起動" とは コンテナのプロセスが立ち上がっただけ であり、MySQL サーバー自体がリクエストを受け付けられる状態になったことを保証しない
  • MySQL は起動後に 初期設定やテーブル作成などを内部で実行するため、起動完了までに時間がかかる
  • そのため、アプリが MySQL の起動直後に接続を試みると、まだ MySQL が受け入れ可能な状態でなく、ECONNREFUSED エラーが発生する。

③ Prisma などのデータベースクライアントが MySQL に接続できない

  • MySQL が起動していない間に prisma.$connect() が実行されると、接続エラーが発生する。
  • これは Prisma に限らず、一般的なデータベースクライアントが MySQL への接続を試みる際にも発生する問題。

healthcheck が実質必須になる条件

healthcheckは基本的には推奨となるが、以下の条件に当てはまる場合、healthcheck を入れないと MySQL の起動遅延による接続エラーが発生しやすくなる

  1. アプリが起動時に即データベースへ接続する設計

    • Prisma のように prisma.$connect() がアプリの起動時に実行される 場合、DB が準備できる前に接続を試みるためエラーになる。
  2. データベースの起動が遅い(MySQL, PostgreSQL など)

    • MySQL や PostgreSQL は起動直後にすぐ接続可能になるわけではなく、初期設定やデータロードが完了するまで時間がかかる
    • depends_on だけでは コンテナが起動したこと しか保証されず、DB がリクエストを受け付けられるとは限らない。
  3. アプリがリトライ機能を持たない(接続エラー時に自動で再試行しない)

    • healthcheck を入れない場合、アプリ側で 「接続エラー時にリトライする」 実装があれば問題にならないが、ない場合は一度失敗すると再試行せずクラッシュする。
  4. コンテナのオーケストレーションを Docker-Compose で管理している

    • Kubernetes では livenessProbereadinessProbe を使うが、Docker-Compose では 明示的に healthcheck を設定しないと起動順を制御できない

5. 解決方法

** docker-compose.ymlhealthcheck を追加する**

version: "3.8"

services:
  app:
    build: .
    ports:
      - "3000:3000"
    depends_on:
      db:
        condition: service_healthy
    environment:

  db:
    image: mysql:8.0
    restart: always
    environment:
      MYSQL_ROOT_PASSWORD: password
      MYSQL_DATABASE: database
      MYSQL_USER: user
      MYSQL_PASSWORD: password
    ports:
      - "3306:3306"
    healthcheck:
      test: ["CMD", "mysqladmin", "ping", "-h", "localhost"]
      interval: 10s
      timeout: 5s
      retries: 5

・動作の流れ

  1. コンテナが起動(でも MySQL はまだ準備中)。
  2. mysqladmin ping を 10 秒ごとに実行し、応答を確認。
  3. 5 回試して 成功すれば healthy、失敗すれば unhealthy になる。
  4. app コンテナは MySQL が healthy になるまで起動しない(depends_on を設定する場合)。

6. まとめ

healthcheck を追加することで、MySQL の完全起動を待ってから app を起動できるようになる。
depends_on: service_healthy を使うことで、MySQL が使用可能になるまで app を待機させることができる。
・Prisma などのデータベースクライアントが MySQL に確実に接続できるようになり、connect ECONNREFUSEDPrismaClientInitializationError のエラーを回避できる。

1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?