Bare-Metal Provisioning своїми руками, або Автоматична підготовка серверів з нуля

Привіт, я Денис та один із моїх напрямків діяльності – розробка інфраструктурних рішень у X5. Сьогодні хотів би поділитися з вами, як можна на базі загальнодоступних інструментів розгорнути автоматичну систему підготовки серверів. На мій погляд, це цікаве, просте та гнучке рішення.

Bare-Metal Provisioning своїми руками, або Автоматична підготовка серверів з нуля

Під підготовкою мається на увазі: зробити з нового сервера з коробки повністю налаштований сервер з о.с. Linux або c гіпервізором ESXi (розлив серверів Windows у цій статті не обговорюється).

Терміни:

  • сервери – сервери, які потрібно налаштувати.
  • інсталл-сервер - основний сервер, який забезпечує весь процес підготовки через мережу.

Навіщо потрібна автоматизація?

Допустимо, є завдання: масово готувати сервери з нуля, у піку – 30 на день. Сервера різних виробників і моделей, на них можуть встановлюватися різні ОС, може бути або відсутній гіпервізор.

Які операції входять до процесу налаштування (без автоматизації):

  • підключити клавіатуру, мишу, монітор до сервера;
  • налаштувати BIOS, RAID, IPMI;
  • оновити прошивки компонентів;
  • розгорнути образ файлової системи (або встановити гіпервізор і скопіювати віртуальні машини);

Примітка. Як варіант, деплой ОС можливий через встановлення з файлом автовідповідей. Але це не обговорюватиметься у статті. Хоча нижче ви побачите, що додати цей функціонал нескладно.

  • настроїти параметри ОС (hostname, IP, інше).

При цьому підході виконуються однакові налаштування послідовно кожному сервері. Ефективність такої роботи дуже низька.

Суть автоматизації – виключити участь людини із процесу підготовки сервера. Максимально наскільки це можливо.

Завдяки автоматизації скорочується час простою між операціями та з'являється можливість підготувати кілька серверів одночасно. Також сильно знижується ймовірність виникнення помилок через людський фактор.

Bare-Metal Provisioning своїми руками, або Автоматична підготовка серверів з нуля

Як відбувається автоматичне налаштування серверів?

Розберемо усі етапи детально.

У вас є linux-сервер, який ви використовуєте як PXE інсталл-сервер. На ньому встановлені та налаштовані служби: DHCP, TFTP.

Отже, завантажуємо сервер (який необхідно налаштувати) PXE. Згадаймо, як це працює:

  • На сервері вибрано завантаження через мережу.
  • Сервер завантажує PXE-ROM мережевої карти і звертається до інстал-сервера DHCP для отримання мережевої адреси.
  • DHCP інстал-сервера видає адресу, а також інструкцію щодо подальшого завантаження через PXE.
  • Сервер завантажує мережевий завантажувач з інстал-сервера за PXE, подальше завантаження відбувається згідно з конфігураційним файлом PXE.
  • Відбувається завантаження на основі отриманих параметрів (ядро, initramfs, точки монтування, образ squashfs та інше).

Примітка. У статті наводиться опис завантаження PXE через BIOS mode. В даний час виробниками активно впроваджується UEFI bootmode. Для PXE відмінність буде в конфігурації DHCP-сервера та наявності додаткового завантажувача.

Розглянемо приклад конфігурації PXE-сервера (меню pxelinux).

Файл pxelinux.cfg/default:

default menu.c32
prompt 0
timeout 100
menu title X5 PXE Boot Menu
LABEL InstallServer Menu
	MENU LABEL InstallServer
	KERNEL menu.c32
	APPEND pxelinux.cfg/installserver
LABEL VMware Menu
	MENU LABEL VMware ESXi Install
	KERNEL menu.c32
	APPEND pxelinux.cfg/vmware
LABEL toolkit // меню по умолчанию
	MENU LABEL Linux Scripting Toolkits
	MENU default
	KERNEL menu.c32
	APPEND pxelinux.cfg/toolkit // переход на следующее меню

Файл pxelinux.cfg/toolkit:

prompt 0
timeout 100
menu title X5 PXE Boot Menu
label mainmenu
    menu label ^Return to Main Menu
    kernel menu.c32
    append pxelinux.cfg/default
label x5toolkit-auto // по умолчанию — автоматический режим
        menu label x5 toolkit autoinstall
        menu default
        kernel toolkit/tkcustom-kernel
        append initrd=toolkit/tk-initramfs.gz quiet net.ifnames=0 biosdevname=0 nfs_toolkit_ip=192.168.200.1 nfs_toolkit_path=tftpboot/toolkit nfs_toolkit_script=scripts/mount.sh script_cmd=master-install.sh CMDIS2=”…”
