はじめに
Dockerでコンテナを起動した際、コンテナが実行中であっても、内部で動作しているアプリケーションが正常に稼働しているとは限りません。
例えば、Webサーバーのプロセスは起動していても、HTTPリクエストに正常に応答できない状態になっている可能性があります。
このような場合に、コンテナ内のアプリケーションが正常に動作しているかを確認するために使用できるのが、DockerfileのHEALTHCHECK命令です。
HEALTHCHECKを使用すると、コンテナ内で定期的にコマンドを実行し、その実行結果によってコンテナの正常性を確認できます。
本記事では、以下の内容について解説します。
- HEALTHCHECKとは何か
- HEALTHCHECKの基本的な書き方
--interval、--timeout、--retriesの役割- HTTPリクエストを使ったヘルスチェックの設定方法
- Dockerfileからイメージをビルドする方法
- コンテナを起動してヘルスチェックを実行する方法
docker inspectでヘルスチェックの結果を確認する方法
実際にApache HTTP Serverを使用したDockerfileを作成し、コンテナの状態を確認していきます。
1. DockerfileのHEALTHCHECKとは
HEALTHCHECKは、コンテナ内で定期的にコマンドを実行し、コンテナの正常性を確認するための命令です。
DockerfileにHEALTHCHECKを記述すると、コンテナ起動後に指定したコマンドが一定間隔で実行されます。
例えば、Webサーバーであれば、コンテナ内からHTTPリクエストを送信し、正常に応答できるか確認する方法があります。
次の例を見てみましょう。
HEALTHCHECK --interval=10s --timeout=5s \
CMD curl -sf http://localhost/ || exit 1
この命令では、コンテナ内からhttp://localhost/にHTTPリクエストを送信し、Webサーバーの応答を確認しています。
curlコマンドが正常に終了すれば、ヘルスチェックは成功と判定されます。
一方、curlコマンドが失敗した場合は、exit 1が実行され、ヘルスチェックは失敗と判定されます。
このように、HEALTHCHECKを設定することで、コンテナが単に起動しているかだけでなく、指定した検査コマンドが正常に実行できるかを確認できます。
1-1. コンテナの起動状態とヘルスチェックの違い
Dockerでは、コンテナが起動しているかどうかを確認するために、次のコマンドを使用できます。
docker ps
ただし、コンテナが起動中であることと、コンテナ内のアプリケーションが正常に応答できることは、必ずしも同じではありません。
HEALTHCHECKを使用すると、コンテナ内部で指定したコマンドの実行結果をもとに、正常性を判定できます。
例えば、HTTPリクエストを送信するヘルスチェックを設定すれば、WebサーバーがHTTPリクエストに応答できるかを検査できます。
なお、ヘルスチェックの結果は、設定したコマンドによる判定です。アプリケーションのあらゆる機能が正常であることを保証するものではありません。
2. HEALTHCHECKの基本構文
HEALTHCHECKは、次の形式で記述します。
HEALTHCHECK [オプション] CMD コマンド
例えば、次のように記述します。
HEALTHCHECK --interval=10s --timeout=5s \
CMD curl -sf http://localhost/ || exit 1
この例では、コンテナ内でcurlを実行し、Webサーバーの応答を確認します。
HEALTHCHECKで使用する主なオプションは、次の3つです。
| オプション | 説明 | PDF記載のデフォルト値 |
|---|---|---|
--interval | ヘルスチェックを実行する間隔 | 30秒 |
--timeout | ヘルスチェックのタイムアウト時間 | 30秒 |
--retries | 異常と判定するまでの連続失敗回数 | 3回 |
それぞれの役割を確認していきましょう。
2-1. –interval:ヘルスチェックの実行間隔
--intervalは、ヘルスチェックを実行する間隔を指定するオプションです。
例えば、次のように記述します。
HEALTHCHECK --interval=10s \
CMD curl -sf http://localhost/ || exit 1
この例では、ヘルスチェックの実行間隔を10秒に設定しています。
10sのsは秒を表します。
参考資料では、--intervalのデフォルト値は30秒と説明されています。
そのため、実行間隔を指定しなかった場合は、基本的に30秒間隔でヘルスチェックが実行されます。
2-2. –timeout:タイムアウト時間
--timeoutは、ヘルスチェックのタイムアウト時間を指定するオプションです。
例えば、次のように記述します。
HEALTHCHECK --timeout=5s \
CMD curl -sf http://localhost/ || exit 1
この場合、ヘルスチェックのタイムアウト時間は5秒です。
指定した時間内にヘルスチェックコマンドが完了しなかった場合、そのチェックは失敗と判定されます。
参考資料では、--timeoutのデフォルト値は30秒と説明されています。
2-3. –retries:失敗回数
--retriesは、ヘルスチェックが何回連続して失敗した場合に、コンテナを異常な状態と判定するかを指定するオプションです。
例えば、次のように記述します。
HEALTHCHECK --retries=3 \
CMD curl -sf http://localhost/ || exit 1
この例では、ヘルスチェックが3回連続で失敗すると、コンテナがunhealthyと判定されます。
参考資料では、デフォルト値は3回と説明されています。
2-4. 複数のオプションを組み合わせる
これらのオプションは、組み合わせて指定できます。
HEALTHCHECK --interval=10s --timeout=5s --retries=3 \
CMD curl -sf http://localhost/ || exit 1
この例では、次のように設定しています。
- 10秒間隔でヘルスチェックを実行する
- 1回のチェックが5秒を超えた場合はタイムアウトする
- 3回連続で失敗した場合は
unhealthyと判定する
このように、オプションを組み合わせることで、ヘルスチェックの実行条件を設定できます。
3. HEALTHCHECKでHTTPリクエストを送信する
参考資料では、Apache HTTP Serverを使用したヘルスチェックの例が紹介されています。
Webサーバーが正常に応答するか確認するために、次のコマンドを使用しています。
curl -sf http://localhost/ || exit 1
このコマンドの内容を確認してみましょう。
3-1. curlコマンドの役割
curlは、HTTPなどのプロトコルを使用して通信するためのコマンドです。
今回の例では、次のコマンドを使用します。
curl -sf http://localhost/
このコマンドは、コンテナ内のlocalhostに対してHTTPリクエストを送信します。
オプションの意味は次のとおりです。
| 指定 | 説明 |
|---|---|
curl | HTTPリクエストを送信する |
-s | 進捗表示などを抑制する |
-f | HTTPエラーステータスの場合に失敗として扱う |
http://localhost/ | 接続先URL |
正常にHTTPリクエストが処理された場合、curlは正常終了します。
一方、接続できない場合やHTTPエラーが発生した場合には、失敗として終了します。
3-2. || exit 1の役割
参考資料では、curlの後ろに次の処理を記述しています。
|| exit 1
||は、前のコマンドが失敗した場合に、後ろのコマンドを実行するためのシェル演算子です。
そのため、次のコマンドでは、
curl -sf http://localhost/ || exit 1
以下のように動作します。
curlでHTTPリクエストを送信するcurlが成功した場合は、正常終了するcurlが失敗した場合は、exit 1を実行する- ヘルスチェックが失敗として判定される
このように、curlの実行結果を利用して、ヘルスチェックの成否を判定しています。
4. HEALTHCHECKを使用したDockerfileを作成する
ここからは、参考資料のApache HTTP Serverの例をもとに、実際にDockerfileを作成します。
参考PDFではCentOS 7を使用していますが、CentOS 7はサポートが終了しているため、現在の開発環境への採用は推奨しません。
ここでは、あくまで参考資料の構成を理解するための例として紹介します。
4-1. 作業ディレクトリを作成する
まず、Dockerfileを配置するディレクトリを作成します。
mkdir docker-healthcheck
cd docker-healthcheck
4-2. Dockerfileを作成する
作業ディレクトリ内にDockerfileという名前のファイルを作成します。
次の内容を記述してください。
FROM centos:7
RUN yum install -y httpd
RUN echo '<h1>OK</h1>' > /var/www/html/index.html
HEALTHCHECK --interval=10s --timeout=5s \
CMD curl -sf http://localhost/ || exit 1
CMD ["/usr/sbin/httpd", "-DFOREGROUND"]
このDockerfileでは、Apacheをインストールし、HTTPリクエストによるヘルスチェックを設定しています。
なお、参考PDFの例ではcurlを使用していますが、環境によってはcurlの導入状況を別途確認する必要があります。また、CentOS 7のパッケージ取得先の状況によっては、このビルドが成功しない可能性があります。
4-3. Dockerfileの各命令を解説
FROM:ベースイメージを指定
FROM centos:7
CentOS 7のイメージをベースとして使用します。
RUN:Apacheをインストール
RUN yum install -y httpd
Dockerイメージのビルド時にApache HTTP Serverをインストールします。
RUN:HTMLファイルを作成
RUN echo '<h1>OK</h1>' > /var/www/html/index.html
Apacheの公開ディレクトリにindex.htmlを作成します。
このファイルには、次のHTMLが記述されます。
<h1>OK</h1>
HEALTHCHECK:正常性を確認
HEALTHCHECK --interval=10s --timeout=5s \
CMD curl -sf http://localhost/ || exit 1
10秒間隔でコンテナ内からHTTPリクエストを送信し、正常に応答するか確認します。
CMD:Apacheを起動
CMD ["/usr/sbin/httpd", "-DFOREGROUND"]
コンテナ起動時にApacheをフォアグラウンドで実行します。
5. Dockerイメージをビルドする
Dockerfileを作成したら、Dockerイメージをビルドします。
参考資料では、次のコマンドを使用しています。
docker build -t myapp .
このコマンドの意味は次のとおりです。
| 指定 | 説明 |
|---|---|
docker build | Dockerfileからイメージをビルドする |
-t myapp | 作成するイメージにmyappという名前を付ける |
. | 現在のディレクトリをビルドコンテキストとして指定する |
ビルドに成功すると、myappという名前のDockerイメージが作成されます。
ビルドしたイメージは、次のコマンドで確認できます。
docker image ls
表示される一覧にmyappがあれば、イメージが作成されています。
6. HEALTHCHECKを設定したコンテナを起動する
ビルドしたイメージからコンテナを起動します。
参考資料では、次のコマンドを使用しています。
docker run -d --name cont1 myapp
各指定の意味は次のとおりです。
| 指定 | 説明 |
|---|---|
docker run | コンテナを作成して起動する |
-d | バックグラウンドで実行する |
--name cont1 | コンテナ名をcont1にする |
myapp | 使用するDockerイメージ |
このコマンドにより、myappイメージからcont1という名前のコンテナが起動します。
コンテナ内では、CMDで指定したApacheが実行されます。
さらに、HEALTHCHECKで指定したコマンドが定期的に実行されます。
今回の設定では、10秒間隔で次のコマンドが実行されます。
curl -sf http://localhost/ || exit 1
このコマンドによって、ApacheがHTTPリクエストに正常に応答するかを確認します。
7. docker inspectでHEALTHCHECKの結果を確認する
参考資料では、docker inspectコマンドを使用してヘルスチェックの実行結果を確認しています。
次のコマンドを実行します。
docker inspect cont1
このコマンドでは、コンテナの詳細情報を取得できます。
取得した情報の中には、ヘルスチェックの実行結果も含まれます。
7-1. HealthのStatusを確認する
参考資料には、次のような出力例が掲載されています。
{
"Health": {
"Status": "healthy",
"FailingStreak": 0,
"Log": [
{
"Start": "2019-09-04T20:08:18.820425313+09:00",
"End": "2019-09-04T20:08:19.245683023+09:00",
"ExitCode": 0,
"Output": "<h1>OK</h1>\n"
}
]
}
}
※これはdocker inspectの出力に含まれるHealth部分の抜粋です。
この例では、Statusがhealthyとなっています。
つまり、指定したヘルスチェックコマンドが成功している状態です。
7-2. Statusの意味
ヘルスチェックの状態は、主に次の値で表されます。
| Status | 意味 |
|---|---|
starting | ヘルスチェックの初期状態 |
healthy | ヘルスチェックが成功している状態 |
unhealthy | ヘルスチェックが連続して失敗し、異常と判定された状態 |
コンテナを起動した直後は、まだヘルスチェックが完了していない場合があります。
その場合、Statusはstartingとして表示されることがあります。
その後、ヘルスチェックが成功するとhealthyになります。
一方、指定した回数だけ連続で失敗すると、unhealthyと判定されます。
7-3. FailingStreakとは
FailingStreakは、ヘルスチェックが連続して失敗した回数を表します。
参考資料の例では、次のようになっています。
"FailingStreak": 0
この場合、連続失敗回数は0回です。
--retries=3を設定した場合、通常は3回連続で失敗するとunhealthyになります。
7-4. ExitCodeとは
ExitCodeは、ヘルスチェックコマンドの終了コードを表します。
参考資料の例では、次のようになっています。
"ExitCode": 0
終了コードが0の場合、ヘルスチェックは成功と判定されます。
一方、失敗を示す終了コードが返された場合は、ヘルスチェックが失敗したものとして扱われます。
今回のDockerfileでは、curlが失敗した場合にexit 1を実行しています。
curl -sf http://localhost/ || exit 1
そのため、HTTPリクエストが失敗した場合は、ヘルスチェックも失敗として扱われます。
7-5. Outputとは
Outputには、ヘルスチェックコマンドの出力内容が記録されます。
参考資料の例では、次のようになっています。
"Output": "<h1>OK</h1>\n"
これは、Apacheが返したHTMLの内容です。
Dockerfileでは、次のようにHTMLファイルを作成しました。
RUN echo '<h1>OK</h1>' > /var/www/html/index.html
そのため、HTTPリクエストが成功すると、<h1>OK</h1>という内容が返されます。
このように、docker inspectでは、ヘルスチェックの状態だけでなく、実際に実行されたコマンドの結果も確認できます。
8. HEALTHCHECKの動作を整理する
今回の例では、Dockerfileに次のようなヘルスチェックを設定しました。
HEALTHCHECK --interval=10s --timeout=5s \
CMD curl -sf http://localhost/ || exit 1
この設定によって、コンテナ起動後に次の処理が行われます。
- コンテナ内でApacheが起動する
- Dockerが指定した間隔でヘルスチェックコマンドを実行する
curlでApacheにHTTPリクエストを送信する- コマンドの終了結果をもとに成功・失敗を判定する
- ヘルスチェックの状態を記録する
docker inspectで結果を確認できる
ヘルスチェックが成功している場合、Health.Statusはhealthyになります。
一方、失敗が指定回数に達した場合は、unhealthyになります。
9. HEALTHCHECKを使用するときの注意点
9-1. コンテナ内で実行できるコマンドを指定する
HEALTHCHECKに指定したコマンドは、コンテナ内で実行されます。
今回の例では、次のコマンドを使用しました。
curl -sf http://localhost/ || exit 1
そのため、コンテナ内でcurlコマンドを実行できる必要があります。
また、http://localhost/でアクセスできるように、Webサーバーが適切に設定されている必要があります。
9-2. ヘルスチェックの間隔を設定する
--intervalを使用すると、ヘルスチェックを実行する間隔を指定できます。
HEALTHCHECK --interval=10s \
CMD curl -sf http://localhost/ || exit 1
実行間隔を短くすると、より頻繁に正常性を確認できます。
一方、ヘルスチェック自体もコマンドを実行する処理であるため、必要以上に短い間隔を設定しないよう注意が必要です。
9-3. タイムアウトと失敗回数を設定する
ヘルスチェックでは、タイムアウト時間と連続失敗回数も設定できます。
HEALTHCHECK --interval=10s --timeout=5s --retries=3 \
CMD curl -sf http://localhost/ || exit 1
この設定では、ヘルスチェックが5秒以内に完了しない場合は失敗となります。
また、3回連続で失敗すると、コンテナはunhealthyと判定されます。
9-4. unhealthyはコンテナの停止を意味しない
HEALTHCHECKでunhealthyと判定されても、それだけでコンテナが自動的に停止・再起動されるわけではありません。
HEALTHCHECKは正常性を判定するための仕組みであり、コンテナの再起動処理そのものではないためです。
ヘルスチェックの状態とコンテナの実行状態は区別して考えましょう。
10. まとめ
今回は、DockerfileのHEALTHCHECK命令について解説しました。
HEALTHCHECKは、コンテナ内で定期的にコマンドを実行し、コンテナやアプリケーションの正常性を確認するための命令です。
例えば、次のように記述することで、WebサーバーへのHTTPリクエストを使用したヘルスチェックを設定できます。
HEALTHCHECK --interval=10s --timeout=5s --retries=3 \
CMD curl -sf http://localhost/ || exit 1
今回のポイントは次のとおりです。
HEALTHCHECKはコンテナ内で定期的にコマンドを実行する--intervalで実行間隔を指定できる--timeoutでタイムアウト時間を指定できる--retriesで異常判定までの連続失敗回数を指定できる- HTTPリクエストを使用してWebサーバーの応答を確認できる
docker inspectでヘルスチェックの状態を確認できるHealth.Statusがhealthyの場合は、設定したヘルスチェックが成功しているunhealthyは、必ずしもコンテナが停止したことを意味しない
DockerfileでWebサーバーなどのアプリケーションを構築する際は、コンテナの起動だけでなく、起動後の正常性をどのように確認するかも重要です。
まずは今回のDockerfileとdocker inspectを使って、ヘルスチェックの仕組みを理解してみましょう。