kubernetesで動かすコンテナのヘルスチェック

## この記事は何

タイトル通り。
kubernetes上でコンテナなWebアプリを動かす時に必要になってくるヘルスチェックや起動時のデータ読み込みをどうやって設定するか。

ドキュメントはこの辺り。
[Configure Liveness and Readiness Probes | Kubernetes](https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-probes/#define-readiness-probes)

コンテナのヘルスチェックには2種類あり、livenessとreadiness。
簡単に説明するとこんな感じか。

- livenessはコンテナそのものが立ち上がっているかどうかをチェックするもの
- readinessはリクエスト受け付け準備が整っているかどうかをチェックするもの

## コンテナのヘルスチェック

コンテナの生存確認にコマンドを使う場合は`exec.command`を指定する。

```yaml
livenessProbe:
  initialDelaySeconds: 10
  periodSeconds: 10
  exec:
    command:
      - "true"
```

`initialDelaySeconds`と`periodSeconds`で初回実行のタイミングと定期実行のスケジュールを設定することが出来る。
他に`timeoutSeconds`, `successThreshold`, `failureThreshold`の設定項目があるので[ドキュメント](https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-probes/#configure-probes)を参照。

実際の設定を見るには`kubectl describe <pod>`を実行すれば良い。
例えばこのようになっている。

podの名前は適当に読み替えてほしい。

```
$ kubectl describe po app-86d46c684c-rf5sj | grep Liveness
   Liveness:   exec [true] delay=10s timeout=1s period=10s #success=1 #failure=3
```

これだと`true`を実行するだけなのでコンテナが立ち上がればlivenessは正常となり、コンテナは無事に立ち上がる。

次はわざと失敗させてみる。

```yaml
livenessProbe:
  initialDelaySeconds: 10
  periodSeconds: 10
  exec:
    command:
      - "false"
```

このような設定にして`kubectl apply`して反映してから`kubectl describe`してみる

Livenessの設定は`true`が`false`に変わっただけ。

```
$ kubectl describe po app-65c89f7c5d-pwdr9 | grep Liveness
    Liveness:   exec [false] delay=10s timeout=1s period=10s #success=1 #failure=3
```

当然`false`を実行すると終了ステータスが失敗扱いになるためlivenessは異常となる。
その結果、コンテナは再作成される。

```
$ kubectl describe po app-65c89f7c5d-pwdr9 | grep Killing
  Normal   Killing                5m (x2 over 6m)   kubelet, minikube  Killing container with id docker://app:Container failed liveness probe.. Container will be killed and recreated.
```

しかし何度やってもlivenessが正常になることはないので、podのstatusを見てみると`CrashLoopBackOff`となってしまっている。

```
$ kubectl get po app-65c89f7c5d-pwdr9
NAME                     READY     STATUS             RESTARTS   AGE
app-65c89f7c5d-pwdr9     1/2       CrashLoopBackOff   6          8m
```

このようにして`livenessProbe`を使ってコンテナのヘルスチェックを行うことが出来る。

## コンテナの疎通チェック

`livenessProbe`はコンテナのヘルスチェック、というだけであってコンテナ内のサービス、例えばWebアプリが正常に起動しているかどうかはまた別の話。
JVMを立ち上げたり最初にデータ読み込みであったりと、アプリケーションによっては最初にリクエストを受け付けられるようになるまでに時間がかかるものもある。
そういった時にヘルスチェック/疎通チェックとして使うのが`readinessProbe`というもの。

先程と違って8080番ポートの/healthパスへHTTPリクエストでコンテナのプロセスへ疎通確認をしてみる。

```yaml
ports:
- containerPort: 8080
  name: api-port
readinessProbe:
  initialDelaySeconds: 5
  periodSeconds: 20
  httpGet:
    path: /health
    port: api-port
    httpHeaders:
    - name: X-k8s-Header
      value: readiness
```

port指定は直接書いてもいいが、一応名前付けしてある。
`initialDelaySeconds`とか`periodSeconds`は`livenessProbe`と同じで[ドキュメント参照](https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-probes/#configure-probes)。

設定値を確認してみると以下のようになっている。

```
$ kubectl describe po app-65c89f7c5d-pwdr9 | grep Readiness
    Readiness:  http-get http://:api-port/health delay=5s timeout=1s period=20s #success=1 #failure=3
```

`httpGet`のAPIリファレンスはこの辺にある。
[Kubernetes API Reference Docs](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.10/#httpgetaction-v1-core)

両方まとめて書くとこんな感じになる。

```yaml
spec:
  containers:
  - name: app
    image: my-app:latest
    ports:
    - containerPort: 8080
      name: api-port
    livenessProbe:
      initialDelaySeconds: 10
      periodSeconds: 10
      exec:
        command:
          - "true"
    readinessProbe:
      initialDelaySeconds: 5
      periodSeconds: 20
      httpGet:
        path: /health
        port: api-port
        httpHeaders:
        - name: X-k8s-Header
          value: readiness
```

## 所感

`livenessProbe`と`readinessProbe`と2つのヘルスチェックがあるが、どちらも同じ処理をさせるならヘルスチェックが2倍走るだけになるので無意味なはず。

うまく使い分けて安全に運用していきたい。
今回は`livenessProbe`ではexec、`readinessProbe`ではhttpGetにしたが、
例えばどちらもhttpGetにして`livenessProbe`では何の処理もせず200返すだけのパス、`readinessProbe`ではDBへのSELECTをするパス、などにすると良いのかもしれない。