Ciao, sono Denis e uno dei miei ambiti di attività è lo sviluppo di soluzioni infrastrutturali in X5. Oggi vorrei condividere con voi come è possibile implementare un sistema automatico per la preparazione dei server utilizzando strumenti pubblici. A mio avviso, si tratta di una soluzione interessante, semplice e flessibile.

Per preparazione si intende: trasformare un nuovo server 'fuori dagli schemi' in un server completamente configurato con sistema operativo Linux o con hypervisor ESXi (rilascio server Windows non verrà discusso in questo articolo).
Terminologia:
- server – server che devono essere configurati.
- install-server – server principale che gestisce l'intero processo di preparazione tramite rete.
Perché è necessaria l'automazione?
Supponiamo che ci sia l'esigenza di preparare in massa i server da zero, con un picco di 30 al giorno. Server di diversi produttori e modelli, su di essi possono essere installati diversi sistemi operativi, e potrebbe esserci o meno un hypervisor.
Quali operazioni rientrano nel processo di configurazione (senza automazione):
- collegare tastiera, mouse, monitor al server;
- configurare BIOS, RAID, IPMI;
- aggiornare i firmware dei componenti;
- espandere l'immagine del file system (oppure installare un hypervisor e copiare le macchine virtuali);
Nota. In alternativa, il deploy del sistema operativo è possibile tramite l'installazione con un file di risposta automatica. Ma questo non sarà trattato nell'articolo. Tuttavia, come vedrete più avanti, aggiungere questa funzionalità non è complicato.
- configurare i parametri del sistema operativo (hostname, IP, altro).
Con questo approccio, vengono eseguite impostazioni identiche in modo sequenziale su ogni server. L'efficacia di questo lavoro è molto bassa.
L'essenza dell'automazione consiste nell'escludere il coinvolgimento umano dal processo di preparazione del server. Il più possibile.
Grazie all'automazione, si riduce il tempo di inattività tra le operazioni e si ha la possibilità di preparare più server contemporaneamente. Inoltre, si riduce significativamente la probabilità di errori a causa del fattore umano.

