【Docker】ヘルスチェックでコンテナの起動タイミングを制御
やりたいこと
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 -d
やdocker-compose start
のコマンドはしっかりヘルスチェックを考慮して起動してくれます。
ただ、docker-compose restart
だとヘルスチェックを無視して起動しちゃうみたいです。
もしdownさせずにコンテナだけ再起動させたければ、docker-compose stop
してdocker-compose start
すればOKです。
まとめ
Dockerのヘルスチェックを設定することで、無事にCI/CDのテストを安定させることができました。
便利すぎるがゆえにうまく扱うのは難しいですが、使いこなせれば強いですね~!
以上、ここまで見ていただきありがとうございます。
皆さまの快適な開発ライフに、ほんの少しでもお役に立てれば幸いです。