Kuasar – runtime с поддержкой sandbox
Что сегодня?
В одной из прошлых статей (https://openscaler.ru/2024/02/19/isulad-kata-k8s/) мы рассмотрели технологию запуска контейнеров в обособленных виртуальных машинах и сегодня нам на рассмотрение попалась ещё одна подобная технология, которая позволит повысить безопасность запуска приложений в контейнерах. Данный проект называется kuasar, с деталями, документацией и примерами мы можете ознакомится пройдя по ссылке https://github.com/kuasar-io/kuasar.
Немного теории
Как написано на сайте проекта, Kuasar – это эффективная контейнерная среда выполнения, которая предоставляет облачные контейнерные решения для всех сценариев, поддерживая несколько методов изолированной среды (sandbox). Написанная на Rust, она предлагает стандартную абстракцию изолированной среды на основе API sandbox. Кроме того, Kuasar предоставляет оптимизированную платформу для ускорения запуска контейнера и сокращения ненужных накладных расходов.
Пока всё выглядит многообещающе. Из таблички https://github.com/kuasar-io/kuasar?tab=readme-ov-file#supported-sandboxes мы узнаём, что на данный момент kuasar подерживает 4 типа sandbox (MicroVM, Wasm, App kernel, runC).
Нас будет интересовать в данном случае MicroVM (где уже по состоянию на февраль 2025 поддерживаются Cloud Hypervisor, QEMU, StratoVir). Напомню, что про виртуализацию StratoVirt на нашем сайте уже была статья — интересующиеся могут пройти и ознакомится по ссылке https://openscaler.ru/2024/05/31/who-is-stratovirt/.
Теперь давайте немного ознакомимся с sandbox API, для этого идём дальше по описанию проекта kuasar.
В мире контейнеров изолированная среда (sandbox) – это технология, используемая для отделения процессов в контейнерах друг от друга и от самой операционной системы. После появления API-интерфейса Sandbox (https://github.com/containerd/containerd/issues/4131) sandbox стала довольно востребованным сервисом при применении технологии контейнеризации.
Kuasar поддерживает несколько типов sandbox, что позволяет пользователям выбирать наиболее подходящие “песочницы” для каждого приложения в соответствии с требованиями приложения.
Так же, упомянем, что Kuasar позволяет запускать несколько типов песочниц на одном узле, что даёт возможность сбалансировать требования пользователей к безопасности, а также позволяет использовать пул ресурсов узлов для удовлетворения различных требований облачных сценариев.
Архитектура Kuasar
Со схемами взаимодействия компонентов Kuasar можно ознакомится прямо на сайте проекта https://github.com/kuasar-io/kuasar?tab=readme-ov-file#kuasar-architecture. Мы не будем копировать их в нашу статью. Заметим однако, что важным компонентом работы Kuasar является containerd, в который добавлена поддержка kuasar. Пишем это замечание, поскольку если кто-то будет руководствоваться инструкцией по установке kuasar размещённой на сайте документации по openeuler (https://docs.openeuler.org/en/docs/24.03_LTS_SP1/docs/Container/kuasar.html), то он ничего не найдёт там про установку и настройку containerd, хотя на самом сайте разработчиков kuasar есть отдельная инструкция по установке связки kuasar + isulad + stratovirt (https://github.com/kuasar-io/kuasar/blob/main/docs/vmm/how-to-run-kuasar-with-isulad-and-stratovirt.md) где чётко прописана установка и настройка containerd. Более того, если посмотреть в SPEC файл сборки RPM пакета kuasar (который входит в официальный репозиторий openeuler и openscaler) видно, что kuasar собран с только с поддержкой QEMU и для запуска с stratovirt надо выполнить пересборку kuasar с его поддержкой.
Теперь давайте перейдём к тестированию kuasar.
Используемый стенд
Для демонстрации kuasar мы будем использовать виртуальный сервер в среде виртуализации oVirt (да, я в курсе, что в документации написано не использовать виртуалки, но мы прокинули CPU со всеми его флагами внутрь виртуальной машины), для теста функциональности этого будет вполне достаточно.
Наша виртуальная машина имеет 4 vCPU и 8Гб оперативной памяти. Объём диска нам не особо важен, но я всё равно упомяну, что он равен 40 Гб. Работает виртуальная машина под управлением недавно опубликованного OpenScaler 24.03 SP1 (скачать и попробовать свежий релиз вы всегда можете пройдя по ссылке https://repo.openscaler.ru/openScaler-24.03-LTS-SP1/ISO/).
Установка kuasar
Для начала установим необходимые CRI утилиты:
tar -zxvf crictl-v1.32.0-linux-amd64.tar.gz -C /usr/local/bin
Подготовим конфигурационный файл, который будет работать с containerd:
/etc/crictl.yaml
runtime-endpoint: unix:///run/containerd/containerd.sock
image-endpoint: unix:///run/containerd/containerd.sock
timeout: 10
Далее, установим CNI плагины:
mkdir -p /opt/cni/bin && mkdir -p /etc/cni/net.d
wget https://github.com/containernetworking/plugins/releases/download/v1.3.0/cni-plugins-linux-amd64-v1.3.0.tgz
tar -zxvf cni-plugins-linux-amd64-v1.3.0.tgz -C /opt/cni/bin/
Скачаем и установим virtio-fs:
wget https://gitlab.com/-/project/21523468/uploads/2f45be3a726b0ff01b38230bfa48000c/virtiofsd-v1.11.0.zip
Распаковываем и помещаем в /usr/local/bin/virtiofsd
Мы попробуем побыть оригинальными и не будем брать привычный QEMU или знакомый нам уже StratoVirt. Мы попробуем запустить нашу MicroVM с использованием cloud-hypervisor (ссылка на сайт проекта https://github.com/cloud-hypervisor/cloud-hypervisor/).
Качаем с сайта проекта последний релиз (v44.0) и помещаем скаченный бинарник по пути /usr/local/bin/cloud-hypervisor
Теперь дошла очередь до установки самого kuasar — для этого с сайта проекта скачиваем последний доступный релиз — https://github.com/kuasar-io/kuasar/releases/tag/v1.0.0, распаковываем его.
С файлами из скаченного архива поступаем следующим образом:
-
config.toml – размещаем в /etc/containerd/config.toml
-
config_clh.toml – размещаем в /var/lib/kuasar/config_clh.toml
-
containerd – размещаем в /usr/local/bin/containerd
-
kuasar.img – размещаем в /var/lib/kuasar/kuasar.img
-
quark-sandboxer – этот файл не понадобится
-
runc-sandboxer – этот файл не понадобится
-
vmlinux.bin – размещаем в /var/lib/kuasar/vmlinux.bin
-
vmm-sandboxer – размещаем в /usr/local/bin/vmm-sandboxer
-
wasm-sandboxer – этот файл не понадобится
Давайте несколько увеличим дефолтные значения для создаваемых виртуальных машин. Внесём в файл /var/lib/kuasar/config_clh.toml следующие изменения:
vcpus = 4
memory_in_mb = 4096
Если у нас не установлен, то установим пакет screen. После его установки, запустим в отдельных сессиях screen следующие команды:
Screen №1:
-
/usr/local/bin/vmm-sandboxer --listen /run/vmm-sandboxer.sock --dir /run/kuasar-vmm
Screen №2:
-
ENABLE_CRI_SANDBOXES=1 /usr/local/bin/containerd
Теперь у нас всё готово для запуска контейнеров.
Тестовый запуск контейнера в sandbox окружении
В качестве задачи мы поставим себе запуск контейнера на основе образа openEuler 24.03 LTS.
Контейнер мы будем запускать внутри pod, который в свою очередь будет запущен внутри виртуальной машины, которую запустит cloud-hypervisor. Такая вот у нас получается «матрёшка».
Сейчас мы подготовим два файла, в формате JSON, один для описания pod, второй для описания контейнера. Если вы не помните наизусть JSON-синтаксис этих файлов, то вам на помощь придёт help команды crictl, вызываемый командами:
crictl run js -p – помощь по JSON конфигурации pod
crictl run js -c – помощь по JSON конфигурации container
Подготавливаем файлы для запуска контейнера
pod.json:
{
"metadata": {
"name": "test-kuasar-sandbox",
"uid": "12345678",
"namespace": "default",
"attempt": 1
},
"hostname": "test-pod",
"log_directory": "",
"dns_config": {
"servers": ["77.88.8.8"]
},
"port_mappings": [],
"labels": {
"group": "test"
},
"linux": {
"security_context": {
"namespace_options": {
"network": 2,
"pid": 1,
"ipc": 0
}
}
}
}
container.json:
{
"metadata": {
"name": "openeuler",
"namespace": "default"
},
"image": {
"image": "openeuler/openeuler:24.03-lts"
},
"command": [
"/bin/sh", "-c", "while true; do sleep 1; done"
],
"log_path": "openeuler.log",
"linux": {
"resources": {
"cpu_period": 10000,
"cpu_quota": 20000
},
"security_context": {
"namespace_options": {
"network": 2,
"pid": 1
}
}
}
}
Обращаем внимание на то, что создаваемая виртуальная машина у нас имеет 4 ядра vCPU, а на создаваемый контейнер мы накладываем ограничение в использовании 2 ядер. Проверим как это будет работать, когда запустим внутри контейнера какую-нибудь нагрузку CPU.
Итак, в начальный момент времени у нас нет созданных pod и контейнеров:
Рис 1. Контейнеры и pod в начале работы.
Запускаем наш контейнер следующей командой:
Рис 2. Запуск pod и контейнера.
Проверяем, что у нас появился pod:
Рис 3. Список pod.
И контейнер:Рис 4. Список контейнеров.
Мы можем провалиться (зайти) внутрь контейнера, используя привычную команду exec:
Рис 5. Попали внутрь контейнера.
Для верности выведем содержимое файла /etc/os-release, чтобы убедиться, что перед нами openeuler:
Рис 6. вывод версии openEuler.
Давайте откроем отдельный терминал на наш сервер (сделаем это, чтобы не выходить из контейнера — он нам ещё понадобится) и посмотрим как выглядит процесс запущенной виртуальной машины. Просто сделаем grep по списку процессов в ОС:
Рис 7. процесс cloud-hypervisor.
Теперь мы проверим, как работает указанное в конфигурации контейнера ограничение на использование CPU, Для этого внутрь контейнера мы создадим нагрузку на CPU просто запустив несколько команд md5sum /dev/urandom (один запуск как правило занимает 1 CPU, то есть 4 запуска вечного подсчёта MD5 на /dev/urandom должны занять 4 CPU):
Рис 8. создаём нагрузку на CPU внутри контейнера.
И как мы можем убедиться, даже при помощи обычной программы top, что виртуальная машина при такой нагрузке занимает только 2 ядра:
Рис 9. реальная нагрузка на CPU, созданная виртуальной машиной
Вуаля! Цель демонстрации достигнута. На этом краткий обзор данной технологии будем считать законченным.
Мы продолжаем следить за её развитием и за развитием других подобных и интересных технологий из стека сообщества openEuler для того, чтобы попробовать их и поделиться своим впечатлением с вами.