label x5toolkit-shell // для отладки - консоль
        menu label x5 toolkit shell
        kernel toolkit/tkcustom-kernel
        append initrd=toolkit/tkcustom-initramfs.gz quiet net.ifnames=0 biosdevname=0 nfs_toolkit_ip=192.168.200.1 nfs_toolkit_path=tftpboot/toolkit nfs_toolkit_script=scripts/mount.sh script_cmd=/bin/bash CMDIS2=”…”

Ядро та initramfs на даному етапі – це проміжний linux-образ, за ​​допомогою якого і відбуватиметься основна підготовка та налаштування сервера.

Як бачите, завантажувач передає багато параметрів ядру. Частина цих параметрів використається самим ядром. А деякі ми можемо використовувати для своїх цілей. Про це буде розказано далі, а поки що можна просто запам'ятати, що всі передані параметри будуть доступні в проміжному linux-образі через /proc/cmdline.

Де їх взяти, ядро ​​та initramfs?
За основу можна вибрати будь-який linux-дистрибутив. На що звертаємо увагу при виборі:

  • завантажувальний образ має бути універсальним (наявність драйверів, можливості встановлення додаткових утиліт);
  • швидше за все, потрібно кастомізувати initramfs.

Як це зроблено у нашому рішенні для X5? В якості основи обрано CentOS 7. Перевіримо наступний трюк: підготуємо майбутню структуру образу, запакуємо її в архів і створимо initramfs, всередині якого буде наш архів файлової системи. При завантаженні образу архів розгортатиметься у створюваний розділ tmpfs. Таким чином ми отримаємо мінімальний, при цьому повноцінний live-образ linux з усіма необхідними утилітами, що складається всього з двох файлів: vmkernel та initramfs.

#создаем директории: 

mkdir -p /tftpboot/toolkit/CustomTK/rootfs /tftpboot/toolkit/CustomTK/initramfs/bin

#подготавливаем структуру:

yum groups -y install "Minimal Install" --installroot=/tftpboot/toolkit/CustomTK/rootfs/
yum -y install nfs-utils mariadb ntpdate mtools syslinux mdadm tbb libgomp efibootmgr dosfstools net-tools pciutils openssl make ipmitool OpenIPMI-modalias rng-tools --installroot=/tftpboot/toolkit/CustomTK/rootfs/
yum -y remove biosdevname --installroot=/tftpboot/toolkit/CustomTK/rootfs/

# подготавливаем initramfs:

wget https://busybox.net/downloads/binaries/1.31.0-defconfig-multiarch-musl/busybox-x86_64 -O /tftpboot/toolkit/CustomTK/initramfs/bin/busybox
chmod a+x /tftpboot/toolkit/CustomTK/initramfs/bin/busybox
cp /tftpboot/toolkit/CustomTK/rootfs/boot/vmlinuz-3.10.0-957.el7.x86_64 /tftpboot/toolkit/tkcustom-kernel

# создаем /tftpboot/toolkit/CustomTK/initramfs/init (ниже содержание скрипта):

#!/bin/busybox sh
/bin/busybox --install /bin
mkdir -p /dev /proc /sys /var/run /newroot
mount -t proc proc /proc
mount -o mode=0755 -t devtmpfs devtmpfs /dev
mkdir -p /dev/pts /dev/shm /dev/mapper /dev/vc
mount -t devpts -o gid=5,mode=620 devpts /dev/pts
mount -t sysfs sysfs /sys
mount -t tmpfs -o size=4000m tmpfs /newroot
echo -n "Extracting rootfs... "
xz -d -c -f rootfs.tar.xz | tar -x -f - -C /newroot
echo "done"
mkdir -p /newroot/dev /newroot/proc /newroot/sys
mount --move /sys  /newroot/sys
mount --move /proc /newroot/proc
mount --move /dev  /newroot/dev
exec switch_root /newroot /sbin/init

# упаковываем rootfs и initramfs:

cd /tftpboot/toolkit/CustomTK/rootfs
tar cJf /tftpboot/toolkit/CustomTK/initramfs/rootfs.tar.xz --exclude ./proc --exclude ./sys --exclude ./dev .
cd /tftpboot/toolkit/CustomTK/initramfs
find . -print0 | cpio --null -ov --format=newc | gzip -9 > /tftpboot/toolkit/tkcustom-initramfs-new.gz

Отже, ми вказали ядро ​​і initramfs, які повинні бути завантажені. В результаті на даному етапі, завантаживши проміжний образ linux PXE, ми отримаємо консоль ОС.

