コンテンツにスキップ

07. livenessProbeとreadinessProbe

DeploymentではlivenessProbereadinessProbeを定義できる。

これらを設定しておけばPodの調子が悪いときにDeploymentがPodを再起動させたり、Serviceに転送を行わなくさせることができる。

livenessProbe readinessProbe
判定内容 Pod が生きているか Pod がリクエストを処理できるか
失敗時の動作 Pod を再起動する Service から一時的に除外する
用途 フリーズ・クラッシュの検知 起動中・高負荷時のトラフィック制御
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
apiVersion: apps/v1
kind: Deployment
spec:
  template:
    spec:
      containers:
        - env:
          image: postgres:17
          livenessProbe: # Podが生きているか確認する
            exec:
              command:
                - pg_isready
                - -U
                - postgres
            failureThreshold: 5
            periodSeconds: 5
            timeoutSeconds: 5
          readinessProbe: # Podがリクエスト処理可能か確認する
            exec:
              command:
                - pg_isready
                - -U
                - postgres
            initialDelaySeconds: 5
            periodSeconds: 10

livenessProbereadinessProbeより緩く設定する方が良いらしい。というのもlivenessProbeが厳しすぎると、高負荷で一時的に応答が遅いPodを再起動してしまい、かえって状況を悪化させてしまうからである。

readinessProbeの動作を確認する

存在しないヘルスチェック用エンドポイントにアクセスさせ、readinessProbeが必ず失敗するようにする。こうするとServiceはPodへの転送を除外するはずである。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
apiVersion: apps/v1
kind: Deployment
spec:
  template:
    spec:
      # 略
      containers:
        - env:
          image: # 略
          name: app
          readinessProbe: # Podがリクエスト処理可能か確認する
            httpGet:
              path: /api/not-found # ヘルスチェック用エンドポイント
              port: 3000
            initialDelaySeconds: 5 # 起動後何秒後にチェックを開始するか
            periodSeconds: 10 # 何秒ごとにチェックするか
      restartPolicy: Always
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
$ kubectl apply -f ./k8s/
$ kubectl describe pod app
# 略
Events:
  Type     Reason     Age                  From               Message
  ----     ------     ----                 ----               -------
  Normal   Scheduled  2m14s                default-scheduler  Successfully assigned default/app-f658764dd-8ftjr to minikube
  Normal   Pulling    2m11s                kubelet            Pulling image "192.168.11.42:8085/nextjs-todo-example:latest"
  Normal   Pulled     2m11s                kubelet            Successfully pulled image "192.168.11.42:8085/nextjs-todo-example:latest" in 49ms (49ms including waiting). Image size: 295936324 bytes.
  Normal   Created    2m11s                kubelet            Container created
  Normal   Started    2m10s                kubelet            Container started
  Warning  Unhealthy  108s (x2 over 118s)  kubelet            Readiness probe failed: Get "http://10.244.0.8:3000/api/not-found": dial tcp 10.244.0.8:3000: connect: connection refused
  Warning  Unhealthy  87s (x2 over 97s)    kubelet            Readiness probe failed: Get "http://10.244.0.8:3000/api/not-found": context deadline exceeded (Client.Timeout exceeded while awaiting headers)
  Warning  Unhealthy  10s (x8 over 78s)    kubelet            Readiness probe failed: HTTP probe failed with statuscode: 404

10.244.0.8のPodがエンドポイントhttp://10.244.0.8:3000/api/not-foundにアクセスしようとして失敗している。

1
2
3
4
5
$ kubectl get endpoints app -w
Warning: v1 Endpoints is deprecated in v1.33+; use discovery.k8s.io/v1 EndpointSlice
NAME   ENDPOINTS         AGE
app    10.244.0.7:3000   56m
app    10.244.0.7:3000   56m

kubectl get endpointsでServiceの転送先Podのエンドポイント一覧を確認できる。ヘルスチェックに失敗しているために10.244.0.8のPodは転送対象外になっていることがわかる。

1
2
3
4
5
$ kubectl get endpoints app -w
Warning: v1 Endpoints is deprecated in v1.33+; use discovery.k8s.io/v1 EndpointSlice
NAME   ENDPOINTS         AGE
app    10.244.0.7:3000   56m
app    10.244.0.7:3000   56m

