====== Proxmox & packer: автоматизация подготовки VM ====== ==== Зачем всё это нужно ==== Полный ответ на этот вопрос лежит в подходе IaC, что заслуживает отдельной статьи. В рамках же данного материала будет продемонстрирован пример создания шаблона ВМ через packer. Наличие такого образа позволяет заранее установить внутрь всё необходимое единожды, тем самым сократить время развертывания целевой системы. ==== Packer ==== Hashicorp разработала packer для возможности создания универсального образа операционной системы (golden image), в который заранее упаковывается всё необходимое. На основе этого образа далее уже развёртываются виртуальные машины с нужным набором софта. В терминологии packer так называемый builder выполняет непосредственно сборку, а с помощью [[https://www.packer.io/plugins|плагинов ]]билдера указывается целевая платформа: в основном это облачные провайдеры типа AWS, Yandex, но есть и локальные QEMU, Proxmox и даже Docker или Ansible. Все дальнейшие инструкции будут применимы к плагину [[https://www.packer.io/plugins/builders/proxmox|Proxmox]]. Packer подключается к облаку или локальному гипервизору, создаёт ВМ с указанными параметрами и выполняет установку ОС на основе файла автоматической установки (например, для rpm-based используется kickstart, для deb-based – Subiquity в случае с Ubuntu). А после установки формирует эталонный шаблон из которого клонируются ВМ. ==== cloud-init ==== Казалось бы, packer позволил автоматизировать ручной этап. Но при этом добавил новых ручных действий, которые придётся выполнить. Например, какой IP-адрес, хостнейм или ssh-key назначать ВМ, создаваемой из шаблона? Ведь при создании каждой новой ВМ придётся это как-то вручную указывать и менять “эталонный” образ… Или же другой случай: после установки ОС необходимо каждый раз накатывать какой-то типовой софт через ansible, что тоже отнимает время на ручные действия. Тут в игру вступает cloud-init – разработка от компании Canonical. С помощью cloud-init можно выполнить инициализацию ОС до её финальной загрузки. Такое часто можно встретить в облаках. После создания ВМ из подготовленного шаблона с помощью packer запускается cloud-init, который считывает конфигурационный файл и выполняет указанные там действия. Это может быть как создание нужных юзеров, ключей, установка софта или запуск плейбуков и т.д. ==== Как это работает ====
Все действия выполнены на Proxmox 7 и Ubuntu 22.04, в которой используется **установщик Subiquity**.**1. Packer.** Конфигурационные файлы могут быть в формате HCL или JSON. В рамках данной статьи будет использоваться HCL. В секции source описывается ВМ с нужными параметрами. Тут есть важный параметр boot_command: в нём указывается, как запустить операционную систему. Причём в boot_command указаны комбинации, эмулирующие нажатие физических клавиш, как если бы это делалось вручную в консоли гипервизора. В данном случае packer переключается в консоль grub, указывает ядро для загрузки и добавляет параметры, которые необходимо выкачать по http. Веб-сервером выступает сам packer – **установщик ОС подключается к машине, с которой packer был запущен**. С помощью этих параметров, полученных через http, будет произведена автоустановка Ubuntu.
Про wsl и сеть. Если packer запущен в WSL, то в идеале он должен получать адрес из той же подсети, в которой создаются VM в Proxmox, чтобы они могли подключиться к веб-серверу Packer. В противном случае будет возникать ошибка на этапе “**Reached target Host and Network Name Lookups**” или на этапе загрузки AppArmor. Ещё подойдет как [[https://chemejon.io/how-to-use-packer-and-subiquity-on-wsl2/|вариант ]]''portproxy''.**2. cloud-init.** Для работы cloud-init потребуется два YAML файла: ''user-data'' и ''meta-data''. В user-data указываются необходимые модули, с помощью которых можно выполнить те или иные действия – создать файлы, пользователей и т.д. Примеры различных конфигов user-data можно посмотреть в [[https://cloudinit.readthedocs.io/en/latest/topics/examples.html|документации]]. **Для автоматической установки Ubuntu используется также конфигурация cloud-init: ** * Во время установки subiquity создаст конфиг для ''cloud-init'' по пути ''/target/var/lib/cloud/seed/nocloud-net/user-data''. * Если секция ''user-data'' включена в autoinstall, то subiquity [[https://github.com/canonical/subiquity/blob/2ddde49a436982716d1192538427ccd14eb9d32c/subiquity/models/subiquity.py#L197|соединит ]]содержимое user-data с файлом, который был создан ранее по пути''/target/var/lib/cloud/seed/nocloud-net/user-data'' * При первой загрузке ОС cloud-init прочитает этот файл и выполнит из него необходимые действия (создаст первого пользователя или установит нужный софт). То есть проще говоря, конфиг для автоустановки Ubuntu такой же, как и для cloud-init, но в начале файла используется специфичная конструкция ''autoinstall '' для инсталлятора subiquity, а далее уже используются нативные модули cloud-init. ==== Разбор конфигурационных файлов ==== Чтобы безмолвно не выкладывать весь конфиг целиком, стоит разобрать некоторые моменты. * Структура репозитория следующая:
.
├── README.md
└── ubuntu-server-jammy
├── http
│ ├── meta-data
│ └── user-data
├── ubuntu-server-jammy.pkr.hcl
└── variables.pkr.hcl
* Имя основного конфигурационного файла для пакера **должно заканчиваться *.pkr.hcl**.
* В файле variables.pkr.hcl можно определить **значения** переменных, но мне удобнее это делать через переменные окружения (ещё можно указать значения при запуске packer). Для примера я оставил этот файл в репе с закомментированными значения.
* Основные настройки cloud-init указываются в user-data, а в meta-data указывается служебная информация. **Важно! Файл meta-data должен быть, даже если он пустой.**
Теперь что касается самого конфигурационного файла ubuntu-server-jammy.pkr.hcl. Для его понимания стоит изучить HCL, тем кто работал с terraform будет проще, т.к. там по сути тоже самое. Основные моменты, на которые стоит обратить внимание:
* В переменных packer для подключения к гипервизору указывается значения из переменных окружения посредством функции ''default = env("PROXMOX_API_URL")''
* Имя, vm_id и описание шаблона можно выбрать любое, но удобно использовать число для vm_id из диапазона, который не пересекается с ID будущих ВМ.
* Предварительно необходимо скачать локально на гипервизор Proxmox ISO-образ с нужным дистрибутивом, указав его в ''iso_file = "local:iso/ubuntu-22.04.1-live-server-amd64.iso"''. Можно также скачать через пакер, указав адрес дистрибутива, но логичнее подготовить образ заранее, чтобы ускорить процесс сборки.
* Оперативную память для установки ''ubuntu-22.04'' лучше выставить в 2 Гб
* В разделе boot_command важно указать последовательность загрузки образа. В данном случае дополнительно выставлены таймауты для задержки после команд, т.к. при сборке packer не успевал ввести и выполнить одну команду, как начинал следующую.
* При сборке шаблона packer выступает в роли веб-сервера, к которому подключается установщик Ubuntu. Соответственно, на машине, с которой происходит запуск пакера, должен быть открыть соответствующий порт… который явно по умолчанию не указан и может быть в разных диапазонах, поэтому в конфиге стоит явно задать этот диапазон http_port_min и http_port_max.
* После установки шаблонной системы и её запуска, пакер должен подключиться по SSH к этой ОС и выполнить некоторые команды. Для этого подключения необходимо указать в конфигурационном файле логин\пароль (или ssh ключ). **Важный момент:** если на хосте, откуда запускается packer, настроен ssh-агент и в конфиге пакера включен ''ssh_disable_agent_forwarding'', то подключение к серверу будет осуществлено под локальным пользователем с пробросом агента. В данном же случае в качестве примера указан более простой случай, когда используется простой логин\пароль вида ubuntu\ubuntu
* После того, как шаблонная система запущена и к ней осуществлено подключение по ssh, необходимо выполнить некие действия по финальной настройке образа. За это отвечает раздел provisioner. В данном случае это простой shell с некоторыми командами:пока cloud-init не создаст файл /var/lib/cloud/instance/boot-finished, packer будет ждать
* после этого необходимо прибрать после себя, запустив команду cloud-init clean
* а также удалив всю информацию о ssh подключениях и сбросить machine-id, чтобы не клонировать виртуалки с одинаковыми значениями
* в конце явно выполнить sync, чтобы данные записались на диск
* **есть примеры готовых скриптов по очистке шаблона ** **[[https://github.com/DanHam/packer-virt-sysprep|тут**]]**
Также стоит пробежаться по файлу cloud-init, на основе которого выполняется автоматическая установка ОС:
* Понять суть файла несложно, там всё стандартно: локаль, раскладка, установка SSH…
* Дополнительно ставится пакет sudo (и агент гипервизора), чтобы packer мог в shell provisioner выполнить команды от рута
И самый главный момент – создание пользователей. Здесь уже будут создаваться юзеры и пароли как для packer (с помощью которого он будет выполнять shell-команды из своего конфига), а также конечный пользователь для подключения по SSH после клонирования и запуска ВМ. Здесь важно указать хеш пароля (создав командой mkpasswd –method=SHA-512 –rounds=4096 например). Также можно указать публичный ключ, что будет намного удобнее. Примеры можно посмотреть [[https://cloudinit.readthedocs.io/en/latest/topics/examples.html|тут]].
==== Как это запустить ====
Для сборки и установки шаблона необходимо:
* Установить packer версии не менее 1.8
* Склонировать репозиторй с гитхаб выше
* В файле с переменными нужно указать данные своего гипервизора (можно сделать отдельного юзера с отдельными правами). Или же экспортировать переменные окружения:
export PROXMOX_API_TOKEN_ID='root@pam!packer'
export PROXMOX_API_TOKEN_SECRET="7bf07389-db62-4985-aef3-58640dff3beb"
export PROXMOX_API_URL="https://192.168.3.100:8006/api2/json"
* Указать в user-data свой приватный ключ или пароль для своего юзера (а юзера ubuntu оставить или переименовать при необходимости – через него будет подключаться сам пакер)
* Запустить сборку и дождаться установки, после чего шаблонная ОС будет автоматически выключена при успешной установке
packer build ubuntu-server-jammy.pkr.hcl
После того, как шаблон появится в гипервизоре, для быстрого создания новой ВМ необходимо выполнить клонирование:
{{https://it-lux.ru/wp-content/uploads/2022/10/изображение.png?nolink&}}
После указать имя ВМ:
{{https://it-lux.ru/wp-content/uploads/2022/10/изображение-1.png?nolink&}}
Теперь важно указать корректные значения для новой ВМ. Для этого надо скорректировать в разделе cloud-init IP-адрес, маску и шлюз + остальные параметры при необходимости и перегенировать образ уже клонированной ВМ, после чего выполнить запуск:
{{https://it-lux.ru/wp-content/uploads/2022/10/изображение-2-1024x285.png?nolink&}}
Подключиться к запущенной ВМ можно по указанному выше IP-адресу (если он задан статически) и с логином\паролем или ssh-ключом, который указан в файле user-data