[Kubernetes]リソース制御の動作を確認する 2


はじめに

前回はリソース制御の基本的な動作を確認しました。
今回は前回に続いて、こういう場合はどうなるんだろう?ということを実際に確認してみたいと思います。
なお、今回はCPUだけに絞って検証していきます。

リソース不足の場合

今回の検証環境のworkerノードは2vCPU(2000m)搭載しています。
ここにNginxとRedis 2つのコンテナを持つPodをデプロイしますが、requestsとlimitsを以下の図のように設定します。
requests(下限)の合計が2200mとなり、workerノードのリソースを超えています。

このPodをデプロイします。マニフェストは前回と同様で、requestsとlimitsの値が異なるだけです。

$ kubectl apply -f nginx_redis-quota.yaml
deployment.apps/resource-quota created
$ kubectl get pod
NAME                                 READY   STATUS    RESTARTS   AGE
no-resource-quota-77d577889b-2lsck   2/2     Running   0          45s
no-resource-quota-77d577889b-mlgvr   2/2     Running   0          46s
resource-quota-6bfdcb475d-5hqn5      0/2     Pending   0          9s
resource-quota-6bfdcb475d-fjk29      0/2     Pending   0          9s

PodがPendingとなりました。詳細を確認します。

$ kubectl describe pod resource-quota-6bfdcb475d-5hqn5
Name:           resource-quota-6bfdcb475d-5hqn5
・・・
Events:
  Type     Reason            Age                From               Message
  ----     ------            ----               ----               -------
  Warning  FailedScheduling  36s (x2 over 36s)  default-scheduler  0/3 nodes are available: 3 Insufficient cpu.

CPUが足りなくてスケジューリングできていませんね。
前回確認した結果だとrequestsの値は、無負荷状態では確保されていなかったですが、requestsの合計値がノードのvCPUを超えるとスケジューリングできないようですね。

リソース競合の場合

requestsとlimitsの値を変更して、「requestsの合計 < vCPU < limitsの合計」としました。

$ kubectl apply -f nginx_redis-quota.yaml
deployment.apps/resource-quota configured
$ kubectl get pod
NAME                                 READY   STATUS    RESTARTS   AGE
no-resource-quota-77d577889b-2lsck   2/2     Running   0          32m
no-resource-quota-77d577889b-mlgvr   2/2     Running   0          32m
resource-quota-7549bdf4df-845dw      2/2     Running   0          19s
resource-quota-7549bdf4df-r9rc6      2/2     Running   0          10s

設定値を確認しておきます。

$ kubectl describe node k8s-worker01
Name:               k8s-worker01
・・・
Non-terminated Pods:          (5 in total)
  Namespace                   Name                                  CPU Requests  CPU Limits    Memory Requests  Memory Limits  AGE
  ---------                   ----                                  ------------  ----------    ---------------  -------------  ---
  default                     no-resource-quota-77d577889b-mlgvr    0 (0%)        0 (0%)        0 (0%)           0 (0%)         40m
  default                     resource-quota-7549bdf4df-845dw       1500m (75%)   2500m (125%)  300Mi (10%)      500Mi (18%)    8m24s
  kube-system                 calico-node-cgdgk                     250m (12%)    0 (0%)        0 (0%)           0 (0%)         80d
  kube-system                 kube-proxy-gqt42                      0 (0%)        0 (0%)        0 (0%)           0 (0%)         80d
  metallb-system              speaker-scqps                         100m (5%)     100m (5%)     100Mi (3%)       100Mi (3%)     36d
Allocated resources:
  (Total limits may be over 100 percent, i.e., overcommitted.)
  Resource           Requests     Limits
  --------           --------     ------
  cpu                1850m (92%)  2600m (130%)
  memory             400Mi (14%)  600Mi (21%)
  ephemeral-storage  0 (0%)       0 (0%)

Requestsの設定値は92%ですが、Limitsは130%とvCPUの値を超えていますね。

動作確認

各コンテナにログインして、CPUに負荷をかけてCPUの使用率を確認します。
ただ、Pod単位でしか負荷がわからないので、Podを作り直すことにしました。以下のように1Pod/1コンテナにしました。

リソース制御しているPodはReplicaSetをスケールしても良かったんですが、設定値が異なる場合にどのようになるのか確認したかったので、別のDeploymentにしました。

