Top.Mail.Ru
OSEN-НИЙ SAAALEСкидка 50% на виртуальный хостинг и VDS
до 30.11.2025 Подробнее
Выберите продукт

Packer + cloud-init: собираем золотой образ для быстрых развёртываний на VDS

Надо запускать новые VDS за минуты и без ручных правок? Разберём Packer + cloud-init: архитектуру пайплайна, минимальные HCL/YAML, провижининг, очистку перед снимком, локальную проверку и процесс релизов.
Packer + cloud-init: собираем золотой образ для быстрых развёртываний на VDS

Зачем «золотой» образ и почему Packer + cloud-init

«Золотой» образ — это эталонная, воспроизводимая и проверенная сборка ОС с базовой настройкой, драйверами виртуализации, агентами мониторинга и минимально необходимыми пакетами. Из такого образа можно быстро поднимать новые VDS без дрейфа конфигурации и долгих провижинингов на первом запуске. Ключевые выгоды: одинаковая база для всех окружений, ускорение развёртываний, предсказуемая безопасность и понятная процедура обновлений.

В связке packer и cloud-init роли разделены идеально: packer отвечает за сборку и воспроизводимость образа, а cloud-init — за первичную настройку экземпляра при первом буте (пользователь, SSH-ключи, пакеты, переменные окружения, growpart/resizefs и т. п.). Такой дуэт позволяет вынести тяжёлую работу в этап сборки, а оставшееся — автоматизировать на старте каждой виртуалки.

Цели и требования к «золотому» образу

  • Совместимость с гипервизором (обычно KVM): virtio-драйверы, qemu-guest-agent, консоль по ttyS0.
  • Установленный cloud-init с корректным порядком модулей и настроенной стратегией datasource.
  • Безопасные настройки SSH (ключи вместо паролей, запрет root-входа паролем), обновления безопасности и базовые sysctl.
  • Авторасширение раздела (growpart) и файловой системы на первом старте.
  • Чистота перед снимком: удалены временные файлы, сброшены machine-id, ssh_host_keys, логи, кеши пакетных менеджеров.
  • Маркировка версии образа (лейбл/файл с версией) и чёткая процедура обновления.

Архитектура пайплайна

Схема проста: packer поднимает временную виртуалку под qemu/kvm, устанавливает/настраивает ОС, добавляет cloud-init и агенты, оптимизирует и чистит систему, затем делает снапшот готового диска (например, qcow2). Далее образ публикуется в вашем каталоге шаблонов, откуда он используется при создании новых VDS. При первом запуске экземпляр считывает user-data через cloud-init и выполняет заключительную настройку, специфичную для проекта.

Если вы как раз уходите с общего хостинга, пригодится практическое «руководство по переезду на VDS» — смотрите материал «Переезд с общего хостинга на VDS» по ссылке в нашей базе знаний: Переезд с общего хостинга на VDS.

Сборка VM под qemu/kvm в пайплайне Packer

Минимальный HCL-шаблон packer (qemu)

Ниже — упрощённый пример. Он ставит базовую систему из ISO, включает cloud-init и qemu-guest-agent, добавляет настройки и делает очистку перед снимком. Параметры ISO/пользователя/пароля вынесены в переменные.

packer {
  required_version = ">= 1.10.0"
}

variable "image_version" { default = "2025.01" }
variable "vm_name" { default = "golden-debian" }
variable "iso_url" { description = "Path to local ISO or mirror" }
variable "iso_checksum" { description = "sha256:..." }
variable "ssh_username" { default = "packer" }
variable "ssh_password" { default = "packer" }

