Google Cloudとコンテナの継続的なセキュリティ
本文の内容は、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やメモリに高い要求を突きつける現在の社会が、この問題の一端を担っているのです。
この記事の中で、あなたはきっと気づくはずです:
KubernetesでPodのevictionが発生する理由はいくつかあります。最も重要なものは
Preemptionとは、新しいPodをスケジュールする必要があるが、十分なリソースを持つ適切なNodeがない場合、kube-schedulerは優先度の低いPodをいくつかevicting(終了)させることによって、新しいPodがそのNodeに属することができるかどうかをチェックすることです。
まずはKubernetesのスケジューリングがどのように機能するかを理解しましょう。
Kubernetesのスケジューリングは、Podをノードに割り当てるプロセスです。
デフォルトでは、スケジューリングを担当するKubernetesのエンティティである kube-scheduler
がコントロールプレーンで実行されています。Podはマッチするノードが見つかるまでは Pending state でスタートします。
PodをNodeに割り当てるプロセスは、次のような流れで行われます。
フィルタリングのステップでは、 kube-scheduler
が現在のPodが配置される可能性のあるすべてのノードを選択します。ここではTaintsやTolerationsのような機能が考慮されます。終了すると、そのPodに適したNodeのリストが作成されます。
スコアリングのステップでは、 kube-scheduler
は前のステップで得られたリストを取得し、各ノードにスコアを割り当てます。このようにして、候補ノードは最も適切なものから最も適切でないものへと並べられます。2つのノードが同じスコアを持っている場合、kube-schedulerはそれらをランダムに並べます。フィルタリングとスコアリングの処理
しかし、Podを実行するのに適したNodeがない場合はどうなるでしょうか?その場合、Kubernetesはpreemptionを開始し、新しいPodを割り当てるために優先度の低いPodをevictさせようとします。
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
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"
これは、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
ベリークラブにとっては不思議な時代です...。
preemptionとは別に、Kubernetesはディスクプレッシャー、CPU、OOM(Out of Memory)などのノードリソースを常にチェックしています。
ノード内のリソース(CPUやメモリなど)の消費量がある閾値に達した場合、kubelet
はリソースを解放するためにPodのevictingを開始します。退去順序の決定には、QoS(Quality of Service)が考慮されます。
Kubernetesでは、Podには3つのQoSクラスが設定されており、リソースが不足した場合にどの程度evictedさせるか、可能性が低いものから高いものまで定義されています。
QoSクラスはどのようにPodに割り当てられるのでしょうか?これは、CPUとメモリのリミットとリクエストに基づいています。備忘録として。
リミットとリクエストの詳細については、例を交えてKubernetesのリミットとリクエストを理解するをご確認ください。KubernetesのQoSクラス
以下のような、PodにはGuaranteedというQoSクラスが割り当てられます。
Guaranteed Podは、通常、ノード内の別のPodを割り当てるためにevictedされることはありません。
以下のような、PodにはBurstableというQoSクラスが割り当てられます:
Burstable Podはevictedさせられる可能性がありますが、次のカテゴリに比べるとその可能性は低くなります。
以下のような、PodにはBestEffortというQoSクラスが割り当てられます。
BestEffort Podは、ノードでノードプレッシャープロセスが発生した場合に、最も高い確率でevictionさせられます。
重要:LimitsとRequestsには、ephemeral-storageのような他の利用可能なリソースがあるかもしれませんが、それらはQoS Classの計算には使用されません。
QoSチートシート
前述のように、QoS Classはノードプレッシャーによるevictionのために考慮されます。以下は、内部で行われる処理です。
kubeletはevictedさせるPodを以下の順番でランク付けしています:
BestEffort
または Burstable
Burstable
Pods、または Guaranteed
PodsKubernetesは、グループ1からのPodをグループ2よりも先にevictさせようとします。
上記から得られるいくつかのポイント:
Guaranteed
Podは通常、evictedから安全です。 kubelet
は他のPodをスケジュールするためにそれらをevictedさせることはありません。しかし、一部のシステムサービスがより多くのリソースを必要とする場合、kubeletは必要に応じてGuaranteed
Podsを終了させます(常に最も低い優先度で)。この記事では、preemptionとnode-pressure evictionに焦点を当てましたが、Podは他の方法でもevictedさせることができます。例えば以下のようなものがあります。
Kubernetes Eviction APIを使用して、いずれかのノードにあるPodのon-demand evictionをリクエストすることができます。
KubernetesのTaintとTolerationsを使用すると、PodをNodeにどのように割り当てるべきかをガイドすることができます。しかし、既存のNodeに NoExecute
taint を適用すると、それを許容しないすべてのPodが即座にevictedさせられてしまいます。
Nodeが使えなくなったり、もう作業したくなくなったりすることがあります。kubectl cordon
コマンドはその上で新しいPodがスケジュールされるのを防ぎますが、現在のPodを一度に全て完全に空にすることも可能です。 kubectl drain nodename
を実行すると、そのノードのgraceful termination periodを尊重して、そのノード内のすべての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 Advisorを利用することで、クラスターリソースの可用性を確認し、Podのevictionを防止することができます。特徴としては、:
Sysdig Advisorは、ライブログ、パフォーマンスデータ、推奨される改善策によって、平均解決時間(MTTR)を短縮します。Kubernetesのトラブルシューティングのための簡単にする仕組みです!
30日間無料でお試しください!