🐳 Раздел 14 · Вопрос #2

В чём отличие контейнера от виртуальной машины

Главное фундаментальное отличие заключается в уровне абстракции виртуализации:


🟢 Junior Level

30-секундный ответ

Главное фундаментальное отличие заключается в уровне абстракции виртуализации:

  • Виртуальная машина (ВМ) виртуализирует аппаратное обеспечение (Hardware): поверх физического сервера работает гипервизор (KVM, VMware ESXi, VirtualBox), а каждая ВМ запускает свою собственную полноценную гостевую операционную систему (Guest OS) со своим собственным ядром, драйверами и системными демонами.
  • Контейнер виртуализирует операционную систему (OS): все контейнеры на сервере работают как обычные изолированные процессы, разделяющие одно общее ядро хоста (Host OS Kernel).

Наглядная аналогия из жизни

  • Виртуальная машина — это отдельный частный дом: у него собственный фундамент, свои стены, крыша, автономный водопровод и котельная. Это гарантирует максимальную независимость, но требует огромных затрат на постройку и обслуживание.
  • Контейнер — это квартира в современном жилом комплексе: у всех квартир общий фундамент, крыша, единые трубы отопления и охрана дома (общее ядро ОС), но внутри вашей квартиры есть свои стены, счётчики ресурсов и замок на двери (namespaces и cgroups).

Сводная таблица базовых различий

| Критерий | Виртуальная машина (ВМ) | Контейнер (Docker / Podman) | | :— | :— | :— | | Что виртуализируется | Физическое железо (CPU, RAM, BIOS, NIC) | Операционная система (системные вызовы ядра) | | Ядро ОС | Своё независимое ядро в каждой ВМ | Одно общее ядро хостовой системы | | Время старта | 1–5 минут (полная загрузка ОС) | < 1 секунды (запуск обычного процесса) | | Размер образа | Гигабайты (от 2 до 20+ ГБ) | Мегабайты (от 30 до 300 МБ) | | Оверхед на CPU/RAM | 5–15% CPU + сотни МБ на саму ОС | < 1% CPU, накладные расходы только на процесс | | Изоляция | Аппаратная (максимальная) | Процессная (логическая) |


🟡 Middle Level

Архитектура: Гипервизор vs Container Engine

1. Устройство виртуальной машины

ВМ работает под управлением гипервизора:

  • Тип 1 (Bare-Metal): гипервизор устанавливается прямо на «голое железо» без промежуточной ОС (VMware ESXi, KVM, Xen, Microsoft Hyper-V).
  • Тип 2 (Hosted): гипервизор запускается как программа поверх обычной хостовой ОС (VirtualBox, VMware Workstation). Гипервизор эмулирует виртуальные контроллеры дисков, виртуальную память и сетевые адаптеры.

2. Устройство контейнера

Контейнеры управляются Container Runtime (containerd, CRI-O, Docker):

  • Внутри контейнера нет отдельного ядра и нет слоя эмуляции оборудования.
  • Изоляция процессов обеспечивается подсистемой Namespaces (PID, NET, MNT, USER, IPC, UTS).
  • Ограничение памяти и процессорного времени обеспечивается подсистемой cgroups v2.
  • Контейнер — это нативный процесс хоста. Вызов ps aux на хосте Linux отобразит процесс Java-приложения наряду с системными демонами.
# Процессы контейнера видны на хосте Linux как обычные системные процессы:
ps aux | grep java

# Получить реальный PID процесса контейнера в пространстве хоста:
docker inspect --format '' payment-service-app

# Проверить ограничения памяти в cgroups v2 для данного контейнера:
cat /sys/fs/cgroup/system.slice/docker-<container-id>.scope/memory.max

Дисковая подсистема: Блочные образы vs Layered FS (Overlay2)

  • Виртуальная машина: работает с монолитным виртуальным диском фиксированного или динамического размера (.qcow2, .vmdk), форматируемым в файловую систему (ext4, NTFS). Образ диска трудно версионировать и переиспользовать.
  • Контейнер: использует каскадную файловую систему OverlayFS (Overlay2). Слои неизменяемы и разделяются между десятками контейнеров: если 20 микросервисов используют образ eclipse-temurin:21, слой JRE весом 200 МБ хранится на диске и кэшируется в оперативной памяти сервера в единственном экземпляре.

Гибридный подход: MicroVMs (Kata Containers, Firecracker)

