liveness・readiness・startup Probe の違い
v1.37 時点(2026年10月26日 確認)
目次
この記事では、コンテナの状態を kubelet が定期的に確かめる診断である Probe の仕組みを、図で説明します。liveness・readiness・startup の 3 種類の Probe がそれぞれ何を確かめ、失敗したときに kubelet が何をするのかがわかります。readiness Probe の結果が Pod の Ready を通して、Service の転送先にどうつながるのかもわかります。後半では kind のクラスタで readiness Probe をわざと失敗させ、その Pod が Service の転送先から外れることを確かめる手順を示します。liveness Probe の失敗でコンテナが再起動される様子も短く見ます。
Service がふだんの通信を ready のエンドポイントにだけ送ることを見た第21回の内容を前提にしています。まだの方は先にこちらをどうぞ。
以下の図は、コンテナが 1 つの Pod で、3 種類の Probe の結果によって Pod の Ready とコンテナの再起動がどう移り変わるかを表しています。
startup Probe や liveness Probe が決まった回数(failureThreshold)続けて失敗すると、kubelet はコンテナを止め、コンテナは restartPolicy(第9回)に従います。破線の「再起動」が起きるのは、restartPolicy が再起動を求めるときだけです。一方、readiness Probe が失敗しても、コンテナは止められません。Pod が Ready でなくなり、Service の転送先から外れるだけです。図では、kubelet がコンテナを止める失敗にだけ赤を使っています。
参考:Liveness, Readiness, and Startup Probes | Kubernetes、Liveness, Readiness, and Startup Probes | Kubernetes、Liveness, Readiness, and Startup Probes | Kubernetes
図は主な流れだけを描いています。startup Probe を書かないコンテナは、起動するとすぐに枠の中から始まります。readiness Probe を書いたコンテナは、枠の中の「Ready でない」から始まると読めます(「Probe の結果と、書かないときの扱い」で説明します)。図の「readiness 成功」は、既定では 1 回の成功です(successThreshold。「設定のフィールドと既定値」で説明します)。
Probe とは
Probe は kubelet がコンテナに対して定期的に行う診断(diagnostic) です。公式ドキュメントによると、Kubernetes では Probe を定義して、Pod の中のコンテナの健康状態を見張り続けられます。診断のために、kubelet はコンテナの中でコードを実行するか、ネットワークのリクエストを送ります。kubelet は第4回で見たとおり、各ノードで動き、Pod の中でコンテナが動いていることを確かめるエージェントです。
参考:Liveness, Readiness, and Startup Probes | Kubernetes、Pod Lifecycle | Kubernetes
公式ドキュメントは、Probe の結果をもとに Kubernetes ができることとして、健康でないコンテナの再起動と、準備ができていないコンテナへの通信の停止を挙げています。kubelet は動いているコンテナに対して、目的の違う 3 種類の Probe を行えます。どれも書くかどうかは選べます(optionally)。Probe はコンテナごとに、Pod の spec.containers[] の中に livenessProbe、readinessProbe、startupProbe のフィールドで書きます。
参考:Liveness, Readiness, and Startup Probes | Kubernetes、Pod | Kubernetes API Reference
3 種類の Probe の役割と、失敗したときに起きることを、公式ドキュメントに沿って次の表にまとめます。表の「失敗したとき」は 1 回の失敗ではなく、後で説明する failureThreshold の回数だけ続けて失敗したときのことです。
| Probe | 役割 | いつ動くか | 失敗したとき |
|---|---|---|---|
| startup Probe | コンテナの中のアプリケーションが起動したかを確かめる | 起動のときだけ | kubelet がコンテナを止め、コンテナは restartPolicy に従う |
| liveness Probe | コンテナをいつ再起動するかを決める | 定期的 | kubelet がコンテナを止め、コンテナは restartPolicy に従う |
| readiness Probe | コンテナが通信を受け付けられるかを決める | 定期的。コンテナのライフサイクルのあいだずっと動く | kubelet が Pod の Ready を false にする。コンテナは止めない |
参考:Liveness, Readiness, and Startup Probes | Kubernetes、Liveness, Readiness, and Startup Probes | Kubernetes、Liveness, Readiness, and Startup Probes | Kubernetes
表の Ready は第5回と第9回で見た Pod の状態(conditions)の 1 つです。公式ドキュメントは Ready を、Pod がリクエストに応えられ、一致するすべての Service の負荷分散の対象に加えるべき状態、と説明しています。
この回では「ready」という言葉が、コンテナ、Pod、EndpointSlice の 3 つの段階で出てきます。readiness Probe はコンテナごとに、そのコンテナが ready かどうかを決めます。Pod の状態には、Pod のすべてのコンテナが ready であることを表す ContainersReady もあります。公式ドキュメントによると、Pod が ready とみなされるのは、Pod のすべてのコンテナが ready で、readinessGates に書いた条件もすべて True のときです。この回のように readinessGates を書かなければ、コンテナがすべて ready のときに Ready になると読めます。kubectl get pods の READY 列の 1/1 は、ready のコンテナの数とコンテナの数を表すと考えられます(第9回)。EndpointSlice のエンドポイントの serving は Pod の Ready に対応し、第21回で見たとおり、Service の転送先になるのは ready のエンドポイントです。
参考:Pod Lifecycle | Kubernetes、Pod Lifecycle | Kubernetes、Pod | Kubernetes API Reference、EndpointSlices | Kubernetes
なぜ Probe が必要なのか
第9回で見たとおり、kubelet は終了したコンテナを、Pod の restartPolicy に従って再起動します。しかし、プログラムが終了しないまま、正しく動かなくなることもあります。公式ドキュメントは liveness Probe が見つけられるものの例として、デッドロックを挙げています。アプリケーションは動いているのに、処理を先へ進められない状態です。プログラムが終了しないので、restartPolicy だけでは再起動のきっかけが生まれないと考えられます。公式ドキュメントは、こうした状態のコンテナを再起動すると、不具合があってもアプリケーションを使える状態にしやすくなる、と説明しています。逆に、問題が起きたときにプログラムが自分で異常終了するなら、kubelet が restartPolicy に従って対応するので、liveness Probe は必ずしも要りません。
参考:Liveness, Readiness, and Startup Probes | Kubernetes、Liveness, Readiness, and Startup Probes | Kubernetes
第21回で見たとおり、Probe を書いていない nginx の Pod は、コンテナが動き出せば Ready になると考えられます(理由は「Probe の結果と、書かないときの扱い」で説明します)。ところが、アプリケーションによっては、動き出してから通信を受けられるようになるまでに時間がかかります。公式ドキュメントは例として、ネットワークの接続を張る、ファイルを読み込む、キャッシュを温める、といった時間のかかる初期の処理を挙げています。キャッシュは一般に、よく使うデータをすぐ取り出せる場所に置いておく仕組みで、温めるとはそこへ前もってデータを読み込んでおくことです。そのあいだに Service から通信が届くと、要求に応えられないはずです。readiness Probe を書くと、Probe が成功するまで Pod に通信を送らないようにできます。
参考:Liveness, Readiness, and Startup Probes | Kubernetes、Liveness, Readiness, and Startup Probes | Kubernetes
起動に時間がかかるアプリケーションには、もう 1 つ困りごとがあります。公式ドキュメントが示す目安の式に liveness Probe の既定値を入れると 0 + 3 × 10 = 30 秒です(「設定のフィールドと既定値」で説明します)。起動にこれより長く、たとえば 2 分かかるアプリケーションでは、起動の途中で止められるおそれがあると考えられます。回数や間隔を増やせば起動はできますが、動き出してからのデッドロックに気づくのも遅れます。公式ドキュメントによると、最初の起動に時間がかかるアプリケーションでは、デッドロックにすばやく対応するという liveness Probe の目的を損なわずに、その設定を決めるのが難しくなることがあります。そこで、liveness Probe の間隔を長くする代わりに、起動のあいだだけ別の設定で確かめられるのが startup Probe です。
参考:Liveness, Readiness, and Startup Probes | Kubernetes、Configure Liveness, Readiness and Startup Probes | Kubernetes
Probe の仕組み
3 つの Probe が動く順番
startup Probe を書いたコンテナでは、startup Probe が成功するまで、Kubernetes は liveness Probe と readiness Probe を実行しません。そのあいだに、アプリケーションは初期の処理を終えられます。startup Probe は起動のときだけ実行され、定期的に実行される liveness Probe や readiness Probe とは違います。
liveness Probe と readiness Probe は、互いの成功を待ちません。タスクのページ(Configure Liveness, Readiness and Startup Probes)は、2 つの Probe は成功するのに互いに依存しない、と注意しています(Caution)。liveness Probe は readiness Probe の成功を待たずに動きます。どちらも、実行を遅らせたいときは initialDelaySeconds を書くか、startup Probe を使えます。readiness Probe はコンテナのライフサイクルのあいだずっと動くので、一度 Ready になったあとで失敗すれば、Ready から外れます。公式ドキュメントは、一時的な障害や過負荷から回復するまでのあいだにも readiness Probe が役立つ、と説明しています。
参考:Liveness, Readiness, and Startup Probes | Kubernetes、Liveness, Readiness, and Startup Probes | Kubernetes、Configure Liveness, Readiness and Startup Probes | Kubernetes
Probe の結果と、書かないときの扱い
kubelet は Probe を実行するたびに結果を判定し、それに応じて動きます。結果は 3 つあり、主な 2 つを次の表にまとめます。
| 結果 | 公式ドキュメントの説明 |
|---|---|
Success | コンテナが診断に合格した |
Failure | コンテナが診断に失敗した。kubelet の動きは Probe の種類で違う(次の段落) |
このほかに Unknown(診断そのものが失敗した)という結果もあります。そのときは何もするべきではなく(no action should be taken)、kubelet はそのあとも確かめ続けます。Probe のページには、どんなときに Unknown になるかの例が無いので、この記事ではこれ以上扱いません。
公式ドキュメントによると、failureThreshold 回続けて失敗したとき、liveness Probe と startup Probe では、Kubernetes はコンテナを健康でないとみなし、その 1 つのコンテナだけを再起動します。止めるときは、そのコンテナの terminationGracePeriodSeconds(終了までの猶予の時間)に従います。readiness Probe が失敗したときは、kubelet は失敗したコンテナを動かし続け、Probe も続けます。そのうえで、Pod の Ready を false にします。
ここでいう再起動は第9回で見た restartPolicy による再起動と同じく、Pod の中でコンテナを動かし直すものだと考えられます。公式ドキュメントは、コンテナが止められたあと restartPolicy に従う、と書いているからです。コンテナが止められて再起動されるようにしたい場合は、liveness Probe を書き、restartPolicy を Always か OnFailure にするよう公式ドキュメントは説明しています。restartPolicy が Never なら、止められたコンテナは再起動されないと考えられます。第9回で見たとおり、Deployment の Pod では restartPolicy は Always だけです。liveness Probe や startup Probe の失敗は、第9回で見た CrashLoopBackOff の原因の 1 つにも挙がっています。
参考:Liveness, Readiness, and Startup Probes | Kubernetes、Pod Lifecycle | Kubernetes
Probe を書かないときの扱いも決まっています。公式ドキュメントによると、コンテナがある種類の Probe を持たないとき、kubelet はその結果をいつも Success とみなします。第21回の nginx の Pod(Probe を 1 つも書いていない)が、コンテナが動き出せば Ready になると考えられたのは、このためです。
readiness Probe を書いたときは、扱いが変わります。公式ドキュメントによると、readiness Probe では、最初の待ち時間(initialDelaySeconds)が過ぎるまで、結果を Failure とみなします。また、readiness Probe が spec にあると、Pod は通信を受けずに起動し、Probe が成功し始めてから通信を受け始めます。そのため、readiness Probe を書いたコンテナは Ready でない状態から始まり、initialDelaySeconds が過ぎて Probe が成功するまでそのままだ、と読めます。
参考:Liveness, Readiness, and Startup Probes | Kubernetes、Liveness, Readiness, and Startup Probes | Kubernetes
確かめ方:4 つの方法
Probe でコンテナを確かめる方法は 4 つあります。公式ドキュメントによると、1 つの Probe には、4 つの方法のうちちょうど 1 つを書く必要があります(must)。それぞれの方法と、成功とみなす条件を次の表にまとめます。
| 方法 | 何をするか | 成功とみなす条件 |
|---|---|---|
exec | 指定したコマンドをコンテナの中で実行する | コマンドが終了コード 0 で終わる |
httpGet | Pod の IP アドレスの、指定したポートとパスに HTTP の GET リクエストを送る | 応答のステータスコードが 200 以上 400 未満 |
tcpSocket | Pod の IP アドレスの、指定したポートに TCP で接続する | ポートが開いている。接続した直後にコンテナが接続を閉じても、健康とみなす |
grpc | gRPC(通信の仕組みの 1 つ)で、ヘルスチェックの呼び出しをする | 応答の status が SERVING |
exec のコマンドは、API リファレンスによると、シェルを通さずにそのまま実行されます。シェルの書き方を使いたいときは、シェルを明示して呼び出します。Pod が多いクラスタでは、exec がノードの負荷になることがあります(注意点の表)。
httpGet の成否は応答のステータスコードだけで決まります。ステータスコードは一般に、HTTP の応答に付く 3 桁の数で、200 番台は成功、300 番台は別の場所への案内(転送)を表します。grpc は v1.27 から安定版(Stable)で、対象のアプリケーションは gRPC のヘルスチェックの決まり(gRPC Health Checking Protocol)を実装しているべき(should)です。
参考:Liveness, Readiness, and Startup Probes | Kubernetes、Liveness, Readiness, and Startup Probes | Kubernetes
設定のフィールドと既定値
以下は公式ドキュメントにある、3 種類の Probe をすべて書いた Pod のマニフェストです(そのまま引用しています)。フィールドの形を見るための例で、この記事の手順では使いません。
apiVersion: v1
kind: Pod
metadata:
name: probe-example
spec:
containers:
- name: app
image: registry.k8s.io/e2e-test-images/agnhost:2.40
ports:
- containerPort: 8080
startupProbe:
httpGet:
path: /healthz
port: 8080
failureThreshold: 30
periodSeconds: 10
livenessProbe:
httpGet:
path: /healthz
port: 8080
initialDelaySeconds: 10
periodSeconds: 5
timeoutSeconds: 3
failureThreshold: 3
readinessProbe:
httpGet:
path: /ready
port: 8080
periodSeconds: 5image の agnhost は置き場所の名前(e2e-test-images)から、テスト用のイメージだと考えられます。例として形を見るだけで十分です。3 つの Probe はどれも、確かめ方(ここでは httpGet)と、タイミングや回数のフィールドを組み合わせて書きます。startup Probe と liveness Probe が同じ /healthz を確かめ、readiness Probe だけが別の /ready を確かめています。タイミングと回数のフィールドを、v1.37 時点の公式ドキュメントに沿って次の表にまとめます。
| フィールド | 内容 | 既定値(最小値) |
|---|---|---|
initialDelaySeconds | コンテナが起動してから、Probe を始めるまでの秒数 | 0 秒(0) |
periodSeconds | Probe を実行する間隔の秒数 | 10 秒(1) |
timeoutSeconds | Probe がタイムアウトするまでの秒数 | 1 秒(1) |
successThreshold | 失敗のあと、成功とみなすのに要る、続けての成功の回数 | 1(1) |
failureThreshold | 全体として失敗とみなすのに要る、続けての失敗の回数 | 3(1) |
terminationGracePeriodSeconds | 失敗したコンテナを止め始めてから、強制的に止めるまでの猶予の秒数 | Pod の値を引き継ぐ。Pod でも書かなければ 30 秒(1) |
表のいくつかには補足があります。initialDelaySeconds について、公式ドキュメントは、startup Probe を書いた場合、liveness Probe と readiness Probe の待ち時間は startup Probe が成功するまで始まらない、と説明しています。periodSeconds については、コンテナが Ready でないあいだ、readiness Probe は設定した間隔以外のときにも実行されることがあります(may)。Pod を早く Ready にするためです。
successThreshold は、liveness Probe と startup Probe では 1 でなければなりません(must)。そのため、1 より大きくして「何回か続けて成功したら Ready に戻す」設定ができるのは、readiness Probe だけだと読めます。逆に terminationGracePeriodSeconds は readiness Probe には書けず、書くと API サーバーに拒否されます。readiness Probe の失敗ではコンテナを止めないので、猶予の時間を使う場面が無いと考えられます。
参考:Liveness, Readiness, and Startup Probes | Kubernetes、Liveness, Readiness, and Startup Probes | Kubernetes、Pod | Kubernetes API Reference
Probe の設定は Pod を作ったあとでは変えられません。API リファレンスによると、Pod のコンテナの livenessProbe、readinessProbe、startupProbe はどれも更新できない(Cannot be updated)フィールドです。Deployment の Pod なら、Pod のひな形を書き換えて、新しい Pod に入れ替えることになります(第12回)。
startup Probe を使うかどうかの目安も、公式ドキュメントにあります。コンテナの起動にふだん initialDelaySeconds + failureThreshold × periodSeconds の秒数より長くかかるなら、liveness Probe と同じところを確かめる startup Probe を書くべき(should)だとしています。式の値を liveness Probe の設定と読むと、liveness Probe の既定値をそのまま使う場合は 0 + 3 × 10 = 30 秒になる計算です。そのうえで、liveness Probe の既定値は変えずに、startup Probe の failureThreshold を起動に足りるだけ大きくするべき(should)だとしています。公式ドキュメントの例(failureThreshold: 30、periodSeconds: 10)では、アプリケーションは起動を終えるまでに最大 5 分(30 × 10 = 300 秒)使えます。300 秒たっても成功しなければ、コンテナは止められ、Pod の restartPolicy に従います。
参考:Liveness, Readiness, and Startup Probes | Kubernetes、Configure Liveness, Readiness and Startup Probes | Kubernetes
readiness Probe と Service の転送先
readiness Probe の結果が Service の転送先に届くまでには、複数のコンポーネントがかかわります。以下の図は、後半の手順の Deployment my-nginx の 2 つの Pod のうち、1 つの readiness Probe が失敗したときに、誰が何を見て、何を書き換えるかを表しています。
kubelet が readiness Probe を実行して Pod の Ready を書き換え、endpointslice-controller が Pod を見張って EndpointSlice を書き換えます。Pod へ向かう線はどれも、Pod 1 つずつではなく Pod の枠に向けて引いてあります。kubelet は各ノードで動くので、Pod ごとに、その Pod があるノードの kubelet が受け持つと考えられますが、図では 1 つにまとめています。点線は監視、破線は書き換える・持つ(管理する)関係、実線は Probe の実行とラベルセレクタを表します。
参考:Liveness, Readiness, and Startup Probes | Kubernetes、Liveness, Readiness, and Startup Probes | Kubernetes、EndpointSlices | Kubernetes、Service | Kubernetes
流れを公式ドキュメントに沿って追います。まず、readiness Probe を実行するのは kubelet です。readiness Probe が failureThreshold 回続けて失敗すると、kubelet は Pod の Ready を false にします。Pod Lifecycle のページも、kubelet が管理する Pod の状態(conditions)の 1 つとして Ready を挙げています。
参考:Liveness, Readiness, and Startup Probes | Kubernetes、Pod Lifecycle | Kubernetes
次に EndpointSlice です。Probe のページによると、readiness Probe が失敗の状態を返すと、EndpointSlice のコントローラー(第21回の endpointslice-controller)は、その Pod に合うすべての Service の EndpointSlice から、Pod の IP アドレスを取り除きます。API リファレンスの readinessProbe の説明も、Probe が失敗するとコンテナは Service のエンドポイントから外される、としています。一方、EndpointSlice のページは、EndpointSlice にはセレクタに合うすべての Pod への参照が入ると書いています。そのうえで、エンドポイントの serving の状態が Pod の Ready に対応し、ready はほぼ「serving で、terminating ではない」ことを表す、と説明しています。これらの書き方からは、Ready でない Pod のエンドポイントが EndpointSlice から消えるのか、ready が false のまま残るのかは読み分けられません。どちらの場合でも、ready が true の転送先からは外れることになります。なお、この回の Service は spec.publishNotReadyAddresses を書いていない前提です(true にすると、ready はいつも true になります)。
参考:Liveness, Readiness, and Startup Probes | Kubernetes、Pod | Kubernetes API Reference、EndpointSlices | Kubernetes、EndpointSlices | Kubernetes
最後に、第21回で見たとおり、各ノードの kube-proxy は EndpointSlice を見張って、ノードの転送の規則を設定します。図では kube-proxy を省いています。Probe のページは、readiness Probe が失敗した Pod は一致する Service から通信を受けなくなる、と説明しています。図では kube-apiserver(第4回)も省きました。公式ドキュメントによると、ノード(とそこで動く Pod)からの API の利用は、すべて API サーバーで終わります。kubelet が Ready を書き換えるのも、kube-apiserver を通してです。endpointslice-controller も、kube-apiserver を通して Pod や EndpointSlice を読み書きしていると考えられます。
参考:Virtual IPs and Service Proxies | Kubernetes、Liveness, Readiness, and Startup Probes | Kubernetes、Communication between Nodes and the Control Plane | Kubernetes、Cluster Architecture | Kubernetes
Pod の Ready は Deployment のローリングアップデートにもかかわります。第13回で見たとおり、Deployment は、新しい Pod が Ready のまま、コンテナが落ちずに minReadySeconds の秒数がたつと、その Pod を使える(available)とみなします。公式ドキュメントも、Pod がいつ ready とみなされるかは Container Probes の節を見るよう案内しています。第12回で見た、展開が終わらずに止まる原因の 1 つにも、readiness Probe の失敗が挙がっています。readiness Probe が成功しない新しい Pod は使える状態にならないので、更新が先へ進まないと考えられます。
なお、Pod を消すときに通信を切り離すためだけなら、readiness Probe は必ずしも要りません。公式ドキュメントによると、Pod が消されるとそのエンドポイントの ready は false になり、ふだんの通信には使われなくなるからです(第21回)。
3 つの Probe の使い分け
公式ドキュメントはそれぞれの Probe をどんなときに使うかを説明しています。要点を次の表にまとめます。
| Probe | 公式ドキュメントが挙げる使いどころ |
|---|---|
| startup Probe | 起動に時間がかかるコンテナ |
| liveness Probe | 失敗したらコンテナを止めて再起動させたいとき(restartPolicy は Always か OnFailure) |
| readiness Probe | Probe が成功してから通信を送りたいとき。保守のためにコンテナ自身が転送先から外れたいときや、バックエンドのサービスが使えるかを確かめたいときにも使える |
liveness Probe と readiness Probe の関係について、公式ドキュメントは次のように説明しています。readiness Probe が liveness Probe と同じ内容のこともあります(might be the same)。その場合でも readiness Probe を書いておけば、Pod は通信を受けずに起動します。liveness Probe でよくある形は、readiness Probe と同じ軽い HTTP のパス(例の /healthz や /ready のような URL のパス)を確かめ、failureThreshold をより大きくすることです。こうすると、強制的に止められる前に、Pod がしばらく ready でない状態になります。また、readiness 用の、liveness Probe とは別のエンドポイント(HTTP ならパス)を確かめるようにすると、コンテナ自身が保守のために転送先から外れられます(can)。
アプリケーションがバックエンドのサービス(一般にはデータベースなど)に強く依存しているときは、liveness Probe と readiness Probe の両方を書き、liveness Probe でアプリケーション自体の健康を、readiness Probe でそれに加えて必要なバックエンドが使えるかを確かめる方法があります(can)。エラーしか返せない Pod に通信を送らずに済むからです。
参考:Liveness, Readiness, and Startup Probes | Kubernetes、Liveness, Readiness, and Startup Probes | Kubernetes
手元で試す
ここまでの内容を手元の kind のクラスタで試す手順を示します。第21回の Deployment my-nginx に、ファイルの有無を確かめる readiness Probe を足して動かします。コンテナの中でファイルを作ったり消したりして、readiness Probe が失敗した Pod が Ready から外れ、EndpointSlice の転送先からも外れることを確かめます。最後に、公式ドキュメントの例を使って、liveness Probe の失敗ではコンテナが再起動されることも短く見ます。
この節で引用する出力の例は、公式ドキュメントにある、ほかのクラスタのものです。表示の形を見るためのもので、名前や IP アドレスなどの値は手元とは違います。各段の最後には成功かどうかを見分ける点を短く挙げます。どれも公式ドキュメントから予想される結果で、手元で実行して確かめたものではありません。
コマンドは macOS や Linux のシェル(bash や zsh)で実行する前提で書いています。Windows では WSL(Windows の中で Linux を動かす仕組み)などを使ってください。試す環境は次のとおりです。
| 項目 | 内容 |
|---|---|
| kind | v0.33.0 |
| Kubernetes | v1.37.0(kind v0.33.0 の既定のノードイメージ) |
| ノード構成 | マルチノード(クラスタ名 multi-node):コントロールプレーン 1、ワーカー 2 |
| 必要なもの | Docker、kubectl(v1.36〜v1.38)、テキストエディタ、端末(ターミナル)2 つ |
参考:Release v0.33.0 · kubernetes-sigs/kind、Version Skew Policy | Kubernetes
kind でクラスタを作る手順は、以下の記事で解説しています。この回は第21回と同じマルチノードのクラスタを使います。
kind で検証用のクラスタを作るDocker のコンテナをノードにして、手元のマシンに Kubernetes のクラスタを作るツール kind の仕組みを図で説明します。kind create cluster で何が起きるかを押さえ、シングルノードとマルチノードのクラスタを作って、ノードの正体が Docker のコンテナであることを確かめる手順を紹介します。マルチノードのクラスタを用意する
第21回と同じ次の設定ファイルを使います。公式ドキュメントの例をそのまま引用しています。kind-multi-node.yaml という名前で、コマンドを実行するディレクトリに保存します。前の回までに保存したファイルが残っていれば、それを使えます。
# three node (two workers) cluster config
kind: Cluster
apiVersion: kind.x-k8s.io/v1alpha4
nodes:
- role: control-plane
- role: worker
- role: workerまず、前の回のクラスタが残っていないかを確かめます。
$ kind get clusters
multi-node が表示されたら、作り直さずにそのまま使えるので、クラスタを作る次のコマンドは飛ばします。表示されなければ、クラスタを作ってから、もう一度一覧します。
$ kind create cluster --name multi-node --config kind-multi-node.yaml
$ kind get clusters
kind get clusters に multi-node が表示されれば、クラスタができています。第3回で決めたとおり、ここからのコマンドには --context kind-multi-node を付けて、操作するクラスタをはっきりさせます。続けて、ノードを一覧します。
$ kubectl get nodes --context kind-multi-node
ノードが 3 つ表示され、STATUS 列が Ready になっていれば準備ができています。Ready になっていなければ、少し待ってからもう一度実行します。
前の回のクラスタを使い続けている場合は、my-nginx という Deployment と Service、run: my-nginx のラベルを持つ Pod が無いことを確かめます。第21回で見たとおり、この Deployment は自分自身のラベルを持たないので、Deployment と Service は名前を、Pod はラベルを手がかりに調べます。
$ kubectl get deployments,services --context kind-multi-node
$ kubectl get pods -l run=my-nginx --context kind-multi-node
1 つ目のコマンドの一覧に my-nginx が無く、2 つ目のコマンドで見つからないことを知らせる 1 行が出れば、そのまま進めます。kubernetes という Service は第21回で見たとおり、この回で作るものではないので、そのままにします。my-nginx が表示されたら、次のコマンドで消してから進みます。
$ kubectl delete deployment my-nginx --ignore-not-found --context kind-multi-node
$ kubectl delete service my-nginx --ignore-not-found --context kind-multi-node
マニフェストを用意する
使うマニフェストは 2 つです。1 つ目は第21回の Deployment(run-my-nginx.yaml)に readiness Probe を足したものです。readiness-nginx.yaml という名前で、コマンドを実行するディレクトリに保存します。
apiVersion: apps/v1
kind: Deployment
metadata:
name: my-nginx
spec:
selector:
matchLabels:
run: my-nginx
replicas: 2
template:
metadata:
labels:
run: my-nginx
spec:
containers:
- name: my-nginx
image: nginx
ports:
- containerPort: 80
readinessProbe:
exec:
command:
- cat
- /tmp/healthy
initialDelaySeconds: 5
periodSeconds: 5参考:Connecting Applications with Services | Kubernetes、Configure Liveness, Readiness and Startup Probes | Kubernetes、Pod | Kubernetes API Reference
第21回のマニフェストとの違いは最後の readinessProbe の 7 行だけです。足した行の意味を次の表にまとめます。
| フィールド | 値 | 意味 |
|---|---|---|
exec.command | cat /tmp/healthy | コンテナの中でファイル /tmp/healthy を表示する。ファイルがあれば終了コード 0 で成功、無ければ失敗になるはず |
initialDelaySeconds | 5 | コンテナが起動してから 5 秒たつと、Probe を始める |
periodSeconds | 5 | 5 秒ごとに Probe を実行する |
参考:Configure Liveness, Readiness and Startup Probes | Kubernetes、Liveness, Readiness, and Startup Probes | Kubernetes
この readiness Probe は、公式ドキュメントの readiness Probe の例(/bin/cat /tmp/healthy)とほぼ同じ形です。successThreshold と failureThreshold は書いていないので、既定値の 1 と 3 になります。nginx のイメージが /tmp/healthy を作ることは無いと考えられるので、このままでは readiness Probe は失敗し続けるはずです。手順の途中で、このファイルを手で作ったり消したりします。
参考:Configure Liveness, Readiness and Startup Probes | Kubernetes
2 つ目は第21回と同じ Service です。公式のチュートリアルのマニフェストをそのまま引用しています。第21回で保存した nginx-svc.yaml が残っていれば、それを使えます。
apiVersion: v1
kind: Service
metadata:
name: my-nginx
labels:
run: my-nginx
spec:
ports:
- port: 80
protocol: TCP
selector:
run: my-nginxrun: my-nginx のラベルを持つ Pod の、TCP の 80 番のポートに通信を送る ClusterIP の Service です(第21回)。
Pod の監視を始める
ここからは端末を 2 つ使います。第21回までと同じく、1 つ目の端末で変化を追い続け、2 つ目の端末でマニフェストを渡したり、コンテナの中でコマンドを動かしたりします。この回で 1 つ目の端末が追うのは、run: my-nginx のラベルを持つ Pod です。2 つ目の端末を開いたら、cd でマニフェストを保存したディレクトリに移動しておきます。
1 つ目の端末で、Pod の監視を始めます。この監視は liveness Probe を試す段の前まで止めずに続けます。
$ kubectl get pods -l run=my-nginx --watch --context kind-multi-node
まだ Pod が無いので、見つからないことを知らせる 1 行が出たあと、止まったように見えると考えられます。この段で見るのは READY 列と RESTARTS 列です。READY 列の見方は「Probe とは」の節で見たとおりです。
Deployment と Service を作る
2 つ目の端末で、Deployment と Service のマニフェストを渡します。
$ kubectl apply -f readiness-nginx.yaml --context kind-multi-node
$ kubectl apply -f nginx-svc.yaml --context kind-multi-node
deployment.apps/my-nginx と service/my-nginx が作られたことを知らせる行が出るはずです。1 つ目の端末には、my-nginx- で始まる名前の Pod の行が 2 つ現れ、STATUS 列がやがて Running になると考えられます。ただし READY 列は 0/1 のままのはずです。/tmp/healthy が無いので readiness Probe は失敗し、コンテナが動いていても、Pod は Ready にならないからです。第9回で見た「Running だからといって Ready だとは限らない」状態です。
参考:Liveness, Readiness, and Startup Probes | Kubernetes、Pod Lifecycle | Kubernetes
2 つ目の端末で、EndpointSlice のエンドポイントの IP アドレスと ready の値を表示します。第21回の「Pod と Service を確かめる」の最後に示したコマンドと同じです。
$ kubectl get endpointslices -l kubernetes.io/service-name=my-nginx -o jsonpath='{range .items[*].endpoints[*]}{.addresses[0]}{"\t"}{.conditions.ready}{"\n"}{end}' --context kind-multi-node
参考:JSONPath Support | Kubernetes、EndpointSlice | Kubernetes API Reference
ready が true の行は無いはずです(何も表示されないことも、false の行が並ぶこともあると考えられます。「readiness Probe と Service の転送先」を参照)。
続けて、1 つ目の Pod の様子をくわしく表示します。<Pod 1 の名前> には、1 つ目の端末の NAME 列から 1 つ選んで入れます。もう 1 つの Pod の名前は <Pod 2 の名前> として控えておきます。
$ kubectl describe pod <Pod 1 の名前> --context kind-multi-node
表示の終わりの Events: に、Unhealthy の理由で Readiness probe failed で始まるメッセージが出ていると考えられます。公式ドキュメントの liveness Probe の例では、同じ場所に Liveness probe failed: で始まる Unhealthy のイベントが出ています(後の「liveness Probe の失敗で再起動されることを見る」で引用します)。
参考:Configure Liveness, Readiness and Startup Probes | Kubernetes
この段では、次の 3 点が合っていれば成功です。
- 2 つの Pod の
STATUS列がRunningになる - 2 つの Pod の
READY列が0/1のまま readyを表示するコマンドで、readyがtrueの行が無い
ファイルを作って Ready にする
2 つ目の端末で、2 つの Pod のコンテナの中に /tmp/healthy を作ります。kubectl exec の -- のあとに書いたコマンドが、コンテナの中で実行されます(第10回)。touch は一般に、空のファイルを作るコマンドです。
$ kubectl exec <Pod 1 の名前> --context kind-multi-node -- touch /tmp/healthy
$ kubectl exec <Pod 2 の名前> --context kind-multi-node -- touch /tmp/healthy
公式ドキュメントの Get a Shell の例では、nginx のイメージのコンテナで ls や cat を使い、/bin/bash も起動しています。touch もこのイメージに入っていると考えられます。touch が見つからないというエラーが出たら、kubectl exec <Pod の名前> --context kind-multi-node -- /bin/bash -c 'echo ok > /tmp/healthy' でもファイルを作れるはずです。bash の中で echo と > でファイルに書き込む方法は、Get a Shell の例と同じです。
1 つ目の端末では、数秒のうちに 2 つの Pod の行が書き足され、READY 列が 1/1 になると考えられます。ファイルができたので cat /tmp/healthy が成功し、successThreshold の既定値は 1 なので、1 回の成功で Ready になるからです。間隔は 5 秒ですが、Ready でないあいだは間隔以外のときにも Probe が実行されることがあるので、もっと早いこともあると考えられます。
2 つ目の端末で、もう一度 ready を表示するコマンドを実行します。
$ kubectl get endpointslices -l kubernetes.io/service-name=my-nginx -o jsonpath='{range .items[*].endpoints[*]}{.addresses[0]}{"\t"}{.conditions.ready}{"\n"}{end}' --context kind-multi-node
2 つの IP アドレスの行が並び、どちらも ready が true になっているはずです。EndpointSlice の一覧も表示してみます。
$ kubectl get endpointslices -l kubernetes.io/service-name=my-nginx --context kind-multi-node
公式のチュートリアルの例では、この EndpointSlice の一覧は次のとおりです。
この例は readiness Probe を書いていない第21回の Deployment のものです。手元では、名前の後ろの 7vzhx のような文字列、ENDPOINTS 列の IP アドレス、AGE 列が違うものになるはずです。ENDPOINTS 列にどの状態のエンドポイントが並ぶかは公式ドキュメントで確かめられなかったので(第21回)、転送先かどうかは ready を表示するコマンドで確かめます。
この段では、次の 2 点が合っていれば成功です。
- 2 つの Pod の
READY列が1/1になる readyを表示するコマンドで、2 つの IP アドレスの行のreadyがtrue
readiness Probe を失敗させる
2 つ目の端末で、1 つ目の Pod のコンテナから /tmp/healthy を消します。rm は一般に、ファイルを消すコマンドです。touch と同じく、このイメージに入っていると考えられます。rm が見つからなかったときの代わりの方法は、公式ドキュメントでは確かめられませんでした。
$ kubectl exec <Pod 1 の名前> --context kind-multi-node -- rm /tmp/healthy
1 つ目の端末では、しばらくして 1 つ目の Pod の行が書き足され、READY 列が 0/1 に戻ると考えられます。failureThreshold の既定値は 3 なので、5 秒ごとの Probe が 3 回続けて失敗してから、kubelet が Pod の Ready を false にするからです。ファイルを消してから 10〜15 秒ほどかかると考えられます。2 つ目の Pod の行は 1/1 のままのはずです。
このとき、1 つ目の Pod の STATUS 列は Running、RESTARTS 列は 0 のままのはずです。readiness Probe が失敗しても、kubelet はコンテナを動かし続け、Probe も続けるからです。
READY 列が 0/1 になったら、2 つ目の端末で ready を表示するコマンドを実行します。
$ kubectl get endpointslices -l kubernetes.io/service-name=my-nginx -o jsonpath='{range .items[*].endpoints[*]}{.addresses[0]}{"\t"}{.conditions.ready}{"\n"}{end}' --context kind-multi-node
ready が true の行は、2 つ目の Pod の IP アドレスの 1 行だけになるはずです。ready が true の行に 1 つ目の Pod の IP アドレスが無ければ成功です(行が消えても、false で残っても同じです)。readiness Probe が失敗した Pod は Service の転送先から外れています。Service にも EndpointSlice にも手を触れていないのに、転送先が 1 つ減ったことになります。
参考:Liveness, Readiness, and Startup Probes | Kubernetes、EndpointSlices | Kubernetes
最後に、1 つ目の Pod に /tmp/healthy を作り直します。
$ kubectl exec <Pod 1 の名前> --context kind-multi-node -- touch /tmp/healthy
1 つ目の端末では、1 つ目の Pod の READY 列が再び 1/1 になり、RESTARTS 列は 0 のままのはずです。ready を表示するコマンドでも、2 つの行の ready が true に戻ると考えられます。コンテナを再起動しなくても、Probe が成功すれば転送先に戻ります。
この段では、次の 4 点が合っていれば成功です。
- ファイルを消した Pod の
READY列が0/1になり、もう 1 つの Pod は1/1のまま - ファイルを消した Pod の
STATUS列がRunning、RESTARTS列が0のまま readyを表示するコマンドで、readyがtrueの行が 1 つになる- ファイルを作り直すと、
READY列が1/1に戻り、readyがtrueの行が 2 つになる
liveness Probe の失敗で再起動されることを見る
readiness Probe と比べるために、liveness Probe が失敗したときの動きを、公式ドキュメントの例でそのまま見ます。1 つ目の端末で Ctrl+C を押して、Pod の監視を止めます。続けて、この段で作る liveness-exec という Pod の監視を始めます。まだ無い Pod を名前で指定しないように、次のマニフェストに付いている test: liveness のラベルで絞り込みます。
$ kubectl get pods -l test=liveness --watch --context kind-multi-node
まだ Pod が無いので、見つからないことを知らせる 1 行が出たあと、止まったように見えると考えられます。使うのは、公式ドキュメントの次のマニフェストです(そのまま引用しています)。あとで URL を指定して渡すので、ファイルに保存する必要はありません。
apiVersion: v1
kind: Pod
metadata:
labels:
test: liveness
name: liveness-exec
spec:
containers:
- name: liveness
image: registry.k8s.io/busybox:1.27.2
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参考:Configure Liveness, Readiness and Startup Probes | Kubernetes
公式ドキュメントによると、このコンテナは起動すると /tmp/healthy を作り、30 秒後に消します。kubelet は 5 秒待ってから、5 秒ごとに cat /tmp/healthy を実行します。最初の 30 秒は成功し、そのあとは失敗します。コマンドが 0 以外を返すと(既定では failureThreshold の 3 回続けて失敗すると)、kubelet はコンテナを止めて再起動します。
2 つ目の端末で、公式ドキュメントのマニフェストを URL で指定して渡します。
$ kubectl apply -f https://k8s.io/examples/pods/probe/exec-liveness.yaml --context kind-multi-node
1 つ目の端末で liveness-exec の STATUS 列が Running になってから 30 秒たたないうちに、Pod のイベントを表示します。
$ kubectl describe pod liveness-exec --context kind-multi-node
公式ドキュメントの例では、表示の終わりのイベントは次のとおりで、まだ liveness Probe は失敗していません。
参考:Configure Liveness, Readiness and Startup Probes | Kubernetes
Running になってから 1 分ほどたったら、もう一度同じコマンドでイベントを表示します。公式ドキュメントの手順は「35 秒後」としていますが、ファイルが消えるのは起動から 30 秒後で、そのあと 5 秒ごとの Probe が 3 回続けて失敗してから止められます。そのため、Killing のイベントが出るのは起動から 45 秒ほどたってからだと考えられます。公式の例の出力でも、Started が 53 秒前、Killing が 10 秒前と表示されていて、止められたのは起動の 43 秒ほどあとと読めます。
$ kubectl describe pod liveness-exec --context kind-multi-node
公式ドキュメントの例では、表示の終わりに、liveness Probe が失敗し、コンテナが止められて作り直されたことを示すイベントが出ます。
参考:Configure Liveness, Readiness and Startup Probes | Kubernetes
Unhealthy の行の (x3 over 20s) は、失敗が 3 回あったことを表すと考えられ、failureThreshold の既定値の 3 と合います。そのあとの Killing の行で、kubelet がコンテナを止めて再起動すると知らせています。例の node01 や From 列の kubelet, node01 は公式の例のクラスタのもので、手元ではノードの名前が multi-node-worker のようになり、From 列の書き方も違うことがあると考えられます。Age 列の値も手元とは違います。
さらに 30 秒ほど待ってから、Pod を表示します。
$ kubectl get pod liveness-exec --context kind-multi-node
公式ドキュメントの例では、出力は次のとおりです。
参考:Configure Liveness, Readiness and Startup Probes | Kubernetes
公式ドキュメントによると、RESTARTS 列が増えています。この列は失敗したコンテナが動いている状態に戻った時点で増えます。1 つ目の端末でも、RESTARTS 列が 1 になった行が書き足されているはずです。RESTARTS 列がまだ 0 なら、少し待ってからもう一度表示します。kubelet はコンテナを止めるときに終了までの猶予の時間に従うので、再起動がその分遅れることがあると考えられます。readiness Probe を失敗させた段では RESTARTS 列が 0 のままだったのと比べてください。手元では AGE 列が違い、待った時間によっては RESTARTS 列が 2 以上になっていることもあると考えられます。このコンテナは再起動のたびにファイルを作り直して 30 秒後に消すので、liveness Probe の失敗と再起動を繰り返すはずです。放っておくと、第9回で見た CrashLoopBackOff が表示されることもあると考えられます。
この段では、次の 3 点が合っていれば成功です。
Runningになってから 1 分ほどたったあとのイベントに、Liveness probe failed:で始まるUnhealthyの行と、Killingの行があるliveness-execのRESTARTS列が1以上になる- Pod の名前は
liveness-execのまま変わらない
片付け
1 つ目の端末で Ctrl+C を押して、監視を止めます。
2 つ目の端末で、作った Pod、Service、Deployment を、マニフェストを指定して削除します。liveness-exec は URL で渡したので、名前を指定して消します。
$ kubectl delete pod liveness-exec --context kind-multi-node
$ kubectl delete -f nginx-svc.yaml --context kind-multi-node
$ kubectl delete -f readiness-nginx.yaml --context kind-multi-node
Deployment を消すと、その ReplicaSet と Pod も消えます(第6回)。Service を消すと、第21回と同じく、EndpointSlice も消されると考えられます。Pod を消すコマンドは終了までの猶予の時間(既定では 30 秒)のぶん、終わるまで少しかかることがあります。
少し待ってから、残っていないかを確かめます。liveness-exec は run: my-nginx のラベルを持たないので、ラベルで絞り込まずに Pod を一覧します。
$ kubectl get deployments,pods --context kind-multi-node
$ kubectl get endpointslices -l kubernetes.io/service-name=my-nginx --context kind-multi-node
$ kubectl get services --context kind-multi-node
Pod が Terminating で表示されていたら、少し待ってからもう一度実行します。1 つ目と 2 つ目のコマンドで、見つからないことを知らせる 1 行が出れば、削除できています。3 つ目のコマンドでは、my-nginx は表示されず、kubernetes という Service だけが表示されると考えられます(第21回)。
最後に、クラスタを削除し、消えたことを確かめます。続けて次の回を試す場合は、クラスタを残しておいてもかまいません。
$ kind delete cluster --name multi-node
$ kind get clusters
kind get clusters に multi-node が表示されなくなったことを確かめます。kubeconfig に kind-multi-node のコンテキストが残っていたら、第3回の片付けと同じく kubectl config delete-context kind-multi-node で消します。
注意点
Probe でつまずきやすい点と、あとから変えられない設定、バージョンで変わる点を、次の表にまとめます。
| 項目 | 内容 |
|---|---|
Running でも Ready とは限らない | readiness Probe が成功するまで、Pod は Ready にならない。kubectl get pods では STATUS 列と READY 列を分けて見る |
| readiness Probe の失敗では再起動されない | kubelet は Pod の Ready を false にするだけで、コンテナは動かし続ける。再起動のきっかけになるのは liveness Probe と startup Probe の失敗 |
| liveness Probe の誤りは障害を連鎖させることがある | 公式ドキュメントは、回復できない異常を本当に表すよう注意深く設定する必要がある(must)としている |
Probe はコンテナごと、Ready は Pod ごと | Probe は spec.containers[] に書き、再起動されるのは失敗したコンテナだけ。readinessGates を書かなければ、Pod の Ready はコンテナがすべて ready のときに true になると読める |
| Probe はあとから変えられない | Pod のコンテナの 3 つの Probe はどれも更新できない(Cannot be updated)。Deployment ではひな形を変えて、新しい Pod に入れ替える(第12回) |
exec はノードの負荷になることがある | 実行のたびに複数のプロセスを作る。Pod が多く間隔が短いと、ノードの CPU の負荷が増えるかもしれない(might) |
tcpSocket の host に Service の名前は使えない | kubelet は Pod の中ではなくノードから接続するので、Service の名前(第23回)を解決できない |
| 一部の確かめ方の追加機能はアルファ | v1.37 時点では、grpc を TLS で暗号化する機能と、httpGet を暗号化しない HTTP/2(h2c)で送る機能はアルファで、既定では無効。grpc そのものは v1.27 から安定版 |
参考:Liveness, Readiness, and Startup Probes | Kubernetes、Liveness, Readiness, and Startup Probes | Kubernetes、Liveness, Readiness, and Startup Probes | Kubernetes、Liveness, Readiness, and Startup Probes | Kubernetes、Liveness, Readiness, and Startup Probes | Kubernetes、Pod | Kubernetes API Reference
関連記事
コンテナの再起動を決める restartPolicy と、再起動を繰り返したときの CrashLoopBackOff については、以下の記事で解説しています。
Pod が使える(available)とみなされるまでの時間が、ローリングアップデートの進み方をどう決めるかについては、以下の記事で解説しています。
maxSurge と maxUnavailable の違いDeployment のローリングアップデートの速さと安全性を決める maxSurge と maxUnavailable の仕組みを図で説明します。更新中の Pod の数の上限と下限、割合を数に直すときの丸め方、先に増やすか先に減らすかの違いを押さえ、kind のクラスタで値を変えて Pod の入れ替わり方を比べる手順を紹介します。次の回では Pod の負荷に合わせて Pod の数を自動で増やしたり減らしたりする Horizontal Pod Autoscaler を扱います。
Horizontal Pod Autoscaler を動かして理解する負荷に合わせて Pod の数を自動で増減させる Horizontal Pod Autoscaler(HPA)の仕組みを図で説明します。metrics-server との関係、requests に対する CPU 使用率から目標の数を求める式、増やすときと減らすときの決まりを押さえ、kind のクラスタで負荷をかけて Pod が増える様子を観察する手順を紹介します。