k8s CPU Management Policies

## はじめに

k8sのCPU Managerの挙動を確認した内容を記載する

## CPU Management Policiesとは

- 通常PodはHost上のCPUを共有して利用するが、CPU Management Policiesを使うことで、PodにCPUを占有させることができる
- Kubernetes v1.26からStableに昇格
    - https://github.com/kubernetes/enhancements/issues/3570

https://kubernetes.io/docs/tasks/administer-cluster/cpu-management-policies/

## CPU Management Policies(静的ポリシー)を使用するには

1. kubeletに以下の設定を追加する
    - feature-gates="CPUManager=true"
    - cpu-manager-policy="static"
    - kube-reserved="cpu=500m"

2. Podに以下を指定する
    - QoS classをGuaranteed requestsにすること
    - requests, limitsのCPU指定を整数値を使用すること

**参考**
- https://kubernetes.io/docs/tasks/administer-cluster/cpu-management-policies/#configuration
- https://kubernetes.io/docs/tasks/administer-cluster/cpu-management-policies/#static-policy
- https://github.com/kubernetes/examples/blob/master/staging/cpu-manager/README.md


## 動作確認

### 事前準備 - k8s clusterの構築

minikubeを使用した。インストールは下記を参照

https://qiita.com/n4k4y05h1/items/abff8c110e500ae47437

### 設定 - kubeletの設定変更

minikube起動時に`--extra-config`オプションでkubletの設定を変更する。

```shell: 実行結果
ubuntu@ubuntu:~$ minikube start --cpus=4 --memory='4g' \
  --extra-config=kubelet.feature-gates="CPUManager=true" \
  --extra-config=kubelet.cpu-manager-policy="static" \
  --extra-config=kubelet.cpu-manager-reconcile-period="5s" \
  --extra-config=kubelet.kube-reserved="cpu=500m"
😄  minikube v1.33.0 on Ubuntu 24.04 (vbox/amd64)
✨  Automatically selected the docker driver
📌  Using Docker driver with root privileges
👍  Starting "minikube" primary control-plane node in "minikube" cluster
🚜  Pulling base image v0.0.43 ...
🔥  Creating docker container (CPUs=4, Memory=4096MB) ...
🐳  Preparing Kubernetes v1.30.0 on Docker 26.0.1 ...
    ▪ kubelet.feature-gates=CPUManager=true
    ▪ kubelet.cpu-manager-policy=static
    ▪ kubelet.cpu-manager-reconcile-period=5s
    ▪ kubelet.kube-reserved=cpu=500m
    ▪ Generating certificates and keys ...
    ▪ Booting up control plane ...
    ▪ Configuring RBAC rules ...
🔗  Configuring bridge CNI (Container Networking Interface) ...
🔎  Verifying Kubernetes components...
    ▪ Using image gcr.io/k8s-minikube/storage-provisioner:v5
🌟  Enabled addons: default-storageclass, storage-provisioner
💡  kubectl not found. If you need it, try: 'minikube kubectl -- get pods -A'
🏄  Done! kubectl is now configured to use "minikube" cluster and "default" namespace by default
ubuntu@ubuntu:~$ 
```

### テスト1 - Guaranteed Podのデプロイ

Guaranteed、かつ、CPU指定を整数にしたmanifestファイルを作成し、Applyする。

Podのコア割当を確認するためcpuset.cpusを確認する。
minikubeに4coreあり、そのうちcore1が割り当てられていた。

```shell: 実行結果
ubuntu@ubuntu:~$ kubectl apply -f qos-guaranteed-pod.yaml
pod/qos-guaranteed-pod created
ubuntu@ubuntu:~$ 
ubuntu@ubuntu:~$ kubectl get pod -o custom-columns="NAME:{.metadata.name},QoS Class:{.status.qosClass}"
NAME                 QoS Class
qos-guaranteed-pod   Guaranteed
ubuntu@ubuntu:~$
ubuntu@ubuntu:~$ kubectl exec -ti qos-guaranteed-pod -- bash -c 'cat /sys/fs/cgroup/cpuset.cpus'
1
ubuntu@ubuntu:~$ 
```

<details><summary>qos-guaranteed-pod.yaml</summary>

```yaml: qos-guaranteed-pod.yaml
apiVersion: v1
kind: Pod
metadata:
  name: qos-guaranteed-pod
spec:
  containers:
  - name: nginx
    image: nginx
    resources:
      requests:
        cpu: 1
        memory: "64Mi"
      limits:
        cpu: 1
        memory: "64Mi"
```
</details>

### テスト2 - Besteffort Podのデプロイ

Besteffort Podをデプロイすると、Hostに割り当てた全コア見えている