В публичных облаках (AWS Lambda, AWS Fargate, Google Cloud Run) для устранения риска небезопасного разделения ядра применили технологию MicroVMs:

  • Запуск облегчённой виртуальной машины с минималистичным кастомным ядром Linux без устаревших эмуляторов BIOS/PCI.
  • Время старта MicroVM составляет около 100–150 мс, а потребление памяти — всего около 5 МБ.
  • Внутри такой MicroVM запускается стандартный OCI-контейнер, обеспечивая скорость контейнеров и аппаратную защиту ВМ.

🔴 Senior Level

Аппаратные накладные расходы: Двумерная трансляция страниц (SLAT / EPT)

Senior-инженеру важно понимать причину разницы в производительности на уровне транзисторов CPU:

  1. В виртуальных машинах (Hardware-Assisted Paging):
    • Процессор использует аппаратную технологию Extended Page Tables (EPT) от Intel или Nested Page Tables (NPT) от AMD.
    • Для доступа к памяти процессор вынужден выполнять двумерный проход по таблицам страниц (Two-Dimensional Page Walk): сначала транслировать гостевой виртуальный адрес (GVA) в гостевой физический адрес (GPA), а затем GPA в физический адрес хоста (HPA).
    • При промахе кэша TLB этот проход требует до 24 обращений к памяти, вызывая скрытые задержки в приложениях с интенсивной работой с кучей памяти (например, сборщик мусора GC в больших JVM).
  2. В контейнерах:
    • Трансляция адресов памяти происходит через стандартные таблицы страниц ядра хоста (Virtual Address $\to$ Physical Address) в один шаг.
    • Накладные расходы на работу с оперативной памятью равны строго 0% по сравнению с «голым железом».

Анализ поверхности атаки: Ядро хоста vs Гипервизор

| Компонент | Строк кода (LOC) | Граница изоляции | Риск побега (Escape) | | :— | :— | :— | :— | | Гипервизор KVM | $\approx 20\,000$ строк | Аппаратные кольца процессора (Intel VMX root mode) | Крайне низкий (требует редчайших уязвимостей в virtio) | | Ядро Linux (Контейнеры) | $\approx 30\,000\,000$ строк | Логические проверки в коде ядра (syscall checks) | Существенный (уязвимости ядра, eBPF, драйверы, race conditions) |

Векторы Container Escape:

  1. Небезопасные Capabilities: наличие флага --privileged или привилегии CAP_SYS_ADMIN позволяет контейнеру смонтировать физический диск хоста и перезаписать системные файлы хостовой ОС.
  2. Утечка сокета Docker: проброс /var/run/docker.sock внутрь контейнера даёт атакующему права root на всём сервере.
  3. Эксплойты ядра (Dirty COW, Dirty Pipe): перезапись страниц памяти ядра хоста в обход прав доступа.

Модель памяти: Balloon Driver vs cgroups Memory Limits

  • ВМ: память выделяется монолитно. Для динамического возврата памяти хосту гипервизор использует драйвер «раздувания памяти» (Memory Ballooning): специальный драйвер внутри гостевой ОС раздувает свой буфер, вынуждая Guest OS выгружать страницы в своп. Это медленный и инерционный процесс.
  • Контейнеры: память выделяется по факту использования (динамически). Подсистема cgroups v2 мгновенно отслеживает использование страниц (memory.current). При достижении мягкого лимита (memory.high) ядро плавно тормозит процесс и сбрасывает кэш страниц; при превышении жёсткого лимита (memory.max) — мгновенно активирует OOM Killer.

4 Tricky Questions

1. Как технология аппаратной виртуализации EPT/SLAT влияет на задержки JVM Garbage Collector внутри ВМ по сравнению с запуском в Linux-контейнере?

Ответ: JVM Garbage Collector (особенно G1 и ZGC) непрерывно сканирует миллионы ссылок на объекты в куче. Внутри виртуальной машины процессор использует Extended Page Tables (EPT) для трансляции гостевых адресов в физические адреса сервера. При промахе в буфере ассоциативной трансляции (TLB Miss) процессору приходится выполнять вложенный проход по таблицам страниц (до 24 шагов вместо 4). В результате фазы маркировки и компактизации GC внутри ВМ могут тратить на 10–25% больше процессорных циклов, чем при запуске в контейнере, где трансляция страниц памяти выполняется стандартным одноуровневым блоком MMU без участия гипервизора.


