Здравейте, аз съм Денис и едно от направленията ми на работа е разработката на инфраструктурни решения в X5. Днес бих искал да споделя с вас как може да се внедри автоматизирана система за подготовка на сървъри, използвайки общодостъпни инструменти. Според мен това е интересно, просто и г灵ко решение.

Под подготовката се разбира: да направим от нов сървър от кутия напълно настроен сървър с ОС Linux или с хипервизор ESXi (разливка сървъри Windows в тази статия не се обсъжда).
Термини:
- сървъри – сървъри, които трябва да бъдат настроени.
- инсталл-сървър – основен сървър, който осигурява целия процес на подготовка по мрежата.
Защо е необходима автоматизация?
Да предположим, че имаме задача: масово да подготвяме сървъри от нулата, в пик – 30 на ден. Сървъри от различни производители и модели, на тях може да се инсталират различни ОС, може да има или да няма хипервизор.
Кои операции влизат в процеса на настройка (без автоматизация):
- да свържем клавиатура, мишка и монитор към сървъра;
- да настроим BIOS, RAID, IPMI;
- да обновим фърмуера на компонентите;
- да развернем образ на файловата система (или да инсталираме хипервизор и да копираме виртуални машини);
Забележка. Като вариант, инсталирането на ОС е възможно чрез файл с автоматични отговори. Но това няма да се обсъжда в статията. Въпреки това, по-долу ще видите, че добавяне на тази функционалност не е сложно.
- да настроим параметрите на ОС (hostname, IP, и други).
При този подход се извършват идентични настройки последователно на всеки сървър. Ефективността на такова задължение е много ниска.
Същността на автоматизацията е да се изключи участието на човека в процеса на подготовка на сървъра. Максимално, колкото е възможно.
Благодарение на автоматизацията се съкращава времето на бездействие между операциите и се създава възможност за подготовка на няколко сървъра едновременно. Също така значително се намалява вероятността от възникване на грешки поради човешкия фактор.

Как се извършва автоматичната настройка на сървъри?
Нека разгледаме всичките етапи в детайли.
Вие имате linux-сървър, който използвате като PXE инсталл-сървър. На него са инсталирани и настроени услугите: DHCP, TFTP.
И така, зареждаме сървъра (който трябва да бъде настроен) по PXE. Нека си припомним как работи това:
- На сървъра е избрано зареждане по мрежата.
- Сървърът зарежда PXE-ROM на мрежовата карта и се свързва с инсталационния сървър по DHCP, за да получи мрежов адрес.
- DHCP инсталационният сървър предоставя адрес, а също така и инструкции за последващо зареждане през PXE.
- Сървърът зарежда мрежовото зареждане от инсталационния сървър по PXE, последващото зареждане се извършва съгласно конфигурационния файл PXE.
- Извършва се зареждане на базата на получените параметри (ядро, initramfs, точки на монтиране, образ squashfs и др.).
Забележка. В статията се описва зареждане по PXE чрез BIOS режим. В момента производителите активно внедряват 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 ^Върнете се в основното меню
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-auto
kernel …
append … nfs_toolkit_script=scripts/mount.sh script_cmd=master-install.sh
label toolkit-shell
kernel …
append … nfs_toolkit_script=scripts/mount.sh script_cmd=/bin/bash

Тук в лявата част – меню PXE, в дясната – схема за предаване на управлението.
С предаване на управлението се справихме. В зависимост от избора на PXE менюто ще стартира или скрипта за автоматична конфигурация, или конзолата за отстраняване на грешки.
При автоматичната конфигурация се монтират необходимите директории от инсталационния сървър, които съдържат:
- скриптове;
- съхранени шаблони за BIOS/UEFI на различни сървъри;
- прошивки;
- инструменти за сървъри;
- логове.
След това скриптът mount.sh предава управлението на скрипта master-install.sh от директорията со скриптове.
Дървото на скриптовете (реда на изпълнение) изглежда приблизително така:
- master-install
- sharefunctions (общи функции)
- info (извеждане на информация)
- models (настройка на инсталационните параметри на базата на модела на сървъра)
- prepare_utils (инсталиране на необходимите инструменти)
- fwupdate (обновление на фърмуера)
- diag (елементарна диагностика)
- biosconf (настройки на BIOS/UEFI)
- 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 за някои производители. Всички утилити са налични на официалните сайтове на производителите.

С фърмуерите, мисля, всичко е ясно. Обикновено те се предоставят под формата на опаковани изпълними файлове. Изпълнимият файл контролира процеса на актуализация на фърмуера и съобщава код за завръщане.
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:esxi_password@127.0.0.1
\/vmfs\/volumes\/datastore1\/ovftool\/tools\/ovftool --acceptAllEulas --noSSLVerify --datastore=datastore1 --name=VM2 \/vmfs\/volumes\/nfsshare1\/VM_T\/VM2.ova vi:\/\/root:esxi_password@127.0.0.1
# получаваме стринг с настройките на нашия сървър
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://;s\/^ *//')
UUID=$(vim-cmd hostsvc\/hostsummary | grep uuid | sed 's\/\/g;s\/$//;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
