Bună, eu sunt Denis și unul dintre domeniile mele de activitate este dezvoltarea soluțiilor de infrastructură în X5. Azi aș dori să împărtășesc cu voi cum se poate desfășura un sistem automatizat de pregătire a serverelor folosind unelte disponibile public. Din punctul meu de vedere, este o soluție interesantă, simplă și flexibilă.

Prin pregătire se înțelege: a transforma un server nou din cutie într-un server complet configurat cu sistem de operare Linux sau cu hypervisor ESXi (pe Windows acest subiect nu este discutat în acest articol). servere Serverele care trebuie configurate.
Termeni:
- Server-installer – serverul principal care asigură întregul proces de pregătire prin rețea.
- De ce este necesară automatizarea?
Să presupunem că există o sarcină: a pregăti în masă servere de la zero, cu un vârf de 30 pe zi. Servere de diferiți producători și modele, pe acestea pot fi instalate diverse sisteme de operare, pot avea sau nu hypervisor.
Care sunt operațiile incluse în procesul de configurare (fără automatizare):
conectarea unui tastaturi, mouse și monitor la server;
- configurarea BIOS-ului, RAID-ului, IPMI;
- actualizarea firmware-ului componentelor;
- desfășurarea imaginii sistemului de fișiere (sau instalarea hypervisor-ului și copierea mașinilor virtuale);
- Observație. Ca o opțiune, desfășurarea sistemului de operare este posibilă prin instalare cu un fișier de răspuns automat. Dar acest lucru nu va fi discutat în articol. Deși mai jos veți vedea că adăugarea acestei funcționalități nu este complicată.
configurarea parametrilor sistemului de operare (hostname, IP, altele).
- În această abordare, setările identice sunt efectuate secvențial pe fiecare server. Eficiența acestui mod de lucru este foarte scăzută.
Suscinta automatizării este de a exclude participarea omului din procesul de pregătire a serverului. Atât de mult cât este posibil.
Datorită automatizării, timpul de nefuncționare între operații este redus și apare posibilitatea de a pregăti mai multe servere simultan. De asemenea, se reduce considerabil riscul apariției erorilor din cauza factorului uman.
Cum se desfășoară configurarea automată a serverelor?

