Bonjour, je suis Denis et l'un de mes domaines d'activité est le développement de solutions d'infrastructure chez X5. Aujourd'hui, j'aimerais partager avec vous comment déployer un système automatique de préparation de serveurs en utilisant des outils accessibles. À mon avis, c'est une solution intéressante, simple et flexible.

La préparation consiste à transformer un nouveau serveur prêt à l'emploi en un serveur entièrement configuré avec un système d'exploitation Linux ou avec l'hyperviseur ESXi (le déploiement de serveurs Windows n'est pas discuté dans cet article).
Termes:
- serveurs – serveurs qui doivent être configurés.
- serveur d'installation – serveur principal qui assure tout le processus de préparation via le réseau.
Pourquoi l'automatisation est-elle nécessaire?
Supposons qu'il y ait une tâche : préparer massivement des serveurs à partir de zéro, avec un pic de 30 par jour. Des serveurs de différents fabricants et modèles, différents systèmes d'exploitation peuvent y être installés, avec ou sans hyperviseur.
Quelles opérations sont incluses dans le processus de configuration (sans automatisation) :
- brancher un clavier, une souris, un moniteur au serveur ;
- configurer le BIOS, le RAID, l'IPMI ;
- mettre à jour les firmwares des composants ;
- déployer une image du système de fichiers (ou installer un hyperviseur et copier des machines virtuelles) ;
Remarque. En option, le déploiement du système d'exploitation peut se faire via une installation avec un fichier de réponse automatique. Mais cela ne sera pas discuté dans l'article. Cependant, vous verrez ci-dessous que l'ajout de cette fonctionnalité n'est pas compliqué.
- configurer les paramètres du système d'exploitation (nom d'hôte, IP, etc.).
Avec cette approche, les mêmes configurations sont exécutées successivement sur chaque serveur. L'efficacité d'un tel travail est très faible.
Le but de l'automatisation est d'exclure l'intervention humaine dans le processus de préparation des serveurs. Autant que possible.
Grâce à l'automatisation, le temps d'arrêt entre les opérations est réduit et il devient possible de préparer plusieurs serveurs simultanément. De plus, le risque d'erreurs dues au facteur humain diminue considérablement.