Come avviene la configurazione automatica dei server?
Analizziamo tutte le fasi in dettaglio.
Hai un server linux che utilizzi come server di installazione PXE. Su di esso sono installati e configurati i servizi: DHCP, TFTP.
Quindi, avviamo il server (quello da configurare) tramite PXE. Ricordiamo come funziona:
- È stata selezionata l'avvio di rete sul server.
- Il server carica il PXE-ROM della scheda di rete e si rivolge al server di installazione tramite DHCP per ottenere un indirizzo di rete.
- Il server di installazione DHCP fornisce un indirizzo e istruzioni per il successivo avvio tramite PXE.
- Il server carica il bootloader di rete dal server di installazione tramite PXE, e il successivo caricamento avviene secondo il file di configurazione PXE.
- Avviene il caricamento basato sui parametri ricevuti (kernel, initramfs, punti di montaggio, immagine squashfs e altro).
Nota. L'articolo descrive l'avvio tramite PXE in modalità BIOS. Attualmente, i produttori stanno adottando attivamente la modalità di avvio UEFI. Per PXE la differenza sarà nella configurazione del server DHCP e nella presenza di un bootloader aggiuntivo.
Consideriamo un esempio di configurazione del server PXE (menu pxelinux).
File 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 predefinito
MENU LABEL Linux Scripting Toolkits
MENU default
KERNEL menu.c32
APPEND pxelinux.cfg/toolkit // passaggio al menu successivoFile pxelinux.cfg/toolkit:
prompt 0
timeout 100
menu title X5 PXE Boot Menu
label mainmenu
menu label ^Torna al Menu Principale
kernel menu.c32
append pxelinux.cfg/default
label x5toolkit-auto // predefinito — modalità automatica
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 // per debug - console
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=”…”Il kernel e l'initramfs in questa fase sono un'immagine linux intermedia, grazie alla quale avverrà la preparazione e configurazione principale del server.
Come potete vedere, il bootloader trasmette molti parametri al kernel. Alcuni di questi parametri sono utilizzati dal kernel stesso. Altri possono essere utilizzati per i nostri scopi. Di questo parleremo più avanti, per ora basta ricordare che tutti i parametri trasmessi saranno disponibili nell'immagine linux intermedia attraverso /proc/cmdline.
Dove possiamo trovarli, il kernel e l'initramfs?
Si può scegliere qualsiasi distribuzione linux come base. A cosa dobbiamo prestare attenzione nella scelta:
- l'immagine di avvio deve essere universale (presenza di driver, possibilità di installare utilità aggiuntive);
- probabilmente sarà necessario personalizzare initramfs.
Come è stato realizzato nella nostra soluzione per X5? Abbiamo scelto come base CentOS 7. Eseguiamo il seguente trucco: prepariamo la futura struttura dell'immagine, la imballiamo in un archivio e creiamo un initramfs, all'interno del quale ci sarà il nostro archivio del file system. Al momento dell'avvio dell'immagine, l'archivio verrà estratto nella partizione tmpfs creata. In questo modo otteniamo un'immagine live linux minimale ma completamente funzionale con tutte le utilità necessarie, composta da soli due file: vmkernel e 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.gzQuindi, abbiamo specificato il kernel e initramfs che devono essere caricati. Di conseguenza, in questa fase, caricando l'immagine intermedia linux tramite PXE, otteniamo la console del sistema operativo.
Ottimo, ma ora dobbiamo trasferire il controllo alla nostra 'automazione'.
Questo può essere fatto in questo modo.
Supponiamo che, dopo aver caricato l'immagine, intendiamo trasferire il controllo a uno script mount.sh.
Includeremo lo script mount.sh nell'avvio automatico. Per questo sarà necessario modificare initramfs:
- estrarre initramfs (se utilizziamo la variante di initramfs sopra citata, ciò non è necessario)
- inserire nel caricamento automatico il codice che analizzerà i parametri trasmessi tramite /proc/cmdline e passerà il controllo successivamente;
- comprimere l'initramfs.
Nota. Nel caso del toolkit X5, il controllo di avvio viene passato allo script /opt/x5/toolkit/bin/hook.sh с помощью override.conf в getty tty1 (ExecStart=…)
Quindi, viene caricato un'immagine in cui nel caricamento automatico avvia lo script mount.sh. Successivamente, lo script mount.sh durante l'esecuzione analizza i parametri trasmessi (script_cmd=) e avvia il programma/script necessario.
etichetta toolkit-auto
kernel …
append … nfs_toolkit_script=scripts/mount.sh script_cmd=master-install.sh
etichetta toolkit-shell
kernel …
append … nfs_toolkit_script=scripts/mount.sh script_cmd=/bin/bash