Să analizăm toate etapele în detaliu.
Aveți un server Linux pe care îl folosiți ca server de instalare PXE. Pe acesta sunt instalate și configurate serviciile: DHCP, TFTP.
Așadar, pornim serverul (care trebuie configurat) prin PXE. Să ne amintim cum funcționează:
Serverul este setat să se conecteze prin rețea.
- Serverul ales pentru pornire este unul din rețea.
- Serverul încarcă PXE-ROM-ul plăcii de rețea și se conectează la serverul de instalare prin DHCP pentru a obține o adresă de rețea.
- Serverul DHCP al serverului de instalare oferă o adresă, precum și instrucțiuni pentru încărcarea suplimentară prin PXE.
- Serverul încarcă încărcătorul de rețea de la serverul de instalare prin PXE, încărcarea suplimentară avându-se loc conform fișierului de configurare PXE.
- Se efectuează încărcarea pe baza parametrilor obținuți (nucleu, initramfs, puncte de montare, imagine squashfs și altele).
Notă. Articolul prezintă descrierea încărcării prin PXE în modul BIOS. În prezent, producătorii implementează activ modul de boot UEFI. Pentru PXE, distincția va fi în configurația serverului DHCP și în existența unui încărcător suplimentar.
Să examinăm un exemplu de configurare a serverului PXE (meniul pxelinux).
Fișierul 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 implicit
MENU LABEL Linux Scripting Toolkits
MENU default
KERNEL menu.c32
APPEND pxelinux.cfg/toolkit // trecerea la următorul meniuFișierul pxelinux.cfg/toolkit:
prompt 0
timeout 100
menu title X5 PXE Boot Menu
label mainmenu
menu label ^Înapoi la meniul principal
kernel menu.c32
append pxelinux.cfg/default
label x5toolkit-auto // implicit - modul automat
menu label x5 toolkit instalare automată
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 // pentru depanare - consolă
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="..."Nucleul și initramfs în acest stadiu reprezintă o imagine linux intermediară, cu ajutorul căreia se va desfășura pregătirea și configurarea principală a serverului.
După cum vedeți, încărcătorul transmite multe parametri nucleului. O parte din acești parametri sunt utilizați de nucleu. Și anume, alții pot fi folosiți în scopuri proprii. Despre aceasta se va vorbi mai departe, iar între timp putem reține că toți parametrii transmiși vor fi disponibili în imaginea linux intermediară prin /proc/cmdline.
De unde îi putem obține, nucleul și initramfs?
Ca bază, se poate alege orice distribuție linux. Ce trebuie să luăm în considerare la alegere:
- imaginea de boot trebuie să fie universală (să conțină drivere, posibilitatea de instalare a utilitarelor suplimentare);
- cel mai probabil, va fi necesar să personalizăm initramfs.
Cum este realizat acest lucru în soluția noastră pentru X5? Ca bază, am ales CentOS 7. Vom face următorul truc: vom pregăti viitoarea structură a imaginii, o vom împacheta într-un arhiv și vom crea initramfs, în care va fi arhiva noastră a sistemului de fișiere. La pornirea imaginii, arhiva va fi desfăcută în partiția tmpfs creată. Astfel, vom obține o imagine live Linux minimă, dar complet funcțională, cu toate utilitarele necesare, alcătuită din doar două fișiere: vmkernel și 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.gzDeci, am specificat nucleul și initramfs care trebuie încărcate. Ca rezultat, în această etapă, încarcând imaginea intermediară Linux prin PXE, vom obține consola OS.
Excelent, dar acum trebuie să preluăm controlul de la automatizarea noastră.
Acest lucru se poate face astfel.
Să presupunem că, după încărcarea imaginii, planificăm să redirecționăm controlul către scriptul mount.sh.
Vom include scriptul mount.sh în auto-start. Pentru aceasta, va fi necesar să modificăm initramfs:
- desfacem initramfs (dacă folosim varianta de mai sus a initramfs, acest lucru nu este necesar)
- includem codul în autoconfigurare care va analiza parametrii transmiși prin /proc/cmdline și va preda controlul mai departe;
- împachetăm initramfs.
Notă. În cazul toolkit-ului X5, controlul boot-ului este predat scriptului /opt/x5/toolkit/bin/hook.sh с помощью override.conf в getty tty1 (ExecStart=…)
Deci, imaginea se încarcă, în care la autoconfigurare se pornește scriptul mount.sh. Mai departe, scriptul mount.sh analizează parametrii transmiși (script_cmd=) și pornește programul/scriptul necesar.
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

Aici, în partea stângă, este meniul PXE, iar în partea dreaptă - schema de predare a controlului.
Ne-am descurcat cu predarea controlului. În funcție de alegerea din meniul PXE, se lansează fie scriptul de auto-configurare, fie consola de depanare.
În cazul auto-configurării, se montează directoarele necesare de pe serverul de instalare, care conțin:
- scripturi;
- șabloane BIOSS/UEFI salvate pentru diferite servere;
- firmware;
- utilitare pentru servere;
- jurnale.
Apoi, scriptul mount.sh predă controlul scriptului master-install.sh din directorul cu scripturi.
Arborele scripturilor (ordinea lor de execuție) arată cam așa:
- master-install
- sharefunctions (funcții comune)
- info (afisare informații)
- models (instalarea parametrilor de instalare pe baza modelului serverului)
- prepare_utils (instalarea utilitarelor necesare)
- fwupdate (actualizarea firmware-ului)
- diag (diagnosticare elementară)
- biosconf (configurarea BIOS-ului/UEFI)
- clockfix (configurarea timpului pe placa de bază)
- srmconf (configurarea interfeței de acces de la distanță)
- raidconf (configurarea volumelor logice)
unu din:
- preinstall (transferul controlului către instalatorul de sistem de operare sau hipervizor, de exemplu ESXi)
- merged-install (începerea directă a extragerii imaginii)
Acum știm:
- cum să pornim serverul prin PXE;
- cum să transferăm controlul către propriul script.
Să continuăm. Au apărut următoarele întrebări:
- Cum să identificăm serverul pe care îl pregătim?
- Ce utilitare și cum să configurăm serverul?
- Cum să obținem setările pentru un server specific?
Cum să identificăm serverul pe care îl pregătim?
Este simplu – DMI:
dmidecode –s system-product-name
dmidecode –s system-manufacturer
dmidecode –s system-serial-numberAici există toate informațiile necesare: furnizorul, modelul, numărul de serie. Dacă nu sunteți sigur că aceste informații sunt disponibile pe toate serverele, le puteți identifica după adresa MAC. Sau prin ambele metode simultan, dacă furnizorii serverelor sunt diferiți și pe unele modele informațiile despre numărul de serie lipsesc.
Pe baza informațiilor obținute, se montează folderele de rețea de pe serverul de instalare și se încarcă tot ceea ce este necesar (utilitare, firmware și altele).
Ce utilitare și cum să configurăm serverul?
Voi prezenta utilitarele pentru linux pentru unii furnizori. Toate utilitarele sunt disponibile pe website-urile oficiale ale furnizorilor.