```shell: 実行結果
ubuntu@ubuntu:~$ kubectl apply -f qos-besteffort.yaml
pod/qos-besteffort-pod created
ubuntu@ubuntu:~$ 
ubuntu@ubuntu:~$ kubectl get pod -o custom-columns="NAME:{.metadata.name},QoS Class:{.status.qosClass}"
NAME                 QoS Class
qos-besteffort-pod   BestEffort
ubuntu@ubuntu:~$ 
ubuntu@ubuntu:~$ kubectl exec -ti qos-besteffort-pod -- bash -c 'cat /sys/fs/cgroup/cpuset.cpus'
0-3
ubuntu@ubuntu:~$ 
```

<details><summary>qos-besteffort-pod.yaml</summary>

```yaml: qos-besteffort-pod.yaml
apiVersion: v1
kind: Pod
metadata:
  name: qos-besteffort-pod
spec:
  containers:
  - name: nginx
    image: nginx
```
</details>

### テスト3 - Burstable Podのデプロイ

Burstable Podをデプロイすると、Hostに割り当てた全コア見えている

```shell: 実行結果
ubuntu@ubuntu:~$ kubectl apply -f qos-burstable.yaml
pod/qos-burstable-pod created
ubuntu@ubuntu:~$ 
ubuntu@ubuntu:~$ kubectl get pod -o custom-columns="NAME:{.metadata.name},QoS Class:{.status.qosClass}"
NAME                QoS Class
qos-burstable-pod   Burstable
ubuntu@ubuntu:~$ 
ubuntu@ubuntu:~$ kubectl exec -ti qos-burstable-pod -- bash -c 'cat /sys/fs/cgroup/cpuset.cpus'
0-3
ubuntu@ubuntu:~$ 
```

<details><summary>qos-burstable-pod.yaml</summary>

```yaml: qos-burstable-pod.yaml
apiVersion: v1
kind: Pod
metadata:
  name: qos-burstable-pod
spec:
  containers:
  - name: nginx
    image: nginx
    resources:
      requests:
        cpu: 1
        memory: "64Mi"
```
</details>


### テスト4 - Guaranteed Podのデプロイ(cpu-manager-policy=noneの場合)

static policyをOFFにしてguaranteed Podをデプロイすると、割り当ては空になっていた。
burstableやbesteffortでも同様だった。

```shell: 実行結果
ubuntu@ubuntu:~$ minikube start --cpus=4 --memory='4g' \
  --extra-config=kubelet.feature-gates="CPUManager=true" \
  --extra-config=kubelet.cpu-manager-policy="none" \
  --extra-config=kubelet.cpu-manager-reconcile-period="5s" \
  --extra-config=kubelet.kube-reserved="cpu=500m"
😄  minikube v1.33.0 on Ubuntu 24.04 (vbox/amd64)
✨  Automatically selected the docker driver
📌  Using Docker driver with root privileges
👍  Starting "minikube" primary control-plane node in "minikube" cluster
🚜  Pulling base image v0.0.43 ...
🔥  Creating docker container (CPUs=4, Memory=4096MB) ...
🐳  Preparing Kubernetes v1.30.0 on Docker 26.0.1 ...
    ▪ kubelet.feature-gates=CPUManager=true
    ▪ kubelet.cpu-manager-policy=none
    ▪ kubelet.cpu-manager-reconcile-period=5s
    ▪ kubelet.kube-reserved=cpu=500m
    ▪ Generating certificates and keys ...
    ▪ Booting up control plane ...
    ▪ Configuring RBAC rules ...
🔗  Configuring bridge CNI (Container Networking Interface) ...
🔎  Verifying Kubernetes components...
    ▪ Using image gcr.io/k8s-minikube/storage-provisioner:v5
🌟  Enabled addons: default-storageclass, storage-provisioner
💡  kubectl not found. If you need it, try: 'minikube kubectl -- get pods -A'
🏄  Done! kubectl is now configured to use "minikube" cluster and "default" namespace by default
ubuntu@ubuntu:~$ 
ubuntu@ubuntu:~$ kubectl apply -f qos-guaranteed.yaml
pod/qos-guaranteed-pod created
ubuntu@ubuntu:~$ 
ubuntu@ubuntu:~$ kubectl get pod -o custom-columns="NAME:{.metadata.name},QoS Class:{.status.qosClass}"
NAME                 QoS Class
qos-guaranteed-pod   Guaranteed
ubuntu@ubuntu:~$ 
ubuntu@ubuntu:~$ kubectl exec -ti qos-guaranteed-pod -- bash -c 'cat /sys/fs/cgroup/cpuset.cpus'

ubuntu@ubuntu:~$
```


### テスト結果

今回確認した一覧は以下。

| # | cpu-manager-policy | Pod QoS Class | Pod内の/sys/fs/cgroup/cpuset.cpus |
|:-:|:-:|:-:|:-:|
| 1 | static | Guaranteed | 1(要求したコア数) |
| 2 | static | Burstable  | 0-3(Hostの全コア) |
| 3 | static | Besteffort | 0-3(Hostの全コア) |
| 4 | none   | Guaranteed | <空> |
| 5 | none   | Burstable  | <空> |
| 6 | none | Besteffort | <空> |