Skip to content

Instantly share code, notes, and snippets.

@fortune
Last active February 12, 2024 12:12
Show Gist options
  • Save fortune/0e8400ac0a0e5c8273503f664f30771e to your computer and use it in GitHub Desktop.
Save fortune/0e8400ac0a0e5c8273503f664f30771e to your computer and use it in GitHub Desktop.
Kubernetes クラスタ上でのヘルスチェック

Kubernetes クラスタ上でのヘルスチェック

Kubernetes クラスタ上で稼働中のコンテナアプリケーションのヘルスチェックにはいくつかの方法がある。

  • コンテナのメインプロセスの死活監視
  • Liveness Probe
  • Readiness Probe

コンテナのメインプロセスの死活監視 では、K8S クラスタのシステムが各 Pod 中の各コンテナのメインプロセスの死活監視を実施し、プロセスが終了してコンテナが終了し、破棄されたら、コンテナを再作成して起動する。これは、Pod の restartPolicy の設定にもよるが、いずれにしろ Pod はそのままであり、再作成はされない。これは、設定なしで勝手に K8S がやってくれるのだが、プロセスがデッドロックを起こしたりして、終了してはいないけれども、仕事をすることができない事態には対処できない。

Liveness ProbeRediness Probe では、

  • httpGet
  • tcpSocket
  • exec

のいずれかの方法でヘルスチェックする。httpGet は HTTP Get リクエストをコンテナに送信し、そのレスポンスの Status コードで成否を判断する。tcpSocket はコンテナのポートへの TCP 接続が成功するかどうか、exec はコンテナ中でチェックスクリプトを実行し、その終了ステータスが 0 になるかどうかで成否を判断する。

Liveness Probe は、失敗回数が閾値を超えたら、コンテナを再起動する。これで、プロセスが終了してはいないけれども仕事ができないような事態に対処できる。

Readiness Probe は、失敗回数が閾値を超えたら、対象となっている Pod 中のポートへリクエストが到達できないようにするものであり、Service リソースオブジェクトと組み合わせて使うものだ。コンテナが再起動されることはなく、正常な状態に戻ったら、また Service リソースオブジェクトからリクエストが転送されるようになる。これにより、アプリケーションが過負荷になったりして一時的にリクエストを処理できなくなった場合に対処できるようになる。

以下では、

  • コンテナのメインプロセスの死活監視
  • Liveness Probe
  • Readiness Probe

の3つについて実験する。

コンテナのメインプロセスの死活監視

kubectl コマンドで、次のように実験用の Pod を起動する。

$ kubectl run test-health-check --image="fortunefield/linux-gcc:ubuntu-22.04" --command -- sleep 10

この Pod test-health-check 内にはコンテナが1つ存在し、そのメインプロセスは 10 秒後に終了する。したがって、10秒ごとにコンテナが再起動されるのを確認できる。

$ kubectl get pods test-health-check -o wide
NAME                READY   STATUS    RESTARTS   AGE   IP          NODE             NOMINATED NODE   READINESS GATES
test-health-check   1/1     Running   0          3s    10.1.0.82   docker-desktop   <none>           <none>

$ kubectl get pods test-health-check -o wide
NAME                READY   STATUS    RESTARTS   AGE   IP          NODE             NOMINATED NODE   READINESS GATES
test-health-check   1/1     Running   0          10s   10.1.0.82   docker-desktop   <none>           <none>

$ kubectl get pods test-health-check -o wide
NAME                READY   STATUS      RESTARTS   AGE   IP          NODE             NOMINATED NODE   READINESS GATES
test-health-check   0/1     Completed   0          12s   10.1.0.82   docker-desktop   <none>           <none>

$ kubectl get pods test-health-check -o wide
NAME                READY   STATUS    RESTARTS     AGE   IP          NODE             NOMINATED NODE   READINESS GATES
test-health-check   1/1     Running   1 (2s ago)   13s   10.1.0.82   docker-desktop   <none>           <none>

