[Kubernetes]Liveness ProbeとReadiness Probeを利用した死活監視

最近触れる機会があったので、自分の備忘録として残します。

# ざっくりまとめると

- Liveness Probeは「アプリがきちんと動作しているか（例：デッドロックなどが発生していないか）」をチェックできる
- Readiness Probeは「そのポッドがトラフィックをさばける状態にあるか」をチェックできる


# Liveness/Readiness Probeとは
Kubernetesには死活監視のための機能が二つ用意されています。
一つはLiveness Probe、もう一つはReadiness Probeと呼ばれているものです。
それぞれ出来ることが異なるので、「どのような目的で監視を行いたいか」という観点からどちらを採用するか選択すると良いかと思います。

# Liveness Probe
公式ドキュメントから抜粋。（参考：[公式ドキュメント（英語）](https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-probes/)）

> The kubelet uses liveness probes to know when to restart a Container. For example, liveness probes could catch a deadlock, where an application is running, but unable to make progress. Restarting a Container in such a state can help to make the application more available despite bugs.

意訳するとこんな感じ。

kubeletはliveness probesを利用することで、いつコンテナが再起動するかを知ることができる。例えばliveness probesはデッドロックを検知することができる。この場合、アプリケーション自体は動いていても、何も処理をすることが出来ないということだ。そのような状況でコンテナを再起動することで、不具合がある中でもアプリケーションの可用性を高めることができるのだ。

つまり、単純にアプリケーションが起動しているか否か、よりも一歩踏み込んで、「アプリがきちんと動いているかどうか」をチェックすることができます。

### 出来ること
以下の「設定方法」に記載した設定で、監視を行うことができます。
ここでいう監視とは、ざっくりいうと、「決まった間隔で、特定の処理（各種コマンド、HTTPリクエスト、TCPソケット）を行う」ということをするみたいです。

なので例えば、死活監視用のシンプルなwebAPIを一つ用意しておいてそれを叩かせる、ということが簡単にできます。

Liveness Probeは失敗を検知した場合、Podを自動的に再起動させます。