source "qemu" "base" {
  accelerator       = "kvm"
  headless          = true
  iso_url           = var.iso_url
  iso_checksum      = var.iso_checksum
  output_directory  = "output/${var.vm_name}-${var.image_version}"
  vm_name           = "${var.vm_name}-${var.image_version}"
  disk_size         = "12G"
  format            = "qcow2"
  http_directory    = "http"
  ssh_username      = var.ssh_username
  ssh_password      = var.ssh_password
  ssh_timeout       = "30m"
  shutdown_command  = "sudo systemctl poweroff"

  boot_wait = "5s"
  boot_command = [
    "<esc><wait>",
    "auto priority=critical preseed/url=http://{{ .HTTPIP }}:{{ .HTTPPort }}/preseed.cfg",
    "<enter>"
  ]
}

build {
  name    = "golden-image"
  sources = ["source.qemu.base"]

  provisioner "shell" {
    inline = [
      "sudo apt-get update",
      "sudo apt-get install -y cloud-init qemu-guest-agent",
      "sudo systemctl enable qemu-guest-agent"
    ]
  }

  provisioner "file" {
    destination = "/tmp/99_fastfox.cfg"
    content = <<EOT
# cloud-init baseline config
preserve_hostname: false
ssh_pwauth: false
users:
  - default
system_info:
  default_user:
    lock_passwd: true
    gecos: Golden Image Default User
    sudo: ["ALL=(ALL) NOPASSWD:ALL"]
    shell: /bin/bash
    groups: ["adm", "sudo"]
resize_rootfs: true
growpart:
  mode: auto
  devices: ["/"]
  ignore_growroot_disabled: false
EOT
  }

  provisioner "shell" {
    inline = [
      "sudo mkdir -p /etc/cloud/cloud.cfg.d",
      "sudo mv /tmp/99_fastfox.cfg /etc/cloud/cloud.cfg.d/99_fastfox.cfg",
      "echo 'GRUB_CMDLINE_LINUX=\"console=ttyS0,115200n8\"' | sudo tee /etc/default/grub.d/50-serial.cfg",
      "sudo update-grub || true"
    ]
  }

  provisioner "shell" {
    inline = [
      "sudo apt-get -y dist-upgrade",
      "sudo apt-get -y autoremove --purge",
      "sudo apt-get clean"
    ]
  }

  provisioner "shell" {
    inline = [
      "sudo systemctl stop rsyslog || true",
      "sudo rm -f /etc/ssh/ssh_host_*",
      "sudo truncate -s0 /etc/machine-id",
      "sudo rm -f /var/lib/dbus/machine-id",
      "sudo ln -s /etc/machine-id /var/lib/dbus/machine-id || true",
      "sudo cloud-init clean --logs",
      "sudo find /var/log -type f -exec truncate -s0 {} +",
      "sudo rm -rf /tmp/* /var/tmp/*"
    ]
  }
}

В боевом окружении вы можете заменить установку из ISO на использование инфраструктурного «базового» cloud-образа и донастройку через packer. Главное — обеспечить в итоге установленный cloud-init и корректный набор драйверов и сервисов для гипервизора.

Полезные настройки cloud-init в образе

Часть настроек имеет смысл «запекать» в образ, чтобы первичный user-data для отдельных проектов был минималистичным. Речь о поведении growpart, дефолтном пользователе, блокировке паролей, политике ssh_pwauth, а также приоритизации источников метаданных (datasource).

# /etc/cloud/ds-identify.cfg
policy: enabled
# Явно укажем список источников метаданных, чтобы cloud-init не тратил время на лишнее
datasource_list: [ NoCloud, ConfigDrive ]

Если в инфраструктуре используется иной источник (например, собственная служба метаданных), добавьте его в список. Так вы ускорите бут и избежите таймаутов ожидания неподходящих источников.

Минимальный user-data для проекта

На момент развёртывания конкретного VDS обычно достаточно передать небольшой user-data с ключом SSH, пакетом необходимых пакетов и парой команд:

#cloud-config
users:
  - name: deploy
    gecos: Deploy User
    sudo: ["ALL=(ALL) NOPASSWD:ALL"]
    groups: ["adm", "sudo"]
    shell: /bin/bash
    ssh_authorized_keys:
      - ssh-ed25519 AAAA... comment
package_update: true
packages:
  - htop
  - curl
  - ca-certificates