În ceea ce privește firmware-urile, cred că este clar. De obicei, acestea sunt furnizate sub formă de fișiere executabile comprimate. Fișierul executabil controlează procesul de actualizare a firmware-ului și raportează codul de returnare.
BIOS și IPMI sunt de obicei configurate prin șabloane. Dacă este necesar, șablonul poate fi editat înainte de încărcare.
Utilitarele RAID ale unor furnizori pot fi, de asemenea, configurate prin șabloane. Dacă nu, va trebui să scrieți un script de configurare.
Ordinea de configurare a RAID-ului este, de cele mai multe ori, următoarea:
- Cerem configurația curentă.
- Dacă există deja volume logice – le ștergem.
- Vedem ce discuri fizice sunt prezente și câte sunt.
- Creăm un nou volum logic. Oprim procesul în caz de eroare.
Cum să obținem setările pentru un server specific?
Să presupunem că setările tuturor serverelor vor fi stocate pe serverul de instalare. În acest caz, pentru a răspunde la întrebarea noastră, trebuie mai întâi să stabilim cum să transmitem setările către serverul de instalare.
La început, este suficient să folosim fișiere text. (Pe viitor, fișierul text poate fi folosit ca metodă de rezervă pentru transferul setărilor).
Putem „partaja” fișierul text pe serverul de instalare. Și să adăugăm montarea acestuia în scriptul mount.sh.
Linile vor arăta, de exemplu, în felul următor:
Aceste linii vor fi transmise într-un fișier de inginer de pe mașina sa de lucru. Apoi, la configurarea serverului, parametrii pentru serverul specific vor fi citiți din fișier.
Dar, pe termen lung, este mai bine să folosim o bază de date pentru a stoca setările, stările și jurnalul instalărilor serverelor.
Desigur, nu ne putem descurca doar cu o bază de date, va fi nevoie să creăm o parte client, prin care setările vor fi transmise în baza de date. Implementarea acestui lucru este mai complicată, în comparație cu un fișier text, dar, de fapt, totul nu este atât de greu cum pare. O versiune minimă a clientului, care va preda pur și simplu date în baza de date, poate fi scrisă de unul singur. Iar îmbunătățirea programului client în viitor poate fi realizată și în modul liber (rapoarte, imprimarea etichetelor, trimiterea notificărilor și altele ce pot fi imaginabile).
Făcând o anumită interogare în baza de date și specificând seria numărului serverului, vom obține parametrii necesari pentru configurarea serverului.
Plus, nu va trebui să inventăm blocaje pentru acces simultan, așa cum ar fi în cazul unui fișier text.
Jurnalul de configurare putem să-l scriem în baza de date în toate etapele și să controlăm procesul de instalare prin evenimente și steaguri ale etapelor de pregătire.
Acum știm cum să:
- bootăm serverul prin PXE;
- transmitem controlul scriptului nostru;
- identificăm serverul care trebuie pregătit după seria numărului;
- configurăm serverul cu utilitarele corespunzătoare;
- transmitem setările în baza de date a serverului de instalare prin partea client.
Am aflat cum:
- serverul care urmează a fi instalat primește setările necesare din baza de date;
- întreaga progresie a pregătirii este înregistrată în baza de date (jurnale, evenimente, steaguri ale etapelor).
Ce se întâmplă cu diferitele tipuri de software instalat? Cum instalăm hipervizorul, copiem VM-ul și configurăm totul?
În cazul desfășurării imaginii sistemului de fișiere (linux) pe hardware, totul este destul de simplu:
- După configurarea tuturor componentelor serverului, desfășurăm imaginea.
- Instalăm bootloader-ul grub.
- Facem chroot și configurăm tot ce este necesar.
Cum să transferi controlul către installer-ul OS (în cazul ESXi).
- Organizăm transmiterea controlului din scriptul nostru către installer-ul hypervisor-ului printr-un fișier de răspuns automat (kickstart):
- Ștergem partițiile curente de pe disc.
- Creăm o partiție de 500MB.
- O marcăm ca fiind bootabilă.
- Formatază în FAT32.
- Copiem fișierele de instalare ESXi în rădăcina acesteia.
- Instalăm syslinux.
- Copiem syslinux.cfg în /syslinux/
default esxi
prompt 1
timeout 50
label esxi
kernel mboot.c32
append -c boot.cfg- Copiem mboot.c32 în /syslinux.
- În boot.cfg trebuie să fie kernelopt=ks=ftp:///ks_esxi.cfg
- Rebootăm serverul.
După repornirea serverului din hard disk-ul său, se va încărca installer-ul ESXi. Toate fișierele necesare pentru instalare se vor încărca în memorie și apoi va începe instalarea ESXi, conform fișierului de răspuns automat specificat.
Iată câteva linii din fișierul de răspuns automat ks_esxi.cfg:
%firstboot --interpreter=busybox
…
# obținem numărul de serie
SYSSN=$(esxcli hardware platform get | grep Serial | awk -F " " '{print $3}')
# obținem IP
IPADDRT=$(esxcli network ip interface ipv4 get | grep vmk0 | awk -F " " '{print $2}')
LAST_OCTET=$(echo $IPADDRT | awk -F'.' '{print $4}')
# conectăm serverul de instalare NFS
esxcli storage nfs add -H is -s /srv/nfs_share -v nfsshare1
# copiem setările temporare ssh, pentru a folosi clientul ssh
mv /etc/ssh /etc/ssh.tmp
cp -R /vmfs/volumes/nfsshare1/ssh /etc/
chmod go-r /etc/ssh/ssh_host_rsa_key
# copiem ovftool, pentru desfășurarea VM-ului acum, plus ar putea fi util mai târziu
cp -R /vmfs/volumes/nfsshare1/ovftool /vmfs/volumes/datastore1/
# desfășurăm VM-ul
/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
# obținem linia cu setările serverului nostru
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
...
# generăm scriptul de configurare a rețelei
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
# setăm parametrul guestinfo.esxihost.id, indicând numărul de serie
echo "guestinfo.esxihost.id = "$SYSSN"" >> /vmfs/volumes/datastore1/VM1/VM1.vmx
echo "guestinfo.esxihost.id = "$SYSSN"" >> /vmfs/volumes/datastore1/VM2/VM2.vmx
...
# actualizăm informația din baza de date
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 ...""
# returnăm setările SSH
rm -rf /etc/ssh
mv /etc/ssh.tmp /etc/ssh
# configurăm rețeaua și restartăm
esxcli system hostname set --fqdn=esx-${G_NICK}.x5.ru
/vmfs/volumes/datastore1/netconf.sh
reboot
În acest moment, hipervizorul este instalat și configurat, iar mașinile virtuale au fost copiate.
Cum să configurăm acum mașinile virtuale?
Am fost puțin isteți: în timpul instalării am setat parametrul guestinfo.esxihost.id = "$SYSSN" în fișierul VM1.vmx, indicând numărul de serie al serverului fizic.
Acum, după pornire, mașina virtuală (cu pachetul vmware-tools instalat) poate accesa acest parametru:
ESXI_SN=$(vmtoolsd --cmd "info-get guestinfo.esxihost.id")Adică, VM-ul va putea să se identifice (știe numărul de serie al gazdei fizice), va face o solicitare la baza de date a serverului de instalare și va obține parametrii care trebuie configurați. Totul este organizat într-un script care trebuie să fie rulat automat la pornirea VM-ului guestos (dar o singură dată: RunOnce).
Acum știm cum să:
- bootăm serverul prin PXE;
- transmitem controlul scriptului nostru;
- identificăm serverul care trebuie pregătit după seria numărului;
- configurarea serverului cu utilitarele corespunzătoare;
- transmiterea setărilor în baza de date a serverului de instalare prin intermediul părții client;
- configurarea diferitelor tipuri de software, inclusiv desfășurarea hypervisor-ului ESXi și configurarea mașinilor virtuale (totul automat).
Am aflat cum:
- serverul care urmează a fi instalat primește setările necesare din baza de date;
- întreaga progresie a pregătirii este înregistrată în baza de date (jurnale, evenimente, steaguri ale etapelor).
Concluzie:
Cred că unicitatea acestei soluții constă în flexibilitatea, simplitatea, capacitățile sale și universalitatea.
Te rog, scrie în comentarii ce părere ai.
Sursa: habr.com
