Logo

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

Sommaire

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:

1. Template Ubuntu

2. Template CentOS

3. Template Windows Server

Contexte

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

1. Template Ubuntu Server (26.04)

Création de la VM:

Après le boot, installation de l'OS. Dans l'installeur:

Fixage de l'adresse IP:

Par 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
Configuration de base du système:

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
Note:

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.

Déploiement

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)

Note:

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.

screencap clonage de VM Ubuntu

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

2. Template CentOS (version 10)

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:

Après le boot, installation de l'OS. Dans l'installeur:

Fixage de l'adresse IP:

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
Configuration de base du système:

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
Note:

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.

Déploiement

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

3. Template Windows Server (2025)

Création d'une nouvelle VM via virt-manager

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:

Server Manager
Personnalisation du template (côté hyperviseur)

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.

Optimisation

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:

  • Des services (windows update, indexation, defender, etc.) peuvent consommer beaucoup de temps CPU par moments.
  • Mais surtout, par défaut Windows utilise des interruptions HPET (High Precision Event Timer) ou APIC pour le polling CPU. On traite cela en activant un timer adapté + des flags hyperv spécifiques + en installant les drivers virtio ainsi que les guest tools.

Vérifier et updater les parties suivantes dans le XML de la VM:

virsh edit template_Windows_2025
  <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).

Personnalisation du template (côté système)

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):

Installation des drivers Virtio-Win

Installer aussi les Virtio-Win guest tools (virtio-win-guest-tools.exe):

Installation des Virtio-Win guest tools

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:

Installation de .NET 3.5 et 4.X
YMMV!

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

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.

Mise à jour du système
Templatisation (sysprep)

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)

Sysprep
Déploiement

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
Note:

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

Cet article a été généré par un humain