本文の内容は、2022年9月20日にJavier Martínezが投稿したブログ(https://sysdig.com/blog/kubernetes-pod-evicted/)を元に日本語に翻訳・再構成した内容となっております。
KubernetesのPodがevictedされるとはどういうことでしょうか?通常は十分なリソースがないために終了させられます。しかし、なぜこのようなことが起こるのでしょうか?
Evictionとは、あるNodeに割り当てられたPodに終了を要求するプロセスです。Kubernetesで最も一般的なケースはPreemptionで、リソースが限られているNodeに新しいPodをスケジュールするために、他のPodを終了させて最初のPodにリソースを残す必要があるのです。
また、Kubernetesは常にリソースをチェックし、必要に応じてPodを退去させますが、これはNode-pressure evictionと呼ばれる処理です。
毎日、何千ものPodが家から追い出されています。立ち往生し、混乱した彼らは、それまでのライフスタイルを捨てなければならないでしょう。なかには、うなだれる人さえいます。CPUやメモリに高い要求を突きつける現在の社会が、この問題の一端を担っているのです。
この記事の中で、あなたはきっと気づくはずです:
- Podがevictedされる理由: PreemptionとNode-pressure
- Preemption eviction
- Pod Priority Classes
- Node-pressure eviction
- Quality of Service Classes
- その他のevictionタイプ
- PrometheusでKubernetesのPod evictionを監視する
Podがevictedされる理由: PreemptionとNode-pressure
KubernetesでPodのevictionが発生する理由はいくつかあります。最も重要なものは- Preemption
- Node-pressure eviction
Preemption eviction
Preemptionとは、新しいPodをスケジュールする必要があるが、十分なリソースを持つ適切なNodeがない場合、kube-schedulerは優先度の低いPodをいくつかevicting(終了)させることによって、新しいPodがそのNodeに属することができるかどうかをチェックすることです。まずはKubernetesのスケジューリングがどのように機能するかを理解しましょう。
Podのスケジューリング
Kubernetesのスケジューリングは、Podをノードに割り当てるプロセスです。デフォルトでは、スケジューリングを担当するKubernetesのエンティティである
kube-scheduler
がコントロールプレーンで実行されています。Podはマッチするノードが見つかるまでは Pending state でスタートします。PodをNodeに割り当てるプロセスは、次のような流れで行われます。
- Filtering
- Scoring
Filtering
フィルタリングのステップでは、kube-scheduler
が現在のPodが配置される可能性のあるすべてのノードを選択します。ここではTaintsやTolerationsのような機能が考慮されます。終了すると、そのPodに適したNodeのリストが作成されます。Scoring
スコアリングのステップでは、kube-scheduler
は前のステップで得られたリストを取得し、各ノードにスコアを割り当てます。このようにして、候補ノードは最も適切なものから最も適切でないものへと並べられます。2つのノードが同じスコアを持っている場合、kube-schedulerはそれらをランダムに並べます。フィルタリングとスコアリングの処理
しかし、Podを実行するのに適したNodeがない場合はどうなるでしょうか?その場合、Kubernetesはpreemptionを開始し、新しいPodを割り当てるために優先度の低いPodをevictさせようとします。
Pod Priority Classes
preemption処理の際に、特定のPodがevictedされないようにするにはどうしたらいいのでしょうか?おそらく、特定のPodはあなたにとって重要であり、決して終了させるべきではないでしょう。そのため、KubernetesはPriority Classを備えています。
Priority ClassはKubernetesのオブジェクトで、特定のPodに優先度の数値を対応させることができます。値が大きいものほど重要度が高く、evictedされる可能性が低いと分類されます。
現在のPriority Classは、以下のようにしてクエリーすることができます:
kubectl get priorityclasses kubectl get pc NAME VALUE GLOBAL-DEFAULT AGE system-cluster-critical 2000000000 false 2d system-node-critical 2000001000 false 2d
Priority Classの例
Lovenstein氏の漫画Berry Club comic を使って実例をやってみましょう。ブルーベリー、ラズベリー、ストロベリーを表す3つのPodがあります:
NAME READY STATUS RESTARTS AGE blueberry 1/1 Running 0 4h41m raspberry 1/1 Running 0 58m strawberry 1/1 Running 0 5h22m
そして、Priority Classはtrueberryとfalseberryの2つがあります。前者は値が高いほど優先度が高いことを示します。
apiVersion: scheduling.k8s.io/v1 kind: PriorityClass metadata: name: trueberry value: 1000000 globalDefault: false description: "This fruit is a true berry" apiVersion: scheduling.k8s.io/v1 kind: PriorityClass metadata: name: falseberry value: 5000 globalDefault: false description: "This fruit is a false berry"
- ブルーベリーは、trueberry priority class (value = 1000000) を持つようになります。
- ラズベリーとストロベリーは両方とも falseberry priority class (value = 5000) を持ちます。
これは、preemption が発生した場合、ラズベリーとストロベリーはより高い優先順位のPodのためにevictedさせられる可能性が高いということを意味します。
次に、Podの定義に次のように追加して、PodにPriority Classesを割り当てます。
priorityClassName: trueberry
では、さらに3つのフルーツを追加してみましょう。新しいフルーツはすべて、
trueberry
という高いPriority Classを含んでいます。新しい3つのフルーツは、ノードが満たせないメモリやCPUを必要とするため、
kubelet
は新しいフルーツよりも低い優先順位のPodをすべてevictsさせます。ブルーベリーは優先順位が高いため、そのまま実行されます。NAME READY STATUS RESTARTS AGE banana 0/1 ContainerCreating 0 2s blueberry 1/1 Running 0 4h42m raspberry 0/1 Terminating 0 59m strawberry 0/1 Terminating 0 5h23m tomato 0/1 ContainerCreating 0 2s watermelon 0/1 ContainerCreating 0 2s
Kubernetesのプライオリティクラス – 実例
これが最終的な結果です:
NAME READY STATUS RESTARTS AGE banana 1/1 Running 0 3s blueberry 1/1 Running 0 4h43m tomato 1/1 Running 0 3s watermelon 1/1 Running 0 3s
ベリークラブにとっては不思議な時代です…。
Node-pressure eviction
preemptionとは別に、Kubernetesはディスクプレッシャー、CPU、OOM(Out of Memory)などのノードリソースを常にチェックしています。ノード内のリソース(CPUやメモリなど)の消費量がある閾値に達した場合、
kubelet
はリソースを解放するためにPodのevictingを開始します。退去順序の決定には、QoS(Quality of Service)が考慮されます。Quality of Service Classes
Kubernetesでは、Podには3つのQoSクラスが設定されており、リソースが不足した場合にどの程度evictedさせるか、可能性が低いものから高いものまで定義されています。- Guaranteed
- Burstable
- BestEffort
QoSクラスはどのようにPodに割り当てられるのでしょうか?これは、CPUとメモリのリミットとリクエストに基づいています。備忘録として。
- Limits:コンテナが使用できるリソースの最大量。
- Requests:コンテナが実行するために必要な最小限のリソース量。
KubernetesのQoSクラス
Guaranteed
以下のような、PodにはGuaranteedというQoSクラスが割り当てられます。- Pod内のすべてのコンテナには、CPUとメモリに対してLimitsとRequestsの両方が設定されています。
- Pod内のすべてのコンテナで、CPU LimitとCPU Requestが同じ値になっています。
- Pod内のすべてのコンテナで、メモリLimitとメモリRequestが同じ値になっている。
Guaranteed Podは、通常、ノード内の別のPodを割り当てるためにevictedされることはありません。
Burstable
以下のような、PodにはBurstableというQoSクラスが割り当てられます:- QoS ClassがGuaranteedでない場合。
- Pod内のコンテナに対してLimitsまたはRequestが設定されている。
Burstable Podはevictedさせられる可能性がありますが、次のカテゴリに比べるとその可能性は低くなります。
BestEffort
以下のような、PodにはBestEffortというQoSクラスが割り当てられます。- Pod内のどのコンテナにもLimitsとRequestsが設定されていない場合。
BestEffort Podは、ノードでノードプレッシャープロセスが発生した場合に、最も高い確率でevictionさせられます。
重要:LimitsとRequestsには、ephemeral-storageのような他の利用可能なリソースがあるかもしれませんが、それらはQoS Classの計算には使用されません。
前述のように、QoS Classはノードプレッシャーによるevictionのために考慮されます。以下は、内部で行われる処理です。
kubeletはevictedさせるPodを以下の順番でランク付けしています:
- 使用量がリクエストを上回っている
BestEffort
またはBurstable
- 使用量がリクエストを下回っている
Burstable
Pods、またはGuaranteed
Pods
上記から得られるいくつかのポイント:
- コンテナ内に非常に低いリクエストを追加した場合、そのPodはグループ1が割り当てられる可能性が高く、つまりevictedされる可能性が高くなります。
- どのPodがevictedされるかはわかりませんが、Kubernetesはグループ2の前にグループ1のPodをevictedさせようとします。
Guaranteed
Podは通常、evictedから安全です。kubelet
は他のPodをスケジュールするためにそれらをevictedさせることはありません。しかし、一部のシステムサービスがより多くのリソースを必要とする場合、kubeletは必要に応じてGuaranteed
Podsを終了させます(常に最も低い優先度で)。
その他のevictionの種類
この記事では、preemptionとnode-pressure evictionに焦点を当てましたが、Podは他の方法でもevictedさせることができます。例えば以下のようなものがあります。API-initiated eviction
Kubernetes Eviction APIを使用して、いずれかのノードにあるPodのon-demand evictionをリクエストすることができます。Taint-based eviction
KubernetesのTaintとTolerationsを使用すると、PodをNodeにどのように割り当てるべきかをガイドすることができます。しかし、既存のNodeにNoExecute
taint を適用すると、それを許容しないすべてのPodが即座にevictedさせられてしまいます。Node drain
Nodeが使えなくなったり、もう作業したくなくなったりすることがあります。kubectl cordon
コマンドはその上で新しいPodがスケジュールされるのを防ぎますが、現在のPodを一度に全て完全に空にすることも可能です。 kubectl drain nodename
を実行すると、そのノードのgraceful termination periodを尊重して、そのノード内のすべてのPodがevictionされます。PrometheusでKubernetesのPod evictionを監視する
クラウドソリューションでは、Prometheusを使用して、Podのevictionsを簡単に監視することができます:kube_pod_status_reason{reason="Evicted"} > 0
PrometheusでEvicted Podsを監視する
これは、クラスター内のすべてのEvicted Podを表示します。また、
kube_pod_status_phase{phase="Failed"}
と組み合わせることで、Podに障害が発生した後にevictedされたものに対してアラートを出すことも可能です。さらに深く掘り下げたい方は、Prometheusでリソースを監視するための以下の記事もご確認ください。
まとめ
ご覧の通り、evictionは、限られたリソース(この場合はPodが使用するノード)を制御できるKubernetesの機能のひとつです。preemptionの間、Kubernetesは新しいものをスケジュールするために優先度の低いPodをevictingさせることによって、リソースを解放しようとします。Priority Classesを使えば、どのPodがpreemption後も実行され続ける可能性が高いかを制御することができます。
実行中、Kubernetesは、Node-pressureをチェックし、必要であればPodをevictedさせます。QoSクラスを使用すると、Node-pressureが発生した場合にどのPodがevictedされやすいかを制御できます。
メモリとCPUはノードの重要なリソースであり、Pod、コンテナ、ノードが適切な量を使用するように設定する必要があります。これらのリソースを適切に管理すれば、コスト面でのメリットだけでなく、重要なプロセスをどのような状況でも稼働させ続けることができる可能性があります。
Sysdig MonitorでPod evictionに先手を打つ
Sysdig Advisorを利用することで、クラスターリソースの可用性を確認し、Podのevictionを防止することができます。特徴としては、:- クラスターキャパシティ管理
- 潜在的なキャパシティの問題を優先的に表示
- ワークロードの適切なサイジングのガイド
Sysdig Advisorは、ライブログ、パフォーマンスデータ、推奨される改善策によって、平均解決時間(MTTR)を短縮します。Kubernetesのトラブルシューティングのための簡単にする仕組みです!
30日間無料でお試しください!
AWS MarketplaceでSysdig Secure DevOps Platformをご購入ください!
Sysdigは、AWS Marketplaceで簡単にご購入いただくことができます。