ビジネスを成功させるためには、コンテナー・ベースのアプリケーションが常に正常に機能していることを確認する必要があります。Kubernetes 内のヘルス・チェック機能は、ポッドに対して特定のチェックを行って、現在の状態に関する情報を判断したり、アプリケーション・ライフサイクルの各段階でアプリケーションの状態を評価したりします。こうしたチェックには、liveness チェックと readiness チェックも含まれます。
このチュートリアルではヘルス・チェックの基本を確認し、Kubernetes 上にデプロイされた Node.js アプリケーションに対してヘルス・チェックを使用する方法を説明します。
ヘルス・チェックのタイプ
Kubernetes 内でのヘルス・チェックには、起動チェック、liveness チェック、readiness チェック、シャットダウン・チェックの 4 つのタイプがあります。
起動チェック
起動チェックは、ポッドの作成時または再起動時に行われるヘルス・チェックです。起動チェックによって、アプリケーションがトラフィックを受信できる状態にするために実行する必要があるすべてのコードが実行されたことを確認します。
アプリケーションの起動中に何らかの問題が発生した場合、起動チェックはエラーを返します。エラーが返されると、Kubernetes はポッドを破棄します。
liveness チェック
liveness チェックはアプリケーションの実行中に行われます。具体的には、liveness チェックによって、アプリケーションが正常に起動しているかどうかを判別し、コンテナーは稼動していてもアプリケーションが機能できないという状態ではないことを確認します。
liveness チェックが失敗した場合、Kubernetes はポッドを破棄し、アプリケーション用の新しいポッドを作成します。
readiness チェック
readiness チェックもアプリケーションの実行中に行われます。readiness チェックは、アプリケーションがトラフィックを受信できる状態になったことを判断するために使用されます。通常は readiness チェックを使用して、アプリケーションが依存しているサービスまたはリソースの可用性を確認します。
例えば、アプリケーションが外部 API に依存している場合、その外部 API が使用可能であるかを判別する readiness チェックを登録します。外部 API が使用可能であれば、ポッドはトラフィックを受信し始めることになります。外部 API が使用不可であれば、readiness エンドポイントから使用不可としてのレスポンスが返されます。この場合、Kubernetes はそのポッドにトラフィックを転送しません。
liveness チェックと readiness チェックを構成する方法については、Kubernetes のドキュメント (https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-probes/) で説明されています。
シャットダウン・チェック
シャットダウン・チェックは、アプリケーションが使用したリソースをすべてクリーンアップしたかどうかを判別します。ネットワーク接続を閉じたり、アプリケーションのシャットダウン前に必要なデータを保存したりするなどのアクティビティーでは、シャットダウン・チェックがよく使用されます。
Kubernetes では、コンテナーが SIGTERM
メッセージを受信した時点で実行されるようにシャットダウン・チェックを構成できます。Kubernetes がコンテナーに SIGTERM
メッセージを送信するということは、終了までの猶予期間の後、コンテナーがシャットダウンされることを意味します。猶予期間が終了すると、Kubernetes はコンテナーに SIGKILL
シグナルを送信し、コンテナーを除去します。Kubernetes はポッドがシャットダウンするまで待機しないことに注意してください。ポッドがシャットダウンしたかどうかに関わらず、猶予期間が過ぎると、Kubernetes は SIGKILL
を送信します。
したがって、デフォルトの猶予期間となっている 30 分よりも長くコンテナーのシャットダウンに時間がかかる場合は、ポッドの YAML 内で terminationGracePeriodSeconds
の値を大きくしてください。
Node.js とヘルス・チェック
Node.js または TypeScript アプリケーションのライフサイクルを管理するには、CloudNativeJS で提供している cloud-health モジュールまたは cloud-health-connect モジュールを使用することをお勧めします。
cloud-health は、readiness チェック、liveness チェック、およびこの 2 つを組み合わせたヘルス・チェックを登録して実行するためのフレームワークになります。また、このモジュールはシャットダウンも処理します。
cloud-health-connect は cloud-health の機能をラップして connect ベースのミドルウェアとして公開し、Express や LoopBack などのサーバー・フレームワークで使用できるようにします。
実際の使用方法: Express.js アプリ内で CloudNativeJS を使用してヘルス・チェックを登録する
4 つのタイプのヘルス・チェックについて説明したので、次はアプリケーション・ライフサイクルを管理するために、それぞれのヘルス・チェックを Node.js Express アプリケーション内で使用する方法を説明します。
前提条件
このチュートリアルの以降の手順に従うには、お使いのマシンにバージョン 8.2.0 以降の Node.js がインストールされている必要があります。
まず始めに、Express ジェネレーターを使用してアプリケーションのスケルトンを作成します。このアプリケーションの新しい空のディレクトリー内にヘルス・チェックをインストールする方法を説明します。Express ジェネレーターはこのディレクトリーの名前をプロジェクトのデフォルトの名前として使用します。
ステップ 1. アプリケーションのスケルトンを作成する
新しいディレクトリーを作成します。
mkdir express-app cd express-app
npx
を使用して Express ジェネレーターを実行します。npx express-generator
アプリケーションをインストールし、起動します。
npm install npm start
これで、スケルトン Express アプリが次の URL で実行中になります。http://localhost:3000
アプリケーションを停止するには、アプリケーションが実行されているターミナル・ウィンドウ内で \*\*Ctrl-C\*\*
を使用します。
Express ジェネレーターによって、次のディレクトリー構造が生成されます。
.
├── app.js
├── bin
| ├── www
├── package-lock.json
├── package.json
├── public
| ├── images
| ├── javascripts
| ├── stylesheets
| | ├── style.css
└── routes
├── index.js
└── users.js
├── views
├── error.jade
├── index.jade
├── layout.jade
7 directories, 10 files
ステップ 2. アプリにヘルス・チェックを追加する
次は、@cloudnative/health-connect
パッケージに含まれている Connect Middleware を使用して、ヘルス・チェックを app.js
ファイルに追加します。
まず、以下のステップに従って liveness チェックを追加します。
@cloudnative/health-connect
を依存関係としてプロジェクトに追加します。npm install @cloudnative/health-connect
HealthChecker を
app.js
に追加します。const health = require('@cloudnative/health-connect'); let healthCheck = new health.HealthChecker();
liveness チェックを登録します。
const livePromise = () => new Promise((resolve, _reject) => { const appFunctioning = true; // You should change the above to a task to determine if your app is functioning correctly if (appFunctioning) { resolve(); } else { reject(new Error("App is not functioning correctly")); } }); let liveCheck = new health.LivenessCheck("LivenessCheck", livePromise); healthCheck.registerLivenessCheck(liveCheck);
liveness チェックの構成が完了したので、次は readiness チェックを構成します。この場合も、上記のステップ 2 で healthCheck を使用して定義したときと同様に構成します。
let readyCheck = new health.PingCheck("example.com");
healthCheck.registerReadinessCheck(readyCheck);
上記の readiness チェックは、@cloudnative
モジュールに含まれている PingCheck
機能を使用して example.com にリクエストを送信します。このリクエストに対するレスポンスを受け取ると、UP
ステータスを返します。このような readiness チェックを使用することで、アプリケーションの依存関係にリクエストを送信して、アプリケーションがリクエストを送受信できるかどうかを確認できます。
上記の方法で、4 つすべてのタイプのチェックを @cloudnative/health
モジュールと @cloudnative/health-connect
モジュールの両方に登録できます。connect
モジュールを使用することにした理由は、Express のミドルウェア機能を使って、それぞれのヘルス・チェックのエンドポイントを登録できるためです。
以下のコマンドを使用して liveness エンドポイントを登録します。
app.use('/live', health.LivenessEndpoint(healthCheck));
readiness エンドポイントを登録します。
app.use('/ready', health.ReadinessEndpoint(healthCheck));
結合した health エンドポイントを登録します。
app.use('/health', health.HealthEndpoint(healthCheck));
これで、npm start
を使用してアプリケーションを再び起動すると、readiness、liveness、結合した health エンドポイントに以下の URL でアクセスできるようになります。
- readiness エンドポイント: http://localhost:3000/ready
- liveness エンドポイント: http://localhost:3000/live
- health エンドポイント: http://localhost:3000/health
各エンドポイントから以下の UP
ステータスが返されるはずです。
- readiness エンドポイント:
{“status”: ”UP”,”checks”:[{“name”: “PingCheck HEAD:example.com:80/“, “state”: “UP”, “data”:{“reason” : ““ }}]}
- liveness エンドポイント:
{“status”: “UP”,“checks”: [{“name”: “LivenessCheck”, “state”: “UP”, “data” :{“reason” : ““ }}]}
- health エンドポイント:
{“status”: ”UP”, ”checks” : [{“name”: “PingCheck HEAD:example.com:80/“, “state”: “UP”, “data”: {“reason”: “” }} , { “name”: “LivenessCheck”, “state”: “UP”, “data”: {“reason” : ““ }}]}
上記のレスポンスを見るとわかるように、/ready
エンドポイントは実装された readiness チェックの結果を表示し、/live
エンドポイントは liveness チェックの結果を表示します。/health
エンドポイントが表示するのは、liveness チェックと readiness チェックを結合したヘルス・チェックの結果です。/health
エンドポイントは、Cloud Foundry など、liveness チェックと readiness チェックのエンドポイントが 1 つしかないクラウド・プラットフォーム内で特に役立ちます。
Node.js アプリにヘルス・チェックがセットアップされました。これで、アプリを Kubernetes クラスターにデプロイできます。