4
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【本気で学ぶKubernetes】コンテナのヘルスチェックを行うProbeに入門

Posted at

はじめに

こんにちは!

本記事は「本気で学ぶKubernetes」シリーズの第8回です。このシリーズでは、Kubernetesの基礎から実践まで、段階的に学んでいきます。

このシリーズは、第1回から順に読むことで体系的に学べる構成にしています。
まだご覧になっていない方は、ぜひ最初からご覧ください!

Kubernetesとは?クラスタ構成の全体像をつかむ

前回は、KubernetesのRBAC(Role-Based Access Control)を使った権限管理について触れました。

今回は、KubernetesのProbe(ヘルスチェック)について学んでいきます。Probeを使うことで、コンテナの健康状態を監視し、異常を検知したり、準備ができていないコンテナにトラフィックを流さないようにしたりできます。

この記事は人間がKubernetesの公式ドキュメントを読み漁りながら、人間の手で書いていますのでご安心ください!

Kubernetesでの運用上の課題

Kubernetesに限らず多くのアプリケーションでは外部のデータベースを使っていたり、APIサーバーを別で作成してアクセスしていることが多いと思います。
プロセス自体は動いていても実はデッドロックが発生していて、アプリケーションが反応/応答できないという状況も考えられます。

そのため安定稼働させるためにはヘルスチェックや死活監視を行なっていくことが重要となります。

KubernetesにはProbeという仕組みが用意されていて、上記のような状況を検知し対応することが可能です。

Probeにはいくつか種類がありますので、今回はそれらについて触れていきたいと思います。

Readiness Probe

Readiness Probe は、コンテナが「トラフィックを受ける準備ができているか」を確認する機能です。

もし失敗した場合はServiceのエンドポイントから除外されますが、コンテナ自体は再起動されません。そのため起動時の初期化待ちや、一時的な過負荷でトラフィックを止めたい場合に使われるようです。

実際にReadiness Probeを設定したPodをデプロイして、挙動を確認してみたいと思います。

公式ドキュメントではregistry.k8s.io/livenessを使っており、古いイメージを使っているようでしたので今回はnginxのイメージを使って確認していこうと思います。

nginxを使ってReadiness Probeの挙動確認用のマニフェストを用意します。

readiness-probe.yaml
apiVersion: v1
kind: Pod
metadata:
  name: readiness-demo
  labels:
    app: readiness-demo
spec:
  containers:
  - name: readiness-demo
    image: nginx:1.25
    ports:
    - containerPort: 80
    readinessProbe:
      httpGet:
        path: /healthz
        port: 80
      initialDelaySeconds: 3
      periodSeconds: 3
      failureThreshold: 3
---
apiVersion: v1
kind: Service
metadata:
  name: readiness-demo-service
spec:
  selector:
    app: readiness-demo
  ports:
  - protocol: TCP
    port: 80
    targetPort: 80

Readiness Probeの設定をみると、/healthzエンドポイントにHTTP GETリクエストを送っています。

initialDelaySeconds: 3は最初のProbe実行までの待機時間、periodSeconds: 3はProbeの実行間隔、failureThreshold: 3は3回失敗したら準備未完了と判定する設定です。

nginxには最初から/healthzというファイルが存在しないため、Readiness Probeは失敗します。後ほど手動でこのファイルを作成することで、Probeが成功するようになります。

デプロイして挙動を確認してみます

kubectl apply -f readiness-probe.yaml

# pod/readiness-demo created
# service/readiness-demo-service created

# Podの確認
kubectl get pods

# NAME             READY   STATUS    RESTARTS   AGE
# readiness-demo   0/1     Running   0          15s

PodはRunning状態ですが、Readiness Probeが失敗しているためREADY0/1になっています。

次に、Serviceのエンドポイントを確認してみます。

kubectl get endpoints readiness-demo-service

# NAME                     ENDPOINTS   AGE
# readiness-demo-service               20s

エンドポイントが空になっています。
これはReadiness Probeが失敗しているため、ServiceはこのPodをバックエンドとして登録していない状況です。

ここでPodの詳細を見てみます。

kubectl describe pod readiness-demo

