cloud-init: виртуалка, готовая к работе сразу после старта
Стандартная ситуация: вы создаёте виртуалку из шаблона или заказываете VPS, ждёте загрузки, заходите под root с паролем по умолчанию, вручную заводите пользователя, кладёте свой SSH-ключ, меняете hostname, поднимаете сеть — и только после этого сервер по-настоящему ваш. Если виртуалки создаются регулярно, эта рутина съедает время и рано или поздно приводит к ошибке по невнимательности — забытому паролю по умолчанию, не тому hostname, не той сети. cloud-init убирает этот шаг целиком: всё перечисленное описывается один раз в конфигурационном файле и применяется автоматически в первые секунды жизни машины, ещё до того, как она станет доступна для обычной работы.
Содержание
Проблема, которую решает cloud-init
Любой образ операционной системы — что скачанный у производителя cloud-образ Ubuntu или Debian, что собственный шаблон в Proxmox — изначально одинаков для всех, кто его использует. У него нет вашего hostname, вашего пользователя, вашего SSH-ключа и вашей сети. Если разворачивать такой образ вручную, разница между "образ" и "готовый к работе сервер" — это набор ручных действий, которые нужно повторять каждый раз одинаково и без ошибок.
cloud-init — это стандартный механизм первоначальной настройки, который выполняет эту разницу автоматически при самом первом запуске виртуальной машины. Его используют практически все крупные облачные провайдеры (AWS, DigitalOcean, Hetzner и другие) для готовых образов, и его же использует Proxmox VE для шаблонов VM. Идея одна и та же: образ остаётся универсальным, а параметры конкретного экземпляра — пользователь, ключ, hostname, сеть, команды первичной настройки — передаются отдельно, в момент создания машины, а не зашиваются в сам образ.
Важно понимать границу: cloud-init — это не система управления конфигурацией вроде Ansible или Puppet, которая поддерживает состояние сервера постоянно. Это одноразовый (по умолчанию) процесс первичной настройки — он делает свою работу один раз при первом запуске и дальше не вмешивается в жизнь системы, если его специально не попросить.
Как это устроено: data source и этапы инициализации
Cloud-init-совместимый образ — это обычный образ ОС с установленным пакетом cloud-init и настроенным на автозапуск набором systemd-юнитов. При загрузке такой системы cloud-init последовательно проходит несколько этапов:
- local (
cloud-init-local.service) — самый ранний этап, ещё до поднятия сети. На нём cloud-init ищет источник данных (data source) на локальных носителях — например, примонтированный ISO-образ с конфигурацией. - network (
cloud-init.serviceв сетевой стадии) — поднимается сеть согласно найденной конфигурации, если она задана явно (иначе остаётся DHCP по умолчанию из образа). - config (
cloud-config.service) — применяются модули конфигурации: пользователи, пакеты, файлы, hostname и прочее изuser-data. - final (
cloud-final.service) — выполняются произвольные команды (runcmd) и модули, которым нужна полностью рабочая система (например, установка пакетов из сети).
Ключевой момент — data source. Это то место, откуда cloud-init берёт конфигурацию. Источники бывают разные:
- NoCloud / ConfigDrive — небольшой виртуальный CD-ROM или диск с двумя файлами,
meta-dataиuser-data, который гипервизор подключает к виртуалке. Именно так работает cloud-init в Proxmox — в свойствах VM указывается диск-заглушка (ide2или подобный), и Proxmox сам генерирует на нёмmeta-data/user-data/network-configна основе того, что вы задали в интерфейсе или черезqm set. - Метаданные облака — в публичных облаках (AWS, GCP, DigitalOcean и т.д.) cloud-init обращается по HTTP к специальному внутреннему адресу метаданных гипервизора и забирает конфигурацию оттуда, без физического диска.
Пока data source не найден и не обработан, система не считается готовой к обычному использованию — именно в этом смысл фразы "до того как система становится доступна": сетевые сервисы могут уже стартовать, но ваш пользователь, ваш ключ и ваша сеть появятся только после прохождения всех этапов.
Нужен сервер под эту задачу?
Разверните VPS MAATRIX за пару минут: NVMe, AMD EPYC, root-доступ, локации UK, США, Франция и РФ. Оплата картой РФ и по СБП.
Арендовать серверМинимальный рабочий user-data
Основной файл конфигурации называется user-data и пишется в формате YAML с обязательной первой строкой #cloud-config — без неё cloud-init может принять файл за произвольный скрипт, а не за декларативную конфигурацию. Вот минимальный, но полностью рабочий пример:
#cloud-config
hostname: app-01
manage_etc_hosts: true
users:
- name: deploy
groups: sudo
shell: /bin/bash
lock_passwd: true
sudo: 'ALL=(ALL) NOPASSWD:ALL'
ssh_authorized_keys:
- ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIGx... deploy@laptop
ssh_pwauth: false
disable_root: true
package_update: true
package_upgrade: false
packages:
- qemu-guest-agent
- curl
runcmd:
- systemctl enable --now qemu-guest-agent
Разберём построчно, что здесь происходит и почему:
hostname— имя машины, которое применяется до того, как вы в неё зайдёте, поэтому в терминале сразу видно правильныйhostname@app-01, а не дефолтное имя из образа.users— создаётся пользовательdeployс sudo без пароля и добавленным SSH-ключом. Ключ прописывается в~/.ssh/authorized_keysавтоматически — заходить надо сразу по ключу, паролем для этого пользователя войти нельзя (lock_passwd: true).ssh_pwauth: false— отключает вход по паролю в SSH вообще, для всех пользователей. Это отдельная настройка отlock_passwdу конкретного юзера — обе вместе закрывают и вход по паролю, и попытку задать/восстановить пароль.disable_root: true— прямой вход под root по SSH запрещён; это стандартная практика, а не паранойя: у root в облачных образах обычно вообще нет пароля, только этот флаг явно фиксирует, что заходить под ним не планируется.packages+package_update: true— при первом старте выполняетсяapt update(или аналог для дистрибутива) и ставятся указанные пакеты.qemu-guest-agent— практический пример: без него Proxmox не увидит IP-адрес виртуалки в своём интерфейсе и не сможет корректно её выключать.runcmd— список произвольных команд шелла, которые выполняются на финальном этапе, когда сеть и пакеты уже готовы. Сюда же можно вписывать запуск собственных скриптов первичной настройки —runcmd: ["/opt/bootstrap.sh"], если такой скрипт заранее положен в образ или подтянут черезwrite_files.
Второй файл, meta-data, обычно минимален — он задаёт как минимум уникальный instance-id:
instance-id: app-01-2026-08-29
local-hostname: app-01
Значение instance-id — не формальность, а именно тот идентификатор, по которому cloud-init определяет, "видел ли он уже эту машину раньше". К этому нюансу мы вернёмся отдельно ниже — он и есть источник самой частой граблей с шаблонами.
Сеть и произвольная настройка при старте
Кроме пользователя и hostname, тем же механизмом задаётся сеть. Для статического IP вместо DHCP в Proxmox это делается либо через веб-интерфейс (вкладка Cloud-Init у виртуалки), либо командой:
qm set 101 --ipconfig0 ip=192.168.10.50/24,gw=192.168.10.1
qm set 101 --nameserver 1.1.1.1
qm set 101 --sshkeys ~/.ssh/id_ed25519.pub
qm set 101 --ciuser deploy
Proxmox сам транслирует эти параметры в файл network-config формата netplan (version 2) и передаёт его виртуалке через тот же ConfigDrive, что и user-data. Если сеть не задана явно — виртуалка поднимется по DHCP, как обычно.
Помимо сети и пакетов, через user-data можно решить практически любую задачу первичной настройки:
- положить произвольные файлы модулем
write_files(конфиги приложений, systemd-юниты, ключи); - расширить корневой раздел под фактический размер диска модулем
growpart(актуально, если диск шаблона был меньше, чем диск клона); - перезагрузить машину в конце настройки модулем
power_state, если после установки пакетов нужен явный reboot.
Всё это выполняется автоматически и одинаково для любого количества создаваемых виртуалок — конфигурация написана один раз, а не повторяется руками при каждом развёртывании.
cloud-init и шаблоны VM: почему одного клонирования недостаточно
Здесь стоит явно проговорить связь с шаблонами и клонированием, потому что именно тут cloud-init решает конкретную практическую проблему. Наивное клонирование виртуальной машины — снял с диска шаблона копию, запустил — технически быстрое, но оставляет ровно те же машинно-специфичные и пользовательские параметры, что были в шаблоне на момент его создания: тот же hostname, тот же SSH-ключ хоста, тот же IP при статической настройке, тот же /etc/machine-id. Без дополнительных действий все клоны от одного шаблона получаются неотличимыми друг от друга там, где они должны отличаться, — и это правится либо руками внутри каждой клонированной машины, либо специальными скриптами де-дупликации, которые нужно поддерживать отдельно.
cloud-init убирает эту проблему не тем, что "починяет" клон после создания, а тем, что переносит момент параметризации на этап первого запуска клона. Шаблон остаётся полностью универсальным — в нём нет ни конкретного hostname, ни конкретного ключа, ни конкретного IP. А конкретные значения передаются явно, в виде отдельных данных (user-data/meta-data/network-config), которые гипервизор подкладывает каждому новому клону индивидуально в момент его создания. В Proxmox это буквально видно в самой команде:
qm clone 9000 101 --name web-01 --full
qm set 101 --ciuser deploy --sshkeys ~/.ssh/id_ed25519.pub
qm set 101 --ipconfig0 ip=192.168.10.51/24,gw=192.168.10.1
qm start 101
Клон 101 при первом старте сам применит именно эти параметры — без захода внутрь машины и без правки файлов вручную. Это принципиально другой подход к той же задаче, что решает и "быстрое разворачивание через шаблон": шаблон отвечает за скорость создания диска, а cloud-init — за то, чтобы каждый экземпляр получил свои, а не общие с шаблоном, параметры. Подробнее о том, как вообще устроено создание первой виртуалки и шаблона в Proxmox, — в статье про Proxmox VE с нуля и первую виртуалку.
Грабля: cloud-init думает, что уже был запущен
Самая частая практическая ошибка — собрать образ-источник, поставить в нём всё нужное программное обеспечение, превратить в шаблон командой qm template, а затем обнаружить, что клоны от этого шаблона либо вообще не применяют user-data, либо применяют его через раз. Причина почти всегда одна: cloud-init уже отработал внутри исходной машины до того, как она стала шаблоном, и сохранил у себя состояние "эта машина уже была инициализирована".
Это состояние хранится в каталоге /var/lib/cloud/instances/<instance-id>/ и в файле-маркере, который cloud-init сверяет с instance-id из meta-data при каждом старте. Если instance-id совпадает с уже виденным — cloud-init резонно решает, что настройка не нужна, и пропускает все этапы. Проблема в том, что при клонировании через диск (а не через honest cloud-provider с уникальными метаданными на каждый инстанс) этот instance-id может не измениться автоматически, и тогда клон наследует "уже настроено" от родителя.
Практический порядок действий при подготовке шаблона:
- Установить пакет
cloud-initв образ-источник до превращения в шаблон — если ставить его уже в клонированную и работающую машину, придётся вручную повторять то, что должно было настроиться само. - Выполнить и проверить всю нужную первоначальную настройку в тестовом запуске образа-источника, если такой запуск был.
- Перед сохранением как шаблон — обязательно очистить состояние предыдущих запусков cloud-init:
cloud-init clean --logs
rm -rf /var/lib/cloud/instances/*
truncate -s 0 /etc/machine-id
- Только после этого выключить машину и выполнить
qm template <id>.
Команда cloud-init clean сбрасывает и файл-маркер инициализации, и накопленные логи; --logs дополнительно чистит журналы предыдущих прогонов, чтобы не путать диагностику будущих клонов со старыми записями. Обнуление /etc/machine-id — отдельная, но родственная мера: этот файл используется systemd для DHCP-идентификаторов и журналирования, и если он одинаков у всех клонов, это тоже создаёт путаницу в сети и логах, хоть и не связанную напрямую с cloud-init.
Если шаблон уже создан без этой очистки и клоны от него не настраиваются, чинить нужно тот же образ-источник (или временно превратить шаблон обратно в обычную VM, выполнить очистку и снова сделать шаблон) — постфактум чистить каждый уже созданный клон бессмысленно, дешевле переделать источник один раз.
Нужен сервер под эту задачу?
Разверните VPS MAATRIX за пару минут: NVMe, AMD EPYC, root-доступ, локации UK, США, Франция и РФ. Оплата картой РФ и по СБП.
Арендовать серверНужны сами нейросети для контента?
Генерируйте изображения, видео и озвучку нейросетями на falapi.io — десятки моделей в одном окне. Оплата картой РФ и по СБП.
Частые вопросы
Работает ли cloud-init внутри готовой, уже запущенной системы?
По задумке — нет, это механизм именно первого запуска. Повторный прогон возможен только через cloud-init clean и рестарт соответствующих сервисов, но это уже ручное вмешательство, а не штатный сценарий.
Что если образ вообще не cloud-init-совместимый?
Тогда диск с user-data/meta-data просто останется незамеченным — система запустится с настройками из самого образа, без применения ваших параметров. Нужно либо установить cloud-init в образ заранее, либо использовать образ, где он уже есть (официальные cloud-образы Ubuntu/Debian им снабжены по умолчанию).
Можно ли через cloud-init обновить конфигурацию уже работающего сервера?
Штатно — нет, инструмент для этого не предназначен и не отслеживает изменения user-data после первого прогона. Для постоянного управления конфигурацией нужен отдельный инструмент вроде Ansible; cloud-init закрывает только начальный этап "от пустого диска до доступного по SSH сервера со своим ключом".
Обязательно ли отключать вход по паролю через ssh_pwauth?
Нет, но это разумная практика по умолчанию, если сервер настраивается через ключи — она устраняет целый класс атак подбором пароля с первой секунды жизни машины, а не после того, как вы вручную об этом вспомните. О самом механизме SSH-ключей и его практической настройке — в статье про SSH-ключи вместо пароля на VPS.
Нужно ли что-то менять на стороне гипервизора, если у меня уже есть готовые VPS без cloud-init?
Нет — cloud-init касается именно момента создания новой машины из образа или шаблона. Для уже работающих серверов эта тема не актуальна, там донастройка hostname и сети выполняется вручную обычным способом, как описано в статье про настройку hostname и /etc/hosts.
Обсудить статью, задать вопрос или начать новую тему
Есть вопрос по этой статье, идея для обсуждения или просто хотите поделиться опытом? Сообщество MAATRIX ждёт. Для общения, пожалуйста, зарегистрируйтесь в нашем личном кабинете.
Перейти в сообщество →