Kata Containers по факту сейчас основной способ запустить контейнеры в изолированной виртуальной машине для большей безопасности. По работе мне приходится запускать образы контейнеров, которым я не всегда могу полностью доверять. Раньше я использовал для этого виртуальною машину в Virtualbox в связке с Docker-Machine, но так как Docker-Machine с 2021 года больше не развивается, я решил рассмотреть варианты замены.

И я был очень удивлен, узнав, что в OpenSuse Tumbleweed, на который я мигрировал после 16 лет с Ubuntu, нет готовых пакетов для Kata Containers. Более того, при этом есть контейнеры для Firecracker microvm, специально созданным в AWS для запуска Linux контейнеров в изолированной среде. Но так как пакеты для Firecracker так же шли без Firecracker-Containerd runtime, я вернулся к идее попробовать Kata Containers.

В 2024 официальная документация Kata Containers гласит, что готовые пакеты доступны только в репозиториях дистрибутивов Fedora и Centos, а так же для Ubuntu через Snap пакеты. В остальных же случаях, например в моем, единственными вариантами остается сборка из исходников или установка уже собранных бинарных файлов из Github с помощью специального скрипта kata-manager.sh. Сами разработчики в документации предлагают именно второй вариант.

Сам скрипт kata-manager.sh просто распакует архив выбранного релиза с Github в /opt/kata, создаст конфиги в /etc/kata-containers/ и настроит симлинки в /usr/bin/ для kata-runtime, kata-collect-data.sh и containerd-shim-kata-v2. Этого уже будет достаточно, чтобы вызов docker run --runtime io.containerd.run.kata.v2 создавал контейнер в виртуальной машине Qemu (по умолчанию) с 1 cpu и 2 gb ram. Интересный факт: containerd ищет runtime в PATH по специальной схеме, и io.containerd.run.kata.v2 превращается в поиск containerd-shim-kata-v2 в PATH без необходимости настраивать что-либо в конфигах.

Чем такая установка хуже установки из пакетов вашего дистрибутива Linux: в данный момент Kata Containers поставляется с собственным полным набором гипервизоров (Qemu, Firecracker, etc...), образов системы для запуска и прочих необходимых файлов, никак не завися от внешних компонентов. И естественно все эти компоненты нужно обновлять в целях обеспечения безопасности. А в данном случае обновлять приходится на свой страх и риск, полностью заменяя файлы предыдущей версии на непроверенные новые. К примеру, у меня в версии 3.6.0 из коробки не заработал Fireckracker. В случае пакетов дистрибутива есть хотя бы шанc на то, что их тестируют как следует. Еще одним последствием обновления будет потенциальная необходимость перезапуска все уже запущенных контейнеров с новой версией, но это будет верным и для установки из пакетов.

Конечно куда более лучшим решением является установка каждой версии в свой отдельный путь. Итак, устанавливаем нужную нам версию с Github:

VERSION=3.8.0
DIR="/opt/kata_$VERSION"
PACKAGE="kata-static-$VERSION-$(uname -m | sed -e 's/x86_64/amd64/' -e 's/aarch64\|arm64/arm64/' -e 's/ppc64le/ppc64le/' -e 's/s390x/s390x/').tar.xz"

curl -LO https://github.com/kata-containers/kata-containers/releases/download/$VERSION/$PACKAGE

sudo mkdir -p "$DIR"

sudo tar -xJf "$PACKAGE" --strip-components=3 -C "$DIR"

Содержимое должно быть успешно распаковано:

$ ll $DIR
total 20
drwxr-xr-x 1 root root   110 Aug 25 12:24 ./
drwxr-xr-x 1 root root   150 Aug 25 12:15 ../
drwxr-xr-x 1 root root   490 Aug 21 17:53 bin/
drwxr-xr-x 1 root root    50 Aug 15 20:52 include/
drwxr-xr-x 1 root root    70 Aug 15 20:52 lib/
drwxr-xr-x 1 root root    30 Aug  9 12:45 libexec/
drwxr-xr-x 1 root root     6 Aug 21 18:01 runtime-rs/
drwxr-xr-x 1 root root   154 Aug 21 18:02 share/
-rw-r--r-- 1 root root    29 Aug 21 18:08 VERSION
-rw-r--r-- 1 root root 13678 Aug 21 18:08 versions.yaml