write_files:
  - path: /etc/motd.d/00-image-version
    content: |
      Golden image version: 2025.01
runcmd:
  - [ systemctl, enable, --now, qemu-guest-agent ]
  - [ sh, -c, "echo 'Deploy bootstrap OK'" ]

Чем меньше логики на этапе первого запуска — тем надёжнее. Сложные сценарии лучше переносить в этап сборки packer или в последующий слой конфигурации (например, через Ansible после старта экземпляра).

Проверка локально: быстрый цикл отладки

Перед публикацией образа удобно проверять его локально. Стандартный подход: поднять VM из собранного qcow2 и подложить seed с user-data в формате NoCloud. После загрузки проверить логи cloud-init и убедиться, что авторасширение диска, доступ по SSH и агенты отрабатывают корректно.

  • Проверить статус: cloud-init status --long.
  • Посмотреть логи: journalctl -u cloud-init -u cloud-init-local -u cloud-config -u cloud-final.
  • Убедиться, что создан пользователь, подставлены ключи, включён qemu-guest-agent, а файловая система расширена.

Проверка логов и статуса cloud-init на тестовой VM

Версионирование и неизменяемость

Рекомендуется встраивать версию образа в артефакт и внутрь файловой системы (например, /etc/image-build или файл в /etc/motd.d). Правила именования: год.месяц.пателевел или семантическая версия с build-метаданными. Не меняйте образ «на месте» — публикуйте новые версии и проводите по ним канареечные развёртывания. Это и есть практика неизменяемых серверов (immutable), которая резко снижает дрейф конфигураций.

Безопасность по умолчанию

  • Запрет паролей по SSH: ssh_pwauth: false, проверка PermitRootLogin prohibit-password в sshd_config.
  • Удаление ssh_host_keys на этапе сборки и регенерация при первом старте.
  • Включение автоматических обновлений безопасности дистрибутива.
  • Сужение списка datasources в ds-identify.cfg, чтобы исключить ложные срабатывания.
  • Логи и временные файлы — под ноль перед снимком; machine-id — обнулить.

Оптимизации времени старта

  • Серийная консоль в GRUB: console=ttyS0 для быстрых диагностик.
  • Порядок модулей cloud-init: первым cloud-init-local для сети, затем cloud-config и cloud-final.
  • Ограничение datasource_list — нет лишних таймаутов.
  • Предварительная установка необходимых пакетов в образ вместо установки на user-data.

Очистка перед публикацией

Список полезных команд для финального шага уже был в примере packer, но повторим общую идею:

  • Удалить host-ключи SSH и обнулить machine-id.
  • Очистить кеши пакетов (apt/dnf), логи в /var/log, временные файлы.
  • Запустить cloud-init clean --logs.
  • Остановить машину штатно (systemctl poweroff) для корректной фиксации файловой системы.

От ISO к «базовому» cloud-образу

Есть два подхода:

  1. Установка из ISO. Полный контроль, но больше времени на сборку: автопостановка через preseed/kickstart, затем установка cloud-init и пакетов.
  2. Кастомизация готового cloud-образа. Быстрее: cloud-init и разметка уже присутствуют, вы лишь вносите корпоративные настройки и агенты. В packer это реализуется через запуск образа в qemu и дальнейшие provisioners.

Выбор зависит от требований к прозрачности цепочки поставки и длительности сборки. Нередко в инфраструктуре применяется смешанный подход: собственный «базовый» образ, собранный из ISO, а затем — проектные кастомизации поверх. Если требуется удобная панель управления, пригодится обзор: сравнение панелей для VDS.

Тест-кейсы до выката

  • Валидность образа: поднимается ли VM, корректно ли работает сеть и консоль.
  • Отработка user-data на первом старте, включая packages, write_files, runcmd.
  • Регенерация ssh_host_keys и доступ по публичному ключу.
  • Расширение раздела и файловой системы на полный размер диска.
  • Версионирование: присутствует ли файл/лейбл версии внутри системы.

