Когда заходит речь о запуске виртуальных машин в Kubernetes через KubeVirt, первый вопрос, который возникает у инженеров: «А какой там оверхед?» Давайте разберём этот вопрос детально, рассмотрев каждую подсистему отдельно: вычисления, хранилище и сеть.

Оверхед на вычисления: спойлер — его нет
Чтобы понять, почему оверхеда на CPU практически нет, нужно разобраться, что такое контейнеризация с точки зрения ядра Linux.
В ядре существуют так называемые неймспейсы (namespaces) — механизм, позволяющий запускать процессы с изолированными подсистемами: отдельной сетью, отдельным mount-пространством, отдельным PID-пространством и так далее.
Ключевой момент: каждый процесс в Linux обязан запускаться в каком-то неймспейсе. Будь то хостовый неймспейс или изолированный — для ядра разницы нет. Процесс обрабатывается одинаково.
Контейнер — это просто процесс, запущенный в изолированных Linux kernel namespaces плюс cgroups. Последние — стандартный механизм ядра для ограничения ресурсов процесса. Cgroups используются не только в контейнеризации, но и в обычном systemd. Классический libvirt тоже применяет cgroups для ограничения ресурсов виртуальных машин.
А что такое виртуальная машина с точки зрения системы? Это всего лишь Linux-процесс QEMU с дополнительными разрешениями и доступом к /dev/kvm.
Если виртуалка — это просто процесс, почему бы не запускать его в контейнере? Именно это KubeVirt и делает.
Разницы нет, запущен QEMU в хостовом неймспейсе ядра или в отдельном, который создал Kubernetes. Оверхеда на вычисления нет.
Небольшая оговорка про libvirt
Есть небольшой оверхед на запуск отдельного libvirt-демона, который KubeVirt использует для настройки параметров виртуалки. Но он минимален.
Интересный архитектурный выбор: обычно запускается один libvirt на хост, управляющий множеством виртуалок. Проблема в том, что иногда он зависает, блокируя управление всеми VM на сервере. В KubeVirt пошли другим путём — отдельный libvirtd-демон на каждую виртуалку. Цена изоляции — дополнительные ресурсы на работу демона рядом с основным процессом VM. Но расход небольшой: libvirtd чаще выступает как shim-прослойка для простых операций: запуск/остановка VM, снятие снапшота, hotplug дисков и интерфейсов, запуск live-миграции.
Хранилище: зависит от подхода
В QEMU есть множество способов подключить виртуальные тома к виртуалке.
Классические варианты:
Создать файл (raw или qcow2) в файловой системе и передать его QEMU
Взять готовое блочное устройство и отдать его QEMU
В обоих случаях используется ядро в качестве посредника — файловая система или блочное устройство должны существовать в хостовой системе.
Прямое подключение: QEMU умеет самостоятельно обращаться к storage и подключать тома напрямую из user-space, минуя ядро. Поддерживаются различные драйверы: Ceph, iSCSI, NBD и другие. Например, Vitastor работает именно по такому принципу — QEMU устанавливает соединение напрямую.
Философия KubeVirt
Основной принцип KubeVirt — быть максимально нативным к Kubernetes. У команды даже есть своеобразный razor: «Если это может быть полезно и для виртуалок, и для контейнеров, это должно быть реализовано в Kubernetes, а не в KubeVirt».
Иногда это замедляет разработку VM-специфичных фич.
В контексте хранилища KubeVirt полностью опирается на сущности Kubernetes — в первую очередь на CSI-драйверы. Kubernetes ожидает, что каждый том — это Filesystem или BlockDevice. Оба режима поддерживаются и не имеют дополнительного оверхеда.
Однако прямое подключение QEMU к storage сейчас не поддерживается — в Kubernetes для этого нет подходящих абстракций.
Реальность такова, что крупный энтерпрайз чаще использует не прямое подключение, а общую файловую систему (NFS от NetApp) или блочные устройства (iSCSI). KubeVirt, кстати, умеет работать с iSCSI напрямую.
Итог по хранилищу: если сравнивать с типичными решениями — оверхеда нет. Если упираться в специфику драйверов QEMU — прямое подключение будет быстрее, но менее универсально. Generic-решения поддерживают только стандартные варианты, а под каждого вендора придётся пилить и поддерживать свою специфику.
Сеть: здесь есть нюансы
У каждого контейнера (или процесса в терминах ядра Linux) может быть свой отдельный сетевой стек с собственными интерфейсами. Для связи контейнерного network namespace с хостовым используются veth-интерфейсы — виртуальный «патчкорд», один конец которого находится в хостовом неймспейсе, другой — в контейнерном. Это база для всех контейнеров.
Снаружи логику обсл��живает CNI-плагин: добавляет интерфейс в Linux bridge (как Flannel) или вешает на него eBPF-программу (как Cilium). С точки зрения системы виртуалка — такой же контейнер, как и все остальные.
Что происходит внутри контейнера
В 95% случаев для виртуалки создаётся TAP-интерфейс, который виден в хостовой системе как обычный сетевой интерфейс. Вопрос в том, как соединить его с внутренним veth-интерфейсом.
Популярные варианты:
Bridge: в ядре создаётся отдельный Linux bridge, в который добавляются внутренний конец veth и TAP-интерфейс виртуалки.
Masquerade: создаётся iptables-правило, копирующее трафик из одного интерфейса в другой.
В обоих случаях есть оверхед по latency — каждое дополнительное звено в цепочке требует дополнительных тактов процессора для обработки пакетов.
Как обойти ограничения
Оверхед небольшой, но есть способы его избежать:
macvtap-cni — биндится напрямую на физический интерфейс машины
SR-IOV — аппаратная виртуализация сети
Как и в случае с хранилищем, QEMU может быть настроен на прямую коммуникацию с SDN в user-space, минуя ядро. KubeVirt имеет ограниченную поддержку этого режима, так как опирается на спецификацию CNI.
Различные CNI-драйверы (например, Kube-OVN) реализуют параллельное API для offloading сети из ядра.
Стоит отметить, что по части сети KubeVirt имеет мощный интерфейс для написания плагинов с произвольной логикой подключения.
Выводы

KubeVirt — это компромисс между производительностью и универсальностью. Если вам нужен максимум производительности и вы готовы поддерживать специфичные решения — можно выжать больше. Если важнее стандартизация, vendor neutrality и простота поддержки — KubeVirt отлично справляется со своей задачей.
P.S. Статья основана на обсуждении в профессиональном сообществе. Благодарю участников за ценные инсайты.
Присоединяйтесь к нашему комьюнити
