Автоматизация пользовательских ISO с помощью `Cloud-Init`

С возвращением, господа читатели. Спасибо, что возвращаетесь, чтобы пополнить копилку ваших знаний. Меня зовут Silent.Mobius, и я ваш верный автор. Прежде чем мы продолжим, давайте подытожим, что мы сделали.

История на данный момент…

В прошлой статье мы изучили структуру настройки дистрибутива Linux, которая в основном выполняется вручную. Обычно это полезно в случаях, когда наш ISO требует предварительной настройки или добавления некоторых инструментов перед использованием для разработки, тестирования, выпуска, развертывания, эксплуатации или мониторинга.
Хотя эта ручная работа может быть полезной, в других случаях возникает необходимость в автоматизации, которая позволяет принимать более динамичные решения, такие как разделение диска на разделы, установка пакетов, настройка служб и многое другое.
Для этих целей почти каждый дистрибутив Linux имеет свои собственные средства автоматизации: У RedHat был KickStarter, у Debian — Pre-Seed, но эти инструменты либо имеют проблемы с документацией, либо полезны только в специальных дистрибутивах.

Введите Cloud-Init.

Согласно документации Cloud-init:

Cloud-init — это стандартный для отрасли мультидистрибутивный метод кросс-платформенной инициализации облачных экземпляров. Он поддерживается всеми основными провайдерами публичных облаков, системами инициализации для частной облачной инфраструктуры и пустой установкой.

Что такое Cloud-Init на самом деле?

Это довольно простой, но мощный способ конфигурирования машин. Предположим, вы хотите настроить машину, для которой требуются некоторые параметры или установленные пакеты. Вы можете подумать о «создать пользователя» или «установить обновления», а также «настроить сеть» или «положить туда файл».

И как это работает?

Каждый раз, когда мы используем #ISO, на аппаратном обеспечении или платформе виртуализации, запускается служба Cloud-init и делает следующее:

  • Проверяет, валидирует и анализирует существующую конфигурацию cloud-init.
  • Применяет через API, команды и конфигурационные изменения конфигурации cloud-init.

Какая среда подходит для Cloud-Init?

Исходя из названия, можно предположить, что облачная. Велики шансы, что большинство хостинг/облачных провайдеров уже поддерживают его. Вы можете ожидать очень вменяемую поддержку, по крайней мере:

  • nocloud : виртуализация или пустой металл
  • aws
  • gcp
  • azure
  • и многие другие…

В качестве примечания

В моих личных случаях использования Cloud-init чаще всего применялся для настройки Ubuntu 18.04 и 20.04 для создания автоматической установки на различные типы оборудования, поэтому в этой статье я хотел бы поделиться некоторыми соображениями на этот счет.

Цель

  • Показать базовую настройку Cloud-Init.
  • Написать файл автоматизации, который позволит вам выполнять задачи
  • Дать советы и рекомендации по использованию Cloud-Init в автоматизированном CI/CD конвейере.

Давайте начнем с самого начала…

Настройка Cloud-Init

Чтобы начать использовать Cloud-init, нам необходимо установить его на базовый образ дистрибутива Linux, который мы используем. В нашем случае ubuntu-20.04.4, последняя стабильная версия дистрибутива ubuntu Linux, уже имеет установленный Cloud-init, нам нужно будет только настроить его, чтобы сделать его готовым для установки #ISO.

Начнем с получения инструментов и файла #ISO для его дизассемблирования:

sudo apt update  && sudo apt install p7zip-full p7zip-rar genisoimage fakeroot xorriso isolinux binutils squashfs-tools 
curl -X GET -OL https://releases.ubuntu.com/20.04.4/ubuntu-20.04.4-live-server-amd64.iso 
7z x -y ubuntu-20.04.4-live-server-amd64.iso  -oiso
Войдите в полноэкранный режим Выйдите из полноэкранного режима

После этого у вас должна появиться папка с именем iso, в которой будут находиться все внутренние файлы #ISO.
Нам нужно будет уведомить ядро Linux о загрузке из пользовательского конфигурационного файла, который также должен инициализировать Cloud-init, и поэтому нам нужно настроить заголовки в основных загрузочных файлах в Ubuntu 20.04

sed -i -e 's/---/ autoinstall  ---/g' iso/isolinux/txt.cfg
sed -i -e 's/---/ autoinstall  ---/g' iso/boot/grub/grub.cfg
sed -i -e 's/---/ autoinstall  ---/g' iso/boot/grub/loopback.cfg
sed -i -e 's,---, ds=nocloud;s=/cdrom/nocloud/  ---,g' iso/isolinux/txt.cfg
sed -i -e 's,---, ds=nocloud\\\;s=/cdrom/nocloud/  ---,g'  iso/boot/grub/grub.cfg
sed -i -e 's,---, ds=nocloud\\\;s=/cdrom/nocloud/  ---,g' iso/boot/grub/loopback.cfg
Вход в полноэкранный режим Выйти из полноэкранного режима

