一覧CL-11-2 · Kubernetesの状態管理

Podの配置条件とCPU・メモリ上限

Pendingの配置失敗と、起動後のCPU・メモリ制限を別の段階として説明します。

説明

Podをどのノードへ置けるかは、CPUやメモリのrequestsなどを使って判断されます。limitsは配置後の実行にかかる上限です。CPUの100mは0.1 CPU、メモリの32Miは33554432バイトを表します。

1台のノードに対して、配置できないCPU要求を持つPodを作ります。要求量を減らして起動した後、コンテナ内のcgroup設定を読み、配置条件と実行上限を照合します。

Pendingの配置失敗と、起動後のCPU・メモリ制限を別の段階として説明します。

1ノードの割当可能量

allocatableはPodへ割り当てられる量です。瞬間のCPU使用率ではありません。

kubectl get node lbox-cl11-control-planeノードの割当可能なCPUとメモリを読む -o jsonpath='{.status.allocatable.cpu}{" CPU\n"}{.status.allocatable.memory}{" memory\n"}'

ここに出るCPU数より大きいrequestsを設定すると、他のPodが動いていなくても配置できません。

2過大なCPU要求を作る

PodのCPU要求を100000 CPUにします。このノードには収まりません。limitsも同じ値にして、requestsがlimitsを超える形式エラーとは分けます。

python3 -cCPU要求が過大なPod定義を作る 'import json; d=json.load(open("deployment.json")); p={"apiVersion":"v1","kind":"Pod","metadata":{"name":"work","labels":{"app":"web"}},"spec":d["spec"]["template"]["spec"]}; r=p["spec"]["containers"][0]["resources"]; r["requests"]["cpu"]="100000"; r["limits"]["cpu"]="100000"; open("pod.json","w").write(json.dumps(p))' kubectl apply -f pod.jsonPodの定義を登録する

定義は受け付けられます。受付時の形式検査と、schedulerが配置先を見つけられるかは別です。

3配置失敗の条件

PodScheduled=Falseになるまで待ち、APIの状態を読みます。

kubectl wait配置条件の判定を待つ --for=condition=PodScheduled=false pod/work --timeout=30s > /dev/null python3 observe.py pending状態と実際のCPU要求を表示する

Pending、scheduled=False、reason=Unschedulableです。コンテナが起動してメモリ不足になった状態ではなく、ノードへ配置する前で止まっています。 APIの100kは100000 CPUを表す数量表記です。

4要求量と上限を下げる

この例ではPodを作り直します。requestsを10m、CPU上限を100mへ下げます。

kubectl delete pod work配置できなかったPodを削除する --wait=true > /dev/null python3 -c要求量10m・上限100mへ直す 'import json; p="pod.json"; d=json.load(open(p)); r=d["spec"]["containers"][0]["resources"]; r["requests"]["cpu"]="10m"; r["limits"]["cpu"]="100m"; open(p,"w").write(json.dumps(d))' kubectl apply -f pod.json修正したPodを作る python3 observe.py wait 1 1 0起動後のReadyを確認する

今度は1個のPodがReadyになります。requestsを満たせるノードがあり、コンテナを起動できました。

5宣言された制限を読む

起動したPodのAPIに保存されたresourcesを確認します。

kubectl get pod work起動したPodのresourcesを読む -o jsonpath='{.spec.containers[0].resources}{"\n"}'

CPU要求は10m、上限は100mです。メモリ要求は8Mi、上限は32Miで、配置の予約量と実行上限に差があります。

6CPUの実行枠を確認する

cgroup v2のcpu.maxにはquotaとperiodがマイクロ秒で入ります。

kubectl exec work -- cat /sys/fs/cgroup/cpu.maxカーネルへ渡されたCPU上限を読む

10000 / 100000 = 0.1 CPUです。この期間内で使えるCPU時間の上限であり、CPUを常に10%使う命令ではありません。

7メモリ使用量の上限を確認する

memory.maxを読み、32Miの換算値と照合します。

kubectl exec work -- cat /sys/fs/cgroup/memory.maxカーネルのメモリ上限を読む python3 -c32Miをバイト数へ換算する 'print(32 * 1024 * 1024)'

どちらも33554432です。上限に達した際のメモリ回収やOOM処理は、配置前のrequests判定とは異なります。

まとめ

requestsは配置の判断に使われ、現在の使用率とは異なります。

CPUとメモリのlimitsは実行時の上限です。

この演習ではcgroupの設定値を照合し、OOM発生そのものは扱っていません。

操作履歴と解説を振り返れます。

Kubernetes 1.37.0 / kind 0.33.0 / Linux arm64

1
kubectl get node lbox-cl11-control-plane -o jsonpath='{.status.allocatable.cpu}{" CPU\n"}{.status.allocatable.memory}{" memory\n"}'
14 CPU
8124000Ki memory
2
python3 -c 'import json; d=json.load(open("deployment.json")); p={"apiVersion":"v1","kind":"Pod","metadata":{"name":"work","labels":{"app":"web"}},"spec":d["spec"]["template"]["spec"]}; r=p["spec"]["containers"][0]["resources"]; r["requests"]["cpu"]="100000"; r["limits"]["cpu"]="100000"; open("pod.json","w").write(json.dumps(p))' kubectl apply -f pod.json
pod/work created
3
kubectl wait --for=condition=PodScheduled=false pod/work --timeout=30s > /dev/null python3 observe.py pending
phase=Pending scheduled=False reason=Unschedulable
cpu_request=100k
4
kubectl delete pod work --wait=true > /dev/null python3 -c 'import json; p="pod.json"; d=json.load(open(p)); r=d["spec"]["containers"][0]["resources"]; r["requests"]["cpu"]="10m"; r["limits"]["cpu"]="100m"; open(p,"w").write(json.dumps(d))' kubectl apply -f pod.json python3 observe.py wait 1 1 0
pod/work created
pods=1 ready=1 restarts=0
5
kubectl get pod work -o jsonpath='{.spec.containers[0].resources}{"\n"}'
{"limits":{"cpu":"100m","memory":"32Mi"},"requests":{"cpu":"10m","memory":"8Mi"}}
6
kubectl exec work -- cat /sys/fs/cgroup/cpu.max
10000 100000
7
kubectl exec work -- cat /sys/fs/cgroup/memory.max python3 -c 'print(32 * 1024 * 1024)'
33554432
33554432

演習完了