Comment se déroule la configuration automatique des serveurs?
Analysons toutes les étapes en détail.
Vous avez un serveur linux que vous utilisez comme serveur d'installation PXE. Il dispose des services suivants installés et configurés : DHCP, TFTP.
Donc, nous démarrons le serveur (qui doit être configuré) via PXE. Rappelons-nous comment cela fonctionne :
- Le serveur est configuré pour démarrer à partir du réseau.
- Le serveur charge le PXE-ROM de la carte réseau et se connecte au serveur d'installation via DHCP pour obtenir une adresse réseau.
- Le serveur d'installation DHCP attribue une adresse ainsi qu'une instruction pour le démarrage ultérieur via PXE.
- Le serveur charge le bootstrap réseau depuis le serveur d'installation par PXE, le démarrage ultérieur se fait selon le fichier de configuration PXE.
- Le démarrage s'effectue sur la base des paramètres reçus (noyau, initramfs, points de montage, image squashfs, etc.).
Remarque. Cet article décrit le démarrage par PXE en mode BIOS. Actuellement, les fabricants intègrent activement le mode de démarrage UEFI. La différence pour PXE réside dans la configuration du serveur DHCP et l'existence d'un bootstrap supplémentaire.
Examinons un exemple de configuration d'un serveur PXE (menu pxelinux).
Fichier 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 par défaut
MENU LABEL Linux Scripting Toolkits
MENU default
KERNEL menu.c32
APPEND pxelinux.cfg/toolkit // passage au menu suivantFichier pxelinux.cfg/toolkit :
prompt 0
timeout 100
menu title X5 PXE Boot Menu
label mainmenu
menu label ^Retour au menu principal
kernel menu.c32
append pxelinux.cfg/default
label x5toolkit-auto // par défaut - mode automatique
menu label installation automatique du toolkit x5
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 // pour le débogage - console
menu label shell du toolkit x5
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="…"Le noyau et l'initramfs à ce stade constituent une image linux intermédiaire, qui sera utilisée pour la préparation et la configuration principale du serveur.
Comme vous pouvez le voir, le chargeur de démarrage transmet de nombreux paramètres au noyau. Certains de ces paramètres sont utilisés par le noyau lui-même, tandis que d'autres peuvent être utilisés à nos fins. Cela sera expliqué plus tard, mais pour l'instant, vous pouvez simplement retenir que tous les paramètres transmis seront disponibles dans l'image linux intermédiaire via /proc/cmdline.
D'où les obtenir, le noyau et l'initramfs ?
Vous pouvez choisir n'importe quelle distribution linux comme base. Voici ce à quoi nous devons prêter attention lors du choix :
- l'image de démarrage doit être polyvalente (présence de pilotes, possibilité d'installer des utilitaires supplémentaires);
- Il faudra probablement personnaliser l'initramfs.
Comment cela est-il fait dans notre solution pour X5 ? Nous avons choisi CentOS 7 comme base. Nous allons réaliser cette astuce : préparer la future structure de l'image, l'archiver et créer l'initramfs, à l'intérieur duquel se trouvera notre archive du système de fichiers. Lors du démarrage de l'image, l'archive sera extraite dans la partition tmpfs créée. Ainsi, nous obtiendrons une image live Linux minimale mais complète avec tous les utilitaires nécessaires, composée de seulement deux fichiers : vmkernel et 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.gzDonc, nous avons spécifié le noyau et l'initramfs qui doivent être chargés. En conséquence, à ce stade, en chargeant l'image intermédiaire Linux via PXE, nous obtiendrons la console du système d'exploitation.
Super, mais maintenant il faut transférer le contrôle à notre "automatisation".
Cela peut être fait comme suit.
Supposons qu'après le démarrage de l'image, nous prévoyons de transférer le contrôle au script mount.sh.
Nous allons inclure le script mount.sh dans le démarrage automatique. Pour cela, il faudra modifier l'initramfs :
- décompresser l'initramfs (si nous utilisons la version d'initramfs mentionnée ci-dessus, cela n'est pas nécessaire)
- inclure dans le démarrage automatique du code qui analysera les paramètres transmis via /proc/cmdline et redirigera le contrôle ;
- emballer l'initramfs.
Remarque. Dans le cas de X5 toolkit, le contrôle de démarrage est transmis au script /opt/x5/toolkit/bin/hook.sh с помощью override.conf в getty tty1 (ExecStart=…)
Ainsi, l'image se charge, où le script mount.sh démarre automatiquement. Ensuite, le script mount.sh analyse les paramètres transmis (script_cmd=) et lance le programme/script nécessaire.
label toolkit-auto
noyau …
ajouter … nfs_toolkit_script=scripts/mount.sh script_cmd=master-install.sh
label toolkit-shell
noyau …
ajouter … nfs_toolkit_script=scripts/mount.sh script_cmd=/bin/bash

