Данная статья это авторский перевод/русскоязычная версия моей статьи на Medium, и первая из цикла про этот интересный инструмент.
Пожалуй, наиболее адекватным эпиграфом будет перефразированный английский перевод частушки «по реке плывет топор»:
Down the pipeline flows the code
From the towers of London.
Let it setup by itself
On this fancy piece of iron
Как это часто бывает, данный проект появился в результате случайности. Я всего лишь устанавливал Ubuntu на новую Dell rack workstation, когда элементарная задача неожиданно превратилась в «увлекательную». Зато открыло для меня совершенно новый уровень.
Поскольку это не совсем сервер, в машине нет модуля IPMI. Зато у этой модной железки есть 2 порта USB-C/DisplayPort и ни одного простого интерфейса для монитора. К сожалению, в коробке не было фирменного адаптера USB-C/DP – HDMI или в display port. А no-name, который оказался у меня в офисе под рукой, требовал изрядных танцев с бубном, чтобы на экране можно было увидеть хоть что-нибудь, пока к машине нельзя было добраться по SSH.
Поскольку машина предназначалась для тестов и разработки, переустанавливать систему приходилось неоднократно. Мне довольно быстро надоело это занятие, и я задумался, а можно ли как-то без этих альтернативных ощущений с монитором? Воображение рисовало идеальное конечное решение: хотелось вставить флэшку в бездыханную железяку, и на выходе получить вход по SSH. С одной стороны, без IPMI короткий ответ «нет» - нужно хотя бы вручную выбрать загрузочный диск, а лучше настроить boot sequence в BIOS. К сожалению, из коробки железяка мало того, что не загружается с внешнего носителя, так еще требуется сменить настройку RAID, чтобы система увидела внутренний SSD. И сделать это необходимо с едва работающим монитором. Но есть и хорошая новость: достаточно добраться до BIOS хотя бы один раз.
После этого жизнь начинает играть новыми красками. Поиск быстро привел меня к Ubuntu autoinstall https://ubuntu.com/server/docs/install/autoinstall Но если бы все было так просто. Как это часто бывает, качество документации не просто оставляет желать, но иногда может вводить в заблуждение. Например, я долго не мог разобраться с разницей между Ubuntu autoinstall и cloud-init. Позже объясню, почему.
С другой стороны, путешествие по граблям оказалось неожиданно полезным. Разработанные workarounds очень пригодились в дальнейшем, и них я расскажу в следующих статьях. Данный цикл статей это попытка восполнить пробел в документации, и поделиться знанием об очень интересном инструменте Ubuntu, и куда это может завести.
Это первая статья из цикла, и в ней мы реализуем простейший вариант. Мы создадим загрузочный образ ISO, который пока просто накатывает минимальный Ubuntu server. Все настройки по-умолчанию, сеть DHCP, OpenSSH сервер, логин и пароль. Я буду использовать авторизацию SSH по паролю, но ничего не мешает использовать ключи.
Все происходит полностью автоматически, причем без клавиатуры и монитора: вставили флэшку, нажали кнопку «вкл», и получили систему с SSH. И оно правда работает.
Готовим ингредиенты
Autoinstall использует yaml, который должен называться "user-data". Для ISO с автозапуском мы сохраним его в папке “/nocloud”. Вот содержимое /nocloud/user-data:
#cloud-config
autoinstall:
version: 1
identity:
hostname: ubuntu22auto
username: ubuntulogin
password: <mkpasswd -m sha-512 ubuntupass>
ssh:
install-server: yes
allow-pw: yes
Это минимально возможный конфиг autoinstall.
Важный момент: после установки система перезагрузится. Поскольку все происходит на полном автомате, система ничего не спросит, и ничем не выдаст свои намерения. На этот счет у меня есть любимый анекдот:
Человек приходит в патентное бюро регистрировать свое изобретение, универсальную бритвенную машину. Патентный клерк его спрашивает:
- Расскажите пожалуйста немного про свое изобретение? Как работает ваша машина?
- Ну вы вставляете в нее свое лицо, нажимаете на кнопку, и она вас бреет.
- Очень интересно.... Но лица же у людей все разные?
- Первый раз да.
Некоторые гипервизоры и карты IPMI сами отключат загрузочный образ при перезагрузке. Но давайте сделаем гарантированно безопасный вариант. На мой взгляд, наиболее чистой и аккуратной реализацией для автоматической установки без всего является выключение машины после установки системы. Таким образом у нас появляется совершенно четкая индикация, когда нужно извлечь загрузочный носитель, и включить сервер. Это можно сделать, добавив в конфиг bash комманду (об этом позже), но в autoinstall уже есть встроенная функция. Достаточно добавить:
shutdown: poweroff
Итак, у нас есть yaml для autoinstall. Теперь нужно объяснить Ubuntu, как его активировать. За это отвечает grub.cfg:
menuentry "Ubuntu autoinstall test" {
set fgxpayload=keep
linux /casper/vmlinuz "ds=nocloud;s=/cdrom/nocloud/" debug autoinstall ---
initrd /casper/initrd.gz
}
Вот, что на самом деле запускает автоматическую установку: “ds=nocloud;s=/cdrom/nocloud/” debug autoinstall Это папка, где лежит наш файл user-data, который мы только что создали. Данная строчка стоила мне изрядного количества седых волос - у меня получилось надежно заставить это работать с кавычками. Желающим не возбраняется поэкспериментировать с escape символами без кавычек. Так же, для прода я бы заменил ‘debug’ на ‘quiet’.
Настраиваем среду разработки
Итак, конфиги готовы. А как их теперь встроить в загрузочный ISO образ Ubuntu?
Документация autoinstall обычно описывает хардкор вариант через боль, и не слишком подробно. К этому мы тоже придем в дальнейших статьях цикла, по мере продвижения в сторону сложных сценариев и сборки образа с помощью CI/CD pipeline. Пока начнем с простого, и будем наращивать сложность постепенно.
Итак, просто и не больно это делается с помощью приложения CUBIC, Custom Ubuntu ISO Creator, https://github.com/PJ-Singh-001/Cubic. Давайте его установим. Начнем с чистой виртуалки Ubuntu 22.04 Desktop в качестве среды для сборки образа. Дальше все просто, как написано в readme:
sudo apt-add-repository universe
sudo apt-add-repository ppa:cubic-wizard/release
sudo apt update
sudo apt install --no-install-recommends cubic
Теперь он откликается на "cubic" в терминале. Создаем папку под наш проект, например U22AutoInstallBuildV0.1:
Скачиваем ISO образ Ubuntu server. Я сохраню его в папке "Downloads". Обратите внимание на ссылку, которую я использую. В дальнейшем это пригодится:
wget http://releases.ubuntu.com/22.04/ubuntu-22.04.4-live-server-amd64.iso
Теперь, выбираем его в качестве исходника, и настраиваем проект. CUBIC подтянет метаданные из ISO. Давайте внесем изменения:
Распаковываем дистрибутив ISO:
Теперь мы попадаем в chroot shell, где можно вносить изменения в дистрибутив. В данной статье мы этого делать не будем, поэтому пока пропускаем:
На этом экране мы могли бы изменить версию ядра, если бы у нас были варианты на выбор. Раздел "Preseed", вероятно, наследие старых версий Debian/Ubuntu. Свежие версии Ubuntu устанавливаются с помощью Subiquity, и не используют preseed файлы:
Редактируем конфиги с помощью VSCode.
Вкладка “Boot” уже более полезна. Помните, нам необходимо внести правки в grub.cfg?
Это можно сделать здесь, но я предпочитаю VSCode.
Если на нашей чистой виртуалке Ubuntu еще не установлен OpenSSH server, то:
sudo apt install openssh-server
Теперь в нее необходимо скопировать ключ ssh, чтобы VSCode не задолбал запросами пароля 100 раз. В случае Windows я предпочитаю MS Windows Terminal который устанавливается из Microsoft Store. В нем уже есть встроенный клиент ssh:
ssh-keygen
Сгенерированные ключи id_rsa & id_rsa.pub лежат в папке .ssh в домашней директории пользователя. В других операционных системах работает примерно так же.
Если у вас чистая Ubuntu, проверьте наличие хотя бы пустого файла ~/.ssh/authorized_keys в домашней директории пользователя. Если его еще нет, создаем:
mkdir -p ~/.ssh
cd ~/.ssh
touch authorized_keys
Теперь копируем публичный ключ с нашей основной машины. В Windows:
scp ~/.ssh/id_rsa.pub ubuntulogin@<remotehost>:~/.ssh/authorized_keys
Проверяем:
ssh ubuntulogin@<remotehost>
Теперь подключаемся из VSCode. Проверьте, что у вас установлен Remote extension pack или хотя бы Remote-SSH:
Не забудьте проверить/поменять логин:
После этого система запросит конфигурацию, и запустит удаленное подключение в новом окне. Чтобы не путаться, я сразу открою непосредственно папку проекта:
Перед нами структура папок дистрибутива Ubuntu в варианте, как ее распаковал CUBIC. В следующих статьях мы посмотрим на нее более детально, а сейчас нас интересует только custom-disk:
Первым делом, создаем папку nocloud и yaml файл user-data, который мы уже сформировали выше. Так же необходимо создать пустой файл meta-data. Он нам не понадобится, но система требует наличие заглушки.
Следующий важный элемент это пароль пользователя:
mkpasswd -m sha-512 ubuntupass
полученный хэш необходимо вставить в наш конфиг:
$6$LmPUjxOfMHOMgRlg$pSXXVlcfwSKUSotcoG6ed7DUu7.iOX7kJEylN9V9z3C96uNBIMfCJjtL1tNjLx9dDbKS/kH9W7B8oIMKxmXb70
Если mkpasswd не установлен по-умолчанию,
добавляем, как указано:
sudo apt install whois
Вот наш рабочий user-data yaml:
Все практически готово. Осталось подредактировать grub.cfg. Он хранится в папке custom-disk/boot/grub:
Это простой конфиг. Я добавил в него пункт меню, причем он запустится по-умолчанию, поскольку стоит первым в списке.
Второе изменение это таймаут. Его я изменил с 30 секунд на 10, но можно и меньше, если не планируете вмешиваться в процесс загрузки.
Собираем ISO
На этом все. Остается только запаковать это обратно в ISO образ. Нажимаем "Next", и можно запускать. Лично я предпочитаю паковать образы xz, почему объясню в следующих статьях.
Проверяем готовый образ
В CUBIC есть функция проверки “Test” готового ISO с помощью QEMU. Она может быть полезной для простых сценариев (убедитесь, что у вас настроена вложенная виртуализация). Пробуем:
К сожалению, в моей практике работает нестабильно. В частности потому, что обычно я запускаю его на виртуалках:
Вам может повезти больше. Это зависит от гипервизора, ресурсов, некоторых тонкостей в настройках, фазы луны и т.д. С ESXi мне обычно везет больше, и то на простых образах, а в данном случае я использую Hyper-V. В любом случае, для реальных проектов я от этого способа давно отказался, и использую полноценные виртуалки.
Создадим выделенную виртуальную машину для теста. Проверяем, что в ней есть стандартные настройки под Ubuntu. ESXi, Proxmox, XCP-NG, LXD ничего дополнительно не требуют. Hyper-V, который я использую для данного демо, требует отключить “Enable Secure Boot”:
Подключаем наш полученный образ.... и оно просто работает:
Итог
В данной статье мы научились создавать образ Ubuntu с простейшими настройками для автоматической установки. Так же я обратил ваше внимание на некоторые грабли. Еще мы настроили среду для сборки образов с необходимыми утилитами, и успешно протестировали полученный ISO.
В следующих статьях, мы рассмотрим уже более сложные сценарии.