Есть много доступных гипервизоров на выбор, по умолчанию используется Qemu:

$ ll $DIR/share/defaults/kata-containers/
total 420
drwxr-xr-x 1 root root   906 Aug 21 18:02 ./
drwxr-xr-x 1 root root    30 Aug 21 18:01 ../
-rw-r--r-- 1 root root 10930 Aug 21 18:02 configuration-acrn.toml
-rw-r--r-- 1 root root 19799 Aug 21 18:02 configuration-clh.toml
-rw-r--r-- 1 root root 16708 Aug 21 18:02 configuration-fc.toml
-rw-r--r-- 1 root root 29756 Aug 21 18:02 configuration-qemu-coco-dev.toml
-rw-r--r-- 1 root root 28990 Aug 21 18:02 configuration-qemu-nvidia-gpu-snp.toml
-rw-r--r-- 1 root root 28964 Aug 21 18:02 configuration-qemu-nvidia-gpu-tdx.toml
-rw-r--r-- 1 root root 29631 Aug 21 18:02 configuration-qemu-nvidia-gpu.toml
-rw-r--r-- 1 root root 28098 Aug 21 18:02 configuration-qemu-se.toml
-rw-r--r-- 1 root root 27635 Aug 21 18:02 configuration-qemu-sev.toml
-rw-r--r-- 1 root root 29032 Aug 21 18:02 configuration-qemu-snp.toml
-rw-r--r-- 1 root root 28798 Aug 21 18:02 configuration-qemu-tdx.toml
-rw-r--r-- 1 root root 29649 Aug 21 18:02 configuration-qemu.toml
-rw-r--r-- 1 root root 13910 Aug 21 18:02 configuration-remote.toml
-rw-r--r-- 1 root root 17523 Aug 21 18:02 configuration-stratovirt.toml
lrwxrwxrwx 1 root root    23 Aug 21 18:02 configuration.toml -> configuration-qemu.toml
-rw-r--r-- 1 root root 10232 Aug 21 18:03 genpolicy-settings.json
-rw-r--r-- 1 root root 36237 Aug 21 18:03 rules.rego
drwxr-xr-x 1 root root   280 Aug 21 18:01 runtime-rs/

Подробнее про конфигурацию можно прочитать здесь и здесь.

Теперь нам остается только создать необходимы симлинки:

sudo ln -s $DIR /opt/kata
sudo ln -s /opt/kata/share/defaults/kata-containers /etc/kata-containers
sudo ln -s /opt/kata/bin/containerd-shim-kata-v2 /usr/bin/containerd-shim-kata-v2
sudo ln -s /opt/kata/bin/kata-runtime /usr/bin/kata-runtime

Проверяем, что все сработало, запустив контейнер busybox:

$ sudo docker run --runtime io.containerd.run.kata.v2 busybox uname -a
Linux 88c1b982e983 6.1.62 #1 SMP Wed Jul 17 13:00:20 UTC 2024 x86_64 GNU/Linux

Чтобы сделать Kata рантаймом по умолчанию, нужно в /etc/docker/daemon.json добавить "default-runtime": "io.containerd.run.kata.v2":

$ cat /etc/docker/daemon.json
{
  "default-runtime": "io.containerd.run.kata.v2"
}

И перезагрузить docker:

sudo systemctl reload docker

Проверяем:

$ sudo docker run busybox uname -a
Linux 88c1b982e983 6.1.62 #1 SMP Wed Jul 17 13:00:20 UTC 2024 x86_64 GNU/Linux

В будущем при установке новой версии нам нужно будет всего лишь поменять симлинк:

sudo rm -f /opt/kata
sudo ln -s $DIR /opt/kata

Если же мы хотим иметь возможность использовать разные версии Kata runtime без переключения симлинка /opt/kata, то нам придется использовать пару хаков. Сложность заключается в том, что в исполняемые файлы Kata местами намертво зашит путь /opt/kata, а так же два пути конфигурационных файлов:

