Автор: DevOps Team Leader компании Hostkey Егор Гараджа
Мы уже рассказывали об устройстве кухни по сборке LiveCD для Linux на базе Centos/RockyLinux, которую мы используем в компании Hostkey. Пришло время поговорить об устройстве сборки WindowsPE-дистрибутива в Linux-инфраструктуре, автоматизации этого процесса с помощью Jenkins и разворачивании систем на базе MS Windows через этот хэлпер.
Традиционно PXE-deploy Windows реализуется в рамках общей инфраструктуры Microsoft, включая DHCP/DNS/TFTP и прочие сервисы. В нашей инфраструктуре узловым сервером для развертывания ОС является Foreman, и разворачивать деплойную среду отдельно для Microsoft с самого начала казалось нецелесообразным.
Много лет назад нами был выбран путь с загрузкой wim-образа WindowsPE через iPXE. Образ собирался на инфраструктуре Microsoft вручную, за кухней следил один человек. С ростом компании и усложнением задач мы решили максимально автоматизировать процессы сборки и управления образом. В это же время перед нами возникла задача по поддержке UEFI-инсталляций, оказавшаяся не такой тривиальной, как можно предположить.
Автоматизация подготовки образа
Прежде всего было необходимо отвязаться от инфраструктуры Microsoft для создания образа. Для этой цели мы решили использовать старый проект wimtools, в данном случае поддержка RedHat-систем находится на хорошем уровне, и мы получили готовый SPEC.
Этот набор консольных утилит позволяет работать с wim-образами и производить их модификацию. Для подготовки образа WindowsPE нам необходимы:
-
ванильный дистрибутив Windows (например, Windows 10);
-
утилита mkwinpeimg из состава wimtools;
-
стартовый cmd-скрипт для WindowsPE.
В процессе сборки можно оверлеем добавить произвольную директорию с необходимым набором скриптов и ПО. Мы добавляем в WinPE последнюю версию PowerShell с Github Microsoft, набор скриптов для осуществления установки ОС и ряд утилит, также необходимых для взаимодействия с Foreman.
Пример команды сборки:
mkwinpeimg --iso --windows-dir=/mnt/windowsrepo --overlay=./PEAddons --start-script=./startpe.cmd windowspe-${BUILD_NUMBER}.iso
По пути /mnt/windowsrepo доступен ISO-образ ванильной версии Windows 10, смонтированный как loop-устройство.
В результате длительной работы с образом у нас сформировалась примерно следующая кухня сборки:
-
Задача Jenkins по сборке wimtools-rpm (мы уже рассказывали, как можно организовать базовую работу с пакетами в инфраструктуре).
-
Задача Jenkins по сборке и доставке на центральный репозиторий WindowsPE ISO-образа.
-
Репозиторий Git, содержащий основной набор скриптов и небольших бинарников для работы внутри образа. Те самые startpe.cmd и директория PEAddons, внутри которой мы выделили директорию для PowerShell, bin — для небольших утилит вроде нашего самописного инструмента на Go для работы с syslog и scripts — для дополнительных скриптов и так далее.
-
Репозиторий для драйверов устройств windows_driver_store, который мы также разместили в Git для версионирования; проблема крупных бинарников решается через LFS.
-
Наше внутреннее зеркало с ванильными дистрибутивами, откуда берется ISO-донор для создания PE-образа. Этот же репозиторий используется уже в процессе установки ОС.
Все, кроме зеркала с ISO-образами, хранится и версионируется в Git. Такой подход очень важен и удобен, когда над инфраструктурой работает более одного человека.
Если есть все необходимое в Git и набор Linux-утилит для сборки, задача легко автоматизируется в Jenkins:
#!/usr/bin/env bash
ssh-agent bash -c "ssh-add $GITLAB_KEY; git clone -b $short_branch git@gitlab.example.com:windows_driver_store.git PEAddons/drivers"
wget -nv https://github.com/PowerShell/PowerShell/releases/download/v$PWSHVER/PowerShell-$PWSHVER-win-x64.zip
unzip -qqo PowerShell-$PWSHVER-win-x64.zip -d PEAddons/pwsh/ || true
rm -rf PowerShell-$PWSHVER-win-x64.zip PEAddons/drivers/.git
sed "1aecho Starting windowspe-${BUILD_NUMBER}" -i ./startpe.cmd
mkwinpeimg --iso --windows-dir=/mnt/windowsrepo --overlay=./PEAddons --start-script=./startpe.cmd windowspe-${BUILD_NUMBER}.iso
Скрипты и связка с Foreman
Важной задачей при организации разворачивания системы нужна такая организация образа, при которой контроль за его поведением будет вынесен на внешний сервис. Подобное решение позволит исключить необходимость пересборки образа под каждую отдельную установку.
По стандарту WindowsPE стартовым скриптом должен быть startpe.cmd. Это, по сути, обычный bat-файл со всеми ограничениями стандартного shell Microsoft, мы используем его для старта PowerShell-скриптов.
Первым и основным скриптом является одноименный скрипт getforeman.ps1, его и запускает startpe.cmd (код ниже: PowerShell).
Главная проблема при организации деплоя Windows через вызов его ISO-образа через iPXE заключается в том, что вы не можете прокинуть внутрь образа никакие параметры, то есть образ внутри себя должен получить достаточную информацию, чтобы затем пойти и получить скрипты на Foreman. Сами скрипты генерируются в процессе деплоя и доступны по ссылкам вида:
http://foreman.example.com/unattended/provision?token=xxxxxxxx
То есть нам нужен токен хоста. Токен можно получить у самого Foreman, если знать имя хоста, которое передается в том числе через dhcp самому хосту.
Для получения этого имени в CLI мы используем утилиту dhcptest.exe:
$dhcphostname = ( & $env:SystemDrive\bin\dhcptest.exe --mac $netinfo.macaddress --query --print-only 12[str] --quiet )
Далее мы получаем токен хоста, с помощью запроса к Foreman, который делается через пользователя с правами на просмотр:
$creds = "$($user):$($foremanpass.$location)"
$uri = $foremanuri.$location
$encodedCreds = [System.Convert]::ToBase64String([System.Text.Encoding]::ASCII.GetBytes($creds))
$basicAuthValue = "Basic $encodedCreds"
$Headers = @{
Authorization = $basicAuthValue
}
$foremanhostinfo = @{ $location=$(Invoke-RestMethod -Uri "$uri/api/hosts/$dhcphostname" -Headers $Headers -SkipCertificateCheck) }
$token = $foremanhostinfo.$location.token
С помощью токена мы можем запросить все необходимые provision-скрипты уже непосредственно с Foreman. Задача решена.
Дальнейшие задачи связаны уже с организацией процедуры установки на Foreman. Это также обширная тема, особенно учитывая UEFI-деплой, которой мы надеемся посвятить отдельную статью.
Важным моментом в такой системе остается вопрос безопасности. Адрес Foreman, ограниченного пользователя для взаимодействия с ним и прочие параметры приходится зашивать непосредственно в скрипт получения информации и при их изменении пересобирать образ. Если вопрос удобства решается сборкой, то безопасность — более тонкая материя. Именно вопрос безопасности заставил нас смотреть в сторону более сложных вариантов установки, исключающих WindowsPE. Тем не менее в непубличных инфраструктурах, нуждающихся в Windows, но не требующих большой инфраструктуры Microsoft для его разворачивания, реализация развертывания систем через WindowsPE может оказаться хорошим вариантом.