Добре, але тепер необхідно передати управління нашої "автоматизації".

Це можна зробити так.

Припустимо, після завантаження образу ми плануємо передавати управління скриптом mount.sh.
Увімкнемо скрипт mount.sh в автозапуск. Для цього потрібно модифікувати initramfs:

  • розпакувати initramfs (якщо використовуємо наведений вище варіант initramfs, це не потрібно)
  • включити в автозавантаження код, який буде аналізувати параметри, що передаються через /proc/cmdline і передавати управління далі;
  • запакувати initramfs.

Примітка. У разі X5 toolkit управління завантаження передається в скрипт /opt/x5/toolkit/bin/hook.sh с помощью override.conf в getty tty1 (ExecStart=…)

Отже, завантажується образ, у якому автозапуску стартує скрипт mount.sh. Далі скрипт mount.sh у процесі виконання аналізує передані параметри (script_cmd=) та запускає необхідну програму/скрипт.

label toolkit-автоматичний
kernel …
append … nfs_toolkit_script=scripts/mount.sh script_cmd=master-install.sh

label toolkit-оболонка
kernel …
append … nfs_toolkit_script=scripts/mount.sh script_cmd=/bin/bash

Bare-Metal Provisioning своїми руками, або Автоматична підготовка серверів з нуля

Тут у лівій частині меню PXE, у правій – схема передачі управління.

З передачею управління ми розібралися. Залежно від вибору PXE-меню, запускається або скрипт автоналаштування, або консоль для налагодження.

У разі автоматичного налаштування монтуються необхідні директорії з інсталл-сервера, в яких присутні:

  • скрипти;
  • збережені шаблони BIOS/UEFI різних серверів;
  • прошивки;
  • утиліти для серверів;
  • логі.

Далі скрипт mount.sh передає управління скрипту master-install.sh із директорії зі скриптами.

Дерево скриптів (порядок їх запуску) виглядає приблизно так:

  • master-install
  • sharefunctions (загальні функції)
  • info (виведення інформації)
  • models (установка параметрів інсталяції на основі моделі сервера)
  • prepare_utils (установка необхідних утиліт)
  • fwupdate (оновлення прошивок)
  • diag (елементарна діагностика)
  • biosconf (налаштування біосу/уефі)
  • clockfix (налаштування часу на мат. платі)
  • srmconf (налаштування інтерфейсу віддаленого інтерфейсу)
  • raidconf (налаштування логічних томів)

один з:

  • preinstall (передача управління інсталятору ОС або гіпервізора, наприклад ESXi)
  • merged-install (безпосередній старт розпакування образу)

Тепер ми знаємо:

  • як завантажувати сервер з PXE;
  • як передати управління у свій скрипт.


Продовжимо. Стали актуальними такі питання:

  • Як ідентифікувати сервер, який ми готуємо?
  • Якими утилітами та як конфігурувати сервер?
  • Як отримати установки для конкретного сервера?

Як ідентифікувати сервер, який ми готуємо?

Це просто – DMI:

dmidecode –s system-product-name
dmidecode –s system-manufacturer
dmidecode –s system-serial-number

Тут є все, що потрібне: вендор, модель, серійний номер. Якщо ви не впевнені, що ця інформація представлена ​​у всіх серверах, можете ідентифікувати їх за MAC-адресою. Або обома способами одночасно, якщо вендори серверів різні і на деяких моделях інформація про серійний номер просто відсутня.

На основі отриманої інформації монтуються мережеві папки з інстал-сервера та підвантажується все необхідне (утиліти, прошивки та інше).

Якими утилітами та як конфігурувати сервер?

Наведу утиліти для Linux для деяких виробників. Усі утиліти доступні на офіційних сайтах вендорів.

Bare-Metal Provisioning своїми руками, або Автоматична підготовка серверів з нуля

З прошивками, я гадаю, все зрозуміло. Зазвичай вони постачаються у вигляді упакованих виконуваних файлів. Виконуваний файл контролює процес оновлення прошивки та повідомляє код повернення.

BIOS та IPMI зазвичай налаштовуються через шаблони. При необхідності шаблон можна редагувати перед завантаженням.

Утиліти RAID у деяких вендорів також можуть налаштовувати шаблон. Якщо це не так, то доведеться написати сценарій налаштування.

Порядок налаштування RAID найчастіше наступний:

  • Вимагаємо поточну конфігурацію.
  • Якщо вже є логічні масиви – перемо.
  • Дивимося, які фізичні диски є і скільки їх.
  • Створюємо новий логічний масив. Перериваємо процес у разі помилки.