$ kubectl get pods test-health-check -o wide
NAME                READY   STATUS    RESTARTS     AGE   IP          NODE             NOMINATED NODE   READINESS GATES
test-health-check   1/1     Running   1 (8s ago)   19s   10.1.0.82   docker-desktop   <none>           <none>

$ kubectl get pods test-health-check -o wide
NAME                READY   STATUS    RESTARTS      AGE   IP          NODE             NOMINATED NODE   READINESS GATES
test-health-check   1/1     Running   1 (10s ago)   21s   10.1.0.82   docker-desktop   <none>           <none>

$ kubectl get pods test-health-check -o wide
NAME                READY   STATUS      RESTARTS      AGE   IP          NODE             NOMINATED NODE   READINESS GATES
test-health-check   0/1     Completed   1 (13s ago)   24s   10.1.0.82   docker-desktop   <none>           <none>

$ kubectl get pods test-health-check -o wide
NAME                READY   STATUS      RESTARTS      AGE   IP          NODE             NOMINATED NODE   READINESS GATES
test-health-check   0/1     Completed   1 (18s ago)   29s   10.1.0.82   docker-desktop   <none>           <none>

$ kubectl get pods test-health-check -o wide
NAME                READY   STATUS      RESTARTS      AGE   IP          NODE             NOMINATED NODE   READINESS GATES
test-health-check   0/1     Completed   1 (21s ago)   32s   10.1.0.82   docker-desktop   <none>           <none>

$ kubectl get pods test-health-check -o wide
NAME                READY   STATUS             RESTARTS      AGE   IP          NODE             NOMINATED NODE   READINESS GATES
test-health-check   0/1     CrashLoopBackOff   1 (14s ago)   36s   10.1.0.82   docker-desktop   <none>           <none>

$ kubectl get pods test-health-check -o wide
NAME                READY   STATUS    RESTARTS      AGE   IP          NODE             NOMINATED NODE   READINESS GATES
test-health-check   1/1     Running   2 (17s ago)   39s   10.1.0.82   docker-desktop   <none>           <none>

$ kubectl get pods test-health-check -o wide
NAME                READY   STATUS    RESTARTS      AGE   IP          NODE             NOMINATED NODE   READINESS GATES
test-health-check   1/1     Running   2 (20s ago)   42s   10.1.0.82   docker-desktop   <none>           <none>

$ kubectl get pods test-health-check -o wide
NAME                READY   STATUS             RESTARTS      AGE   IP          NODE             NOMINATED NODE   READINESS GATES
test-health-check   0/1     CrashLoopBackOff   2 (23s ago)   69s   10.1.0.82   docker-desktop   <none>           <none>

$ kubectl get pods test-health-check -o wide
NAME                READY   STATUS    RESTARTS      AGE   IP          NODE             NOMINATED NODE   READINESS GATES
test-health-check   1/1     Running   3 (31s ago)   77s   10.1.0.82   docker-desktop   <none>           <none>

10 秒という短い時間でプロセスが終了するので、コンテナを再起動するときに Pod の STATUS が CrashLoopBackOff になり、再起動されるまでの間隔が大きくなる。

オプションに --restart=Never を指定すると、コンテナのメインプロセスが終了しても、コンテナを再作成して再起動しなくなる。デフォルトは、Always なので上のような挙動になるのだ。

Liveness Probe

kubectl コマンドで Deployment リソースオブジェクトを作成する。Pod にしないのは、実行中にマニフェストを変更するためだ。

$ kubectl create deployment kuard --image=gcr.io/kuar-demo/kuard-amd64:1 --replicas=1
deployment.apps/kuard created

次に、kubectl edit コマンドにより、マニフェストファイルを動的に変更して、Liveness Probe の設定を追加する。

$ kubectl edit deployment kuard

