TL;DR:
Création et déploiement de templates sur le homelab: Ubuntu, CentOS, Windows Server.
Concepts:
Virtualisation, création de VM, clonage de VM
Outils:
Ubuntu, KVM/libvirt, CentOS, Windows Server
On va créer des templates pour 3 OS différents requis lors des tests ultérieurs prévus sur le homelab. Je les ai organisés dans trois sous-parties:
On dispose d'un homelab faisant tourner des machines virtuelles KVM/libvirt (QEMU).
On veut pouvoir gérer les déploiements de templates Ubuntu Server et Windows Server pour faire des tests, de façon automatisée.
On part de "rien" (un serveur physique tout juste installé avec un hyperviseur KVM et virt-manager).
(description du déploiement du serveur utilisé)
On a téléchargé les images ISO des trois OS à installer:
On a aussi téléchargé la dernière version de l'iso des virtio guest tools pour windows:
https://github.com/qemus/virtiso-x86/
Préparation supplémentaire à faire éventuellement côté host:
Ajouter un partage NFS pour échanger facilement des fichiers avec les VM guests (par exemple le répertoire /data/public):
# apt install nfs-kernel-server
# vi /etc/exports
/data/public 192.168.122.0/24(rw,sync,no_subtree_check,no_root_squash)
# vi /etc/default/nfs-kernel-server
RPCNFSDCOUNT=8
RPCMOUNTDOPTS="--manage-gids"
# systemctl restart nfs-kernel-server
Création de la VM:
template_Ubuntu_2604.qcow2Après le boot, installation de l'OS. Dans l'installeur:
(X) Ubuntu Server[X] Search for third-party drivers(X) Use an entire disk et [X] Set up this disk as an LVM grouptemplate-ubuntu26(X) Skip for now[X] Install OpenSSH serverPar commodité je fixe dans mon template l'adresse IP qui vient d'être réservée via le DHCP. Ce sera l'adresse temporaire du template au démarrage. Exemple:
Vérifier la conf réseau:
root@template-ubuntu26:~# cat /etc/netplan/00-installer-config.yaml
# This is the network config written by 'subiquity'
network:
ethernets:
enp1s0:
dhcp4: true
dhcp6: true
match:
macaddress: 52:54:00:70:c3:4c
set-name: enp1s0
version: 2
Vérification de l'IP:
root@template-ubuntu26:~# ip -4 addr show dev enp1s0
2: enp1s0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
altname enx52540070c34c
inet 192.168.122.236/24 metric 100 brd 192.168.122.255 scope global dynamic enp1s0
valid_lft 2917sec preferred_lft 2917sec
Editer la conf réseau:
root@template-ubuntu26:~# vi /etc/netplan/00-installer-config.yaml
# This is the network config written by 'subiquity'
network:
ethernets:
enp1s0:
dhcp4: no
addresses: [192.168.122.236/24]
gateway4: 192.168.122.1
nameservers:
addresses: [192.168.122.1]
dhcp6: no
match:
macaddress: 52:54:00:70:c3:4c
set-name: enp1s0
version: 2
Editer /etc/hosts et ajouter une entrée pour la machine hôte:
192.168.122.1 host
Générer si besoin une clé ssh sur le host et copier la partie publique dans ~/.ssh/authorized_keys sur la nouvelle VM:
$ cat >>~/.ssh/authorized_keys <<EOF
ssh-ed25519 AAAAxxxxxxxxxxxxxxxxxx= admin@host
EOF
Effectuer la personnalisation souhaitée. Exemple:
$ cat >>~/.bashrc <<EOF
export VISUAL=vim
export EDITOR=vim
EOF
$ cat >>~/.vimrc <<EOF
set noautoindent
set shiftwidth=2
set paste
EOF
$ sudo apt remove unattended-upgrades
$ sudo apt install keyutils nfs-common net-tools unzip ethtool cpufrequtils htop lsof curl wget git pciutils usbutils
Faire une mise à jour du système:
# apt update && apt upgrade -y && apt autoremove -y
# reboot
Créer le script /root/masterize.sh qui va permettre de "nettoyer" le système avant clonage:
systemctl stop rsyslog 2>/dev/null || true
sync
apt clean
rm -rf /var/lib/apt/lists/*
journalctl --rotate
journalctl --vacuum-time=1s
find /var/log -type f -exec truncate -s0 {} \;
: > /var/log/wtmp
: > /var/log/btmp
rm -rf /tmp/*
rm -rf /var/tmp/*
rm -rf /var/crash/*
rm -rf /var/lib/systemd/coredump/*
rm -f /etc/ssh/ssh_host_*
rm -f /etc/machine-id
touch /etc/machine-id
rm -f /var/lib/dbus/machine-id
ln -s /etc/machine-id /var/lib/dbus/machine-id
rm -f /var/lib/systemd/random-seed
if command -v cloud-init >/dev/null 2>&1; then
cloud-init clean --logs
fi
rm -f /var/lib/NetworkManager/*lease*
rm -rf /var/lib/systemd/network/*
rm -rf /var/lib/dhcp/*
history -c
history -w
rm -f /root/.bash_history
rm -f /home/*/.bash_history
sync
Ce script permet de faire le cleanup des logs, de l'historique des commandes, etc. On ne met pas #!/bin/bash au début et on ne le rend pas exécutable avec un chmod +x, pour ne pas risquer de le lancer accidentellement.
Lancer la commande:
# . /root/masterize.sh
Puis, arrêter la VM en lui envoyant une commande shutdown via virt-manager pour qu'elle s'arrête proprement.
Le template Ubuntu est prêt.
Pour déployer un template:
Faire un clone de la VM template_Ubuntu_2604
Bien choisir un nom pour le volume de stockage correspondant à la VM clonée (plutôt que le nom template_Ubuntu_2604-clone.qcow2 par défaut)
J'aime bien que le nom du premier disque virtuel mappé soit nommé comme la VM. Pour les disques suivants j'ajoute des suffixes "_disk1", "_disk2", etc.
Se loguer sur le template
Editer /etc/netplan/0*.yaml pour définir l'adresse IP
Editer /etc/hostname pour définir le nom d'hôte
Redémarrer
C'est parti pour tester "le Windows des Linux", avec sa gui par défaut sur un serveur et ses innombrables commandes d'abstraction qui éloignent le sysadmin des fichiers de configuration.
La raison à cela est un déploiement ultérieur d'un lab CyberArk PAM, dont les composants tels que le PSM for SSH sont fournis en paquets RPM pour Redhat/CentOS.
Création de la VM:
template_CentOS_10.qcow2Install CentOS Stream 10)Après le boot, installation de l'OS. Dans l'installeur:
Utiliser la commande nmtui pour une interface interactive en mode texte afin de modifier la conf IP, ou bien utiliser la commande nmcli qui est le standard:
Vérifier l'IP actuelle:
# nmcli connection show
NAME UUID TYPE DEVICE
enp1s0 aeb085f1-9e1a-34e9-b927-70ec18087157 ethernet enp1s0
lo a1121441-eca1-4f52-8204-e48c926b36b9 loopback lo
Passer la conf en IP fixe:
# nmcli connection modify enp1s0 ipv4.method manual ipv4.addresses 192.168.122.189/24 ipv4.gateway 192.168.122.1 ipv4.dns 192.168.122.1 connection.autoconnect yes
# nmcli con up id enp1s0 # (si l'interface n'est pas encore activée)
# nmcli device reapply enp1s0
Le fichier de conf qui a été modifié par nmcli est /etc/NetworkManager/system-connections/enp1s0.nmconnection
Editer /etc/hosts et ajouter une entrée pour la machine hôte:
192.168.122.1 host
Générer si besoin une clé ssh sur le host et copier la partie publique dans ~/.ssh/authorized_keys sur la nouvelle VM:
$ cat >>~/.ssh/authorized_keys <<EOF
ssh-ed25519 AAAAxxxxxxxxxxxxxxxxxx= admin@host
EOF
Effectuer la personnalisation souhaitée. Exemple:
dnf install qemu-guest-agent
systemctl enable qemu-guest-agent
Faire une mise à jour du système:
# dnf check-update && dnf upgrade -y && dnf autoremove -y
# reboot
Créer le script /root/masterize.sh qui va permettre de "nettoyer" le système avant clonage:
systemctl stop rsyslog 2>/dev/null || true
sync
dnf clean all
rm -rf /var/cache/dnf/*
journalctl --rotate
journalctl --vacuum-time=1s
find /var/log -type f -exec truncate -s0 {} \;
: > /var/log/wtmp
: > /var/log/btmp
rm -rf /tmp/*
rm -rf /var/tmp/*
rm -rf /var/crash/*
rm -f /etc/ssh/ssh_host_*
rm -f /etc/machine-id
touch /etc/machine-id
rm -f /var/lib/dbus/machine-id
ln -s /etc/machine-id /var/lib/dbus/machine-id
rm -f /var/lib/systemd/random-seed
rm -rf /var/lib/NetworkManager/*
rm -rf /var/lib/dhclient/*
history -c
history -w
rm -f /root/.bash_history
rm -f /home/*/.bash_history
sync
Ce script permet de faire le cleanup des logs, de l'historique des commandes, etc. On ne met pas #!/bin/bash au début et on ne le rend pas exécutable avec un chmod +x, pour ne pas risquer de le lancer accidentellement.
Lancer la commande:
# . /root/masterize.sh
Puis, arrêter la VM en lui envoyant une commande shutdown via virt-manager pour qu'elle s'arrête proprement.
Le template CentOS est prêt.
Pour déployer un template:
Faire un clone de la VM template_CentOS_10
Bien choisir un nom pour le volume de stockage correspondant à la VM clonée (plutôt que le nom template_CentOS_10-clone.qcow2 par défaut)
Se loguer sur le template
Utiliser nmtui ou nmcli pour setter la conf réseau comme indiqué plus haut.
Setter le hostname:
# hostnamectl set-hostname nouvelle_vm
Redémarrer
Création d'une nouvelle VM via virt-manager
template_Windows_2025.qcow2 (je lui mets 80 GiB pour être tranquille, au lieu des 40 GiB suggérés)Après le boot, installation de l'OS. Dans l'installeur:
Après le reboot: définir un mot de passe pour Administrator dans Customize settings puis passer la procédure de first-boot (send diag. data to Microsoft) et se loguer. On arrive sur le dashboard:
Après avoir déployé la VM avec un template par défaut on ne maîtrise pas forcément les paramètres précis de virtio définis dans le XML de la VM. Il faut donc vérifier ça car des paramètres importants peuvent manquer.
Une conséquence visible à cela est que la consommation CPU apparente de la VM sous qemu/kvm reste élevée même quand la VM est idle. Plusieurs raisons à cela:
Vérifier et updater les parties suivantes dans le XML de la VM:
virsh edit template_Windows_2025
cpu: <cpu mode='host-passthrough' check='partial'>
<topology sockets='X' cores='X' threads='X'/>
<feature policy='require' name='vmx'/>
<feature policy='require' name='hypervisor'/>
<feature policy='require' name='lahf_lm'/>
<feature policy='require' name='hle'/>
<feature policy='require' name='fsgsbase'/>
</cpu>
<features>
<acpi/>
<apic/>
<hyperv>
<relaxed state='on'/>
<vapic state='on'/>
<spinlocks state='on' retries='8191'/>
<vpindex state='on'/>
<runtime state='on'/>
<synic state='on'/>
<stimer state='on'/>
<reset state='on'/>
<vendor_id state='on' value='KVMHv'/>
</hyperv>
<kvm>
<hidden state='on'/>
</kvm>
</features>
<clock offset='localtime'>
<timer name='rtc' tickpolicy='catchup'/>
<timer name='pit' tickpolicy='delay'/>
<timer name='hpet' present='no'/>
<timer name='hypervclock' present='yes'/>
</clock>
Normalement, au moins une partie de ces paramètres sont déjà présents quand on a installé un OS Windows Server via virt-manager, mais ça dépend des versions : souvent il faut les ajouter manuellement (ou les préciser sous forme d'options correspondantes si on déploie une VM windows avec la commande virt-install plutôt que via la gui virt-manager).
Après l'installation du système, installer tous les drivers manquants pour le hardware virtuel depuis l'ISO des drivers virtio (virtio-win-gt-x64.msi):
Installer aussi les Virtio-Win guest tools (virtio-win-guest-tools.exe):
Désactiver le firewall système (pas obligatoire pour un environnement de lab):
(console PowerShell)
netsh advfirewall set allprofiles state off
Activer RDP: dans Server Manager => Local Server => Remote Desktop (cliquer sur Disabled et l'activer).
Activer de même SSH en cliquant sur Disabled à côté de Remote SSH Access.
Installer les features: toujours dans le Server Manager, aller en haut à droite dans le menu Manage et sélectionner Add Roles and Features.
Pour des VM de test, je désinstalle Defender ; pour cela ouvrir une console PowerShell:
Uninstall-WindowsFeature -Name Windows-Defender
(c'est un peu long)
A la fin, il met un message de succès:
PS C:\Users\Administrator> Uninstall-WindowsFeature -Name Windows-Defender
Success Restart Needed Exit Code Feature Result
------- -------------- --------- --------------
True Yes SuccessRest... {Microsoft Defender Antivirus}
WARNING: You must restart this server to finish the removal process
Redémarrer comme demandé:
shutdown -r
Après le reboot, retourner dans le Server Manager et installer les Features .NET 3.5 et .NET 4.X:
Ces composants que je suggère d'installer sont pour les projets prévus sur le lab en environnement Windows. A ajuster selon vos besoins.
Supprimer l'inutile image de fond qui ralentit les connexions distantes: ouvrir un shell cmd et taper:
gpedit.msc
Ceci ouvre le Local Group Policy Editor
C:\Windows\Web\Screen\img105.jpg
Faire toute autre modif à effectuer avant sysprep, selon le contexte (exemples):
Faire une mise à jour du système (WSUS ou autre) afin de partir sur une base propre.
Exécuter (Win+R):
C:\windows\system32\sysprep\sysprep.exe
Sélectionner les options shutdown et Generalize (sinon problème de duplicate SID au moment du join domain)
Faire un clone de la VM template_Windows_2025
Bien choisir un nom pour le volume de stockage correspondant à la VM clonée (plutôt que le nom template_Windows_2025-clone.qcow2 par défaut)
Se loguer sur le template
Setter l'adresse IP
Si la machine est destinée à joindre un domaine AD, mettre l'IP d'un contrôleur de domaine en DNS
Mapper le point de montage NFS
Changer le hostname (et faire le join domain si client AD)
Conf réseau & hostname (exemple):
PS> Rename-Computer -NewName "nouveau-serveur" -Restart
PS> New-NetIPAddress -InterfaceAlias "Ethernet" -IPAddress 192.168.122.100 -PrefixLength 24 -DefaultGateway 192.168.122.1
PS> Set-DnsClientServerAddress -InterfaceAlias "Ethernet" -ServerAddresses 192.168.122.1
Activer Windows:
PS> slmgr /ipk TVRH6-WHNXV-R9WG3-9XRFY-MY832
PS> slmgr /skms kms8.msguides.com
PS> slmgr /ato
Pour utiliser la bonne clé pour la version déployée, voir https://learn.microsoft.com/fr-fr/windows-server/get-started/kms-client-activation-keys.
Faire maintenant le join domain si le serveur est client AD.
--
TG - 07/2026