$ kata-runtime --show-default-config-paths
/etc/kata-containers/configuration.toml
/opt/kata/share/defaults/kata-containers/configuration.toml

Конфиги можно переопределить с помощью переменной KATA_CONF_FILE. Так же containerd-shim-kata-v2 будет искать kata-runtime в PATH. Все это можно решить с помощью скрипта-обертки.

Теперь нам нужно обновить все файлы для использование нашего нового пути вместо /opt/kata:

grep -rlI '/opt/kata' "$DIR" | sudo xargs sed -i "s|/opt/kata|$DIR|g"

К сожалению, это не решит проблему с вшитым в Qemu путем для поиска bios, поэтому нам все же понадобится симлинка /opt/kata. Если вы еще ее не создали, то пора:

sudo ln -s $DIR /opt/kata

Хорошая новость заключается в том, что благодаря изменениям в конфигах kata-runtime будет использовать именно свои собственные образы системы и бинарные файлы, а не находящиеся по умолчанию в /opt/kata.

Осталось создать скрипты для запуска containerd-shim-kata-v2:

cat <<EOF | sudo tee "/usr/bin/containerd-shim-kata_$(echo "$VERSION" | sed 's/\./_/g')-v2" > /dev/null
#!/bin/sh
export KATA_CONF_FILE="$DIR/share/defaults/kata-containers/configuration.toml"
export PATH="$DIR/bin:\$PATH"
exec $DIR/bin/containerd-shim-kata-v2 "\$@"
EOF

sudo chmod +x "/usr/bin/containerd-shim-kata_$(echo "$VERSION" | sed 's/\./_/g')-v2"

И kata-runtime:

cat <<EOF | sudo tee "/usr/bin/kata-runtime-$VERSION" > /dev/null
#!/bin/sh
export KATA_CONF_FILE="$DIR/share/defaults/kata-containers/configuration.toml"
export PATH="$DIR/bin:\$PATH"
exec $DIR/bin/kata-runtime "\$@"
EOF

sudo chmod +x "/usr/bin/kata-runtime-$VERSION"

Проверяем:

$ echo "io.containerd.run.kata_$(echo "$VERSION" | sed 's/\./_/g').v2"
io.containerd.run.kata_3_8_0.v2

$ sudo docker run --runtime io.containerd.run.kata_3_8_0.v2 busybox uname -a
Linux 88c1b982e983 6.1.62 #1 SMP Wed Jul 17 13:00:20 UTC 2024 x86_64 GNU/Linux

По умолчанию Kata runtime запускает виртуальную машину с 1 cpu и 2 gb ram. Чтобы переопределить эти параметры, нам нужно передать docker run параметры --cpus (-c у меня не заработала) и -m или --memory, причем заданные параметры будут прибавляться к параметрам по умолчанию, то есть --cpus 1 --memory 512m приведет к использованию 2 cpu и 2.5 gb memory. При этом реальная память хоста не блокируется на эти 2.5 gb, а используется в меру необходимости.

Все остальное, вроде сети, должно работать по умолчанию. Например мы можем получить ответ от nginx:

$ sudo docker run -d --name nginx nginx
8663b33cad7e5b820be85468aa760e6ea34fc870adf7d924922788266041c898

$ sudo docker inspect -f '{{range.NetworkSettings.Networks}}{{.IPAddress}}{{end}}' nginx
172.17.0.2

$ curl 172.17.0.2
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
html { color-scheme: light dark; }
body { width: 35em; margin: 0 auto;
font-family: Tahoma, Verdana, Arial, sans-serif; }
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>
<p>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p>
<p><em>Thank you for using nginx.</em></p>
</body>
</html>

Монтирование тоже работает нормально:

$ sudo docker run --runtime io.containerd.run.kata_3_8_0.v2 -v /tmp:/tmp busybox ls /tmp
dbus-1b94OvKJfW
sddm-auth-ad8346f2-fbc8-4b74-9c03-e33d1136248e
systemd-private-a2ad86d46c374394957b41737f945998-ModemManager.service-tsH78Z
systemd-private-a2ad86d46c374394957b41737f945998-bluetooth.service-Bct8TG
systemd-private-a2ad86d46c374394957b41737f945998-dbus-broker.service-mpkAbN
systemd-private-a2ad86d46c374394957b41737f945998-fwupd.service-1Uiyrr
systemd-private-a2ad86d46c374394957b41737f945998-iio-sensor-proxy.service-1IKcZf
systemd-private-a2ad86d46c374394957b41737f945998-irqbalance.service-VvFZzU
systemd-private-a2ad86d46c374394957b41737f945998-polkit.service-58al8n
systemd-private-a2ad86d46c374394957b41737f945998-power-profiles-daemon.service-U13kul
systemd-private-a2ad86d46c374394957b41737f945998-systemd-logind.service-r2T6Xu
systemd-private-a2ad86d46c374394957b41737f945998-upower.service-aUQ6HX
tmp.CERJypVFNb
tmp.Lk54RYD5Tl
tmp.OWS9PKcNm8
tmp.cUYADP9m4f
tmp.hTZnG0skQ4
tmp.k3XnzrTg2k
tmp.mFpNhgIVQT
tmp.mvGoSlep7Z
tmp.nIDfmAGIo2
tmp.yQNEJyMj86

$ sudo docker run --runtime io.containerd.run.kata_3_8_0.v2 -v /tmp:/tmp busybox mount
none on / type virtiofs (rw,relatime)
proc on /proc type proc (rw,nosuid,nodev,noexec,relatime)
tmpfs on /dev type tmpfs (rw,nosuid,size=65536k,mode=755)
devpts on /dev/pts type devpts (rw,nosuid,noexec,relatime,gid=5,mode=620,ptmxmode=666)
sysfs on /sys type sysfs (ro,nosuid,nodev,noexec,relatime)
tmpfs on /sys/fs/cgroup type tmpfs (ro,nosuid,nodev,noexec,relatime)
cgroup on /sys/fs/cgroup/devices type cgroup (ro,nosuid,nodev,noexec,relatime,devices)
cgroup on /sys/fs/cgroup/cpu,cpuacct type cgroup (ro,nosuid,nodev,noexec,relatime,cpu,cpuacct)
cgroup on /sys/fs/cgroup/hugetlb type cgroup (ro,nosuid,nodev,noexec,relatime,hugetlb)
cgroup on /sys/fs/cgroup/net_cls,net_prio type cgroup (ro,nosuid,nodev,noexec,relatime,net_cls,net_prio)
cgroup on /sys/fs/cgroup/perf_event type cgroup (ro,nosuid,nodev,noexec,relatime,perf_event)
cgroup on /sys/fs/cgroup/freezer type cgroup (ro,nosuid,nodev,noexec,relatime,freezer)
cgroup on /sys/fs/cgroup/pids type cgroup (ro,nosuid,nodev,noexec,relatime,pids)
cgroup on /sys/fs/cgroup/blkio type cgroup (ro,nosuid,nodev,noexec,relatime,blkio)
cgroup on /sys/fs/cgroup/memory type cgroup (ro,nosuid,nodev,noexec,relatime,memory)
cgroup on /sys/fs/cgroup/cpuset type cgroup (ro,nosuid,nodev,noexec,relatime,cpuset)
cgroup on /sys/fs/cgroup/systemd type cgroup (rw,nosuid,nodev,noexec,relatime,xattr,name=systemd)
mqueue on /dev/mqueue type mqueue (rw,nosuid,nodev,noexec,relatime)
shm on /dev/shm type tmpfs (rw,relatime)
none on /tmp type virtiofs (rw,relatime)
kataShared on /etc/resolv.conf type virtiofs (rw,relatime)
kataShared on /etc/hostname type virtiofs (rw,relatime)
kataShared on /etc/hosts type virtiofs (rw,relatime)
tmpfs on /proc/timer_list type tmpfs (rw,nosuid,size=65536k,mode=755)
proc on /proc/bus type proc (ro,relatime)
proc on /proc/fs type proc (ro,relatime)
proc on /proc/irq type proc (ro,relatime)
proc on /proc/sys type proc (ro,relatime)

ps: если вы ищете Senior или Lead DevOps в Европе - welcome:
- linkedin
- github

Комментарии (0)