Релизы и обновления: процесс

Фиксируйте HCL и cloud-config в репозитории, используйте теги для релизов, храните артефакты с контрольными суммами. Держите две ветки: stable и next. Новая версия проходит автоматические тесты (проверка загрузки, доступности по SSH, отработки cloud-init), далее — канареечный выпуск на часть новых VDS. Только после стабилизации — перевод в stable.

FastFox VDS
Облачный VDS-сервер в России
Аренда виртуальных серверов с моментальным развертыванием инфраструктуры от 195₽ / мес

Типичные ошибки и отладка

  • Долгая загрузка cloud-init. Проверьте datasource_list и сетевые таймауты. В логах часто видно ожидание ненужных источников.
  • Нет авторасширения диска. Убедитесь, что включены growpart и resize_rootfs, а корневой раздел размечён подходящим образом.
  • Не генерируются SSH host keys. Проверьте наличие соответствующих systemd-юнитов и отсутствие предзапечённых ключей в образе.
  • Проблемы с агентом гостя. Убедитесь, что установлен и включён qemu-guest-agent, проверьте сокеты и разрешения.
  • Случайные конфликты сети. Если вы используете netplan или NetworkManager, проверьте, не мешает ли им конфигурация от cloud-init. Иногда полезно делегировать сети только одной системе.

Расширение пайплайна: Ansible, тесты, подписи

packer легко дополняется Ansible-провижинингом для более сложных ролей (например, предустановка агента мониторинга, логгера, базовых правил auditd). Автотесты на стадии сборки можно реализовать через скрипты проверки сервисов и логов. Для целостности добавляйте контрольные суммы и подписи артефактов.

Итог: packer даёт воспроизводимый артефакт, cloud-init — быстрый и минималистичный провижининг на первом старте. Вместе они формируют надёжную основу для массовых развёртываний VDS, сводя ручные действия к нулю и повышая безопасность.

Чек-лист перед публикацией образа

  • cloud-init установлен, модули выполняются, datasource_list настроен.
  • Включён qemu-guest-agent, консоль доступна по ttyS0.
  • SSH-пароли отключены, ключи не запечены в образе.
  • Готовность к росту диска на первом старте.
  • Версия образа зафиксирована внутри системы и в имени артефакта.
  • Проведены локальные тесты и проверка логов cloud-init.
  • Очистка выполнена: логи, кеши, machine-id, ssh_host_keys.

Заключение

Собственный «золотой» образ — это инструмент, который окупается с первого десятка развёртываний. Связка packer + cloud-init обеспечивает быстрое масштабирование и предсказуемые релизы. Начните с минимальной базы (драйверы, cloud-init, агент гостя, безопасность по умолчанию), выстройте процесс версионирования и канареек, и через пару итераций у вас появится стабильный, хорошо документированный образ, который экономит часы на каждом новом сервере.

Поделиться статьей

Вам будет интересно

Безопасные миграции MySQL: pt‑online‑schema‑change и gh‑ost без простоя OpenAI Статья написана AI Fastfox

Безопасные миграции MySQL: pt‑online‑schema‑change и gh‑ost без простоя

Если таблицы уже на десятках гигабайт, обычный ALTER грозит блокировками и простоями. Разбираем онлайн‑миграции MySQL с pt‑online‑ ...
journald или rsyslog: настраиваем персистентность, rate‑limit и форвардинг OpenAI Статья написана AI Fastfox

journald или rsyslog: настраиваем персистентность, rate‑limit и форвардинг

Как выбрать между journald и rsyslog, включить хранение на диске, настроить rate‑limit и надёжный форвардинг на коллектор? В матер ...
TLS до базы данных: шифрование MySQL/PostgreSQL с валидацией CA OpenAI Статья написана AI Fastfox

TLS до базы данных: шифрование MySQL/PostgreSQL с валидацией CA

Подключения к БД часто ходят по внутренним сетям — и потому их шифрованием пренебрегают. Разбираем, как включить TLS для MySQL и P ...