2. Можно ли запустить Linux-контейнер на Windows-сервере и Windows-контейнер на Linux-сервере? Как это устроено технически?

Ответ:

  • Linux-контейнер на Windows: Да, можно, но только через скрытую виртуализацию! На Windows (в Docker Desktop) запускается легковесная виртуальная машина с ядром Linux (через подсистему WSL 2 или Hyper-V). Linux-контейнеры делят ядро этой вспомогательной ВМ, а не самой Windows.
  • Windows-контейнер на Linux: Физически невозможно. Windows-контейнеры требуют наличия ядра Windows (ntoskrnl.exe) и системных библиотек Win32/NTDLL. Ядро Linux не умеет выполнять системные вызовы Windows NT Kernel. Запуск возможен только внутри полноценной виртуальной машины с установленной Windows OS.

3. В чём архитектурная разница между изоляцией MicroVM (AWS Firecracker) и песочницей gVisor (Google)?

Ответ:

  • AWS Firecracker (MicroVM): запускает реальное легковесное ядро Linux в аппаратно изолированном пространстве виртуализации (KVM). Контейнер общается со своим собственным микроядром через стандартные системные вызовы. Граница безопасности поддерживается на аппаратном уровне CPU.
  • gVisor (Google): это программный перехватчик системных вызовов в пользовательском пространстве (User-Space Kernel), написанный на Go (модуль Sentry). Приложение думает, что делает вызовы к ядру Linux, но Sentry эмулирует и фильтрует системные вызовы, изолируя процесс от реального ядра хоста без создания гипервизора.

4. Что произойдёт с контейнером и виртуальной машиной при падении (Kernel Panic) ядра операционной системы хоста?

Ответ:

  • Для всех контейнеров на сервере: поскольку абсолютно все контейнеры разделяют единственное ядро хостовой ОС, падение ядра (Host Kernel Panic) мгновенно приводит к одновременной аварийной остановке всех до единого контейнеров на этой физической машине.
  • Для виртуальных машин: падение ядра гостевой ОС (Guest Kernel Panic) внутри одной конкретной ВМ изолировано внутри её виртуального пространства: остальные виртуальные машины и гипервизор хоста продолжат работать без сбоев. Однако если упадёт сам гипервизор хоста (Type 1 Bare-Metal OS), все ВМ на этом физическом сервере также синхронно прекратят работу.

🎯 Шпаргалка для интервью

Топ-5 фундаментальных отличий

  1. Ядро ОС: ВМ несёт своё собственное ядро; контейнеры делят одно общее ядро хоста Linux.
  2. Абстракция: ВМ виртуализирует аппаратное железо (гипервизор); контейнеры изолируют процессы (Namespaces + cgroups).
  3. Скорость: ВМ стартует минуты; контейнер стартует за миллисекунды.
  4. Ресурсы: ВМ требует резервирования гигабайтов RAM под гостевую ОС; контейнер тратит память только на сам процесс и рантайм.
  5. Безопасность: ВМ обеспечивает аппаратную изоляцию; в контейнерах граница безопасности — это код ядра хоста.

Матрица принятия решений (Архитектурный выбор)

| Бизнес-требование | Рекомендация | Причина | | :— | :— | :— | | Микросервисы, CI/CD, высокая плотность | 🟢 Контейнеры | Мгновенный запуск, минимальный оверхед, идеальная повторяемость | | Untrusted Multi-Tenancy (публичное SaaS)| 🟢 ВМ или MicroVMs | Гарантия невозможности Container Escape | | Запуск Windows + Linux на одном сервере | 🟢 Виртуальные машины| Контейнеры не могут эмулировать чужое ядро ОС | | Legacy-монолиты с жесткой привязкой к драйверам| 🟢 Виртуальные машины| Полный контроль над версией ядра и модулями |

Красные флаги на собеседовании (Чего говорить нельзя)

  • ❌ «Контейнеры абсолютно безопасны, так как они полностью изолированы» — общее ядро создаёт риск Container Breakout.
  • ❌ «Контейнер — это просто урезанная ВМ» — грубое архитектурное непонимание; в контейнере нет гостевой ОС и нет гипервизора.
  • ❌ «Внутри каждого Docker-контейнера загружается своё маленькое ядро Linux» — ядро на сервере всегда ровно одно (ядро хоста).

Связанные вопросы