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"
コメント