livenessProbeの動作を確認する

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
apiVersion: apps/v1
kind: Deployment
spec:
  template:
    spec:
      containers:
        - env:
          image: # 略
          name: app
          ports:
            - containerPort: 3000
              protocol: TCP
          resources: # CPUの使用量の下限・上限を指定する
            requests:
              cpu: "4m" # Pod1個で0.004コアを確保する
            limits:
              cpu: "10m" # Pod1個で最大0.01コアを確保する
          livenessProbe: # Podが生きているか確認する
            httpGet:
              path: /api/health # ヘルスチェック用エンドポイント
              port: 3000
            initialDelaySeconds: 5 # 起動後何秒後にチェックを開始するか
            periodSeconds: 10 # 何秒ごとにチェックするか
            timeoutSeconds: 5 # この秒数以内に応答しなかったら失敗扱い
            failureThreshold: 10 # この回数だけ失敗したら再起動
          readinessProbe: # Podがリクエスト処理可能か確認する
            httpGet:
              path: /api/health # ヘルスチェック用エンドポイント
              port: 3000
            initialDelaySeconds: 5 # 起動後何秒後にチェックを開始するか
            periodSeconds: 10 # 何秒ごとにチェックするか
            timeoutSeconds: 5 # この秒数以内に応答しなかったら失敗扱い
            failureThreshold: 3 # この回数だけ失敗したらトラフィック除外
      restartPolicy: Always
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
$ kubectl apply -f ./k8s/
$ kubectl get pods -w
NAME                   READY   STATUS              RESTARTS   AGE
app-7f4bf9767c-47jpd   0/1     ContainerCreating   0          3s
app-d6c589c74-8g8v7    1/1     Running             0          30m
db-6fb7c4997c-tvdws    0/1     ContainerCreating   0          2s
db-6ffc45cf54-phs6f    0/1     Completed           0          30m
db-6ffc45cf54-phs6f    0/1     Completed           0          30m
db-6ffc45cf54-phs6f    0/1     Completed           0          30m
db-6fb7c4997c-tvdws    0/1     Running             0          3s
app-7f4bf9767c-47jpd   0/1     Running             0          5s
db-6fb7c4997c-tvdws    1/1     Running             0          14s
app-7f4bf9767c-47jpd   1/1     Running             0          58s
app-d6c589c74-8g8v7    1/1     Terminating         0          31m
app-d6c589c74-8g8v7    1/1     Terminating         0          31m
app-d6c589c74-8g8v7    0/1     Completed           0          31m
app-d6c589c74-8g8v7    0/1     Completed           0          31m
app-d6c589c74-8g8v7    0/1     Completed           0          31m
app-7f4bf9767c-47jpd   0/1     Running             1 (3s ago)   104s
app-7f4bf9767c-47jpd   1/1     Running             1 (54s ago)   2m35s
app-7f4bf9767c-47jpd   0/1     Running             2 (2s ago)    3m23s
app-7f4bf9767c-47jpd   1/1     Running             2 (55s ago)   4m16s
app-7f4bf9767c-47jpd   0/1     Running             3 (2s ago)    5m3s
app-7f4bf9767c-47jpd   1/1     Running             3 (46s ago)   5m47s
app-7f4bf9767c-47jpd   0/1     Running             4 (2s ago)    6m43s
app-7f4bf9767c-47jpd   1/1     Running             4 (44s ago)   7m25s
app-7f4bf9767c-47jpd   0/1     Running             5 (1s ago)    8m22s
app-7f4bf9767c-47jpd   1/1     Running             5 (43s ago)   9m4s
app-7f4bf9767c-47jpd   0/1     Running             6 (2s ago)    10m
app-7f4bf9767c-47jpd   1/1     Running             6 (48s ago)   10m
app-7f4bf9767c-47jpd   0/1     CrashLoopBackOff    6 (1s ago)    11m
説明
NAME Pod名。Deployment名-ReplicaSet識別子-Pod識別子の形式
READY 準備完了コンテナ数/総コンテナ数。readinessProbe が成功すると分子が増える
STATUS Podの状態。主なものは下表
RESTARTS 再起動回数。括弧内は最後に再起動してからの経過時間
AGE Podが作成されてからの経過時間

STATUSの値と意味を以下に示す。

STATUS 意味
ContainerCreating イメージ取得・コンテナ起動中
Running コンテナが動いている(readinessは別)
Terminating 停止処理中
Completed 正常終了(通常の Pod は終了しないので過渡的な表示)
CrashLoopBackOff 起動に繰り返し失敗している
\[ \begin{align} \mathrm{initialDelaySeconds} + (\mathrm{failureThreshold} - 1) \times \mathrm{periodSeconds} &= 5 + (10 - 1) \times 10 \\ &= 5 + 90 \\ &= 95s \end{align} \]
1
2
3
NAME                   READY   STATUS              RESTARTS   AGE
app-7f4bf9767c-47jpd   1/1     Running             0          58s
app-7f4bf9767c-47jpd   0/1     Running             1 (3s ago)   104s

READYが0/1になっている行はreadinessProbeに失敗している。

RESTARTSの増えた行のAGEの差分を取ると概ね95秒になっている。

1
2
3
4
NAME                   READY   STATUS              RESTARTS   AGE
app-7f4bf9767c-47jpd   0/1     Running             1 (3s ago)   104s
app-7f4bf9767c-47jpd   0/1     Running             2 (2s ago)    3m23s
app-7f4bf9767c-47jpd   0/1     Running             3 (2s ago)    5m3s