CrashLoopBackOffとは?Kubernetes CrashLoopBackOffイベントをアラート、デバッグ/トラブルシューティング、修復する方法

By 清水 孝郎 - JULY 1, 2021

SHARE:

本ブログ記事は、2018年3月27日にKnox Andersonが投稿した内容(https://sysdig.com/blog/debug-kubernetes-crashloopbackoff)ですが、2021年7月現在でも依然として人気のあるブログ記事となっています。日本語に翻訳・再構成した内容にて再掲いたします。

このブログでは、KubernetesのCrashLoopBackOffイベントを視覚化し、アラートを発し、デバッグ/トラブルシューティングする方法についてお話します。ベテランのKubernetesユーザなら誰でも知っているように、Kubernetes CrashLoopBackOffイベントは日常茶飯事です。誰もが一度は経験したことがあると思いますが、通常はコンテナ内のトラブルシューティングツールにアクセスできず、頭を悩ませることになります。

KubernetesのCrashLoopBackOffとは?どのような意味なのか?

CrashloopBackOffとは、ポッドが起動して、クラッシュして、また起動して、またクラッシュして、という状態です。

PodSpecには、ポッド内のすべてのコンテナに適用される、Always、OnFailure、Neverの可能な値を持つrestartPolicyフィールドがあります。デフォルト値は Always で、restartPolicy は、同一ノード上の kubelet によるコンテナの再起動のみを参照します(そのため、ポッドが別のノードで再スケジュールされると、再起動カウントはリセットされます)。kubeletによって再起動された失敗したコンテナは、5分を上限とする指数関数的なバックオフ遅延(10s、20s、40s …)で再起動され、正常に実行された10分後にリセットされます。以下は、restartPolicyフィールドを持つPodSpecの一例です。

apiVersion: v1
kind: Pod
metadata:
  name: dummy-pod
spec:
  containers:
    - name: dummy-pod
      image: ubuntu
  restartPolicy: Always

CrashLoopBackOffはなぜ起こるのでしょうか?

Googleで検索してみると、クラッシュループイベントはさまざまな理由で発生することがわかります(しかも頻繁に発生します)。ここでは、なぜクラッシュループが発生するのかについて、代表的な原因を挙げてみます。

クラスター内にCrashLoopBackOffがあるかどうかを確認するにはどうすればよいですか?

通常のkubectl get podsコマンドを実行すると、現在CrashLoopBackOffになっているポッドの状態を確認することができます。

kubectl get pods --namespace nginx-crashloop
NAME                     READY     STATUS             RESTARTS   AGE
flask-7996469c47-d7zl2   1/1       Running            1          77d
flask-7996469c47-tdr2n   1/1       Running            0          77d
nginx-5796d5bc7c-2jdr5   0/1       CrashLoopBackOff   2          1m
nginx-5796d5bc7c-xsl6p   0/1       CrashLoopBackOff   2          1m

実際、Errorステータスのポッドがあれば、おそらくすぐにCrashLoopBackOffになるでしょう:

kubectl get pods --namespace nginx-crashloop
NAME                     READY     STATUS    RESTARTS   AGE
flask-7996469c47-d7zl2   1/1       Running   1          77d
flask-7996469c47-tdr2n   1/1       Running   0          77d
nginx-5796d5bc7c-2jdr5   0/1       Error     0          24s
nginx-5796d5bc7c-xsl6p   0/1       Error     0          24s

kubectl describe podを実行すると、そのポッドの詳細な情報が得られます:

kubectl describe pod nginx-5796d5bc7c-xsl6p --namespace nginx-crashloop
Name:           nginx-5796d5bc7c-xsl6p
Namespace:      nginx-crashloop
Node:           ip-10-0-9-132.us-east-2.compute.internal/10.0.9.132
Start Time:     Tue, 27 Mar 2018 19:11:05 +0200
Labels:         app=nginx-crashloop
                name=nginx
                pod-template-hash=1352816737
                role=app
Annotations:    kubernetes.io/created-by={"kind":"SerializedReference","apiVersion":"v1","reference":{"kind":"ReplicaSet","namespace":"nginx-crashloop","name":"nginx-5796d5bc7c","uid":"fb9e9518-f542-11e7-a8f2-065cff0...
Status:         Running
IP:             10.47.0.15
Controlled By:  ReplicaSet/nginx-5796d5bc7c
Containers:
  nginx:
    Container ID:   docker://513cab3de8be8754d054a4eff45e291d33b63e11b2143d0ff782dccc286ba05e
    Image:          nginx
    Image ID:       docker-pullable://nginx@sha256:c4ee0ecb376636258447e1d8effb56c09c75fe7acf756bf7c13efadf38aa0aca
    Port:           <none>
    State:          Waiting
      Reason:       CrashLoopBackOff
    Last State:     Terminated
      Reason:       Error
      Exit Code:    1
      Started:      Tue, 27 Mar 2018 19:13:15 +0200
      Finished:     Tue, 27 Mar 2018 19:13:16 +0200
    Ready:          False
    Restart Count:  4
    Environment:    <none>
    Mounts:
      /etc/nginx/nginx.conf from config (rw)
      /var/run/secrets/kubernetes.io/serviceaccount from default-token-chcxn (ro)
Conditions:
  Type           Status
  Initialized    True 
  Ready          False 
  PodScheduled   True 
Volumes:
  config:
    Type:      ConfigMap (a volume populated by a ConfigMap)
    Name:      nginxconfig
    Optional:  false
  default-token-chcxn:
    Type:        Secret (a volume populated by a Secret)
    SecretName:  default-token-chcxn
    Optional:    false
QoS Class:       BestEffort
Node-Selectors:  nginxcrash=allowed
Tolerations:     node.alpha.kubernetes.io/notReady:NoExecute for 300s
                 node.alpha.kubernetes.io/unreachable:NoExecute for 300s
Events:
  Type     Reason                 Age               From                                               Message
  ----     ------                 ----              ----                                               -------
  Normal   Scheduled              2m                default-scheduler                                  Successfully assigned nginx-5796d5bc7c-xsl6p to ip-10-0-9-132.us-east-2.compute.internal
  Normal   SuccessfulMountVolume  2m                kubelet, ip-10-0-9-132.us-east-2.compute.internal  MountVolume.SetUp succeeded for volume "config"
  Normal   SuccessfulMountVolume  2m                kubelet, ip-10-0-9-132.us-east-2.compute.internal  MountVolume.SetUp succeeded for volume "default-token-chcxn"
  Normal   Pulled                 1m (x3 over 2m)   kubelet, ip-10-0-9-132.us-east-2.compute.internal  Successfully pulled image "nginx"
  Normal   Created                1m (x3 over 2m)   kubelet, ip-10-0-9-132.us-east-2.compute.internal  Created container
  Normal   Started                1m (x3 over 2m)   kubelet, ip-10-0-9-132.us-east-2.compute.internal  Started container
  Warning  BackOff                1m (x5 over 1m)   kubelet, ip-10-0-9-132.us-east-2.compute.internal  Back-off restarting failed container
  Warning  FailedSync             1m (x5 over 1m)   kubelet, ip-10-0-9-132.us-east-2.compute.internal  Error syncing pod
  Normal   Pulling                57s (x4 over 2m)  kubelet, ip-10-0-9-132.us-east-2.compute.internal  pulling image "nginx"

Sysdig MonitorでKubernetesのイベントを可視化する

CrashLoopBackOffイベントは、Sysdig Monitorの「Event」で確認することができます。Sysdig Monitorは、KubernetesとDockerのイベントをネイティブに取り込み、ユーザーがアラートを出したり、システムパフォーマンスのチャートに重ねて表示することができます。

Sysdigに取り込まれたKubernetesのイベント

kubernetes:
    node:
      - TerminatedAllPods       # Terminated All Pods      (information)
      - RegisteredNode          # Node Registered          (information)*
      - RemovingNode            # Removing Node            (information)*
      - DeletingNode            # Deleting Node            (information)*
      - DeletingAllPods         # Deleting All Pods        (information)
      - TerminatingEvictedPod   # Terminating Evicted Pod  (information)*
      - NodeReady               # Node Ready               (information)*
      - NodeNotReady            # Node not Ready           (information)*
      - NodeSchedulable         # Node is Schedulable      (information)*
      - NodeNotSchedulable      # Node is not Schedulable  (information)*
      - CIDRNotAvailable        # CIDR not Available       (information)*
      - CIDRAssignmentFailed    # CIDR Assignment Failed   (information)*
      - Starting                # Starting Kubelet         (information)*
      - KubeletSetupFailed      # Kubelet Setup Failed     (warning)*
      - FailedMount             # Volume Mount Failed      (warning)*
      - NodeSelectorMismatching # Node Selector Mismatch   (warning)*
      - InsufficientFreeCPU     # Insufficient Free CPU    (warning)*
      - InsufficientFreeMemory  # Insufficient Free Mem    (warning)*
      - OutOfDisk               # Out of Disk              (information)*
      - HostNetworkNotSupported # Host Ntw not Supported   (warning)*
      - NilShaper               # Undefined Shaper         (warning)*
      - Rebooted                # Node Rebooted            (warning)*
      - NodeHasSufficientDisk   # Node Has Sufficient Disk (information)*
      - NodeOutOfDisk           # Node Out of Disk Space   (information)*
      - InvalidDiskCapacity     # Invalid Disk Capacity    (warning)*
      - FreeDiskSpaceFailed     # Free Disk Space Failed   (warning)*
    pod:
      - Pulling           # Pulling Container Image          (information)
      - Pulled            # Ctr Img Pulled                   (information)
      - Failed            # Ctr Img Pull/Create/Start Fail   (warning)*
      - InspectFailed     # Ctr Img Inspect Failed           (warning)*
      - ErrImageNeverPull # Ctr Img NeverPull Policy Violate (warning)*
      - BackOff           # Back Off Ctr Start, Image Pull   (warning)
      - Created           # Container Created                (information)
      - Started           # Container Started                (information)
      - Killing           # Killing Container                (information)*
      - Unhealthy         # Container Unhealthy              (warning)
      - FailedSync        # Pod Sync Failed                  (warning)
      - FailedValidation  # Failed Pod Config Validation     (warning)
      - OutOfDisk         # Out of Disk                      (information)*
      - HostPortConflict  # Host/Port Conflict               (warning)*
    replicationController:
      - SuccessfulCreate    # Pod Created        (information)*
      - FailedCreate        # Pod Create Failed  (warning)*
      - SuccessfulDelete    # Pod Deleted        (information)*
      - FailedDelete        # Pod Delete Failed  (warning)*

カスタムイベントは、Sysdig MonitorのイベントAPIに送信して、相関やアラートにも利用できます。例えば、Jenkinsから新しいデプロイメントを実行したとき、壊れたバージョンのロールバックを行ったとき、クラウドインフラストラクチャーが変更されたときなどに、カスタムイベントを送信することができます。

Sysdig Monitorのカスタムイベントセクションでは、分散したKubernetes環境で発生したすべてのイベントのフィードを見ることができます。ここでは、タイムスタンプ、イベント名、説明、重大度、その他の詳細を見ることができます。

crashloop events

個々のイベントをクリックすると、そのイベントの詳細が表示され、インフラのどこで発生したのか、より詳細な情報が表示されます。

Kubernetes event detail
また、これらのイベントをシステムの動作と相関させることもできます。下の画像を見ると、特定のバックオフイベントがいつ発生し、それがシステムのパフォーマンスに変化をもたらしたかどうかがすぐにわかります。

compared metrics

KubernetesのCrashLoopBackOffに関するアラートの出し方

アラートを出すためには、kubernetes.pod.restart.rateというメトリクスを使います。これにより、ポッドの再起動の傾向を時系列で分析し、異常があった場合は速やかにチームに通知することができます。

Pod restart alert

お使いの環境の遅延に応じて、時間設定を切り替えてください。このアラートは、いずれかのポッドが4分間に3回以上再起動した場合に作動するように設定されており、通常はCrashLoopBackOffイベントの指標となります。このアラートは、Kubernetes環境のデフォルトアラートの1つです。

Sysdig Captureを有効にすることも、CrashLoopBackOffのトラブルシューティングには非常に重要です。Sysdigキャプチャーとは、アラートが発生した時点でシステム上で起こったことをすべて記録したものです。キャプチャーはSysdig Inspectで開くことができ、フォレンジック分析やトラブルシューティングのための詳細な分析を行うことができるため、チームはインシデントへの対応と回復を迅速に行うことができます。

同様に、Sysdigが収集したイベントに基づいてCrashLoopBackOffアラートを設定することもできます。

Kubernetes event alerts

KubernetesにおけるCrashLoopBackOffのデバッグ/トラブルシューティング/修復方法

CrashLoopBackOffが発生していると思われるホストを選択してキャプチャーを開始することで、任意のタイミングでSysdigのキャプチャーを手動で行うことができます。また、Sysdigのオープンソースがホストにインストールされていれば、手動でキャプチャーすることもできます。しかし、ここではSysdig Monitorの機能を利用して、アラート(この場合はCrashLoopBackOffのアラート)への対応として自動的にキャプチャーファイルを取得します。

トラブルシューティングの最初のアクションアイテムは、ホスト上でイベントが発生した時点で記録されたキャプチャーファイルを開くことです。

Sysdig capture file

Sysdig Monitorでキャプチャーを開くと、Sysdig Inspectのブラウザーウィンドウが表示されます。Inspectでは、より効率的な相関分析やトラブルシューティング分析のために、GUIでシステムコール分析を行うことができます。Sysdig Inspectは、当社のコンテナランタイムセキュリティ製品であるSysdig Secureで、事後分析やフォレンジックにも利用されます。

CrashLoopBackOff debug / troubleshooting
このイベントのトラブルシューティングには、Sysdig Inspectのインフラストラクチャー・カラムで発生しているすべての事象を確認します。「Docker Events」のタイルを選択すると、それらのイベントが下部のタイムラインに表示されます。

ここで何が起こっているのか、トラブルシューティングをしてみましょう。最初のステップとしては、「Container Died Events」をドリルダウンするのが良いでしょう。

CrashLoopBackOff debug Docker died
どうやら、Nginxコンテナに問題が発生しているようです。タイムスタンプを見ると、コンテナが作成されてからすぐに死んでいます。どれかのNginxコンテナを掘り下げて、左側にあるProcesssを選択してみましょう。

Nginxコンテナは「nginx」という1つのプロセスしか実行しないことがわかっているので、「Processs」から「proc.name = nginx.CrashLoopBackOff」でフィルタリングします。

CrashLoopBackOff debug crashing processes
Sysdig Inspectのフィルターは、Sysdigのオープンソース・シンタックスを使用しており、アクティビティを特定するのに利用できます。

「Errors」セクションをクリックしてみますが、システムコールの失敗など、重要なものは何も表示されません。「Files」セクションに移動して、ファイルシステムのアクティビティを調べてみましょう。そこにはerror.logファイルがあり、おそらく何らかの情報が得られるでしょう。I/O Streamsアイコンをクリックすると、ファイルシステムのI/Oアクティビティを確認できます。

CrashLoopBackOff debug access files

コンテナが停止するまでのerror.logファイルの内容から、Nginxが設定されたアップストリームサーバを解決できなかったことがわかります。Nginxが失敗した理由はわかりましたが、そのポッドに設定されていたDNSサーバーを確認することはできないのでしょうか?もちろん、resolv.confのストリームを取得して戻ってください。

CrashLoopBackOff debug error.log

CrashLoopBackOff debug resolv.conf

ここからさらに進んで、DNSリクエスト53/UDPを見てみると、応答が見つからなかったようです。NginxのReplicaSetsを先にデプロイし、上流のKubernetesサービスを後からデプロイしたことが、トラブルシューティングの手がかりとなります。Nginxには、クライアントからのリクエスト時ではなく、起動時にプロキシ名(”flask “など)をキャッシュするという特徴があります。言い換えれば、異なるKubernetesエンティティを間違った依存関係の順序でデプロイしてしまったということです。

まとめ

ポッドの再起動のようなものは簡単に見つけることができますが、本番サービスにおける潜在的な劣化への対応と迅速な回復ははるかに困難です。特に、コンテナからのログがなくなってしまった場合や、特定の環境の外で問題を再現できない場合、あるいはコンテナ内にトラブルシューティングツールがない場合などがあります。

そのため、Sysdigキャプチャーのような更なるトラブルシューティングの準備が必要となります。Sysdigキャプチャーは、コンテナの完全なコンテキストを提供し、あらゆるプロセス間通信、書き込まれたファイル、ネットワーク・アクティビティを完全に可視化します。まるでタイムマシンのように システムコール・レベルでのトラブルシューティングは難しいものですが、Sysdig Inspectを使えば簡単です。