【Kubernetes】LivenessProbeとReadinessProbeを試してみる
はじめに
KubernetesにおけるLiveness ProbeとReadiness Probeについて解説し、実際に設定してPodを動かしてみたいと思います。
LivenessProbe/ReadinessProbeとは
LivenessProbe、ReadinessProbeは共に、Kubernetesにおけるコンテナのライフサイクル管理に関する設定となっています。つまり、コンテナが正しくリクエストを処理できるかを検出するための設定になります。
Podのライフサイクル
このページではPodのライフサイクルについて説明します。Podは定義されたライフサイクルに従い Pendingフェーズから始まり、少なくとも1つのプライマリーコンテナが正常に開始した場合はRunningを経由し、次に失敗により終了したコンテナの有無に応じて、SucceededまたはFailedフェーズを経由します。 Podの実行中、kubeletはコンテナを再起動して、ある種の障害を処理できます。Pod内で、Kubernetesはさまざまなコンテナのステータスを追跡して、回復させるためのアクションを決定します。 Kubernetes APIでは、Podには仕様と実際のステータスの両方があります。Podオブジェクトのステータスは、PodのConditionのセットで構成されます。カスタムのReadiness情報をPodのConditionデータに挿入することもできます。 Podはその生存期間に1回だけスケジューリングされます。PodがNodeにスケジュール(割り当て)されると、Podは停止または終了するまでそのNode上で実行されます。 Podのライフタイム 個々のアプリケーションコンテナと同様に、Podは(永続的ではなく)比較的短期間の存在と捉えられます。Podが作成されると、一意のID(UID)が割り当てられ、(再起動ポリシーに従って)終了または削除されるまでNodeで実行されるようにスケジュールされます。 ノードが停止した場合、そのNodeにスケジュールされたPodは、タイムアウト時間の経過後に削除されます。 Pod自体は、自己修復しません。Podがnodeにスケジュールされ、その後に失敗した場合、Podは削除されます。同様に、リソースの不足またはNodeのメンテナンスによりPodはNodeから立ち退きます。Kubernetesは、比較的使い捨てのPodインスタンスの管理作業を処理する、controllerと呼ばれる上位レベルの抽象化を使用します。 特定のPod(UIDで定義)は新しいNodeに"再スケジュール"されません。代わりに、必要に応じて同じ名前で、新しいUIDを持つ同一のPodに置き換えることができます。 volumeなど、Podと同じ存続期間を持つものがあると言われる場合、それは(そのUIDを持つ)Podが存在する限り存在することを意味します。そのPodが何らかの理由で削除された場合、たとえ同じ代替物が作成されたとしても、関連するもの(例えばボリューム)も同様に破壊されて再作成されます。 Podの図 file puller(ファイル取得コンテナ)とWebサーバーを含むマルチコンテナのPod。コンテナ間の共有ストレージとして永続ボリュームを使用しています。 Podのフェーズ Podのstatus項目はPodStatusオブジェクトで、それはphaseのフィールドがあります。 Podのフェーズは、そのPodがライフサイクルのどの状態にあるかを、簡単かつ高レベルにまとめたものです。このフェーズはコンテナやPodの状態を包括的にまとめることを目的としたものではなく、また包括的なステートマシンでもありません。 Podの各フェーズの値と意味は厳重に守られています。ここに記載されているもの以外にphaseの値は存在しないと思ってください。 これらがphaseの取りうる値です。 値 概要 Pending PodがKubernetesクラスターによって承認されましたが、1つ以上のコンテナがセットアップされて稼働する準備ができていません。これには、スケジュールされるまでの時間と、ネットワーク経由でイメージをダウンロードするための時間などが含まれます。 Running PodがNodeにバインドされ、すべてのコンテナが作成されました。少なくとも1つのコンテナがまだ実行されているか、開始または再起動中です。 Succeeded Pod内のすべてのコンテナが正常に終了し、再起動されません。 Failed Pod内のすべてのコンテナが終了し、少なくとも1つのコンテナが異常終了しました。つまり、コンテナはゼロ以外のステータスで終了したか、システムによって終了されました。 Unknown 何らかの理由によりPodの状態を取得できませんでした。このフェーズは通常はPodのホストとの通信エラーにより発生します。 備考:Podの削除中に、kubectlコマンドにはTerminatingが出力されることがあります。このTerminatingステータスは、Podのフェーズではありません。Podには、正常に終了するための期間を与えられており、デフォルトは30秒です。--forceフラグを使用して、Podを強制的に削除することができます。 Nodeが停止するか、クラスターの残りの部分から切断された場合、Kubernetesは失われたNode上のすべてのPodのPhaseをFailedに設定するためのポリシーを適用します。 コンテナのステータス Pod全体のフェーズと同様に、KubernetesはPod内の各コンテナの状態を追跡します。container lifecycle hooksを使用して、コンテナのライフサイクルの特定のポイントで実行するイベントをトリガーできます。 PodがschedulerによってNodeに割り当てられると、kubeletはcontainer runtimeを使用してコンテナの作成を開始します。コンテナの状態はWaiting、RunningまたはTerminatedの3ついずれかです。 Podのコンテナの状態を確認するにはkubectl describe pod [POD_NAME]のコマンドを使用します。Pod内のコンテナごとにStateの項目として表示されます。 各状態の意味は次のとおりです。 Waiting コンテナがRunningまたはTerminatedのいずれの状態でもない場合コンテナはWaitingの状態になります。Waiting状態のコンテナは引き続きコンテナイメージレジストリからイメージを取得したりSecretを適用したりするなど必要な操作を実行します。Waiting状態のコンテナを持つPodに対してkubectlコマンドを使用すると、そのコンテナがWaitingの状態である理由の要約が表示されます。 Running Running状態はコンテナが問題なく実行されていることを示します。postStartフックが構成されていた場合、それはすでに実行が完了しています。Running状態のコンテナを持つPodに対してkubectlコマンドを使用すると、そのコンテナがRunning状態になった時刻が表示されます。 Terminated Terminated状態のコンテナは実行されて、完了したときまたは何らかの理由で失敗したことを示します。Terminated状態のコンテナを持つPodに対してkubectlコマンドを使用すると、いずれにせよ理由と終了コード、コンテナの開始時刻と終了時刻が表示されます。 コンテナがTerminatedに入る前にpreStopフックがあれば実行されます。 コンテナの再起動ポリシー Podのspecには、Always、OnFailure、またはNeverのいずれかの値を持つrestartPolicyフィールドがあります。デフォルト値はAlwaysです。 restartPolicyは、Pod内のすべてのコンテナに適用されます。restartPolicyは、同じNode上のkubeletによるコンテナの再起動のみを参照します。Pod内のコンテナが終了した後、kubeletは5分を上限とする指数バックオフ遅延(10秒、20秒、40秒...)でコンテナを再起動します。コンテナが10分間実行されると、kubeletはコンテナの再起動バックオフタイマーをリセットします。 PodのCondition PodにはPodStatusがあります。それにはPodが成功したかどうかの情報を持つPodConditionの配列が含まれています。kubeletは、下記のPodConditionを管理します: PodScheduled: PodがNodeにスケジュールされました。 PodHasNetwork: (アルファ版機能; 明示的に有効にしなければならない) Podサンドボックスが正常に作成され、ネットワークの設定が完了しました。 ContainersReady: Pod内のすべてのコンテナが準備できた状態です。 Initialized: すべてのInitコンテナが正常に終了しました。 Ready: Podはリクエストを処理でき、一致するすべてのサービスの負荷分散プールに追加されます。 フィールド名 内容 type このPodの状態の名前です。 status その状態が適用可能かどうか示します。可能な値は"True"、"False"、"Unknown"のうちのいずれかです。 lastProbeTime Pod Conditionが最後に確認されたときのタイムスタンプが表示されます。 lastTransitionTime 最後にPodのステータスの遷移があった際のタイムスタンプが表示されます。 reason 最後の状態遷移の理由を示す、機械可読のアッパーキャメルケースのテキストです。 message ステータスの遷移に関する詳細を示す人間向けのメッセージです。 PodのReadiness FEATURE STATE: Kubernetes v1.
検出するための判断は下記が利用できます。
- コマンド実行
- 特定のポートに対するTCPチェック
- 特定のポートとパスに対するHTTP Getリクエスト
LivenessProbe
LivenessProbeは、コンテナが動いているかを判断します。動いていない場合はコンテナが再起動されます。
コンテナに不具合があったときにクラッシュできない場合に利用されます。
設定例は下記です。
1livenessProbe:
2 httpGet: # HTTPによるチェック
3 path: /healthz
4 port: 8080
5 initialDelaySeconds: 30 # 最初にチェックするまでの待機時間
6 periodSeconds: 60 # チェックする頻度
ReadinessProbe
ReadinessProbeは、コンテナがリクエストに応答できるかを判断します。応答できない場合はリクエストが送られてこないようになります。
コンテナ起動時にファイルなどを読み込み時間がかかる場合に利用されます。
設定例は下記です。LivenessProbeと項目は同じになります。
1readinessProbe:
2 httpGet: # HTTPによるチェック
3 path: /healthz
4 port: 8080
5 initialDelaySeconds: 30 # 最初にチェックするまでの待機時間
6 periodSeconds: 60 # チェックする頻度
LivenessProbeを使ってみる
LivenessProbeを使ってみます。
作成するPodのマニフェストpod-liveness.yml
は下記の通りです。
1apiVersion: v1
2kind: Pod
3metadata:
4 labels:
5 test: liveness
6 name: liveness-http
7spec:
8 containers:
9 - name: liveness
10 image: k8s.gcr.io/liveness
11 args:
12 - /server
13 livenessProbe:
14 httpGet:
15 path: /healthz
16 port: 8080
17 httpHeaders:
18 - name: X-Custom-Header
19 value: Awesome
20 initialDelaySeconds: 3
21 periodSeconds: 3
イメージとして利用しているk8s.gcr.io/liveness
は始めの10秒は200ステータスが返しますが、その後は500ステータスを返すようになっています。
Liveness Probe、Readiness ProbeおよびStartup Probeを使用する
このページでは、Liveness Probe、Readiness ProbeおよびStartup Probeの使用方法について説明します。 kubeletは、Liveness Probeを使用して、コンテナをいつ再起動するかを認識します。 例えば、アプリケーション自体は起動しているが、処理を継続することができないデッドロック状態を検知することができます。 このような状態のコンテナを再起動することで、バグがある場合でもアプリケーションの可用性を高めることができます。 kubeletは、Readiness Probeを使用して、コンテナがトラフィックを受け入れられる状態であるかを認識します。 Podが準備ができていると見なされるのは、Pod内の全てのコンテナの準備が整ったときです。 一例として、このシグナルはServiceのバックエンドとして使用されるPodを制御するときに使用されます。 Podの準備ができていない場合、そのPodはServiceのロードバランシングから切り離されます。 kubeletは、Startup Probeを使用して、コンテナアプリケーションの起動が完了したかを認識します。 Startup Probeを使用している場合、Startup Probeが成功するまでは、Liveness Probeと Readiness Probeによるチェックを無効にし、これらがアプリケーションの起動に干渉しないようにします。 例えば、これを起動が遅いコンテナの起動チェックとして使用することで、起動する前にkubeletによって 強制終了されることを防ぐことができます。 始める前に Kubernetesクラスターが必要、かつそのクラスターと通信するためにkubectlコマンドラインツールが設定されている必要があります。 このチュートリアルは、コントロールプレーンのホストとして動作していない少なくとも2つのノードを持つクラスターで実行することをおすすめします。 まだクラスターがない場合、minikubeを使って作成するか、 以下のいずれかのKubernetesプレイグラウンドも使用できます: Killercoda Play with Kubernetes バージョンを確認するには次のコマンドを実行してください: kubectl version. コマンド実行によるLiveness Probeを定義する 長期間実行されているアプリケーションの多くは、再起動されるまで回復できないような異常な状態になることがあります。 Kubernetesはこのような状況を検知し、回復するためのLiveness Probeを提供します。 この演習では、registry.k8s.io/busyboxイメージのコンテナを起動するPodを作成します。 Podの構成ファイルは次の通りです。 pods/probe/exec-liveness.yaml apiVersion: v1 kind: Pod metadata: labels: test: liveness name: liveness-exec spec: containers: - name: liveness image: registry.k8s.io/busybox args: - /bin/sh - -c - touch /tmp/healthy; sleep 30; rm -f /tmp/healthy; sleep 600 livenessProbe: exec: command: - cat - /tmp/healthy initialDelaySeconds: 5 periodSeconds: 5 この構成ファイルでは、Podは一つのContainerを起動します。 periodSecondsフィールドは、kubeletがLiveness Probeを5秒おきに行うように指定しています。 initialDelaySecondsフィールドは、kubeletが最初のProbeを実行する前に5秒間待機するように指示しています。 Probeの動作としては、kubeletはcat /tmp/healthyを対象のコンテナ内で実行します。 このコマンドが成功し、リターンコード0が返ると、kubeletはコンテナが問題なく動いていると判断します。 リターンコードとして0以外の値が返ると、kubeletはコンテナを終了し、再起動を行います。
Podを作成します。
1kubectl apply -f pod-liveness.yaml
Podの詳細からEventsを確認するとUnhealthy
となっているメッセージがあり、LivenessProbeが失敗していることがわかります。
その後コンテナを再起動していることがわかります。
1❯ kubectl describe pod liveness-http
2Name: liveness-http
3Namespace: default
4
5 :
6 :
7
8Events:
9 Type Reason Age From Message
10 ---- ------ ---- ---- -------
11 Normal Scheduled 42s default-scheduler Successfully assigned default/liveness-http to docker-desktop
12 Normal Pulled 41s kubelet Successfully pulled image "k8s.gcr.io/liveness" in 1.2591876s
13 Normal Pulled 20s kubelet Successfully pulled image "k8s.gcr.io/liveness" in 1.5981415s
14 Warning Unhealthy 4s (x6 over 28s) kubelet Liveness probe failed: HTTP probe failed with statuscode: 500
15 Normal Killing 4s (x2 over 22s) kubelet Container liveness-container failed liveness probe, will be restarted
16 Normal Pulling 4s (x3 over 42s) kubelet Pulling image "k8s.gcr.io/liveness"
17 Normal Created 2s (x3 over 40s) kubelet Created container liveness-container
18 Normal Started 2s (x3 over 40s) kubelet Started container liveness-container
19 Normal Pulled 2s kubelet Successfully pulled image "k8s.gcr.io/liveness" in 1.4489923s
ReadinessProbeを使ってみる
次に、ReadinessProbeを使ってみます。
作成するPodのマニフェストpod-readiness.yml
は下記の通りです。
内容はLivenessProbeとほぼ同じです。
initialDelaySeconds
を20秒にしています。
1apiVersion: v1
2kind: Pod
3metadata:
4 labels:
5 test: readiness
6 name: readiness-http
7spec:
8 containers:
9 - name: readiness-container
10 image: k8s.gcr.io/liveness
11 args:
12 - /server
13 readinessProbe:
14 httpGet:
15 path: /healthz
16 port: 8080
17 httpHeaders:
18 - name: X-Custom-Header
19 value: Awesome
20 initialDelaySeconds: 20
21 periodSeconds: 5
Podを作成します。
1kubectl apply -f pod-readiness.yaml
Podの詳細からEventsを確認すると20秒たったところでUnhealthy
となりReadinessProbeが失敗していることがわかります。
1❯ kubectl describe pod readiness-http
2Name: readiness-http
3Namespace: default
4
5 :
6 :
7
8Events:
9 Type Reason Age From Message
10 ---- ------ ---- ---- -------
11 Normal Scheduled 28s default-scheduler Successfully assigned default/readiness-http to docker-desktop
12 Normal Pulling 28s kubelet Pulling image "k8s.gcr.io/liveness"
13 Normal Pulled 26s kubelet Successfully pulled image "k8s.gcr.io/liveness" in 1.7735424s
14 Normal Created 26s kubelet Created container readiness-container
15 Normal Started 26s kubelet Started container readiness-container
16 Warning Unhealthy 4s kubelet Readiness probe failed: HTTP probe failed with statuscode: 500
Podのステータスを見てみるとREADYが0/1となり、リクエストを受けなくなっています。
1❯ kubectl get pod
2NAME READY STATUS RESTARTS AGE
3readiness-http 0/1 Running 0 22s
まとめ
- LivenessProbeはコンテナが動いているかチェック
- ReadinessProbeはコンテナがリクエストを受け付けられるかチェック