#  Warning  Unhealthy  3s (x7 over 21s)   kubelet            Readiness probe failed: HTTP probe failed with statuscode: 404

Readiness probe failed: HTTP probe failed with statuscode: 404というメッセージが表示されていますが、/healthzファイルが存在しないため、404エラーが返されていなす。

では、コンテナ内に/healthzファイルを作成してみます。

kubectl exec readiness-demo -- bash -c "echo 'OK' > /usr/share/nginx/html/healthz"

# Podの確認
kubectl get pods

# NAME             READY   STATUS    RESTARTS   AGE
# readiness-demo   1/1     Running   0          45s

READY1/1に変わり、これはReadiness Probeが成功しました。

Serviceのエンドポイントも確認してみると、PodのIPアドレスが登録されていることが確認できます。

kubectl get endpoints readiness-demo-service

# NAME                     ENDPOINTS      AGE
# readiness-demo-service   10.228.1.77:80   50s

上記のように、もしReadiness Probeが失敗してもコンテナは再起動されず、Serviceのエンドポイントから除外されるようになっています。
Probeが成功すれば、自動的にエンドポイントに追加されますので準備ができていないPodにトラフィックが送られるといったことはなくなりますね。

Liveness Probeを試してみる

Liveness Probeは、アプリケーションが正常に動作しているかを確認します。失敗すると、Kubernetesがコンテナを再起動します。

こちらもまずはマニフェストを作成します。

liveness-probe.yaml
apiVersion: v1
kind: Pod
metadata:
  name: liveness-demo
spec:
  containers:
  - name: liveness-demo
    image: nginx:1.25
    ports:
    - containerPort: 80
    lifecycle:
      postStart:
        exec:
          command: ['sh', '-c', 'echo "OK" > /usr/share/nginx/html/healthz']
    livenessProbe:
      httpGet:
        path: /healthz
        port: 80
      initialDelaySeconds: 3
      periodSeconds: 5
      failureThreshold: 2

今回はlivenessProbeを設定しています。

このマニフェストでは、lifecycle.postStartを使ってコンテナ起動時に/healthzファイルを作成しています。

そのため、Pod起動時はLiveness Probeが成功します。後ほど手動でこのファイルを削除することで、Liveness Probeが失敗し、コンテナが再起動される様子を確認できます。

デプロイして挙動を確認してみます。

kubectl apply -f liveness-probe.yaml

# pod/liveness-demo created

Podの状態を確認してみます。。

kubectl get pods

# NAME            READY   STATUS    RESTARTS   AGE
# liveness-demo   1/1     Running   0          10s

READY1/1RESTARTSは0ということで、Liveness Probeは成功していることがわかります。

/healthzファイルを削除してみると、

kubectl exec liveness-demo -- rm /usr/share/nginx/html/healthz

# Defaulted container "liveness-demo" out of: liveness-demo, setup (init)

数秒待ってから、Podの状態を監視してみます。

kubectl get pods -w

# NAME            READY   STATUS    RESTARTS   AGE
# liveness-demo   1/1     Running   0          30s
# liveness-demo   1/1     Running   1 (1s ago)   42s

RESTARTSが1に増えたことから、Liveness Probeが失敗してKubernetesがコンテナを再起動したことが分かります。

Ctrl+Cで監視を終了して、Podの詳細を確認してみます。

kubectl describe pod liveness-demo

# ・・・略・・・
#  Normal   Killing    28s                kubelet            Container liveness-demo failed liveness probe, will be restarted

今度はContainer liveness-demo failed liveness probe, will be restartedというメッセージが出ていました。

Liveness Probeが失敗した場合はKubernetesのコンテナを再起動し、新しいコンテナを起動することで正常な状態に戻そうとする挙動だということがわかります。

整理すると、用途としては以下のようなイメージでしょうか。

  • Readiness Probe
    • 起動時の初期化待ち、一時的な過負荷でのトラフィック制御
  • Liveness Probe
    • デッドロック、無限ループなどの異常検知

Startup Probeを試してみる

Startup Probeは、起動に時間がかかるアプリケーション専用のProbeとして用意されています。

起動に時間がかかるアプリケーションの場合、早い段階でLiveness Probeによってヘルスチェックが行われてしまうと異常だと検知されてしまう可能性があります。

