containerd + kata containers を試す
kata containers について
kata containers はコンテナ並に軽量かつ従来の hypervisor 型 VM と同等の機能をもつ仮想マシンを作成するための OSS です。現在は Openstack 等を管理する Open Infrastructure Foundation のプロジェクトの一つになっています。
kata containers ではコンテナ環境を作成する際に guest kernel を使った VM 環境を作成し、その中でコンテナに相当する環境を作成するようになっています。これによりホスト側の kernel を共有している従来のコンテナ環境よりもよりセキュアな環境を構築しつつ、コンテナ並みの軽量な動作を実現しています。
kata-container と従来のコンテナの比較。https://katacontainers.io/learn/ より引用
また、containerd との統合機能により kata containers を runc の代わりに low level runtime として使用することができます。今回はこの機能を試してみます。
導入
前提条件
kata containers を使用するためのハードウェア要件は Hardware requirements に確認方法が書かれていますが、具体的な条件は記載されてなさそうなので実際に確認用のコマンド kata-runtime check
を実行して確認します。
kata-containers/kata-containers の Release からアーキテクチャに合った tar をダウンロードして展開すると、opt/kata
ディレクトリに kata containers の動作に必要なファイル一式が含まれているため、これを /opt
ディレクトリ以下にコピーします。
kata containers に関連するバイナリは opt/kata/bin/
にまとめられており、kata-runtime
もこのディレクトリに含まれているためこれを実行します。ハードウェア要件を満たしていて問題ない場合は System can currently create Kata Containers
等が表示されます。
$ /opt/kata/bin/kata-runtime check
WARN[0000] failed to resolve SNP certificates path: /opt/snp/cert_chain.cert
No newer release available
System is capable of running Kata Containers
$ sudo /opt/kata/bin/kata-runtime check
WARN[0000] failed to resolve SNP certificates path: /opt/snp/cert_chain.cert
WARN[0000] Not running network checks as super user arch=amd64 name=kata-runtime pid=36327 source=runtime
System is capable of running Kata Containers
System can currently create Kata Containers
一方で要件を満たさない場合は以下のように error が表示されます(以下は AWS EC2 インスタンス上で実行した例)。
$ sudo /opt/kata/bin/kata-runtime check
WARN[0000] failed to resolve SNP certificates path: /opt/snp/cert_chain.cert
WARN[0000] Not running network checks as super user arch=amd64 name=kata-runtime pid=1471 source=runtime
ERRO[0000] CPU property not found arch=amd64 description="Virtualization support" name=vmx pid=1471 source=runtime type=flag
WARN[0000] modprobe insert module failed arch=amd64 error="exit status 1" module=kvm_intel name=kata-runtime output="modprobe: ERROR: could not insert 'kvm_intel': Operation not supported\n" pid=1471 source=runtime
ERRO[0000] kernel property kvm_intel not found arch=amd64 description="Intel KVM" name=kvm_intel pid=1471 source=runtime type=module
ERRO[0000] ERROR: System is not capable of running Kata Containers arch=amd64 name=kata-runtime pid=1471 source=runtime
上記の結果を見ると以下の条件を満たしていれば良さそうです。
- CPU が 仮想化をサポートしている
- kvm 関連のカーネルモジュールがロードされている。
lsmod
で確認可能
$ lsmod | grep kvm
kvm_amd 155648 400
ccp 110592 1 kvm_amd
kvm 1036288 1 kvm_amd
AWS などのクラウドの仮想マシンを使用する場合、KVM がサポートされたタイプ (ベアメタルインスタンスなど) を使用する必要があります。
インストール
今回は openstack 上に構築した以下の VM を使って検証します。
- OS: ubuntu 22.04 LTS
- メモリ: 16 GB
- vCPU: 4
kata containers のインストール方法は Install Guide に記載の通りいくつかあります。
- パッケージマネージャーでインストール
- インストールスクリプトを実行してインストール
- 手動でインストール
手動でインストールする場合は kata-containers/kata-containers の Release から kata-container の tar をダウンロードしてして配置すれば ok です。既に前提条件のところで実行済みなのでスキップして ok
kata 関連のバイナリは /opt/kata/bin
に配置されるので、よく使う実行ファイルは /usr/local/bin
などパスが通っている場所にシンボリックリンクを作成しておくと楽です。
sudo ln -s /opt/kata/bin/kata-runtime /usr/local/bin
sudo ln -s /opt/kata/bin/containerd-shim-kata-v2 /usr/local/bin
使い道
kata containers の使用用途や tips などは How to Guide にたくさん記載されています。
ここではこの中からいくつか試してみます。
containerd と組み合わせて使う
How to use Kata Containers and Containerd の内容
kata containers は low level runtime の機能があるため、containerd + runc の組み合わせにおいて runc の代わりに kata containers を使ってコンテナを動作させることができます。containerd と組み合わせて使用する場合、containerd の動作を確認するため以下も必要になります。こちらのインストール手順は割愛。
- containerd
- runc
- cni
kata containers を使うには containerd の構成ファイル config.toml
において以下のように設定を追加、編集します。ドキュメントではフィールド名が plugins.cri
となっていますが、手元の環境では plugins."io.containerd.grpc.v1.cri"
とする必要がありました。(このあたりは containerd のインストール方法や設定ファイルの作成方法によるかも)
設定によっては plugins."io.containerd.grpc.v1.cri".containerd
などに他のプロパティが設定済みの場合もありますが、その際は削除する必要はなくそのままで ok。
[plugins."io.containerd.grpc.v1.cri".containerd]
no_pivot = false
[plugins."io.containerd.grpc.v1.cri".containerd.runtimes]
[plugins."io.containerd.grpc.v1.cri".containerd.runtimes.runc]
privileged_without_host_devices = false
runtime_type = "io.containerd.runc.v2"
[plugins."io.containerd.grpc.v1.cri".containerd.runtimes.runc.options]
BinaryName = ""
CriuImagePath = ""
CriuPath = ""
CriuWorkPath = ""
IoGid = 0
[plugins."io.containerd.grpc.v1.cri".containerd.runtimes.kata]
runtime_type = "io.containerd.kata.v2"
privileged_without_host_devices = true
pod_annotations = ["io.katacontainers.*"]
container_annotations = ["io.katacontainers.*"]
[plugins."io.containerd.grpc.v1.cri".containerd.runtimes.kata.options]
ConfigPath = "/opt/kata/share/defaults/kata-containers/configuration.toml"
containerd を再起動して変更を適用。
sudo systemctl restart containerd.service
これにより containerd で kata containers を使えるようになりました。ホスト側では runc と kata containers が両方ともインストールされており、コンテナ作成時に --runtime
オプションを指定することで使用する runtime を切り替えられる状態になっています。
動作を確認するために、ドキュメントの通り crictl
で pod とコンテナを作成してみます。
pod の定義
metadata:
attempt: 1
name: busybox-sandbox
namespace: default
uid: hdishd83djaidwnduwk28bcsb
log_directory: /tmp
linux:
namespaces:
options: {}
container の定義
etadata:
name: busybox
image:
image: docker.io/busybox:latest
command:
- top
log_path: busybox.0.log
まずは kata containers を使用せず、通常の runc を使って pod を作成。
sudo crictl runp pod.yml
作成した pod を確認。
$ sudo crictl pods
WARN[0000] runtime connect using default endpoints: [unix:///run/containerd/containerd.sock unix:///run/crio/crio.sock unix:///var/run/cri-dockerd.sock]. As the default settings are now deprecated, you should set the endpoint instead.
POD ID CREATED STATE NAME NAMESPACE ATTEMPT RUNTIME
78aeda417c97e 2 minutes ago Ready busybox-sandbox default 1 kata
pod に container を追加。
sudo crictl create 78aeda417c97e container.yml pod.yml
container を開始。
sudo crictl start 630998a5900f7
container の確認。
$ sudo crictl ps -a -pod 78aeda417c97e
WARN[0000] runtime connect using default endpoints: [unix:///run/containerd/containerd.sock unix:///run/crio/crio.sock unix:///var/run/cri-dockerd.sock]. As the default settings are now deprecated, you should set the endpoint instead.
WARN[0000] image connect using default endpoints: [unix:///run/containerd/containerd.sock unix:///run/crio/crio.sock unix:///var/run/cri-dockerd.sock]. As the default settings are now deprecated, you should set the endpoint instead.
CONTAINER IMAGE CREATED STATE NAME ATTEMPT POD ID POD
630998a5900f7 docker.io/busybox:latest 2 minutes ago Created busybox 0 78aeda417c97e unknown
container 内でシェルを起動して接続し、カーネルのバージョンを確認。
$ sudo crictl exec -it 630998a5900f7 sh
/ # uname -ar
Linux kata 5.15.0-50-generic #56-Ubuntu SMP Tue Sep 20 13:23:26 UTC 2022 x86_64 GNU/Linux
containerd + runc の構成では docker 等と同様にホスト側のカーネルを共有しているため、コンテナ内でカーネルバージョンを確認するとホスト側のカーネルが表示されます。
ホスト側でも同じコマンドを実行するとバージョンが一致していることが確認できます (kata
は hostname に対応)。
$ uname -ar
Linux kata 5.15.0-50-generic #56-Ubuntu SMP Tue Sep 20 13:23:26 UTC 2022 x86_64 x86_64 x86_64 GNU/Linux
一方で kata containers ではホスト側のカーネルとは別の guest kernel 内でコンテナ環境を実行するため、ホスト側とは別のカーネルバージョンが表示されます。
crictl で kata containers を使うには -r, --runtime
オプションで kata
を指定します。
$ sudo crictl runp -r kata pod.yaml
$ sudo crictl create e9cdd306453ac container.yml pod.yml
$ sudo crictl start 2c6a61e43d886
$ sudo crictl exec -it 2c6a61e43d886 sh
/ # uname -ar
Linux 6.1.62 #1 SMP Fri Aug 9 10:43:25 UTC 2024 x86_64 GNU/Linux
カーネルバージョンが 6.1.62
になっているのでホスト側のカーネルとは別のものが使用されていることがわかります。
ちなみに /opt/kata/share/kata-containers
に MBR boot イメージや initd、カーネルイメージらしきファイルが配置されているので、仮想環境作成時の guest kernel にはここにあるものが使われてそうです(詳しくは調べてない)。
$ ls -l /opt/kata/share/kata-containers
total 905916
-rw-r--r-- 1 ubuntu ubuntu 76921 Aug 9 10:43 config-6.1.62-135
-rw-r--r-- 1 ubuntu ubuntu 77162 Aug 9 10:43 config-6.1.62-135-dragonball-experimental
-rw-r--r-- 1 ubuntu ubuntu 79303 Aug 9 10:43 config-6.1.62-135-nvidia-gpu
-rw-r--r-- 1 ubuntu ubuntu 86857 Aug 9 10:47 config-6.7-135-confidential
-rw-r--r-- 1 ubuntu ubuntu 85862 Aug 9 10:44 config-6.7-135-nvidia-gpu-confidential
-rw-r--r-- 1 ubuntu ubuntu 14819498 Aug 16 20:55 kata-alpine-3.18.initrd
-rw-r--r-- 1 ubuntu ubuntu 68381502 Aug 16 20:57 kata-cbl-mariner-2.0-mariner.initrd
lrwxrwxrwx 1 ubuntu ubuntu 37 Aug 21 16:07 kata-containers-confidential.img -> kata-ubuntu-latest-confidential.image
lrwxrwxrwx 1 ubuntu ubuntu 37 Aug 16 20:56 kata-containers-initrd-confidential.img -> kata-ubuntu-20.04-confidential.initrd
lrwxrwxrwx 1 ubuntu ubuntu 35 Aug 16 20:57 kata-containers-initrd-mariner.img -> kata-cbl-mariner-2.0-mariner.initrd
lrwxrwxrwx 1 ubuntu ubuntu 23 Aug 16 20:55 kata-containers-initrd.img -> kata-alpine-3.18.initrd
lrwxrwxrwx 1 ubuntu ubuntu 24 Aug 21 16:04 kata-containers.img -> kata-ubuntu-latest.image
-rw-r--r-- 1 ubuntu ubuntu 47354120 Aug 16 20:56 kata-ubuntu-20.04-confidential.initrd
-rw-r--r-- 1 ubuntu ubuntu 268435456 Aug 21 16:07 kata-ubuntu-latest-confidential.image
-rw-r--r-- 1 ubuntu ubuntu 268435456 Aug 21 16:04 kata-ubuntu-latest.image
-rw-r--r-- 1 ubuntu ubuntu 435 Aug 21 16:07 root_hash.txt
-rw-r--r-- 1 ubuntu ubuntu 44796144 Aug 9 10:43 vmlinux-6.1.62-135
-rw-r--r-- 1 ubuntu ubuntu 44809200 Aug 9 10:43 vmlinux-6.1.62-135-dragonball-experimental
-rw-r--r-- 1 ubuntu ubuntu 47046728 Aug 9 10:43 vmlinux-6.1.62-135-nvidia-gpu
-rw-r--r-- 1 ubuntu ubuntu 43444024 Aug 9 10:47 vmlinux-6.7-135-confidential
-rw-r--r-- 1 ubuntu ubuntu 41301608 Aug 9 10:44 vmlinux-6.7-135-nvidia-gpu-confidential
lrwxrwxrwx 1 ubuntu ubuntu 28 Aug 9 10:47 vmlinux-confidential.container -> vmlinux-6.7-135-confidential
lrwxrwxrwx 1 ubuntu ubuntu 42 Aug 9 10:43 vmlinux-dragonball-experimental.container -> vmlinux-6.1.62-135-dragonball-experimental
lrwxrwxrwx 1 ubuntu ubuntu 39 Aug 9 10:44 vmlinux-nvidia-gpu-confidential.container -> vmlinux-6.7-135-nvidia-gpu-confidential
lrwxrwxrwx 1 ubuntu ubuntu 29 Aug 9 10:43 vmlinux-nvidia-gpu.container -> vmlinux-6.1.62-135-nvidia-gpu
lrwxrwxrwx 1 ubuntu ubuntu 18 Aug 9 10:43 vmlinux.container -> vmlinux-6.1.62-135
-rw-r--r-- 1 ubuntu ubuntu 6702032 Aug 9 10:43 vmlinuz-6.1.62-135
-rw-r--r-- 1 ubuntu ubuntu 6706928 Aug 9 10:43 vmlinuz-6.1.62-135-dragonball-experimental
-rw-r--r-- 1 ubuntu ubuntu 6982208 Aug 9 10:43 vmlinuz-6.1.62-135-nvidia-gpu
-rw-r--r-- 1 ubuntu ubuntu 10534912 Aug 9 10:47 vmlinuz-6.7-135-confidential
-rw-r--r-- 1 ubuntu ubuntu 7426048 Aug 9 10:44 vmlinuz-6.7-135-nvidia-gpu-confidential
lrwxrwxrwx 1 ubuntu ubuntu 28 Aug 9 10:47 vmlinuz-confidential.container -> vmlinuz-6.7-135-confidential
lrwxrwxrwx 1 ubuntu ubuntu 42 Aug 9 10:43 vmlinuz-dragonball-experimental.container -> vmlinuz-6.1.62-135-dragonball-experimental
lrwxrwxrwx 1 ubuntu ubuntu 39 Aug 9 10:44 vmlinuz-nvidia-gpu-confidential.container -> vmlinuz-6.7-135-nvidia-gpu-confidential
lrwxrwxrwx 1 ubuntu ubuntu 29 Aug 9 10:43 vmlinuz-nvidia-gpu.container -> vmlinuz-6.1.62-135-nvidia-gpu
lrwxrwxrwx 1 ubuntu ubuntu 18 Aug 9 10:43 vmlinuz.container -> vmlinuz-6.1.62-135
ホスト側の qemu のプロセスで -kernel /opt/kata/share/kata-containers/vmlinux-6.1.62-135
が指定されているのでこれが使われてそう。
qemu プロセスの詳細
/opt/kata/bin/qemu-system-x86_64 -name sandbox-756f7c14c0f7915313fd028b4f044975eb1e0a61a71c3236506eaed8daf11766 -uuid 50a9c16a-133f-4355-92c5-e7b96b70a34e -machine q35,accel=kvm,nvdimm=on -cpu host,pmu=off -qmp unix:fd=3,server=on,wait=off -m 2048M,slots=10,maxmem=17025M -device pci-bridge,bus=pcie.0,id=pci-bridge-0,chassis_nr=1,shpc=off,addr=2,io-reserve=4k,mem-reserve=1m,pref64-reserve=1m -device virtio-serial-pci,disable-modern=true,id=serial0 -device virtconsole,chardev=charconsole0,id=console0 -chardev socket,id=charconsole0,path=/run/vc/vm/756f7c14c0f7915313fd028b4f044975eb1e0a61a71c3236506eaed8daf11766/console.sock,server=on,wait=off -device nvdimm,id=nv0,memdev=mem0,unarmed=on -object memory-backend-file,id=mem0,mem-path=/opt/kata/share/kata-containers/kata-ubuntu-latest.image,size=268435456,readonly=on -device virtio-scsi-pci,id=scsi0,disable-modern=true -object rng-random,id=rng0,filename=/dev/urandom -device virtio-rng-pci,rng=rng0 -device vhost-vsock-pci,disable-modern=true,vhostfd=4,id=vsock-3140714432,guest-cid=3140714432 -chardev socket,id=char-26f658329c5bb05b,path=/run/vc/vm/756f7c14c0f7915313fd028b4f044975eb1e0a61a71c3236506eaed8daf11766/vhost-fs.sock -device vhost-user-fs-pci,chardev=char-26f658329c5bb05b,tag=kataShared,queue-size=1024 -rtc base=utc,driftfix=slew,clock=host -global kvm-pit.lost_tick_policy=discard -vga none -no-user-config -nodefaults -nographic --no-reboot -object memory-backend-file,id=dimm1,size=2048M,mem-path=/dev/shm,share=on -numa node,memdev=dimm1 -kernel /opt/kata/share/kata-containers/vmlinux-6.1.62-135 -append tsc=reliable no_timer_check rcupdate.rcu_expedited=1 i8042.direct=1 i8042.dumbkbd=1 i8042.nopnp=1 i8042.noaux=1 noreplace-smp reboot=k cryptomgr.notests net.ifnames=0 pci=lastbus=0 root=/dev/pmem0p1 rootflags=dax,data=ordered,errors=remount-ro ro rootfstype=ext4 console=hvc0 console=hvc1 quiet systemd.show_status=false panic=1 nr_cpus=4 selinux=0 systemd.unit=kata-containers.target systemd.mask=systemd-networkd.service systemd.mask=systemd-networkd.socket scsi_mod.scan=none -pidfile /run/vc/vm/756f7c14c0f7915313fd028b4f044975eb1e0a61a71c3236506eaed8daf11766/pid -smp 1,cores=1,threads=1,sockets=4,maxcpus=4
nerdctl を使う場合
nerdctl で kata containers を使う場合 --runtime io.containerd.kata.v2
のように使用する runtime を指定します。
こちらの方が docker CLI を同じように使えるので楽です。
$ sudo nerdctl run --runtime io.containerd.kata.v2 --name kata -d busybox sleep 1000000
$ sudo nerdctl exec -it kata sh
/ # uname -ar
Linux ce0888fa77a7 6.1.62 #1 SMP Fri Aug 9 10:43:25 UTC 2024 x86_64 GNU/Linux
runc を指定する場合は以下。
$ sudo nerdctl run --name no-kata -d busybox sleep 1000000
44b515c5a82b74341a33987a0bee4854a3e7ab0977d6d865d93b95e87cbb2470
$ sudo nerdctl exec -it no-kata sh
/ # uname -ar
Linux 44b515c5a82b 5.15.0-50-generic #56-Ubuntu SMP Tue Sep 20 13:23:26 UTC 2022 x86_64 GNU/Linux
ホスト側のプロセス
nerdctl を使って runc でコンテナを作成した場合、ホスト側では以下のようなプロセスが実行されます。
/usr/bin/containerd-shim-runc-v2 -namespace default -id b467cb3270d0ad7e1a552a108ce955531c6c31ddabb318cf5f5a0d459a417b40 -address /run/containerd/containerd.sock
\_ /usr/local/bin/nerdctl _NERDCTL_INTERNAL_LOGGING /var/lib/nerdctl/1935db59
\_ sleep 1000000
kata containers を使った場合は以下のプロセスが実行されています。デフォルトでパイパーバイザーに qemu を使用するようになっているため、/opt/kata/bin/qemu-system-x86_64
で実際に qemu のプロセスが実行されていることが確認できます。
/opt/kata/bin/containerd-shim-kata-v2 -namespace default -address /run/containerd/containerd.sock -publish-binary -id 756f7c14c0f7915313fd028b4f044975eb1e0a61a71c3236506eaed8daf11766
\_ /opt/kata/libexec/virtiofsd --syslog --cache=auto --shared-dir=/run/kata-containers/shared/sandboxes/756f7c14c0f7915313fd028b4f044975eb1e0a61a71c3236506eaed8daf11766/shared --fd=3 --thread-pool-size=1 --announce-submounts
| \_ /opt/kata/libexec/virtiofsd --syslog --cache=auto --shared-dir=/run/kata-containers/shared/sandboxes/756f7c14c0f7915313fd028b4f044975eb1e0a61a71c3236506eaed8daf11766/shared --fd=3 --thread-pool-size=1 --announce-submounts
\_ /opt/kata/bin/qemu-system-x86_64 -name sandbox-756f7c14c0f7915313fd028b4f044975eb1e0a61a71c3236506eaed8daf11766 -uuid 50a9c16a-133f-4355-92c5-e7b96b70a34e -machine q35,accel=kvm,nvdimm=on -cpu host,pmu=off -qmp unix:fd=3,server=on,wait=off -m 2048M,slots=10,maxmem=17025M -device pci-bridge,bus=pcie.0,id=pci-bridge-0,chassis_nr=1,shpc=off,addr=2,io-reserve=4k,mem-reserve=1m,pref64-reserve=1m -device virtio-serial-pci,disable-modern=true,id=serial0 -device virtconsole,chardev=charconsole0,id=console0 -chardev socket,id=charconsole0,path=/run/vc/vm/756f7c14c0f7915313fd028b4f044975eb1e0a61a71c3236506eaed8daf11766/console.sock,server=on,wait=off -device nvdimm,id=nv0,memdev=mem0,unarmed=on -object memory-backend-file,id=mem0,mem-path=/opt/kata/share/kata-containers/kata-ubuntu-latest.image,size=268435456,readonly=on -device virtio-scsi-pci,id=scsi0,disable-modern=true -object rng-random,id=rng0,filename=/dev/urandom -device virtio-rng-pci,rng=rng0 -device vhost-vsock-pci,disable-modern=true,vhostfd=4,id=vsock-3140714432,guest-cid=3140714432 -chardev socket,id=char-26f658329c5bb05b,path=/run/vc/vm/756f7c14c0f7915313fd028b4f044975eb1e0a61a71c3236506eaed8daf11766/vhost-fs.sock -device vhost-user-fs-pci,chardev=char-26f658329c5bb05b,tag=kataShared,queue-size=1024 -rtc base=utc,driftfix=slew,clock=host -global kvm-pit.lost_tick_policy=discard -vga none -no-user-config -nodefaults -nographic --no-reboot -object memory-backend-file,id=dimm1,size=2048M,mem-path=/dev/shm,share=on -numa node,memdev=dimm1 -kernel /opt/kata/share/kata-containers/vmlinux-6.1.62-135 -append tsc=reliable no_timer_check rcupdate.rcu_expedited=1 i8042.direct=1 i8042.dumbkbd=1 i8042.nopnp=1 i8042.noaux=1 noreplace-smp reboot=k cryptomgr.notests net.ifnames=0 pci=lastbus=0 root=/dev/pmem0p1 rootflags=dax,data=ordered,errors=remount-ro ro rootfstype=ext4 console=hvc0 console=hvc1 quiet systemd.show_status=false panic=1 nr_cpus=4 selinux=0 systemd.unit=kata-containers.target systemd.mask=systemd-networkd.service systemd.mask=systemd-networkd.socket scsi_mod.scan=none -pidfile /run/vc/vm/756f7c14c0f7915313fd028b4f044975eb1e0a61a71c3236506eaed8daf11766/pid -smp 1,cores=1,threads=1,sockets=4,maxcpus=4
\_ /usr/local/bin/nerdctl _NERDCTL_INTERNAL_LOGGING /var/lib/nerdctl/1935db59
コンテナ作成速度の比較
kata containers はコンテナ並に軽量との記載はありますが、実際にコンテナ作成速度やコンテナのリソース(メモリ使用量など)にどれぐらいの差があるのかを確認するため、以下のような簡単なシェルスクリプトを使ってコンテナを 100 個直列で作成した際の動作を見てみます。
#!/bin/bash
set -xue
for i in {000..099}
do
sudo nerdctl run -d --name test-$i nginx:alpine
done
イメージは軽量な nginx:alpine
にしておきます。
runc の場合
比較のため、まずは kata containers を使用せず runc
でコンテナを起動した際の動作を確認してみます。
作成したコンテナに対して sudo nerdctl inspect [name]
で Created"
によりコンテナの作成時刻が確認できるので、test-000 と test-099 の時刻の差分よりコンテナ作成にかかった時間を計算すると 32 秒となりました。1 コンテナあたりに変換すると 0.4 秒となります。
また、sudo nerdctl stats
で各コンテナの統計情報が確認できます。これで見るとメモリ使用量は 1 コンテナあたり約 4.3 MB となっていました。特にアクセスは行っていないため CPU 使用率の有意な変化は見られませんでした。
その他、htop
でホスト側のメモリ使用量を確認すると約 4.3 GB となっていました。
kata containers の場合
kata containers で実行するために --runtime io.containerd.kata.v2
を追加します。
#!/bin/bash
set -xue
for i in {000..100}
do
sudo nerdctl run -d --runtime io.containerd.kata.v2 --name test-$i nginx:alpine
done
bash test.sh
で実行した際にコンテナの作成ログが標準出力に表示されますが、実際やってみると runc と比較して 1 コンテナの作成に時間がかかるのが目に見えてわかります(それでも通常使用ではそこまで気になるほどではないですが)。また、87 コンテナ起動したあたりで以下のエラーにより作成に失敗しました。
WARN[0000] cannot set cgroup manager to "systemd" for runtime "io.containerd.kata.v2"
FATA[0047] failed to create shim task: Failed to Check if grpc server is working: rpc error: code = DeadlineExceeded desc = timed out connecting to vsock 4203134821:1024: unknown
エラー内容はホスト側のリソース不足によるためホスト側のスペックを上げれば解決する可能性あり。
作成できたコンテナから上記と同様の計算を行うと以下のようになりました。
- 1 コンテナの作成にかかる時間は 2.1 秒。
- 1 コンテナあたりのメモリ使用量は 8.8 MB
-
htop
で確認した際のホストのメモリ使用量は 13.3 GB
測定のまとめ
runc と kata containers でそれぞれ測定した際の結果を表にまとめると以下のようになります。
項目 | runc | kata containers |
---|---|---|
コンテナ作成にかかる時間 (秒/コンテナ) | 0.4 | 2.1 |
コンテナあたりのメモリ使用量 (MB) | 4.3 | 8.8 |
ホストのメモリ使用量 (GB) | 4.3 | 13.3 |
そこまで厳密な検証ではないですが、runc と比較するとコンテナ作成時間や 1 コンテナのメモリ使用量に有意な差があり、通常のコンテナランタイムと完全に同等のパフォーマンスでコンテナを作成できるというわけではないようです。とはいえ kata containers は VM を作ってその中でコンテナを動かしているので、コンテナの約 2 倍のメモリや数秒程度でこれらの環境を作成・管理できているという点は注目するべきかもしれません。
上記は kata containers のパイパーバイザーに qemu を使用した際の測定であるため、他のハイパーバイザーに切り替えた際に結果が異なることもあります。その他ホスト側の CPU のスペック等色々依存する要因は考えられるため、上記の結果はあくまで一例として捉えるのが良さそうです。
仕組み
kata containers を runc の代わりとして使用した際のアーキテクチャは Containerd Runtime V2 API: Shim V2 API に簡単な図があります。runc を使う場合、containerd は containerd-shim v2 を通じてコンテナを管理する構成になっています(container のリポジトリの Runtime v2 にある図などを参考)。一方で kata containers では kata-agent と呼ばれるコンポーネントが guest kernel を使った VM の管理やその中でのコンテナの作成などを管理しています。そして containerd と kata-manager の仲介となるのが containerd-shim-kata-v2
となっています。
https://github.com/kata-containers/kata-containers/blob/main/docs/design/arch-images/shimv2.svg より引用
containerd-shim-kata-v2 を導入以前は kata-proxy や kata-runtime などいろいろな処理がありましたが、導入後は containerd-shim-kata-v2 がまとめて管理するようになっています。なので runc の部分がそのまま kata-agent による pod sandbox に置き換わったと考えれば良さそうです。
ハイパーバイザーを切り替える
kata containers で仮想環境を作成する際にデフォルトでは QEMU が使用されますが、他のパイパーバイザーを使用することもできます。サポートされているハイパーバイザーは Hypervisors に記載されています。ここでは VMM 用に設計された cloud-hypervisor に切り替えてコンテナを作ってみます。
cloud-hypervisor 用の実行ファイルや設定ファイルは kata containers インストール時の tar に含まれているため追加のインストール作業は不要です。ただ nerdctl から clh の runtime を指定するには、/etc/containerd/config.toml
に runtimes.kata-clh
の追加が必要です(他の方法でもできるかも)。
[plugins."io.containerd.grpc.v1.cri".containerd.runtimes.kata]
runtime_type = "io.containerd.kata.v2"
runtime_path = "/opt/kata/bin/containerd-shim-kata-v2"
privileged_without_host_devices = true
pod_annotations = ["io.katacontainers.*"]
container_annotations = ["io.katacontainers.*"]
[plugins."io.containerd.grpc.v1.cri".containerd.runtimes.kata.options]
ConfigPath = "/opt/kata/share/defaults/kata-containers/configuration.toml"
+ [plugins."io.containerd.grpc.v1.cri".containerd.runtimes.kata-clh]
+ runtime_type = "io.containerd.kata-clh.v2"
/usr/local/bin/containerd-shim-kata-clh-v2
を作成。中身は clh 用の kata containers 設定ファイルを指定し、残りの引数を containerd-shim-kata-v2
に渡すだけの単純なシェルスクリプト。パスは環境に合わせて変更する。
#!/bin/bash
KATA_CONF_FILE=/etc/kata-containers/configuration-clh.toml /usr/local/bin/containerd-shim-kata-v2 $@
sudo systemctl restart containerd
で変更を適用すると、--runtime io.containerd.kata-clh.v2
でハイパーバイザーを clh に指定してコンテナを起動できるようになります。
$ sudo nerdctl run --runtime io.containerd.kata-clh.v2 --name kata-clh -d docker.io/library/nginx:latest
WARN[0000] cannot set cgroup manager to "systemd" for runtime "io.containerd.kata-clh.v2"
9bb18310cc891271bcad5fabbb6b684027788e0747671fcbc76f12bb6205c991
$ sudo nerdctl exec -it kata-clh bash
ERRO[0000] resize pty error="\"no tty\": unavailable"
root@9bb18310cc89:/#
root@9bb18310cc89:/# uname -ar
Linux 9bb18310cc89 6.1.62 #1 SMP Fri Aug 9 10:43:25 UTC 2024 x86_64 GNU/Linux
ホスト側でプロセスを確認すると、qemu の代わりに /opt/kata/bin/cloud-hypervisor
プロセスが起動していることが確認できます。
/opt/kata/bin/containerd-shim-kata-v2 -namespace default -address /run/containerd/containerd.sock -publish-binary -id de47cc0b26d51b69b867db32bc9904ac17329740ceaeffe3319641fc2c37902d
\_ /opt/kata/libexec/virtiofsd --syslog --cache=auto --shared-dir=/run/kata-containers/shared/sandboxes/de47cc0b26d51b69b867db32bc9904ac17329740ceaeffe3319641fc2c37902d/shared --fd=3 --thread-pool-size=1 --announce-submounts
| \_ /opt/kata/libexec/virtiofsd --syslog --cache=auto --shared-dir=/run/kata-containers/shared/sandboxes/de47cc0b26d51b69b867db32bc9904ac17329740ceaeffe3319641fc2c37902d/shared --fd=3 --thread-pool-size=1 --announce-submounts
\_ /opt/kata/bin/cloud-hypervisor --api-socket /run/vc/vm/de47cc0b26d51b69b867db32bc9904ac17329740ceaeffe3319641fc2c37902d/clh-api.sock
\_ /usr/local/bin/nerdctl _NERDCTL_INTERNAL_LOGGING /var/lib/nerdctl/1935db59
せっかくなので先程と同様にコンテナ 100 個を作成した際のパフォーマンスもみておきます。
同じ条件でコンテナを作成したところ、qemu では 87 個ほど作成した辺りでエラーとなりましたが。 clh の場合はエラーとならず 100 個まで作成できました。
1 コンテナの作成時間などを計算したところ以下のようになりました。
項目 | qemu | clh |
---|---|---|
コンテナ作成にかかる時間 (秒/コンテナ) | 2.1 | 2.1 |
コンテナあたりのメモリ使用量 (MB) | 8.8 | 8.8 |
ホストのメモリ使用量 (GB) | 13.3 | 13.1 |
Hypervisors の比較表では Container Creation speed
, Memory density
が qemu では good であるのに対し clh ではいずれも excellent となっていますが、今回の検証では qemu と clh でほぼ差異がない結果となりました。コンテナ数やコンテナイメージを変えたりするなど条件を変えた場合に clh の方がパフォーマンスが良い結果になることが期待されます。
ハイパーバイザーに関しては Virtualization in Kata Containers も少し記載があります。
kubernetes で使う
kubernetes で containerd + kata containers を使う際の手順は How to use Kata Containers and containerd with Kubernetes を参照。上記の手順では containerd のインストールや CNI の設定なども書かれていますが、既に k8s で containerd を使う準備ができている場合、必要な手順は kata containers 用の Runtime Class を設定すれば使えるようになります。
apiVersion: node.k8s.io/v1
kind: RuntimeClass
metadata:
name: kata
handler: kata
作成した runtimeClass を使用するには、pod のマニフェストに runetimeClassName
を指定します。deployment の場合は pod template の方に定義する必要がある点に注意。
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
labels:
app: nginx
spec:
replicas: 10
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
runtimeClassName: kata
containers:
- name: nginx
image: nginx:alpine
ports:
- containerPort: 80
検証のため、containerd で runc のみをインストールしたノード kata-w1
と、runc + kata containers を使えるようにしたノード kata
を用意します。上記の runtimeClass の定義の場合、ノードが kata containers 等の runtime が設定済みで実行できるかどうかを判別しません。そのため、kata container が使用できないノード kata-w1
にも pod がスケジュールされます。
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
nginx-deployment-d49c76cf-fhgsj 0/1 ContainerCreating 0 90s <none> kata-w1 <none> <none>
nginx-deployment-d49c76cf-fnnq6 0/1 ContainerCreating 0 90s <none> kata-w1 <none> <none>
nginx-deployment-d49c76cf-gkh9w 1/1 Running 0 90s 10.244.2.9 kata <none> <none>
nginx-deployment-d49c76cf-j77v9 0/1 ContainerCreating 0 90s <none> kata-w1 <none> <none>
nginx-deployment-d49c76cf-jfps7 1/1 Running 0 90s 10.244.2.7 kata <none> <none>
nginx-deployment-d49c76cf-kjd7g 0/1 ContainerCreating 0 90s <none> kata-w1 <none> <none>
nginx-deployment-d49c76cf-ln72w 1/1 Running 0 90s 10.244.2.8 kata <none> <none>
nginx-deployment-d49c76cf-nn4gm 1/1 Running 0 90s 10.244.2.10 kata <none> <none>
nginx-deployment-d49c76cf-tkqsd 1/1 Running 0 90s 10.244.2.11 kata <none> <none>
nginx-deployment-d49c76cf-vsj9r 0/1 ContainerCreating 0 90s <none> kata-w1 <none> <none>
kubectl describe [pod_name]
で見ると runtime が見つからない等のエラーが発生していることがわかります。
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal Scheduled 3m41s default-scheduler Successfully assigned default/nginx-deployment-d49c76cf-fhgsj to kata-w1
Warning FailedCreatePodSandBox 5s (x17 over 3m40s) kubelet Failed to create pod sandbox: rpc error: code = Unknown desc = failed to get sandbox runtime: no runtime for "kata" is configured
runtime が対応しているノードにだけ pod を配置するには runtimeclass に scheduling を設定する必要があります。ドキュメントにはマニフェストの記載例がありませんが、RedHat の 6.2. スケジューリングメカニズムをカプセル化するための RuntimeClass オブジェクトの作成 にあるのでこれを参考にします。
現時点では nodeSelector, tolerations がサポートされていて、基本的に node に設定された label に基づいて pod 配置可能なノードを制御する形式になっています。一例として、kata container が使えるノードには runtime-kata=true
を設定します。
kubectl label nodes kata runtime-runc=true
kubectl label nodes kata runtime-kata=true
kubectl label nodes kata-w1 runtime-runc=true
runtimeClass では nodeSelector で runtime-kata: "true"
を指定。
apiVersion: node.k8s.io/v1
kind: RuntimeClass
metadata:
name: kata
handler: kata
scheduling:
nodeSelector:
runtime-kata: "true"
これで再度 replica 数 10 の deployment を作成すると、すべての pod が runtime-kata: "true"
のラベルを持つ kata
ノードに配置されるようになります。
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
nginx-deployment-d49c76cf-9mftt 1/1 Running 0 34s 10.244.2.15 kata <none> <none>
nginx-deployment-d49c76cf-dn4w6 1/1 Running 0 34s 10.244.2.17 kata <none> <none>
nginx-deployment-d49c76cf-gb76f 1/1 Running 0 34s 10.244.2.20 kata <none> <none>
nginx-deployment-d49c76cf-hvrj8 1/1 Running 0 34s 10.244.2.21 kata <none> <none>
nginx-deployment-d49c76cf-kvq44 1/1 Running 0 34s 10.244.2.13 kata <none> <none>
nginx-deployment-d49c76cf-n8vck 1/1 Running 0 34s 10.244.2.18 kata <none> <none>
nginx-deployment-d49c76cf-t7zr4 1/1 Running 0 34s 10.244.2.14 kata <none> <none>
nginx-deployment-d49c76cf-vjm62 1/1 Running 0 34s 10.244.2.16 kata <none> <none>
nginx-deployment-d49c76cf-xkjq9 1/1 Running 0 34s 10.244.2.12 kata <none> <none>
nginx-deployment-d49c76cf-xm5s2 1/1 Running 0 34s 10.244.2.19 kata <none> <none>
クラスタ内で kata containers をサポートしている/していないノードが混在している場合は上記のような方法でサポートしているノードのみで pod を起動させることができます。
ちなみに pod のプロパティとして Runtime Class Name: kata
が指定されていることは確認できますが、実際にコンテナがどのような runtime で起動されるかはノード側の CRI 側に依存しているため、pod が kata containers を使って起動されたかどうかを示す固有の情報はありません。
$ k describe pod nginx-deployment-d49c76cf-9mftt
Name: nginx-deployment-d49c76cf-9mftt
Namespace: default
...
Runtime Class Name: kata
...
Containers:
nginx:
Container ID: containerd://00dc76dad52234b6bda10daaef70e870908ae76cd3895d1acab87a99ac3f89ca
前に見たように pod が起動しているノード上では kata 関係のプロセスが動作しているのでそちらで判別できます。
annotation で hypervisor の設定を制御する
kata containers ではコンテナやポッドに annotation をつけることで様々な動作を設定できます。サポートされている annotation は Kata Configuration Annotations に一覧があります。例えば VM (コンテナ) に割り当てるメモリを変更するには io.katacontainers.config.hypervisor.default_memory
という annotation に割り当てるメモリ量を MiB 単位で指定するというような具合になります。
nerdctl ではメジャーバージョン 2 より annotation のオプションに対応しているのでこちらで動作を確認してみます。
まず普通に kata containers でコンテナを起動して、コンテナ内から CPU、メモリを確認すると CPU が1、メモリは 2 GB 割り当てられていることが確認できます。
$ sudo nerdctl run --runtime io.containerd.kata.v2 --name kata -it docker.io/library/ubuntu
WARN[0000] cannot set cgroup manager to "systemd" for runtime "io.containerd.kata.v2"
root@7c454968eae8:/#
root@7c454968eae8:/# free -h
total used free shared buff/cache available
Mem: 1.9Gi 47Mi 1.9Gi 28Ki 8.5Mi 1.9Gi
Swap: 0B 0B 0B
root@7c454968eae8:/# cat /proc/cpuinfo
processor : 0
vendor_id : AuthenticAMD
cpu family : 23
model : 24
model name : AMD Ryzen 5 3550H with Radeon Vega Mobile Gfx
stepping : 1
microcode : 0x8108109
cpu MHz : 2096.054
cache size : 512 KB
physical id : 0
siblings : 1
core id : 0
cpu cores : 1
apicid : 0
initial apicid : 0
fpu : yes
fpu_exception : yes
cpuid level : 13
wp : yes
flags : fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush mmx fxsr sse sse2 syscall nx mmxext fxsr_opt pdpe1gb rdtscp lm rep_good nopl cpuid extd_apicid tsc_known_freq pni pclmulqdq ssse3 fma cx16 sse4_1 sse4_2 x2apic movbe popcnt tsc_deadline_timer aes xsave avx f16c rdrand hypervisor lahf_lm cmp_legacy svm cr8_legacy abm sse4a misalignsse 3dnowprefetch osvw perfctr_core ssbd ibpb vmmcall fsgsbase tsc_adjust bmi1 avx2 smep bmi2 rdseed adx smap clflushopt sha_ni xsaveopt xsavec xgetbv1 clzero xsaveerptr virt_ssbd arat npt nrip_save arch_capabilities
bugs : sysret_ss_attrs null_seg spectre_v1 spectre_v2 spec_store_bypass retbleed smt_rsb srso div0
bogomips : 4192.10
TLB size : 1024 4K pages
clflush size : 64
cache_alignment : 64
address sizes : 48 bits physical, 48 bits virtual
power management:
kata containers から起動されるホスト側の qemu プロセスの引数で指定されている -m 2048M
がメモリ、-smp 1
が cpu 1 に対応しています(たぶん)。
qemu プロセスの詳細
/opt/kata/bin/qemu-system-x86_64 -name sandbox-fc4b38ccfa3cdf758559413f993ff677c7e51737b59332ac81135406ae2dda32 -uuid 0f043adf-7e49-4a36-824b-4dde7ba028f5 -machine q35,accel=kvm,nvdimm=on -cpu host,pmu=off -qmp unix:fd=3,server=on,wait=off -m 2048M,slots=10,maxmem=17013M -device pci-bridge,bus=pcie.0,id=pci-bridge-0,chassis_nr=1,shpc=off,addr=2,io-reserve=4k,mem-reserve=1m,pref64-reserve=1m -device virtio-serial-pci,disable-modern=true,id=serial0 -device virtconsole,chardev=charconsole0,id=console0 -chardev socket,id=charconsole0,path=/run/vc/vm/fc4b38ccfa3cdf758559413f993ff677c7e51737b59332ac81135406ae2dda32/console.sock,server=on,wait=off -device nvdimm,id=nv0,memdev=mem0,unarmed=on -object memory-backend-file,id=mem0,mem-path=/opt/kata/share/kata-containers/kata-ubuntu-latest.image,size=268435456,readonly=on -device virtio-scsi-pci,id=scsi0,disable-modern=true -object rng-random,id=rng0,filename=/dev/urandom -device virtio-rng-pci,rng=rng0 -device vhost-vsock-pci,disable-modern=true,vhostfd=4,id=vsock-3794461917,guest-cid=3794461917 -chardev socket,id=char-b8b8147ca7b201a2,path=/run/vc/vm/fc4b38ccfa3cdf758559413f993ff677c7e51737b59332ac81135406ae2dda32/vhost-fs.sock -device vhost-user-fs-pci,chardev=char-b8b8147ca7b201a2,tag=kataShared,queue-size=1024 -rtc base=utc,driftfix=slew,clock=host -global kvm-pit.lost_tick_policy=discard -vga none -no-user-config -nodefaults -nographic --no-reboot -object memory-backend-file,id=dimm1,size=2048M,mem-path=/dev/shm,share=on -numa node,memdev=dimm1 -kernel /opt/kata/share/kata-containers/vmlinux-6.1.62-135 -append tsc=reliable no_timer_check rcupdate.rcu_expedited=1 i8042.direct=1 i8042.dumbkbd=1 i8042.nopnp=1 i8042.noaux=1 noreplace-smp reboot=k cryptomgr.notests net.ifnames=0 pci=lastbus=0 root=/dev/pmem0p1 rootflags=dax,data=ordered,errors=remount-ro ro rootfstype=ext4 console=hvc0 console=hvc1 quiet systemd.show_status=false panic=1 nr_cpus=4 selinux=0 systemd.unit=kata-containers.target systemd.mask=systemd-networkd.service systemd.mask=systemd-networkd.socket scsi_mod.scan=none -pidfile /run/vc/vm/fc4b38ccfa3cdf758559413f993ff677c7e51737b59332ac81135406ae2dda32/pid -smp 1,cores=1,threads=1,sockets=4,maxcpus=4
次に以下の annotation を設定して cpu を 2、メモリを 1 GB に変更してみます。
sudo nerdctl run --runtime io.containerd.kata.v2 \
--name kata \
--annotation io.katacontainers.config.hypervisor.default_max_vcpus=2 \
--annotation io.katacontainers.config.hypervisor.default_vcpus=2.0 \
--annotation io.katacontainers.config.hypervisor.default_memory=1024 \
-it --rm docker.io/library/ubuntu
以下のエラーが発生
failed to create containerd task: failed to create shim task: annotation io.katacontainers.config.hypervisor.default_vcpus is not enabled: unknown
色々調べると annotation を設定するためには明示的に enable に指定する必要があるようです。annotations はソースコードとしては以下の箇所で処理されています。
NumVCPUs float32 `toml:"default_vcpus"`
DefaultMaxVCPUs uint32 `toml:"default_maxvcpus"`
MemorySize uint32 `toml:"default_memory"`
このフィールド名に基づいて、kata container の設定ファイルである /etc/kata-containers/configuration.toml
の enable_annotations
に有効化したい annotation を追加します。
# List of valid annotation names for the hypervisor
# Each member of the list is a regular expression, which is the base name
# of the annotation, e.g. "path" for io.katacontainers.config.hypervisor.path"
- enable_annotations = ["enable_iommu", "virtio_fs_extra_args", "kernel_params"]
+ enable_annotations = ["enable_iommu", "virtio_fs_extra_args", "kernel_params", "default_vcpus", "default_max_vcpus", "default_memory"]
手元の環境では kata runtime 実行時に上記の設定ファイルがうまく読み込まれなかったため、以下も追加で設定しました。このあたりは環境によるかも
-
/usr/local/bin/containerd-shim-kata-v2
内で KATA_CONF_FILE で読み込むファイルを明示的に指定。 - 残りの引数は
/opt/kata/bin/containerd-shim-kata-v2
実行時に受け渡す。
#!/bin/bash
KATA_CONF_FILE=/etc/kata-containers/configuration.toml /opt/kata/bin/containerd-shim-kata-v2 $@
再度 annotation をつけてコンテナを作成
sudo nerdctl run --runtime io.containerd.kata.v2 \
--name kata \
--annotation io.katacontainers.config.hypervisor.default_max_vcpus=2 \
--annotation io.katacontainers.config.hypervisor.default_vcpus=2.0 \
--annotation io.katacontainers.config.hypervisor.default_memory=1024 \
-it --rm docker.io/library/ubuntu
cpu が 2 つに増えており、メモリが 1 GB になっていることがわかります。
root@eec0c2ee2217:/# cat /proc/cpuinfo
processor : 0
vendor_id : AuthenticAMD
cpu family : 23
model : 24
model name : AMD Ryzen 5 3550H with Radeon Vega Mobile Gfx
stepping : 1
microcode : 0x8108109
cpu MHz : 2096.054
cache size : 512 KB
physical id : 0
siblings : 1
core id : 0
cpu cores : 1
apicid : 0
initial apicid : 0
fpu : yes
fpu_exception : yes
cpuid level : 13
wp : yes
flags : fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush mmx fxsr sse sse2 syscall nx mmxext fxsr_opt pdpe1gb rdtscp lm rep_good nopl cpuid extd_apicid tsc_known_freq pni pclmulqdq ssse3 fma cx16 sse4_1 sse4_2 x2apic movbe popcnt tsc_deadline_timer aes xsave avx f16c rdrand hypervisor lahf_lm cmp_legacy svm cr8_legacy abm sse4a misalignsse 3dnowprefetch osvw perfctr_core ssbd ibpb vmmcall fsgsbase tsc_adjust bmi1 avx2 smep bmi2 rdseed adx smap clflushopt sha_ni xsaveopt xsavec xgetbv1 clzero xsaveerptr virt_ssbd arat npt nrip_save arch_capabilities
bugs : sysret_ss_attrs null_seg spectre_v1 spectre_v2 spec_store_bypass retbleed smt_rsb srso div0
bogomips : 4192.10
TLB size : 1024 4K pages
clflush size : 64
cache_alignment : 64
address sizes : 48 bits physical, 48 bits virtual
power management:
processor : 1
vendor_id : AuthenticAMD
cpu family : 23
model : 24
model name : AMD Ryzen 5 3550H with Radeon Vega Mobile Gfx
stepping : 1
microcode : 0x8108109
cpu MHz : 2096.054
cache size : 512 KB
physical id : 1
siblings : 1
core id : 0
cpu cores : 1
apicid : 1
initial apicid : 1
fpu : yes
fpu_exception : yes
cpuid level : 13
wp : yes
flags : fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush mmx fxsr sse sse2 syscall nx mmxext fxsr_opt pdpe1gb rdtscp lm rep_good nopl cpuid extd_apicid tsc_known_freq pni pclmulqdq ssse3 fma cx16 sse4_1 sse4_2 x2apic movbe popcnt tsc_deadline_timer aes xsave avx f16c rdrand hypervisor lahf_lm cmp_legacy svm cr8_legacy abm sse4a misalignsse 3dnowprefetch osvw perfctr_core ssbd ibpb vmmcall fsgsbase tsc_adjust bmi1 avx2 smep bmi2 rdseed adx smap clflushopt sha_ni xsaveopt xsavec xgetbv1 clzero xsaveerptr virt_ssbd arat npt nrip_save arch_capabilities
bugs : sysret_ss_attrs null_seg spectre_v1 spectre_v2 spec_store_bypass retbleed smt_rsb srso div0
bogomips : 4192.10
TLB size : 1024 4K pages
clflush size : 64
cache_alignment : 64
address sizes : 48 bits physical, 48 bits virtual
power management:
root@eec0c2ee2217:/# free -h
total used free shared buff/cache available
Mem: 985Mi 41Mi 949Mi 32Ki 8.6Mi 944Mi
Swap: 0B 0B 0B
ホスト側の qemu プロセスを比較すると引数が -m 1024M
, -smp 2
に変更されていることが確認できます。
qemu プロセスの詳細
/opt/kata/bin/qemu-system-x86_64 -name sandbox-94710f792caefe73519d9269ce80cc4340a90602274ebf1c20686433911ac07c -uuid f8638b72-72bd-4ff0-9095-acca9755d29c -machine q35,accel=kvm,nvdimm=on -cpu host,pmu=off -qmp unix:fd=3,server=on,wait=off -m 1024M,slots=10,maxmem=17013M -device pci-bridge,bus=pcie.0,id=pci-bridge-0,chassis_nr=1,shpc=off,addr=2,io-reserve=4k,mem-reserve=1m,pref64-reserve=1m -device virtio-serial-pci,disable-modern=true,id=serial0 -device virtconsole,chardev=charconsole0,id=console0 -chardev socket,id=charconsole0,path=/run/vc/vm/94710f792caefe73519d9269ce80cc4340a90602274ebf1c20686433911ac07c/console.sock,server=on,wait=off -device nvdimm,id=nv0,memdev=mem0,unarmed=on -object memory-backend-file,id=mem0,mem-path=/opt/kata/share/kata-containers/kata-ubuntu-latest.image,size=268435456,readonly=on -device virtio-scsi-pci,id=scsi0,disable-modern=true -object rng-random,id=rng0,filename=/dev/urandom -device virtio-rng-pci,rng=rng0 -device vhost-vsock-pci,disable-modern=true,vhostfd=4,id=vsock-1826160476,guest-cid=1826160476 -chardev socket,id=char-7f812da4e742018b,path=/run/vc/vm/94710f792caefe73519d9269ce80cc4340a90602274ebf1c20686433911ac07c/vhost-fs.sock -device vhost-user-fs-pci,chardev=char-7f812da4e742018b,tag=kataShared,queue-size=1024 -rtc base=utc,driftfix=slew,clock=host -global kvm-pit.lost_tick_policy=discard -vga none -no-user-config -nodefaults -nographic --no-reboot -object memory-backend-file,id=dimm1,size=1024M,mem-path=/dev/shm,share=on -numa node,memdev=dimm1 -kernel /opt/kata/share/kata-containers/vmlinux-6.1.62-135 -append tsc=reliable no_timer_check rcupdate.rcu_expedited=1 i8042.direct=1 i8042.dumbkbd=1 i8042.nopnp=1 i8042.noaux=1 noreplace-smp reboot=k cryptomgr.notests net.ifnames=0 pci=lastbus=0 root=/dev/pmem0p1 rootflags=dax,data=ordered,errors=remount-ro ro rootfstype=ext4 console=hvc0 console=hvc1 quiet systemd.show_status=false panic=1 nr_cpus=2 selinux=0 systemd.unit=kata-containers.target systemd.mask=systemd-networkd.service systemd.mask=systemd-networkd.socket scsi_mod.scan=none -pidfile /run/vc/vm/94710f792caefe73519d9269ce80cc4340a90602274ebf1c20686433911ac07c/pid -smp 2,cores=1,threads=1,sockets=2,maxcpus=2
上記のように kata containers では annotation を使うことで VM や hypervisor の動作を制御することが可能となっています。
k8s の場合は pod annotations に設定することで同様の動作が実現できます。
apiVersion: apps/v1
kind: Deployment
metadata:
name: ubuntu
labels:
app: ubuntu
spec:
replicas: 1
selector:
matchLabels:
app: ubuntu
template:
metadata:
labels:
app: ubuntu
annotations:
io.katacontainers.config.hypervisor.default_max_vcpus: "2"
io.katacontainers.config.hypervisor.default_vcpus: "2.0"
io.katacontainers.config.hypervisor.default_memory: "1024"
spec:
runtimeClassName: kata
containers:
- name: ubuntu
image: ubuntu:23.04
command:
- sleep
- "36000"
Discussion