$ kubectl get pod -o wide
NAME                                 READY   STATUS    RESTARTS   AGE   IP               NODE           NOMINATED NODE   READINESS GATES
no-resource-quota-77d577889b-2lsck   2/2     Running   2          23h   192.168.69.252   k8s-worker02   <none>           <none>
no-resource-quota-77d577889b-mlgvr   2/2     Running   2          23h   192.168.79.77    k8s-worker01   <none>           <none>
resource-quota1-557b598fc9-2lqqg     1/1     Running   1          17h   192.168.79.66    k8s-worker01   <none>           <none>
resource-quota1-557b598fc9-8bcdr     1/1     Running   1          17h   192.168.69.205   k8s-worker02   <none>           <none>
resource-quota2-565c7b64fc-8tr5r     1/1     Running   1          17h   192.168.79.76    k8s-worker01   <none>           <none>
resource-quota2-565c7b64fc-qtng4     1/1     Running   1          17h   192.168.69.251   k8s-worker02   <none>           <none>

まずはrequests:500m/limits:1000mのPodに負荷をかけます。

$ kubectl exec -it resource-quota1-557b598fc9-2lqqg /bin/bash
root@resource-quota1-557b598fc9-2lqqg:/# yes >/dev/null &
[1] 12
root@resource-quota1-557b598fc9-2lqqg:/# yes >/dev/null &
[2] 13

CPU使用率を確認します。

$ kubectl top pod
NAME                                 CPU(cores)   MEMORY(bytes)
no-resource-quota-77d577889b-2lsck   2m           11Mi
no-resource-quota-77d577889b-mlgvr   2m           11Mi
resource-quota1-557b598fc9-2lqqg     992m         2Mi
resource-quota1-557b598fc9-8bcdr     0m           1Mi
resource-quota2-565c7b64fc-8tr5r     0m           1Mi
resource-quota2-565c7b64fc-qtng4     0m           1Mi

ほぼlimitsの値になってますね。

次にrequests:1000m/limits:1500mのPodに同様に負荷をかけ、CPU使用率を確認します。

$ kubectl top pod
NAME                                 CPU(cores)   MEMORY(bytes)
no-resource-quota-77d577889b-2lsck   1m           11Mi
no-resource-quota-77d577889b-mlgvr   1m           11Mi
resource-quota1-557b598fc9-2lqqg     625m         2Mi
resource-quota1-557b598fc9-8bcdr     0m           1Mi
resource-quota2-565c7b64fc-8tr5r     1251m        2Mi
resource-quota2-565c7b64fc-qtng4     0m           1Mi

どちらもrequestsを超えて同じような比率でリソースを分け合っていますね。
なお、この時点でノードのvCPUは使い切っています。

$ kubectl top node
NAME           CPU(cores)   CPU%   MEMORY(bytes)   MEMORY%
k8s-master     209m         10%    1007Mi          36%
k8s-worker01   2000m        100%   484Mi           17%
k8s-worker02   129m         6%     525Mi           19%

さらに、制限をかけていないPodにログインして同様に負荷をかけ、CPU使用率を確認します。

$ kubectl top pod
NAME                                 CPU(cores)   MEMORY(bytes)
no-resource-quota-77d577889b-2lsck   2m           11Mi
no-resource-quota-77d577889b-mlgvr   4m           11Mi
resource-quota1-557b598fc9-2lqqg     626m         2Mi
resource-quota1-557b598fc9-8bcdr     0m           1Mi
resource-quota2-565c7b64fc-8tr5r     1280m        2Mi
resource-quota2-565c7b64fc-qtng4     0m           1Mi

5分ほど待ってみましたが、制限をかけていないPod(no-resource-quota-77d577889b-mlgvr)は使用率がほとんど上がりませんでした。

まとめ

前回は、「リソース制御をしていないPod -> リソース制御をしているPod」の順に負荷をかけました。リソース制御をしていないPodだけでCPUを使い切っている状態でリソース制御しているPodに負荷をかけると、requests(下限)ではなく、limits(上限)までPodはCPUを割り当てられました。
ということは、リソースの割り当ては早い順ではなく、リソース制御の設定値(requestsだけでなくlimitsも)が優先されて、リソース制御していないPodは他のPodの上限値まで割り当てたあとの余りのリソースが割り当てられるということになりますね。