そのためinitialDelaySecondsを長く設定する必要がありますが、長くしすぎると逆に起動後に異常が発生した場合の検知が遅れてしまいます。

Startup Probeで起動時と通常時で異なる設定を使い分けられるようになります。

マニフェストを作成します。

startup-probe.yaml
apiVersion: v1
kind: Pod
metadata:
  name: startup-demo
spec:
  initContainers:
  - name: slow-start
    image: busybox:1.36
    command: ['sh', '-c', 'echo "Simulating slow startup..." && sleep 15']
  - name: setup
    image: nginx:1.25
    command: ['sh', '-c', 'echo "OK" > /usr/share/nginx/html/healthz']
    volumeMounts:
    - name: html
      mountPath: /usr/share/nginx/html
  containers:
  - name: startup-demo
    image: nginx:1.25
    ports:
    - containerPort: 80
    livenessProbe:
      httpGet:
        path: /healthz
        port: 80
      initialDelaySeconds: 0
      periodSeconds: 5
      failureThreshold: 2
    startupProbe:
      httpGet:
        path: /healthz
        port: 80
      initialDelaySeconds: 0
      periodSeconds: 3
      failureThreshold: 10
    volumeMounts:
    - name: html
      mountPath: /usr/share/nginx/html
  volumes:
  - name: html
    emptyDir: {}

このマニフェストでは、Liveness ProbeとStartup Probeの両方を設定しています。

Startup Probeの設定を見てみると、periodSeconds: 3failureThreshold: 10としていて、3秒ごとに確認し最大10回までの失敗を許容する設定になっています。

一方で、Liveness ProbeはperiodSeconds: 5failureThreshold: 2としているので、Startup Probe成功後は5秒ごとにチェックして、2回失敗したら再起動します。

デプロイして挙動を確認します。

kubectl apply -f startup-probe.yaml

# pod/startup-demo created

Podの状態を確認します。

kubectl get pods

# NAME           READY   STATUS     RESTARTS   AGE
# startup-demo   0/1     Init:0/2   0          5s

Init:0/2となっていますが、これは2つのInitContainerのうち最初のものが実行中(準備中)であることが分かります。

15秒ほど待ってから再度確認してみます。

kubectl get pods

# NAME           READY   STATUS    RESTARTS   AGE
# startup-demo   1/1     Running   0          20s

Running状態になりました。
InitContainerの完了してからメインコンテナが起動し、Startup Probeが成功したためコンテナが準備完了状態になっています。

kubectl describe podで詳細を確認してみます。

kubectl describe pod startup-demo

Conditionsセクションを見ると、以下のようになっています。

# Conditions:
#  Type                        Status
#  PodReadyToStartContainers   True
#  Initialized                 True
#  Ready                       True
#  ContainersReady             True
#  PodScheduled                True

ReadyTrueになっています。

上記のようにStartup Probeを使うことで、起動に時間がかかるアプリケーションでも起動中にLiveness Probeで再起動されることを防ぐことができます。

Startup Probeは起動が遅いアプリケーションに適していますが、通常のアプリケーションでは基本的にReadinessとLivenessで十分なことも多いように思います。

出典: Kubernetes公式ドキュメント - Configure Liveness, Readiness and Startup Probes

クリーンアップ

全ての挙動確認が終わったので、作成したリソースを削除しておきましょう。

kubectl delete -f readiness-probe.yaml
kubectl delete -f liveness-probe.yaml
kubectl delete -f startup-probe.yaml

まとめと次回予告

今回は、KubernetesのProbe(ヘルスチェック)について触れてきました。

以下のように使い分けをおさせておくと良いと思います。

  • Readiness Probe: トラフィックを受ける準備ができているか確認
  • Liveness Probe: アプリケーションが正常に動作しているか確認する
  • Startup Probe: 起動が重いアプリケーション向けで、成功するまで他のProbeは待機させる

Probeは適切に設定することで、障害の自動復旧とサービスの安定化に繋げられますのでぜひ導入して可用性を高めていきましょう!

次回は、StatefulSetについて触れていきたいと思います!

それでは、また明日!

4
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?