Kubernetesのリソース管理の調査方法
- 消えてほしくないPodが
evictedで強制終了させられている - 特定のpodを安定してノード上で稼働させたい
- k8sにpodが動的にアサインされる予定だが、どのように管理されるか分からない
皆さんこんなご経験はないでしょうか
私はKEDAを用いたイベントドリブンなk8sクラスター運用を行った際に上記のような現象や不安に遭いました。
その際に行った対応を備忘録を兼ねて残します。
k8sのリソース管理について
最初にk8sのリソース管理の仕組みについて説明します。
resouces
k8sではコンテナ単位で使用するメモリ、CPUに制限を設けることができます。
メモリが超過した場合、OOM(Out of Memory)エラーが発生し、コンテナが強制終了されます。
CPUが超過した場合スロットリング(制限)され、処理が遅くなります。
nginxのレプリカセットを作成するymlを例に挙げますが、manifestにおけるリソース指定は以下のようにresoucesで行います。
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
labels:
app: nginx
spec:
replicas: 3
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:latest
resources:
requests:
cpu: "250m" # 最低250m(0.25CPU)を保証
memory: "256Mi" # 最低256MiBのメモリを保証
limits:
cpu: "500m" # 最大500m(0.5CPU)まで使用可能
memory: "512Mi" # 最大512MiBのメモリまで使用可能
ports:
- containerPort: 80
この例の場合、最低0.25CPU256MiBのメモリを割り当てられ、アクセス負荷によっては0.5CPU512MiBまで利用できる、ということになります。
PriorityClass
ポッドを割り当てるリソースがノードにない場合、k8sはどのようになるでしょう?
この時k8sはPriorityClassとQoSClassという2つのクラスによる辞書式順序を用いてPodを削除することでリソースを管理します。
PriorityClassを確認し劣後するPodを削除、もし全てのPriorityClassが等しい場合はQoSClassを確認して劣後するPodを削除、といった具合です。
PriorityClassは以下のようにリソースとして定義します。
apiVersion: scheduling.k8s.io/v1
kind: PriorityClass
metadata:
name: high-priority
value: 100000 # 優先度のスコア(高いほど優先)
preemptionPolicy: PreemptLowerPriority # 低優先度ポッドを退避させる
globalDefault: false
description: "High priority class for critical workloads"
premptionPolicyは低優先Podをどのように扱うかを定義するエリアで、低優先Podを削除するPreemptLowerPriority、削除しないNeverがあります。
作成したクラスにPodをアサインすることで、優先順位をつけることができます。
apiVersion: v1
kind: Pod
metadata:
name: high-priority-pod
spec:
priorityClassName: high-priority # 先ほど作成したPriorityClassを指定
containers:
- name: nginx
image: nginx
resources:
requests:
memory: "256Mi"
cpu: "250m"
limits:
memory: "512Mi"
cpu: "500m"
QoS
参考:https://kubernetes.io/docs/concepts/workloads/pods/pod-qos/
k8sはQuality of Service (QoS)という概念を持っており、これによって全てのポッドはBestEffort, Burstable, Guranteedの3種類に分類されています。
PriorityClassが等しいとき、k8sはQoSに従って削除するPodを決定します。
BestEffort
最も優先度の低いクラスがBestEffortです。(名前の通りですね)
ノードがリソース不足でPodを整理する必要がある場合、真っ先に削除されます。
ポッドがBestEffortになる基準は以下です。
- どのコンテナも
resourceの定義を持たない
基本的にBestEffortにするのはログのクリーンナップなど、いつでもいいから空いているときに行ってほしい作業に限ります。
Guaranteed
BestEffortと反対に最も優先度の高いクラスがGuranteedになります。
このクラスは他の2つのクラスよりも優先的にノードに配置され、リソースが不足した場合は他のクラスを追い出します。
PodがGuranteedに分類されるためにはCPU・メモリそれぞれについて以下を満たす必要があります。
- ポッド内のすべてのコンテナに、
requestsとlimitが定義されている - ポッド内のすべてのコンテナそれぞれについて、
requestsとlimitが等しい
CPUもメモリもあらかじめ決められた量で利用するということですね。
Burstable
残った中間層がBurstableになります。Podとしてのスケール能力を残しつつ最低限の動作保証を行いたい場合はこのクラスにアサインされるようにします。
Burstableに分類される条件はBestEffortでもGuranteedでもないことですが、書き下すと以下になります。
Guranteedの基準を満たさない- 少なくとも1つのコンテナにメモリかCPUの
requestかlimitが定義されている。
逆引き辞典
k8sのポッドの消費リソースを確認したい
kubectl topコマンドでリソースの確認が行えます。
kubectl top pod
# >>>
# NAME CPU(cores) MEMORY(bytes)
# nginx-deployment-abc123 50m 20Mi
# nginx-deployment-def456 70m 30Mi
# backend-app-xyz789 200m 150Mi
これは実際の消費量に基づくため、resourceで1000m割り当てたからと言って1000mと表示されはしません。
Podと同様にNodeのリソース使用量は以下で確認できます。
kubectl top node
デプロイされているPodがどのQoSに属しているかを確認したい
kubectl describeで詳細情報を取得することで確認できます。
kubectl describe pod <ポッド名> | grep QoS
ちなみにVSCode拡張機能のKubernetesからリソースを右クリック->describeでも簡単に確認できます。メトリック計測などは難しいですが、k8sの簡易GUIとして重宝します。

特定のポッドを優先的にノードに配置したい
確実なのはPriorityの高いクラスに配置することです。業務最優先のPodはまず高PriorityClassに所属されることを考えます。
apiVersion: v1
kind: Pod
metadata:
name: high-priority-pod
spec:
priorityClassName: high-priority # 先ほど作成したPriorityClassを指定
containers:
- name: nginx
image: nginx
resources:
requests:
memory: "256Mi"
cpu: "250m"
limits:
memory: "512Mi"
cpu: "500m"


コメント