Qui a sinistra si trova il menu PXE, a destra – schema di controllo del trasferimento.
Abbiamo chiarito il trasferimento del controllo. A seconda della scelta nel menu PXE, viene avviato o lo script di auto-configurazione o la console di debug.
Nel caso di configurazione automatica, vengono montati le directory necessarie dal server di installazione, che contengono:
- script;
- modelli BIOS/UEFI salvati di vari server;
- firmware;
- utility per server;
- log.
Successivamente, lo script mount.sh trasferisce il controllo allo script master-install.sh dalla directory degli script.
L'albero degli script (l'ordine della loro esecuzione) appare all'incirca così:
- master-install
- sharefunctions (funzioni comuni)
- info (output informativo)
- modelli (installazione delle impostazioni di installazione in base al modello del server)
- prepare_utils (installazione degli strumenti necessari)
- fwupdate (aggiornamento del firmware)
- diag (diagnostica di base)
- biosconf (configurazione del BIOS/UEFI)
- clockfix (impostazione dell'ora sulla scheda madre)
- srmconf (configurazione dell'interfaccia remota)
- raidconf (configurazione dei volumi logici)
uno dei seguenti:
- preinstall (passaggio di controllo all'installatore del sistema operativo o del hypervisor, ad esempio ESXi)
- merged-install (avvio diretto dell'estrazione dell'immagine)
Ora sappiamo:
- come avviare il server tramite PXE;
- come passare il controllo a uno script personalizzato.
Continuiamo. Si pongono le seguenti domande:
- Come identificare il server che stiamo preparando?
- Quali strumenti e come configurare il server?
- Come ottenere le impostazioni per un server specifico?
Come identificare il server che stiamo preparando?
È semplice – DMI:
dmidecode –s system-product-name
dmidecode –s system-manufacturer
dmidecode –s system-serial-numberQui trovi tutto il necessario: fornitore, modello, numero di serie. Se non sei sicuro che queste informazioni siano disponibili su tutti i server, puoi identificarli tramite l'indirizzo MAC. Oppure entrambi i metodi contemporaneamente, se i fornitori dei server sono diversi e su alcuni modelli le informazioni sul numero di serie sono semplicemente assenti.
Sulla base delle informazioni ricevute, vengono montate le cartelle di rete dai server di installazione e vengono caricati tutti i componenti necessari (utilità, firmware e altro).
Quali strumenti e come configurare il server?
Elenco delle utilità per Linux di alcuni produttori. Tutte le utilità sono disponibili sui siti ufficiali dei fornitori.

Per quanto riguarda i firmware, credo sia tutto chiaro. Di solito vengono forniti come file eseguibili confezionati. Il file eseguibile controlla il processo di aggiornamento del firmware e riporta il codice di ritorno.
BIOS e IPMI di solito vengono configurati tramite modelli. Se necessario, il modello può essere modificato prima del caricamento.
Le utilità RAID di alcuni fornitori possono anche essere configurate tramite modelli. Se non è così, sarà necessario scrivere uno script di configurazione.
Il processo di configurazione RAID è di solito il seguente:
- Richiediamo la configurazione attuale.
- Se ci sono già array logici, cancelliamoli.
- Verifichiamo quali dischi fisici sono presenti e quanti sono.
- Creiamo un nuovo array logico. Interrompiamo il processo in caso di errore.
Come ottenere le impostazioni per un server specifico?
Supponiamo che le configurazioni di tutti i server siano memorizzate sul server di installazione. In tal caso, per rispondere alla nostra domanda, dobbiamo prima decidere come trasmettere le configurazioni al server di installazione.
Inizialmente, è possibile utilizzare file di testo. (In futuro, si può usare un file di testo come metodo di backup per la trasmissione delle configurazioni).
Si può 'condividere' un file di testo sul server di installazione e aggiungere il suo montaggio nello script mount.sh.
Le righe saranno, ad esempio, di questo tipo:
Queste righe saranno trasferite in un file dall'ingegnere dal suo computer di lavoro. Successivamente, durante la configurazione del server, i parametri per il server specifico saranno letti dal file.
Tuttavia, in prospettiva, è meglio utilizzare un database per memorizzare le configurazioni, gli stati e i registri delle installazioni dei server.
Certamente, non si può fare a meno di un database, e sarà necessario creare una parte client attraverso la quale verranno trasmessi i parametri al database. Realizzare questo è più complesso rispetto a un file di testo, ma, in effetti, non è così difficile come sembra. Una versione minima del client, che si limiterà a trasmettere i dati al database, è assolutamente fattibile da scrivere da soli. Inoltre, in seguito sarà possibile migliorare il programma client a tempo libero (rapporti, stampa di etichette, invio di notifiche e altro che verrà in mente).
Effettuando una richiesta specifica al database e indicando il numero di serie del server, otterremo i parametri necessari per la configurazione del server.
Inoltre, non sarà necessario inventare blocchi per l'accesso simultaneo, come nel caso di un file di testo.
Possiamo registrare il registro di configurazione nel database in tutte le fasi e controllare il processo di installazione attraverso eventi e flag delle fasi di preparazione.
Ora sappiamo come:
- caricare il server tramite PXE;
- trasferire il controllo al nostro script;
- identificare il server da preparare tramite il numero di serie;
- configurare il server con gli strumenti appropriati;
- trasmettere le impostazioni al database del server di installazione tramite la parte client.
Abbiamo scoperto come:
- il server in fase di installazione riceve le impostazioni necessarie dal database;
- l'intero progresso della preparazione è registrato nel database (log, eventi, flag delle fasi).
E per quanto riguarda i vari tipi di software in fase di installazione? Come installare un hypervisor, copiare una VM e configurare tutto ciò?
Nel caso di implementazione di un'immagine del file system (linux) su hardware, è piuttosto semplice:
- Dopo aver configurato tutti i componenti del server, deployiamo l'immagine.
- Installiamo il bootloader grub.
- Eseguiamo chroot e configuriamo tutto ciò che è necessario.
Come passare il controllo all'installatore del sistema operativo (utilizzando l'esempio di ESXi).
- Organizziamo il passaggio di controllo dal nostro script all'installatore dell'hypervisor tramite un file di risposte automatiche (kickstart):
- Eliminiamo le partizioni attuali sul disco.
- Creiamo una partizione di dimensioni 500MB.
- Segniamo la partizione come avviabile.
- Formattiamo in FAT32.
- Copiamo i file di installazione di ESXi nella radice della partizione.
- Installiamo syslinux.
- Copiamo syslinux.cfg in /syslinux/
default esxi
prompt 1
timeout 50
label esxi
kernel mboot.c32
append -c boot.cfg- Copiamo mboot.c32 in /syslinux.
- In boot.cfg deve esserci kernelopt=ks=ftp:///ks_esxi.cfg
- Riavviamo il server.
Dopo il riavvio, il programma di installazione di ESXi si avvierà dal disco rigido del server. Tutti i file necessari del programma di installazione verranno caricati in memoria e successivamente inizierà l'installazione di ESXi, secondo il file di risposte automatiche specificato.
Riporto qui alcune righe dal file di risposte automatiche ks_esxi.cfg:
%firstboot --interpreter=busybox
…
# otteniamo il numero di serie
SYSSN=$(esxcli hardware platform get | grep Serial | awk -F " " '{print $3}')
# otteniamo l'IP
IPADDRT=$(esxcli network ip interface ipv4 get | grep vmk0 | awk -F " " '{print $2}')
LAST_OCTET=$(echo $IPADDRT | awk -F'.' '{print $4}')
# colleghiamo il server di installazione NFS
esxcli storage nfs add -H is -s /srv/nfs_share -v nfsshare1
# copiamo le impostazioni temporanee ssh, per utilizzare il client ssh
mv /etc/ssh /etc/ssh.tmp
cp -R /vmfs/volumes/nfsshare1/ssh /etc/
chmod go-r /etc/ssh/ssh_host_rsa_key
# copiamo ovftool, per il deployment della VM ora, più potrebbe servirci in seguito
cp -R /vmfs/volumes/nfsshare1/ovftool /vmfs/volumes/datastore1/
# deployiamo la VM
/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
# otteniamo la stringa con le impostazioni del nostro server
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
...
# generiamo lo script di configurazione di rete
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
# impostiamo il parametro guestinfo.esxihost.id, indicando il numero di serie
echo "guestinfo.esxihost.id = "$SYSSN"" >> /vmfs/volumes/datastore1/VM1/VM1.vmx
echo "guestinfo.esxihost.id = "$SYSSN"" >> /vmfs/volumes/datastore1/VM2/VM2.vmx
...
# aggiorniamo le informazioni nel database
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 ...""
# ripristiniamo le impostazioni SSH
rm -rf /etc/ssh
mv /etc/ssh.tmp /etc/ssh
# configuriamo la rete e riavviamo
esxcli system hostname set --fqdn=esx-${G_NICK}.x5.ru
/vmfs/volumes/datastore1/netconf.sh
reboot
A questo punto, l'hypervisor è stato installato e configurato, e le macchine virtuali sono state copiate.
Come configurare ora le macchine virtuali?
Abbiamo fatto un piccolo trucco: durante l'installazione abbiamo impostato il parametro guestinfo.esxihost.id = "$SYSSN" nel file VM1.vmx, specificando il numero di serie del server fisico.
Ora, dopo l'avvio, la macchina virtuale (con il pacchetto vmware-tools installato) può accedere a questo parametro:
ESXI_SN=$(vmtoolsd --cmd "info-get guestinfo.esxihost.id")In altre parole, la VM sarà in grado di identificarsi (sa il numero di serie dell'host fisico), fare una richiesta al database del server di installazione e ottenere i parametri da configurare. Questo viene formalizzato in uno script che deve essere eseguito automaticamente all'avvio della guestos vm (ma una sola volta: RunOnce).
Ora sappiamo come:
- caricare il server tramite PXE;
- trasferire il controllo al nostro script;
- identificare il server da preparare tramite il numero di serie;
- configurare il server con le utilità appropriate;
- trasmettere le impostazioni al database del server di installazione tramite la parte client;
- configurare diversi tipi di software, incluso il dispiegamento dell'hypervisor ESXi e la configurazione delle macchine virtuali (e tutto automaticamente).
Abbiamo scoperto come:
- il server in fase di installazione riceve le impostazioni necessarie dal database;
- l'intero progresso della preparazione è registrato nel database (log, eventi, flag delle fasi).
Risultato:
Credo che l'unicità di questa soluzione risieda nella flessibilità, semplicità, possibilità e versatilità.
Per favore, scrivete nei commenti cosa ne pensate.
Fonte: habr.com