Як отримати установки для конкретного сервера?

Припустимо, налаштування всіх серверів зберігатимуться на інстал-сервері. У такому разі, щоб відповісти на наше запитання, потрібно спочатку вирішити: яким чином передавати налаштування в інстал-сервер.

Спочатку цілком можна обійтися текстовими файлами. (У майбутньому можна використовувати текстовий файл як резервний спосіб передачі налаштувань).

Можна розшарити текстовий файл на інстал-сервері. І додати його монтування в скрипт mount.sh.

Рядки будуть, наприклад, такого виду:

<серійний номер> <ім'я хоста> <підмережа>

Ці рядки будуть передаватися у файл інженером із його робочої машини. Далі при налаштуванні сервера параметри для конкретного сервера будуть прочитані з файлу.

Але, в перспективі, краще задіяти БД для зберігання налаштувань, станів та журналів інсталяцій серверів.

Звичайно, однієї БД не обійтися, і потрібно створити клієнтську частину, за допомогою якої передаватимуться налаштування в базу. Реалізувати це складніше, порівняно з текстовим файлом, але насправді все не так важко, як здається. Мінімальну версію клієнта, який просто передаватиме дані в БД, цілком посильно написати самому. А покращувати клієнтську програму надалі можна буде і у вільному режимі (звіти, друк етикеток, відправлення повідомлень та інше, що спаде на думку).

Зробивши певний запит у базу та вказавши серійний номер сервера, отримаємо необхідні параметри для налаштування сервера.

Плюс нам не потрібно придумувати блокування для одночасного доступу, як у випадку з текстовим файлом.

Журнал налаштування можемо на всіх етапах писати в БД та процес встановлення контролювати через події та прапори етапів підготовки.

Тепер ми знаємо, як:

  • завантажувати сервер з PXE;
  • передавати керування нашому скрипту;
  • ідентифікувати сервер, який потрібно підготувати за серійним номером;
  • конфігурувати сервер відповідними утилітами;
  • передавати налаштування в БД інсталл-сервера за допомогою клієнтської частини.

З'ясували, яким чином:

  • сервер, що інсталюється, отримує необхідні налаштування з БД;
  • весь прогрес підготовки фіксується у БД (логи, події, прапори етапів).

Що щодо різних типів встановлюваного ПЗ? Як встановити гіпервізор, скопіювати ВМ та налаштувати все це?

У разі розгортання образу файлової системи (linux) на залізо все досить просто:

  • Після налаштування всіх компонентів сервера розгортаємо образ.
  • Встановлюємо завантажувач grub.
  • Робимо chroot і налаштовуємо все, що необхідно.

Як передати керування інсталятору ОС (на прикладі ESXi).

  • Організуємо передачу управління з нашого скрипта установнику гіпервізора за файлом автовідповідей (kickstart):
  • Видаляємо поточні розділи на диску.
  • Створюємо розділ розміром 500MB.
  • Позначаємо його як завантажувальний.
  • Форматуємо у FAT32.
  • Копіюємо на нього в корінь інсталяційні файли ESXi.
  • Встановлюємо syslinux.
  • Копіюємо syslinux.cfg в /syslinux/

default esxi
prompt 1
timeout 50
label esxi
kernel mboot.c32
append -c boot.cfg

  • Копіюємо mboot.c32 /syslinux.
  • У boot.cfg має бути kernelopt=ks=ftp:// /ks_esxi.cfg
  • Перезавантажуємо сервер.

Після перезавантаження сервера з його жорсткого диска завантажиться інсталятор ESXi. Усі необхідні файли інсталятора завантажаться в пам'ять і далі почнеться інсталяція ESXi, згідно з вказаним файлом автовідповідей.

Наведу кілька рядків з файлу автовідповідей ks_esxi.cfg:

%firstboot --interpreter=busybox
…
# получаем серийный номер

SYSSN=$(esxcli hardware platform get | grep Serial | awk -F " " '{print $3}')

# получаем IP

IPADDRT=$(esxcli network ip interface ipv4 get | grep vmk0 | awk -F " " '{print $2}')
LAST_OCTET=$(echo $IPADDRT | awk -F'.' '{print $4}')

# подключаем NFS инсталл-сервера

esxcli storage nfs add -H is -s /srv/nfs_share -v nfsshare1

# копируем временные настройки ssh, для использования ssh-клиента

mv /etc/ssh /etc/ssh.tmp
cp -R /vmfs/volumes/nfsshare1/ssh /etc/
chmod go-r /etc/ssh/ssh_host_rsa_key