Ici, à gauche, se trouve le menu PXE, à droite – le schéma de transfert de contrôle.
Nous avons compris le transfert de contrôle. En fonction du choix dans le menu PXE, un script d'auto-configuration ou une console de débogage est lancé.
Dans le cas de l'auto-configuration, les répertoires nécessaires sont montés depuis le serveur d'installation, qui contiennent :
- scripts ;
- les modèles BIOS/UEFI sauvegardés de divers serveurs ;
- firmwares ;
- outils pour serveurs ;
- logs.
Ensuite, le script mount.sh transmet le contrôle au script master-install.sh dans le répertoire des scripts.
L'arborescence des scripts (l'ordre de leur exécution) ressemble à peu près à ceci :
- master-install
- sharefunctions (fonctions générales)
- info (affichage d'informations)
- models (installation des paramètres d'installation en fonction du modèle de serveur)
- prepare_utils (installation des utilitaires nécessaires)
- fwupdate (mise à jour du firmware)
- diag (diagnostic simple)
- biosconf (configuration du BIOS/UEFI)
- clockfix (configuration de l'heure sur la carte mère)
- srmconf (configuration de l'interface à distance)
- raidconf (configuration des volumes logiques)
un des :
- preinstall (transfert de contrôle au programme d'installation du système d'exploitation ou de l'hyperviseur, par exemple ESXi)
- merged-install (démarrage direct du déballage de l'image)
Nous savons maintenant :
- comment démarrer le serveur via PXE ;
- comment transférer le contrôle vers notre propre script.
Continuons. Les questions suivantes deviennent pertinentes :
- Comment identifier le serveur que nous préparons ?
- Avec quels outils et comment configurer le serveur ?
- Comment obtenir les paramètres pour un serveur spécifique ?
Comment identifier le serveur que nous préparons ?
C'est simple – DMI :
dmidecode –s system-product-name
dmidecode –s system-manufacturer
dmidecode –s system-serial-numberIci, vous avez tout ce dont vous avez besoin : fournisseur, modèle, numéro de série. Si vous n'êtes pas sûr que ces informations sont disponibles sur tous les serveurs, vous pouvez les identifier par l'adresse MAC. Ou les deux méthodes simultanément, si les fournisseurs des serveurs sont différents et que sur certains modèles, l'information sur le numéro de série est simplement absente.
Sur la base des informations obtenues, nous montons les dossiers réseau à partir du serveur d'installation et chargeons tout le nécessaire (outils, firmwares, etc.).
Avec quels outils et comment configurer le serveur ?
Je fournirai des utilitaires pour linux pour certains fabricants. Tous les utilitaires sont disponibles sur les sites officiels des fournisseurs.

Pour les firmwares, je pense que tout est clair. Ils sont généralement fournis sous forme de fichiers exécutables compressés. Le fichier exécutable contrôle le processus de mise à jour du firmware et renvoie un code d'erreur.
Le BIOS et l'IPMI sont généralement configurés via des modèles. Si nécessaire, le modèle peut être modifié juste avant le démarrage.
Les utilitaires RAID de certains fournisseurs peuvent également être configurés selon un modèle. Si ce n'est pas le cas, il faudra écrire un script de configuration.
L'ordre de configuration du RAID est le plus souvent le suivant :
- Demandons la configuration actuelle.
- S'il y a déjà des volumes logiques – nous les supprimons.
- Voyons quels disques physiques sont présents et combien il y en a.
- Créons un nouveau volume logique. Interrompons le processus en cas d'erreur.
Comment obtenir les paramètres pour un serveur spécifique ?
Supposons que les configurations de tous les serveurs seront stockées sur le serveur d'installation. Dans ce cas, pour répondre à notre question, il faut d'abord décider : comment transférer les paramètres vers le serveur d'installation.
Au début, il est tout à fait possible de se contenter de fichiers texte. (À l'avenir, on peut utiliser un fichier texte comme méthode de sauvegarde pour la transmission des paramètres).
On peut « partager » un fichier texte sur le serveur d'installation et ajouter son montage dans le script mount.sh.
Les lignes seront, par exemple, de ce type :
Ces lignes seront transmises dans un fichier par l'ingénieur depuis son poste de travail. Ensuite, lors de la configuration du serveur, les paramètres pour ce serveur spécifique seront lus depuis le fichier.
Cependant, à long terme, il est préférable d'utiliser une base de données pour stocker les paramètres, les états et les journaux d'installation des serveurs.
Bien sûr, une seule base de données ne suffira pas, et il faudra créer une partie cliente, qui transmettra les paramètres à la base. Mettre cela en œuvre est plus complexe que pour un fichier texte, mais en réalité, ce n'est pas aussi difficile qu'il y paraît. Il est tout à fait possible d'écrire soi-même une version minimale du client, qui transmettra simplement des données à la base de données. On pourra ensuite améliorer le programme client en mode libre (rapports, impression d'étiquettes, envoi de notifications, et tout autre chose qui pourra venir à l'esprit).
En faisant une certaine requête dans la base et en spécifiant le numéro de série du serveur, nous obtiendrons les paramètres nécessaires pour la configuration du serveur.
De plus, nous n'aurons pas besoin de prévoir des verrouillages pour un accès simultané, comme c'est le cas avec un fichier texte.
Nous pouvons enregistrer le journal de configuration dans la base de données à toutes les étapes et contrôler le processus d'installation via des événements et des drapeaux des étapes de préparation.
Maintenant, nous savons comment :
- charger le serveur via PXE ;
- transférer le contrôle à notre script ;
- identifier le serveur à préparer par son numéro de série ;
- configurer le serveur avec les utilitaires appropriés ;
- transmettre les paramètres à la base de données du serveur d'installation à l'aide de la partie cliente.
Nous avons compris comment :
- le serveur à installer reçoit les paramètres nécessaires depuis la base de données ;
- toute la progression de la préparation est enregistrée dans la base (logs, événements, drapeaux des étapes).
Qu'en est-il des différents types de logiciels à installer ? Comment installer un hyperviseur, copier une VM et configurer tout cela ?
Dans le cas du déploiement d'une image de système de fichiers (Linux) sur du matériel, c'est assez simple :
- Après avoir configuré tous les composants du serveur, nous déployons l'image.
- Nous installons le chargeur grub.
- Nous créons un chroot et configurons tout ce qui est nécessaire.
Comment passer le contrôle à l'installateur du système d'exploitation (avec l'exemple d'ESXi).
- Nous organisons le passage de contrôle de notre script à l'installateur d'hyperviseur via un fichier de réponses automatiques (kickstart) :
- Nous supprimons les partitions actuelles sur le disque.
- Nous créons une partition de 500 Mo.
- Nous la marquons comme amorçable.
- Nous la formatons en FAT32.
- Nous copions les fichiers d'installation d'ESXi à la racine de celle-ci.
- Nous installons syslinux.
- Nous copions syslinux.cfg dans /syslinux/
default esxi
prompt 1
timeout 50
label esxi
kernel mboot.c32
append -c boot.cfg- Nous copions mboot.c32 dans /syslinux.
- Dans boot.cfg, il doit y avoir kernelopt=ks=ftp:///ks_esxi.cfg
- Nous redémarrons le serveur.
Après le redémarrage du serveur, l'installateur d'ESXi se chargera à partir de son disque dur. Tous les fichiers nécessaires à l'installation seront chargés en mémoire, et l'installation d'ESXi commencera conformément au fichier de réponses automatiques spécifié.
Voici quelques lignes du fichier de réponses automatiques ks_esxi.cfg :
%firstboot --interpreter=busybox
…
# Obtention du numéro de série
SYSSN=$(esxcli hardware platform get | grep Serial | awk -F " " '{print $3}')
# Obtention de l'IP
IPADDRT=$(esxcli network ip interface ipv4 get | grep vmk0 | awk -F " " '{print $2}')
LAST_OCTET=$(echo $IPADDRT | awk -F'.' '{print $4}')
# Connexion du serveur d'installation NFS
esxcli storage nfs add -H is -s /srv/nfs_share -v nfsshare1
# Copie des paramètres temporaires SSH pour utilisation avec le client SSH
mv /etc/ssh /etc/ssh.tmp
cp -R /vmfs/volumes/nfsshare1/ssh /etc/
chmod go-r /etc/ssh/ssh_host_rsa_key
# Copie d'ovftool pour déployer des VM maintenant, au cas où cela soit utile plus tard
cp -R /vmfs/volumes/nfsshare1/ovftool /vmfs/volumes/datastore1/
# Déploiement de 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
# Obtention de la ligne avec les paramètres de notre serveur
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
...
# Génération du script de configuration réseau
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
# Définition du paramètre guestinfo.esxihost.id avec le numéro de série
echo "guestinfo.esxihost.id = "$SYSSN"" >> /vmfs/volumes/datastore1/VM1/VM1.vmx
echo "guestinfo.esxihost.id = "$SYSSN"" >> /vmfs/volumes/datastore1/VM2/VM2.vmx
...
# Mise à jour des informations dans la base de données
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 ...""
# Restauration des paramètres SSH
rm -rf /etc/ssh
mv /etc/ssh.tmp /etc/ssh
# Configuration du réseau et redémarrage
esxcli system hostname set --fqdn=esx-${G_NICK}.x5.ru
/vmfs/volumes/datastore1/netconf.sh
reboot
À ce stade, l'hyperviseur est installé et configuré, et les machines virtuelles ont été copiées.
Comment configurer maintenant les machines virtuelles ?
Nous avons un peu triché : lors de l'installation, nous avons défini le paramètre guestinfo.esxihost.id = "$SYSSN" dans le fichier VM1.vmx, en y indiquant le numéro de série du serveur physique.
Maintenant, après le démarrage, la machine virtuelle (avec le paquet vmware-tools installé) peut accéder à ce paramètre :
ESXI_SN=$(vmtoolsd --cmd "info-get guestinfo.esxihost.id")C'est-à-dire que la VM pourra s'identifier (elle connaît le numéro de série de l'hôte physique), faire une requête à la base de données du serveur d'installation et obtenir les paramètres à configurer. Tout cela est formalisé dans un script qui doit être exécuté automatiquement au démarrage de la guestos vm (mais une seule fois : RunOnce).
Maintenant, nous savons comment :
- charger le serveur via PXE ;
- transférer le contrôle à notre script ;
- identifier le serveur à préparer par son numéro de série ;
- configurer le serveur avec les utilitaires appropriés ;
- transmettre les paramètres à la base de données du serveur d'installation via la partie client ;
- configurer différents types de logiciels, y compris déployer l'hyperviseur esxi et configurer les machines virtuelles (et tout automatiquement).
Nous avons compris comment :
- le serveur à installer reçoit les paramètres nécessaires depuis la base de données ;
- toute la progression de la préparation est enregistrée dans la base (logs, événements, drapeaux des étapes).
Résultat :
Je pense que l'unicité de cette solution réside dans sa flexibilité, sa simplicité, ses possibilités et son universalité.
Veuillez écrire dans les commentaires ce que vous en pensez.
Source : habr.com