### サンプル（公式）
Liveness Probe, Readiness Probeの設定はどちらもDeploymentのマニフェストファイルで行います。
サンプルは公式ドキュメントから抜粋。（出典：[Define a liveness command.](https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-probes/#define-a-liveness-command)）

```
apiVersion: v1
kind: Pod
metadata:
  labels:
    test: liveness
  name: liveness-exec
spec:
  containers:
  - name: liveness
    image: k8s.gcr.io/busybox
    args:
    - /bin/sh
    - -c
    - touch /tmp/healthy; sleep 30; rm -rf /tmp/healthy; sleep 600
    livenessProbe:
      exec:
        command:
        - cat
        - /tmp/healthy
      initialDelaySeconds: 5
      periodSeconds: 5
```

この`liveness`コンテナは、起動後に`/tmp/healty`というファイルを作ります。
その後30秒間処理を止めたのち、`/tmp/healty`ファイルを削除します。

これに対して、Liveness Probeによって、
「コンテナ起動から5秒後から(`initialDelaySeconds`)」
「5秒ごとに(`periodSeconds`)」
「`cat /tmp/health`コマンドが実行され(`exec`以下)」ます。

`cat`コマンドは対象のファイルが存在しないと失敗するので、
`/tmp/health`ファイルが削除されたあとは、liveness probeが失敗を検知するようになります。
結果、podの再起動が行われます。

### 設定方法

設定はコンテナごとに行うので、今回は `liveness`という名前のコンテナに対して設定を記載しています。
各パラメータの説明は以下の通りです。

| パラメータ | 説明 |
|:--|:--|
| exec  | 通常のexecコマンドと同様に、どのコマンドを実行して監視を行うか設定できる。  |
| initialDelaySeconds  | コンテナが起動してから、何秒後に監視を始めるかを設定できる。  |
| periodSeconds  | 何秒おきに監視を走らせるかを設定できる。 デフォルトは10秒で、最短で1秒にできる。（そこまでやるか） | 
| timeoutSeconds  | 監視のレスポンスを何秒待つかを設定できる。デフォルト、最小ともに1秒。  |
| successThreshold  | 一回failした後、何回連続で成功すれば「Liveness Probeが成功した」とみなすかを設定できる。デフォルト、最小は1回。  |
| failureThershold  | Liveness Probeが何回連続で失敗した場合にPodを再起動させるかを設定できる。デフォルトは3回、最小は1回。  |

ポイントとしては `periodSeconds`と `timeoutSeconds`の設定かなと考えます。
`periodSeconds`が短ければ短いほど、監視をより高い頻度で行うことができます。
結果的に、アプリの問題をより早く検知することができるようになります。

その一方で、`timeoutSeconds`があまりに短いと、ただアプリがbusyな状態なだけだったにもかかわらず、処理がタイムアウトしてしまい、結果意図しない再起動が発生してしまうことになります。
したがって、タイムアウトの秒数はある程度余裕を持って設定をさせる必要があるかと。

なおHTTPリクエストを投げる場合には、以下のようなパラメータを指定できます。
サンプルは同じく、[こちら](https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-probes/#define-a-liveness-http-request)の公式ドキュメントから。

```
    livenessProbe:
      httpGet:
        path: /healthz
        port: 8080
        httpHeaders:
        - name: X-Custom-Header
          value: Awesome
      initialDelaySeconds: 3
      periodSeconds: 3
```
| パラメータ | 説明 |
|:--|:--|
| host  | 接続先のホストのIPアドレスを指定します。  |
| scheme  | 接続に利用するスキーム(HTTPかHTTPS）を指定できます。デフォルトはHTTPです。  |
| path  | HTTPサーバーにアクセスする際のパスを指定します。  |
| port  | 接続先のポート番号を指定します。  |
| httpHeaders  | リクエストのヘッダの内容を設定することができます。  |


# Readiness Probe
これまた公式から引用。（参考：[公式ドキュメント（英語）](https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-probes/)）
> The kubelet uses readiness probes to know when a Container is ready to start accepting traffic. A Pod is considered ready when all of its Containers are ready. One use of this signal is to control which Pods are used as backends for Services. When a Pod is not ready, it is removed from Service load balancers.

意訳。
kubeletはreadiness probeを利用することで、コンテナがトラフィックを受け入れられる状態になっているかどうかを知ることができます。ポッド内の全てのコンテナが準備ができている状態になって、はじめてポッドの準備ができている、とみなせます。この機能の利用方法の一つとして、どのポッドがServiceのバックエンドとして利用されるかを制御することができます。ポッドの準備ができていない場合、Serviceロードバランサーからポッドが削除されます。

livenessに比べると少しややこしいですが、
readiness probeに失敗した場合、「そのポッドはトラフィックを捌くことができない」として、そのポッドがサービスのエンドポイントから外れ、リクエストが飛んでこないようになります。

### 出来ること
やれることとしてはLivenessとほとんど変わりません。
パラメータに従って、どの頻度でどのような処理を実行するかを設定することができます。

### サンプル（公式）
ReadinessもLivenessと同じような設定ができます。設定方法も、deploymentのマニフェストファイルに記述するだけ。
例は[こちら](https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-probes/#define-readiness-probes)。

```
readinessProbe:
  exec:
    command:
    - cat
    - /tmp/healthy
  initialDelaySeconds: 5
  periodSeconds: 5
```

### 設定方法
大まかな設定方法はLiveness Probeと同じです。
異なるのは、deploymentファイルの中の`livenessProbe`となっている記載を`readinessProbe`に変更するだけです。

実際に動かしたものは後日別記事で公開しまっす。

# まとめと雑感
Liveness ProbeとReadiness Probeはそもそも用途が違うので、
どのような監視を行いたいかから逆算してどちらを（あるいはどちらも）利用するか決めるべき。

あと本筋とは関係ないのですが、
やっぱり公式ドキュメントをしっかり読み込むこと、
その上で自分で手を動かして物を作って理解しようとするのは大事だなと改めて実感しました。

#参考文献
- kubernetes公式ドキュメント  
https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-probes/