モチベーション
webアプリの運用であればk8sクラスタをスケールアウトするが、HPCジョブやAI学習等の高負荷なワークロードを実行する際はノードをスケールアップしたい要件があると思われるため、検証してみた。
検証内容
- ノードのスペックを超えるPodを作成
このとき、Podはpending状態になる想定 - ノードをスケールアップ
手順2の実施後、pending状態であったPodが、スケールアップしたノード上で起動するか確認する。
環境
- kubernetes
- バージョン:v1.21.6
- デプロイツール:kubespray v2.17.1
- ノード構成:controlplane × 1, worker × 2
- 各ノードのスペック
- 仮想CPU数:2
- RAMサイズ:4GB
- ノード
- OS:Ubuntu 20.04.3
- ノードの種類:OpenStackのVM
検証結果
k8sから見えているスケールアップ前のノードのスペックは以下の通り。
$ k describe nodes kube-worker02
Name: kube-worker02
... snip ...
Capacity:
cpu: 2
ephemeral-storage: 50633164Ki
hugepages-1Gi: 0
hugepages-2Mi: 0
memory: 4030532Ki
pods: 110
... snip ...
ノードのスペックを超えるリクエストをもつPodをつくる。
apiVersion: v1
kind: Pod
metadata:
creationTimestamp: null
labels:
run: nginx
name: nginx
spec:
containers:
- image: nginx
name: nginx
resources:
requests:
memory: "5Gi"
cpu: "3"
dnsPolicy: ClusterFirst
restartPolicy: Always
status: {}
$ k get pod
NAME READY STATUS RESTARTS AGE
nginx 0/1 Pending 0 4s
$ k describe pod nginx
... snip ...
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Warning FailedScheduling 22s (x2 over 24s) default-scheduler 0/3 nodes are available: 1 node(s) had taint {node-role.kubernetes.io/master: }, that the pod didn't tolerate, 2 Insufficient cpu, 2 Insufficient memory.
Podのリクエストがノードのスペックを超えるため、Podはpending状態となった。
つづいて、workerノード1台を以下のようにスケールアップする。
- vCPU数:2 => 8
- RAMサイズ:4GB => 12GB
# openstack flavor list
+--------------------------------------+--------------------------------------+-------+------+-----------+-------+-----------+
| ID | Name | RAM | Disk | Ephemeral | VCPUs | Is Public |
+--------------------------------------+--------------------------------------+-------+------+-----------+-------+-----------+
... snip ...
| 8937a33f-7cbd-491d-9b9a-0e5170cc6274 | m1.large | 12288 | 0 | 0 | 8 | True |
... snip ...
+--------------------------------------+--------------------------------------+-------+------+-----------+-------+-----------+
# openstack server resize --flavor 8937a33f-7cbd-491d-9b9a-0e5170cc6274 f127a4db-03b3-4baa-b0e2-b90219370c42
# openstack server show f127a4db-03b3-4baa-b0e2-b90219370c42
+-------------------------------------+----------------------------------------------------------+
| Field | Value |
+-------------------------------------+----------------------------------------------------------+
... snip ...
| OS-EXT-STS:vm_state | resized |
... snip ...
| flavor | m1.large (8937a33f-7cbd-491d-9b9a-0e5170cc6274) |
... snip ...
+-------------------------------------+----------------------------------------------------------+
# openstack server resize --confirm f127a4db-03b3-4baa-b0e2-b90219370c42
# openstack server show f127a4db-03b3-4baa-b0e2-b90219370c42
+-------------------------------------+----------------------------------------------------------+
| Field | Value |
+-------------------------------------+----------------------------------------------------------+
... snip ...
| OS-EXT-STS:vm_state | active |
... snip ...
| flavor | m1.large (8937a33f-7cbd-491d-9b9a-0e5170cc6274) |
... snip ...
+-------------------------------------+----------------------------------------------------------+
先程デプロイしたPodを確認する。
$ k get pod nginx -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
nginx 1/1 Running 0 38m 10.233.71.3 kube-worker02 <none> <none>
スケールアップしたノード上でPodが稼働していることを確認できた。
スケールアップしたノードを確認する。
$ k describe nodes kube-worker02
Name: kube-worker02
... snip ...
Capacity:
cpu: 8
ephemeral-storage: 50633164Ki
hugepages-1Gi: 0
hugepages-2Mi: 0
memory: 12268324Ki
pods: 110
... snip ...
Non-terminated Pods: (6 in total)
Namespace Name CPU Requests CPU Limits Memory Requests Memory Limits Age
--------- ---- ------------ ---------- --------------- ------------- ---
default nginx 3 (37%) 0 (0%) 5Gi (44%) 0 (0%) 39m
kube-system calico-node-tptkn 150m (1%) 300m (3%) 64M (0%) 500M (4%) 20h
kube-system coredns-8474476ff8-g2g7f 100m (1%) 0 (0%) 70Mi (0%) 170Mi (1%) 126m
kube-system kube-proxy-fq6wt 0 (0%) 0 (0%) 0 (0%) 0 (0%) 20h
kube-system nginx-proxy-kube-worker02 25m (0%) 0 (0%) 32M (0%) 0 (0%) 20h
kube-system nodelocaldns-j4x7b 100m (1%) 0 (0%) 70Mi (0%) 170Mi (1%) 20h
... snip ...
ノードのスペックはスケールアップにあわせて変更されていることを確認できた。
OpenStackでVMをリサイズすると、裏でVMが再起動される。
VMを再起動せずにスケールアップした場合のk8sの挙動も確認したいので、次にオンラインスケールアップの検証を実施してみる。
オンラインスケールアップ時の検証
OpenStackではオンラインスケールアップができない(多分)ので、VMが動作するコンピュートノードからvirsh
コマンドを実行することでオンラインスケールアップを実施する。
最初に、検証に使ったnginxのPodを削除する。
kube-controlplane01:~$ k get pod
NAME READY STATUS RESTARTS AGE
nginx 1/1 Running 0 5d
kube-controlplane01:~$ k delete pod nginx
pod "nginx" deleted
kube-controlplane01:~$ k get pod
No resources found in default namespace.
現状のworkerノードkube-worker02
のスペックを確認。
kube-worker02:~$ fgrep 'physical id' /proc/cpuinfo | sort -u | wc -l
8
kube-worker02:~$ free -h
total used free shared buff/cache available
Mem: 11Gi 570Mi 8.5Gi 2.0Mi 2.6Gi 10Gi
Swap: 0B 0B 0B
workerノードkube-worker02
を超えるリソース量を要求するPodを作成する。
apiVersion: v1
kind: Pod
metadata:
creationTimestamp: null
labels:
run: nginx-large
name: nginx-large
spec:
containers:
- image: nginx
name: nginx-large
resources:
requests:
memory: "13Gi"
cpu: "9"
dnsPolicy: ClusterFirst
restartPolicy: Always
status: {}
kube-controlplane01:~$ k apply -f nginx-large.yaml
pod/nginx-large created
kube-controlplane01:~$ k get pod
NAME READY STATUS RESTARTS AGE
nginx-large 0/1 Pending 0 110s
kube-controlplane01:~$ k describe pod nginx-large
... snip ...
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Warning FailedScheduling 10s (x2 over 11s) default-scheduler 0/3 nodes are available: 1 node(s) had taint {node-role.kubernetes.io/master: }, that the pod didn't tolerate, 2 Insufficient cpu, 2 Insufficient memory.
Podのリソース要求を満たすノードが存在しないためPending状態となった。
kube-worker02
が動作するコンピュートノードに乗り込み、kube-worker02
をスケールアップする。
まずは、kube-worker02
が動作するコンピュートノードとKVMにおける仮想マシン名を特定する。
ctl01:~# openstack server show f127a4db-03b3-4baa-b0e2-b90219370c42
+-------------------------------------+----------------------------------------------------------+
| Field | Value |
+-------------------------------------+----------------------------------------------------------+
... snip ...
| OS-EXT-SRV-ATTR:host | cmp001 |
| OS-EXT-SRV-ATTR:hypervisor_hostname | cmp001.xxxxxx.local |
| OS-EXT-SRV-ATTR:instance_name | instance-0000335c |
... snip ...
+-------------------------------------+----------------------------------------------------------+
コンピュートノードに乗り込む。
@cmp001:~# virsh list --all
Id Name State
----------------------------------------------------
1 instance-00002b0e running
2 instance-0000335c running
cmp001:~# virsh dominfo instance-0000335c
Id: 2
Name: instance-0000335c
UUID: f127a4db-03b3-4baa-b0e2-b90219370c42
OS Type: hvm
State: running
CPU(s): 8
CPU time: 98780.1s
Max memory: 12582912 KiB
Used memory: 12582912 KiB
Persistent: yes
Autostart: disable
Managed save: no
Security model: apparmor
Security DOI: 0
Security label: libvirt-f127a4db-03b3-4baa-b0e2-b90219370c42 (enforcing)
以下を参考にスケールアップする。
https://www.eastforest.jp/centos6/3694
まずはvCPU数を追加する。
cmp001:~# virsh vcpucount instance-0000335c
maximum config 8
maximum live 8
current config 8
current live 8
virsh setvcpusコマンドで仮想マシンに割り当てるCPU数を変更できます。ただし最大CPU数を超えることはできません。
--configを指定すると次回起動時から有効になります。--maximumの指定で最大CPU数を変更できますが、動作中の仮想マシンには適用されません。
まずはVMのvCPU数の上限を増やす必要がある。
cmp001:~# virsh setvcpus instance-0000335c 12 --config --maximum
error: invalid argument: CPU topology doesn't match the desired vcpu count
失敗した。
virsh edit
で以下のようにCPUトポロジーとvCPU数を変更することで、vCPU数を変更することができた。
<vcpu placement='static' current='8'>12</vcpu>
<cpu mode='host-passthrough' check='none'>
<topology sockets='12' cores='1' threads='1'/>
</cpu>
cmp001:~# virsh edit instance-0000335c
Domain instance-0000335c XML configuration edited.
root@cmp001:~# virsh vcpucount instance-0000335c
maximum config 12
current config 8
VM再起動後に反映されるため、この時点ではまだ反映さいない。
続いて、メモリの上限を変更する。
root@cmp001:~# virsh dominfo instance-0000335c
... snip ...
Max memory: 12582912 KiB
Used memory: 12582912 KiB
... snip ...
現在のメモリサイズの上限は12GiBなので、16GiBに変更する。
root@cmp001:~# virsh setmaxmem instance-0000335c 16G --config
vCPU数、メモリサイズの上限変更を反映させるためにVMを再起動する。
root@ctl01:~# openstack server reboot --soft f127a4db-03b3-4baa-b0e2-b90219370c42
virsh
コマンドでVMを再起動すると以下の問題があったため、ここではわざわざOpenStackからVMを再起動した。
- VMを起動すると、vCPU, メモリサイズの上限が反映されずフレーバーと同じになってしまう
- VM起動後、しばらくするとVMが勝手に停止されてしまう
root@cmp001:~# virsh vcpucount instance-0000335c
maximum config 12
maximum live 12
current config 8
current live 8
root@cmp001:~# virsh dominfo instance-0000335c
... snip ...
Max memory: 16777216 KiB
Used memory: 12582912 KiB
... snip ...
vCPU数、メモリサイズの上限値が反映された。
続いて、VMをオンラインスケールアップする。
root@cmp001:~# virsh setvcpus instance-0000335c 12
root@cmp001:~# virsh vcpucount instance-0000335c
maximum config 12
maximum live 12
current config 8
current live 12
root@cmp001:~# virsh setmem instance-0000335c 16G
root@cmp001:~# virsh dominfo instance-0000335c
... snip ...
Max memory: 16777216 KiB
Used memory: 16777216 KiB
... snip ...
スケールアップできた!
次にVMに乗り込み、スケールアップされているか確認する。
ubuntu@kube-worker02:~$ fgrep 'physical id' /proc/cpuinfo | sort -u | wc -l
8
ubuntu@kube-worker02:~$ lscpu |grep "CPU(s)"
CPU(s): 12
On-line CPU(s) list: 0-7
Off-line CPU(s) list: 8-11
NUMA node0 CPU(s): 0-7
ubuntu@kube-worker02:~$ free -h
total used free shared buff/cache available
Mem: 15Gi 453Mi 14Gi 1.0Mi 1.0Gi 14Gi
Swap: 0B 0B 0B
メモリサイズは反映されているが、追加したCPUはオフラインになっているので、オンラインにする。
ubuntu@kube-worker02:~$ for i in {8..11}; do echo 1 | sudo tee /sys/devices/system/cpu/cpu${i}/online; done
1
1
1
1
ubuntu@kube-worker02:~$ fgrep 'physical id' /proc/cpuinfo | sort -u | wc -l
12
vCPU数も反映された。
次にPodを確認
ubuntu@kube-controlplane01:~$ k get pod
NAME READY STATUS RESTARTS AGE
nginx-large 0/1 Pending 0 8d
Pendingのまま。
ノードのリソースを確認。
ubuntu@kube-controlplane01:~$ k describe nodes kube-worker02
... snip ...
Capacity:
cpu: 8
ephemeral-storage: 50633164Ki
hugepages-1Gi: 0
hugepages-2Mi: 0
memory: 12201896Ki
pods: 110
... snip ...
ノードのスケールアップは反映されていない。
対象ノードのkubeletを再起動してみる。
ubuntu@kube-worker02:~$ sudo systemctl restart kubelet.service
ubuntu@kube-controlplane01:~$ k describe nodes kube-worker02
... snip ...
Capacity:
cpu: 12
ephemeral-storage: 50633164Ki
hugepages-1Gi: 0
hugepages-2Mi: 0
memory: 16396200Ki
pods: 110
... snip ...
ubuntu@kube-controlplane01:~$ k get pod
NAME READY STATUS RESTARTS AGE
nginx-large 1/1 Running 0 8d
ノードのスケールアップが反映され、Podがrunningとなった!
結論
kubeletは起動時に、ノードのスペックを見に行くようである。
そのため、ノードのスペックを変更した際は、kubeletを再起動する必要がある。