ヘッダー画像

【Docker】ヘルスチェックでコンテナの起動タイミングを制御

投稿 2025年7月19日 最終更新 2025年7月19日 専門用語多め

やりたいこと

depends_onで起動順を制御しても、ちゃんと起動しきっていなくて、CI/CDのテストが成功しない…
みたいなことになったことあるでしょうか?

コンテナの起動 ≠ アプリケーションの起動 なので、コンテナが起動したのではなく、ちゃんと中身のアプリケーションが起動したことを確認してから、次のコンテナを起動してほしい!

ということで今回は例として

  • MySQLのコンテナが起動してから、Tomcatのコンテナを起動
  • Tomcatのコンテナが起動してから、Apacheのコンテナを起動

という順番で起動させる設定を紹介します。

ヘルスチェック設定内容

初めにdocker-composeのファイル全体を載せておきます。

docker-compose.yml

version: "3"
services:
  mysql:
    container_name: "mysql_health_check"
    image: mysql:9.3.0
    # ヘルスチェック
    healthcheck:
      test: "mysqladmin ping -h localhost -u root -ppassword12345"
      timeout: 10s
      interval: 5s
      retries: 10
    environment:
      TZ: Asia/Tokyo
      LANG: ja_JA.UTF-8
      MYSQL_DATABASE: health
      MYSQL_ROOT_PASSWORD: password12345
    ports:
      - "3306:3306"
    volumes:
      - "/dev:/dev"
      - "./mysql/conf.d/my.cnf:/etc/mysql/conf.d/my.cnf"
      - "./mysql/initdb.d:/docker-entrypoint-initdb.d"
      - "./mysql/data:/var/lib/mysql"
      - "./mysql/log:/var/log/mysql"

  tomcat:
    container_name: "tomcat_health_check"
    image: tomcat:9.0.107-jre17
    # 起動順
    depends_on:
      mysql:
        condition: service_healthy
    # ヘルスチェック
    healthcheck:
      test: "curl --fail http://localhost:8080/original/health || exit 1"
      timeout: 30s
      interval: 10s
      retries: 20
      start_period: 30s
    environment:
      TZ: Asia/Tokyo
      LANG: ja_JA.UTF-8
    ports:
      - "8009:8009"
    volumes:
      - "/dev:/dev"
      - "./tomcat/conf:/usr/local/tomcat/conf"
      - "./tomcat/webapps:/usr/local/tomcat/webapps"
      - "./tomcat/logs/app:/usr/local/tomcat/logs/app"
      - "./tomcat/logs/catalina:/usr/local/tomcat/logs/catalina"

  httpd:
    container_name: "httpd_health_check"
    image: httpd:2.4.64
    # 起動順
    depends_on:
      tomcat:
        condition: service_healthy
    environment:
      TZ: Asia/Tokyo
      LANG: ja_JA.UTF-8
    ports:
      - "443:443"
    volumes:
      - "/dev:/dev"
      - "./apache/conf:/usr/local/apache2/conf"
      - "./apache/logs:/usr/local/apache2/logs"

ヘルスチェック設定方法

testコマンド

test:に起動ができたかどうかを判断するコマンドを指定します。

MySQLの場合

pingコマンドを使いMySQLが反応があることを確認します。

mysqladmin ping -h localhost -u root -ppassword12345

Tomcatの場合

Tomcatの場合は、実際にTomcatに直接リクエストを送信し、HTTPステータスコードが200番台で返ってくるかを確認します。

curl --fail http://localhost:8080/original/health || exit 1
ポート番号

ポート番号はTomcatのデフォルトポートである8080を使用しています。

server.xmlがデフォルトのままなら開放できているかと思います。

<?xml version="1.0" encoding="UTF-8"?>
<Server port="8005" shutdown="SHUTDOWN">
  <Service name="Catalina">
    <!-- ヘルスチェックのためにデフォルトポート番号を開放 -->
    <Connector port="8080" protocol="HTTP/1.1"
               connectionTimeout="20000"
               redirectPort="8443"
               maxParameterCount="1000"
    />
  </Service>
</Server>
ヘルスチェックエンドポイント

/original/healthは、Tomcatのアプリケーション内で独自にエンドポイントを作成しています。

import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@WebServlet("/original/health")
public class Health extends HttpServlet {
  @Override
  protected void doGet(final HttpServletRequest request, final HttpServletResponse response) {
    // 必要に応じてヘルスチェック時にチェックしたい処理…
    
    // OKを返却
    response.setStatus(HttpServletResponse.SC_OK);
  }
}

server.xml自体にもヘルスチェック設定があるので、Tomcat起動チェックのみでよければ下記でも良いかと思います。

curl --fail http://localhost:8080/health || exit 1
<?xml version="1.0" encoding="UTF-8"?>
<Server port="8005" shutdown="SHUTDOWN">
  <Service name="Catalina">
    <!-- ヘルスチェックのためにデフォルトポート番号を開放 -->
    <Connector port="8080" protocol="HTTP/1.1"
               connectionTimeout="20000"
               redirectPort="8443"
               maxParameterCount="1000"
    />
    <Engine name="Catalina" defaultHost="localhost">
      <Host name="localhost" appBase="webapps">
          <!-- ヘルスチェックエンドポイントを設定 -->
        <Valve className="org.apache.catalina.valves.HealthCheckValve" path="/health" />
      </Host>
    </Engine>
  </Service>
</Server>

タイムアウト

testコマンドの実行がタイムアウトするまでの時間を指定します。

数字のみではなく、timeout: 30sのように単位も指定します。

インターバル

testコマンドを実行する間隔を指定します。

数字のみではなく、interval: 10sのように単位も指定します。

リトライ回数

testコマンドが失敗した場合のリトライ回数を指定します。

数字のみではなく、retries: 20のように単位も指定します。

開始までの時間

testコマンドを実行し始めるまでの待機時間を指定します。

数字のみではなく、start_period: 30sのように単位も指定します。

Tomcatとかのように、そもそもの起動に時間がかかってしまうようなアプリケーションの場合は、testコマンドを実行するまでの時間を指定することで、失敗しにくくしています。

ちょっとスペック低かったので、30秒ほど待機させてますw

depends_on

ヘルスチェックを設定しているコンテナに対して、depends_onを設定することで、ヘルスチェックのtestコマンドが成功するまで起動タイミングを制御できます。

  • mysqlコンテナのヘルスチェックが成功してから、tomcatコンテナを起動させる
tomcat:
  depends_on:
    mysql:
      condition: service_healthy
  • tomcatコンテナのヘルスチェックが成功してから、httpdコンテナを起動させる
httpd:
  depends_on:
    tomcat:
      condition: service_healthy

ヘルスチェックが効果のあるコマンド

docker-compose up -ddocker-compose startのコマンドはしっかりヘルスチェックを考慮して起動してくれます。

ただ、docker-compose restartだとヘルスチェックを無視して起動しちゃうみたいです。

もしdownさせずにコンテナだけ再起動させたければ、
docker-compose stopしてdocker-compose startすればOKです。

まとめ

Dockerのヘルスチェックを設定することで、無事にCI/CDのテストを安定させることができました。

便利すぎるがゆえにうまく扱うのは難しいですが、使いこなせれば強いですね~!

以上、ここまで見ていただきありがとうございます。

皆さまの快適な開発ライフに、ほんの少しでもお役に立てれば幸いです。

コメント

この記事のコメントはありません。