Примечание: В старых или новых версиях расположение файлов или даже их имена могут отличаться, поэтому потратьте время на поиски и не сдавайтесь. Я верю в тебя

Если вы внимательно посмотрите на последнюю команду sed внутри одинарных кавычек, она указывает путь к имени папки ds=nocloud;s=/cdrom/nocloud. В действительности это не настоящая папка, но мы должны помнить, что во время установки ОС, #ISO монтируется в папку /cdrom как источник ее установки, поэтому нам нужно поместить папку nocloud в папку iso, которая представляет собой корень нашей #ISO. nocloud должен включать два очень важных файла для Cloud-Init:

  • meta-data
  • пользовательские данные .

Мы обсудим эти файлы и другие части Cloud-Init в следующем сегменте. Меньше разговоров — больше работы:

mkdir -p iso/nocloud
touch iso/nocloud/{meta-data,user-data}
Вход в полноэкранный режим Выход из полноэкранного режима

Теперь мы настроили наше окружение, и осталось только создать автоматизацию, о которой мы упоминали ранее.

Автоматизация

Cloud-init использует файл мета-данных для настройки конфигураций и параметров облачного API, а также файл пользовательских данных для настройки уникального поведения ОС во время установки.
Синтаксис для обоих этих способов — YAML, и он довольно структурирован:


#cloud-config
autoinstall:
  version: 1
  early-commands:
  keyboard: 
  locale: 
  identity: 
  users:
  apt:
  ssh:
  network:
  storage:
  late-commands:
  user-data:
    write_files:
    timezone: 
    runcmd:
    bootcmd:
Войти в полноэкранный режим Выйти из полноэкранного режима

Да, действительно. Все написанное выше бесполезно без объяснений. Пожалуйста, имейте в виду, что хотя модули здесь написаны, не все из них являются обязательными. Несмотря на то, что написан Cloud-init и его модули. Итак, давайте погрузимся в суть дела:

  • Начнем с заголовка #cloud-config, в то время как большинство файлов на основе YAML не требуют определенных заголовков, Cloud-init требует этот заголовок, в противном случае запуск Cloud-init завершится ошибкой header is missing.
  • Мы продолжаем с тегом autoinstall, который уведомляет Cloud-init не требовать ввода данных пользователем.
  • Файл продолжается version, который требует Cloud-inits API версии, которая на данный момент все еще является версией 1.
  • Далее идет тег early-commnds, который позволяет нам запустить любые определенные команды или скрипт, которые мы предпочли бы запустить перед установкой. Какие команды или скрипты? В моем случае я использовал скрипт, который определяет тип ssd, будь то обычный SATA диск или NVME, и корректирует конфигурацию Cloud-init по мере необходимости.
    • Обратите внимание, что Cloud-init перезагружается после запуска early-command, что позволяет нам изменить наш конфигурационный файл в соответствии с нашими потребностями.
  • Чтобы не отклоняться от курса, мы используем тег keyboard для создания совместимости с раскладкой клавиатуры наших устройств, которая может отличаться от моей и вашей.
  • Для поддержания курса на тему, тег Locale обеспечивает настройку локального языка нашей системы.
  • Мы продлеваем наш курс с помощью identity, который позволяет нам настроить пользователя по умолчанию. Он может иметь несколько вариантов конфигурации:
    • Если он не настроен, и если не установлен тег users, пользователь и пароль по умолчанию, ubuntu/ubuntu, вставляется автоматически.
  • Чтобы продолжить обсуждение пользователей системы, рассмотрим тег users: этот тег позволяет добавлять пользователей в систему. Пользователи добавляются после добавления групп. Большинство из этих параметров конфигурации не будут выполняться, если пользователь уже существует.
      • требуется только один из паролей
  • Для преследования системных инструментов мы используем apt для установки инструментов, если сеть настроена, или для обновления системы.
  • Чтобы не отклоняться от темы, network обеспечивает конфигурацию сети, и делает это с помощью нескольких типов api, которые можно найти здесь.
  • Ближе к концу мы переходим к тегу storage, который позволяет нам настроить stoage, но по какой-то причине документация Cloud-Init не дает глубокого или какого-либо понимания разделения, на nocloud провайдера. К счастью для нас, я провел небольшое расследование и узнал, что Cloud-init построен на базе программного обеспечения под названием Curtain, которое предоставляет очень глубокое объяснение в отношении разметки, LVM, Raid и так далее.
  • Чтобы продлить драму, мы рассмотрим тег late-commands, который позволяет Cloud-init запускать команды или скрипты после завершения установки.
  • И последний, но не менее важный тег user-data, который сам по себе не дает слишком многого, но имеет несколько подмодулей, которые позволяют добавлять дополнительные части в пространство пользователя с помощью скрипта initialize, .bashrc, .profile и других. Давайте проверим и их:

Слишком много нужно запомнить и обработать, верно?! Итак, вот пример, который вы можете использовать:

#cloud-config
autoinstall:
  version: 1
  identity: {hostname: HOSTNAME, password: "ENCRYPTED-PASSWORD", username: USERNAME}
  keyboard: 
    layout: us
  locale: En_Us.UTF-8
  apt:
    disable_suites: [security]
  ssh:
    install-server: true
  network:
    version: 2
    ethernets:
      eno1:
        match:
          name: en*
        dhcp4: true
  storage:
    config:
      - {name: ubuntu-vg, devices:[partition-2], preserve: false, type: lvm_volgroup, id: lvm_volgroup-0 }
      - {name: ubuntu-lv, volgroup: lvm_volgroup-0, size: 10GB, wipe: superblock, preserve: false, type: lvm_partition, id: lvm_part-0}
      - {fstype: ext4, volume: lvm_part-0, preserve: false, type: format, id: fmt-2 }
      - {path: /, device: fmt-2, type: mount, id: mnt-2}
      - {path: /boot, device: fmt-1, type: mount, id: mnt-1}
      - {path: /boot/efi, device: fmt-0, type: mount, id: mnt-0}
  late-commands:
    - rm -rf /target/etc/update-motd.d/[0-9]*
    - rm -rf /target/etc/cron.{hourly,d,daily,weekly,monthly}/*
    write_files:
      - path: /etc/ssh/sshd_config
        content: |
          LogLevel INFO
          AllowUsers USERNAME
        append: true
    timezone: Asia/Jerusalem
    runcmd:
      - [groupadd, -g, 998, docker]
      - [usermod, -aG, docker, USERNAME]
      - [reboot]
Войти в полноэкранный режим Выход из полноэкранного режима

Хотя это небольшой пример, могут быть дополнительные части, которые можно добавить или убрать.

Советы и рекомендации

Когда дело доходит до создания чего-либо с помощью Cloud-init, лучшим местом для начала всегда будет документация по этому инструменту. Однако, по моему личному опыту, документация по Cloud-init построена не очень организованно, и, кроме того, поведение некоторых инструментов не всегда объясняется при глубоком погружении в тему. Поэтому вот несколько советов, которые облегчат вам работу с Cloud-init:

  • Прочитайте как можно больше github gists. Я смог найти множество примеров, которые просто работают, и это сэкономило мне много времени.
  • Используйте команду cloud-init validate перед закрытием #ISO. Тестирование на пустом железе, пока вы не уверены, что синтаксис Cloud-init не является правильным способом, и после первых нескольких загрузок это станет разочаровывать.
  • Собирайте Yaml-файл по частям. Не нужно закидывать в файл все подряд, а потом пытаться отладить, почему все не получилось.
  • Выполните ручную установку, чтобы получить после установки сгенерированный YAML-файл. У меня были проблемы с настройкой LVM, и я выполнил ручную установку, чтобы получить сгенерированный после установки YAML-файл, который облегчил мне жизнь. Файл обычно хранится в /var/log/installer/ с именем autoinstaller-user-data.
  • Не используйте late-commands или runcmd для установки программного обеспечения. Стратегия должна заключаться в том, чтобы во время установки #ISO на аппаратном обеспечении у вас была подключена сеть, и вы могли использовать тег apt для установки всего, что вам нужно.
    • Если сеть — это не то, что вы можете получить во время установки, загрузите пакеты вручную, упакуйте их как часть вашего #ISO, а затем только установите с помощью runcmd.
    • Обратите внимание, что если возникнут проблемы с зависимостями, например, будет отсутствовать библиотека или пакет, вся установка системы завершится неудачно.
  • Не используйте lxd для тестирования. Он обычно не обеспечивает
  • Создайте сценарий оболочки, который определяет значения для вашего YAML-файла. У меня были проблемы с определением нескольких значений с ранними командами, поэтому при запуске сборки на CI/CD с Jenkins, я запускал shell-скрипт для определения значений до того, как YAML файл был вставлен в #ISO, и менял нужные значения с помощью команды sed. Например, я использовал USERNAME в примере выше, который может быть заменен на silent-mobius с помощью команды sed.
  • Не стесняйтесь экспериментировать.

    Заключение

    Дорогой читатель, моя благодарность за то, что дочитали эту статью до конца. Надеюсь, вы расширили свои знания до новых пределов, и эта статья была для вас информативной, и помните: старайтесь получать удовольствие.

Некоторые ссылки на источники, благодаря которым появилась эта статья

  • Curtin
  • Cloud-init
  • Документация Ubuntu
  • Puget Systems
  • GoCloudLinux
  • Gist 1
  • Gist 2

Спасибо

Оцените статью
devanswers.ru
Добавить комментарий