# копируем ovftool, для развертывания ВМ сейчас, плюс возможно пригодится позже

cp -R /vmfs/volumes/nfsshare1/ovftool /vmfs/volumes/datastore1/

# развертываем ВМ

/vmfs/volumes/datastore1/ovftool/tools/ovftool --acceptAllEulas --noSSLVerify --datastore=datastore1 --name=VM1 /vmfs/volumes/nfsshare1/VM_T/VM1.ova vi://root:[email protected]
/vmfs/volumes/datastore1/ovftool/tools/ovftool --acceptAllEulas --noSSLVerify --datastore=datastore1 --name=VM2 /vmfs/volumes/nfsshare1/VM_T/VM2.ova vi://root:[email protected]

# получаем строку с настройками нашего сервера

ssh root@is "mysql -h'192.168.0.1' -D'servers' -u'user' -p'secretpassword' -e "SELECT ... WHERE servers.serial='$SYSSN'"" | grep -v ^$ | sed 's/NULL//g' > /tmp/servers
...
# генерируем скрипт настройки сети

echo '#!/bin/sh' > /vmfs/volumes/datastore1/netconf.sh
echo "esxcli network ip interface ipv4 set -i=vmk0 -t=static --ipv4=$IPADDR --netmask=$S_SUB || exit 1" >> /vmfs/volumes/datastore1/netconf.sh
echo "esxcli network ip route ipv4 add -g=$S_GW -n=default || exit 1" >> /vmfs/volumes/datastore1/netconf.sh
chmod a+x /vmfs/volumes/datastore1/netconf.sh

# задаем параметр guestinfo.esxihost.id, указываем в нем серийный номер

echo "guestinfo.esxihost.id = "$SYSSN"" >> /vmfs/volumes/datastore1/VM1/VM1.vmx
echo "guestinfo.esxihost.id = "$SYSSN"" >> /vmfs/volumes/datastore1/VM2/VM2.vmx
...
# обновляем информацию в базе

SYSNAME=$(esxcli hardware platform get | grep Product | sed 's/Product Name://' | sed 's/^ *//')
UUID=$(vim-cmd hostsvc/hostsummary | grep uuid | sed 's/ //g;s/,$//' | sed 's/^uuid="//;s/"$//')
ssh root@is "mysql -D'servers' -u'user' -p'secretpassword' -e "UPDATE servers ... SET ... WHERE servers.serial='$SYSSN'""
ssh root@is "mysql -D'servers' -u'user' -p'secretpassword' -e "INSERT INTO events ...""

# возвращаем настройки SSH

rm -rf /etc/ssh
mv /etc/ssh.tmp /etc/ssh

# настраиваем сеть и перезагружаемся

esxcli system hostname set --fqdn=esx-${G_NICK}.x5.ru
/vmfs/volumes/datastore1/netconf.sh
reboot

На цьому етапі встановлено та налаштовано гіпервізор, скопійовано віртуальні машини.

Як налаштувати віртуальні машини?

Ми трохи схитрили: під час інсталяції задали параметр guestinfo.esxihost.id = "$SYSSN" у файлі VM1.vmx, вказали в ньому серійний номер фізичного сервера.

Тепер після старту віртуальна машина (з встановленим пакетом vmware-tools) може отримати доступ до цього параметра:

ESXI_SN=$(vmtoolsd --cmd "info-get guestinfo.esxihost.id")

Тобто ВМ зможе ідентифікувати себе (вона знає серійний номер фізичного хоста), зробити запит до БД інсталл-сервера та отримати параметри, які потрібно налаштувати. Це все оформляється в скрипт, який повинен бути запущений автоматично при старті guestos vm (але одного разу: RunOnce).

Тепер ми знаємо, як:

  • завантажувати сервер з PXE;
  • передавати керування нашому скрипту;
  • ідентифікувати сервер, який потрібно підготувати за серійним номером;
  • конфігурувати сервер відповідними утилітами;
  • передавати налаштування у БД інсталл-сервера за допомогою клієнтської частини;
  • налаштовувати різні типи П.О., у тому числі розгортати гіпервізор esxi та налаштовувати віртуальні машини (і всі автоматично).

З'ясували, яким чином:

  • сервер, що інсталюється, отримує необхідні налаштування з БД;
  • весь прогрес підготовки фіксується у БД (логи, події, прапори етапів).


Підсумок:

Думаю, унікальність цього рішення в гнучкості, простоті, його можливостях та універсальності.

Напишіть, будь ласка, у коментарях, що ви думаєте.

Джерело: habr.com

Додати коментар або відгук