Раньше вы ставили Linux на железо и видели реальные диски, сетевые карты, прерывания. В облаке и на гипервизоре все иначе: ваша система - это гость, который живет внутри чужого хоста. Этот урок про то, чем отличается гостевая система от обычной, чем VM отличается от контейнера, как cloud-init разворачивает свежий инстанс за секунды, и почему два сервера из одного шаблона могут устроить вам конфликт в сети из-за одинакового machine-id. Задача администратора здесь - понимать, где проходит граница между гостем и хостом, и не наступать на грабли клонирования.

Как это работает
Виртуальная машина (VM) под KVM получает эмулированное железо. Гипервизор показывает гостю процессор, память, диски и сетевые карты, которых физически нет. Гость грузит собственное ядро и думает, что он один на машине. Полная эмуляция железа медленная, поэтому используют паравиртуализацию: гость знает, что он виртуальный, и общается с хостом через специальные драйверы virtio. virtio-blk и virtio-scsi - это диски, virtio-net - сеть, virtio-balloon - управление памятью. Они не притворяются реальным контроллером, а напрямую кладут данные в общую с хостом очередь, поэтому работают почти на скорости железа.
Контейнер устроен принципиально иначе. У него НЕТ своего ядра - он использует ядро хоста. Изоляция достигается через namespaces (отдельные PID, сеть, точки монтирования) и cgroups (лимиты на CPU и память). Контейнер легче и стартует мгновенно, но он не может загрузить другое ядро или другой модуль, чем у хоста. VM изолирует сильнее (своя ОС целиком), контейнер - дешевле. Отсюда правило: ядро-зависимая или чужая ОС - VM; масштабируемый сервис на том же ядре - контейнер.
cloud-init - это стандарт первичной настройки облачного инстанса. Образ в облаке универсальный и обезличенный. При первом старте cloud-init читает метаданные от облачной платформы (datasource): из специального HTTP-эндпоинта, ISO-диска cidata (NoCloud) или конфигдрайва. Из них он узнает имя хоста, создает пользователей, кладет SSH-ключи, настраивает сеть и расширяет файловую систему на весь диск. Так один образ превращается в сотни разных серверов без ручной работы.
machine-id - это уникальный идентификатор установки в /etc/machine-id, генерируется при первой загрузке. От него зависят DHCP-идентификатор (DUID), журналы systemd и иногда генерация SSH host-ключей. Если вы клонировали VM вместе с непустым machine-id, два гостя получат от DHCP один и тот же IP - классическая ловушка шаблонов.
Команды и примеры
Понять, гость вы или нет, и какой гипервизор под вами:
Код: Выделить всё
systemd-detect-virt # kvm, qemu, oracle, microsoft, none
systemd-detect-virt -c # только контейнеры: lxc, docker, podman, none
hostnamectl # строка Virtualization: kvm
lscpu | grep Hypervisor # Hypervisor vendor: KVM
Код: Выделить всё
lsblk # диски vda, vdb - это virtio-blk
lspci | grep -i virtio # Virtio network/block device
lsmod | grep virtio # загруженные модули virtio_net, virtio_blk
ip -br link # интерфейс часто enp1s0 на virtio-net
Код: Выделить всё
# Debian 13 / Ubuntu 24.04
apt install cloud-init
# RHEL 10 / Fedora 41+
dnf install cloud-init
Код: Выделить всё
#cloud-config
hostname: web01
users:
- name: deploy
groups: [sudo]
sudo: ALL=(ALL) NOPASSWD:ALL
ssh_authorized_keys:
- ssh-ed25519 AAAA... user@laptop
package_update: true
packages:
- nginx
runcmd:
- systemctl enable --now nginx
Код: Выделить всё
printf 'instance-id: web01\nlocal-hostname: web01\n' > meta-data
genisoimage -output seed.iso -volid cidata -joliet -rock user-data meta-data
# подключаете seed.iso вторым CD-ROM к VM
Код: Выделить всё
cloud-init status --long # done / running / error
cloud-init query userdata # что реально пришло от платформы
journalctl -u cloud-init # лог этапов init/config/final
Код: Выделить всё
cloud-init clean --logs # сброс маркеров, чтобы init отработал заново
truncate -s 0 /etc/machine-id # пустой файл = регенерация при загрузке
rm -f /var/lib/dbus/machine-id # на старых системах это симлинк, проверьте
rm -f /etc/ssh/ssh_host_* # SSH host-ключи перегенерируются на старте
Частые грабли
- Скопировали VM вместе с непустым /etc/machine-id - два гостя дерутся за один IP, потому что DHCP-клиент шлет одинаковый DUID. Перед клонированием machine-id обнуляют, а не удаляют файл совсем.
- Забыли удалить SSH host-ключи в шаблоне - все клоны имеют одинаковый отпечаток сервера, что ломает доверие и пугает SSH-клиентов предупреждением о возможной подмене.
- cloud-init отрабатывает только при ПЕРВОЙ загрузке. Поменяли user-data на работающей машине - ничего не произойдет без cloud-init clean и перезагрузки.
- Первая строка user-data не #cloud-config (например, лишний пробел или BOM) - файл молча игнорируется, инстанс грузится без настроек.
- Диски называются sda вместо vda - значит VM использует эмуляцию SATA/IDE, а не virtio. Производительность падает в разы, проверьте тип контроллера.
- Путаете контейнер и VM при выборе ядра: в контейнере modprobe и sysctl ограничены ядром хоста, своего модуля туда не загрузить.
- На любом инстансе или VM выполните systemd-detect-virt и lsblk - определите гипервизор и убедитесь, что диск это vda (virtio).
- Установите cloud-init и посмотрите cloud-init status --long и cloud-init query userdata - что пришло при создании.
- Соберите seed.iso с user-data из примера (свой ключ, свой hostname) и meta-data, создайте новую VM с этим ISO как вторым приводом.
- После загрузки проверьте: создан ли пользователь deploy, заехал ли ключ, поднялся ли nginx, сменился ли hostname.
- Запишите текущий cat /etc/machine-id, затем выполните cloud-init clean --logs и truncate -s 0 /etc/machine-id.
- Перезагрузите гостя и сравните новый machine-id со старым - он должен измениться.
- Удалите ssh_host_* ключи, перезагрузитесь и убедитесь, что отпечаток сервера сгенерировался заново.
- Чем гость-VM принципиально отличается от контейнера с точки зрения ядра и почему это влияет на выбор технологии?
- Какие задачи решают драйверы virtio и как по выводу lsblk понять, что диск идет через virtio-blk?
- Из каких источников cloud-init берет метаданные и почему он применяет конфигурацию только при первой загрузке?
- Что произойдет с DHCP, если склонировать VM, не обнулив /etc/machine-id, и как это исправить?
- Какие уникальные артефакты нужно удалить или обнулить в золотом образе перед клонированием?
- Какой командой проверить, под каким гипервизором работает текущая система, и чем отличается ключ -c?