kuard Deployment リソースオブジェクトのマニフェストファイルを編集するエディタが開くので、そこで Liveness Probe と次でやる Readiness Probe のための設定を追加する。設定はコンテナごとにやるので、``spec.template.spec.containers` の中に記述する。

    livenessProbe:
      httpGet:
        path: /healthy
        port: 8080
      initialDelaySeconds: 5
      timeoutSeconds: 1
      periodSeconds: 10
      failureThreshold: 3

    readinessProbe:
      httpGet:
        path: /ready
        port: 8080
      initialDelaySeconds: 0
      timeoutSeconds: 1
      periodSeconds: 2
      failureThreshold: 3
      successThreshold: 1

マニフェストの変更により、kuard Deployment オブジェクトの中の Pod が再作成される。次に、ローカルからこの Pod にアクセスできるようにするためにポートフォワードを実行する。

$ kubectl get pods
NAME                              READY   STATUS    RESTARTS   AGE
kuard-9b7598687-pgnhm             1/1     Running   0          13s

$ kubectl port-forward kuard-9b7598687-pgnhm 5555:8080
Forwarding from 127.0.0.1:5555 -> 8080
Forwarding from [::1]:5555 -> 8080

kuard Deployment オブジェクト内には、kuard-9b7598687-pgnhm Pod オブジェクトがあり、その中のコンテナアプリケーションが 8080 ポートを Listen している。上では、ローカルの 5555 番ポートをその 8080 ポートへとフォワードしている。これにより、http://localhost:5555 で Pod のコンテナアプリケーションへリクエストできる。

http://localhost:5555 へとアクセスして、コンテナの Web アプリケーションにリクエストしてページを表示する。そこで、Liveness Probe のタブを選択すると、ヘルスチェックのためのリクエストがマニフェストに追加設定したとおりの間隔でやってきていることがわかる。Status コード 200 を返しているが、このコンテナアプリケーションが /healthy パスに対して、そのレスポンスを返すようにしているからだ。ここで、

Fail

のリンクをクリックしてやると、コンテナアプリケーションは /healthy パスへのリクエストに対し、Status コード 500 を返すようになるので、ヘルスチェックは失敗したとみなされるようになる。失敗回数が閾値(failureThreshold)に達すると、K8S クラスタシステムは、このコンテナを再起動させる。したがって、再起動後に Pod を確認すると、

$ kubectl get pods
NAME                              READY   STATUS    RESTARTS   AGE
kuard-9b7598687-pgnhm             1/1     Running   1 (27s ago)   114m

となり、Pod オブジェクトはそのままだが、コンテナが再起動されたことが確認できる。また、

$ kubectl describe pod kuard-9b7598687-pgnhm

を実行して、この Pod の詳細情報を見てみると、その中に

Events:
  Type     Reason     Age                    From     Message
  ----     ------     ----                   ----     -------
  Normal   Pulled     3m35s (x2 over 117m)   kubelet  Container image "gcr.io/kuar-demo/kuard-amd64:1" already present on machine
  Normal   Created    3m35s (x2 over 117m)   kubelet  Created container kuard-amd64
  Normal   Started    3m35s (x2 over 117m)   kubelet  Started container kuard-amd64
  Warning  Unhealthy  3m35s (x3 over 3m55s)  kubelet  Liveness probe failed: HTTP probe failed with statuscode: 500
  Normal   Killing    3m35s                  kubelet  Container kuard-amd64 failed liveness probe, will be restarted

という表示がある。Liveness Probe に3回失敗し、kuard-amd64 というコンテナを再起動させたことがわかる。

Readiness Probe

同じ Web アプリケーションの表示ページの Readiness Probe のタブで、ヘルスチェックが実行されていることを確認できる。ここでも

Fail

リンクをクリックして、Readiness Probe のチェックが失敗するようにできる。Liveness のときとは違い、失敗回数の閾値に達しても、コンテナの再起動は起こらない。この実験ではやっていないが、連携する Service リソースオブジェクトがあれば、そこからのリクエストがやってこなくなる。その間に Readiness Probe のチェックが成功するようになり、成功回数の閾値に到達すれば、再び Service リソースオブジェクトからのリクエストが転送されてくるようになる。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment