HOWTO : Créer une Image de Base Windows 11 avec KubeVirt et Unattend

Ce guide détaille les étapes pour créer une image Windows 11 généralisée (utilisant unattend.xml pour Sysprep) sur un cluster Kubernetes équipé de KubeVirt. Cette image servira de modèle pour le déploiement rapide de machines virtuelles Windows 11.

Prérequis du Cluster:

Objectif: Produire un VolumeSnapshot ou un PersistentVolumeClaim (PVC) contenant une installation de Windows 11 généralisée, prête à être clonée pour de nouvelles VMs.

1. Prérequis

  • Kubernetes fonctionnel

  • KubeVirt installé

  • Stockage persistant configuré (Block, Disque, ou Partagé)

  • Accès réseau pour le cluster (pour télécharger les ISOs ou pour CDI)

Avant de commencer, rassemblez les éléments suivants :

  • ISO Windows 11 :

    Obtenez une image ISO officielle depuis le site de Microsoft.

  • ISO des pilotes VirtIO :

    Téléchargez la dernière image virtio-win.iso stable. Lien : https://fedorapeople.org/groups/virt/virtio-win/direct-downloads/stable-virtio/

  • Fichier `unattend.xml` :

    Créez ce fichier pour automatiser Sysprep et la phase OOBE (Out-Of-Box Experience). Adaptez l’exemple ci-dessous à vos besoins (langue, fuseau horaire, compte local, mot de passe).

    Exemple minimal de unattend.xml
    <?xml version="1.0" encoding="utf-8"?>
    <unattend xmlns="urn:schemas-microsoft-com:unattend">
        <settings pass="oobeSystem">
            <component name="Microsoft-Windows-International-Core" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS" xmlns:wcm="http://schemas.microsoft.com/WMIConfig/2002/State" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
                <InputLocale>fr-FR</InputLocale>
                <SystemLocale>fr-FR</SystemLocale>
                <UILanguage>fr-FR</UILanguage>
                <UserLocale>fr-FR</UserLocale>
            </component>
            <component name="Microsoft-Windows-Shell-Setup" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS" xmlns:wcm="http://schemas.microsoft.com/WMIConfig/2002/State" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
                <OOBE>
                    <HideEULAPage>true</HideEULAPage>
                    <HideOEMRegistrationScreen>true</HideOEMRegistrationScreen>
                    <HideOnlineAccountScreens>true</HideOnlineAccountScreens>
                    <HideWirelessSetupInOOBE>true</HideWirelessSetupInOOBE>
                    <NetworkLocation>Work</NetworkLocation>
                    <ProtectYourPC>1</ProtectYourPC>
                </OOBE>
                <UserAccounts>
                   <LocalAccounts>
                      <LocalAccount wcm:action="add">
                         <Password>
                            <Value>UABzAHMAdwBvAHIAZAAxACEA</Value>
                            <PlainText>false</PlainText>
                         </Password>
                         <Description>Compte Administrateur Local</Description>
                         <DisplayName>AdminLocal</DisplayName>
                         <Group>Administrators</Group>
                         <Name>AdminLocal</Name>
                      </LocalAccount>
                   </LocalAccounts>
                </UserAccounts>
                <TimeZone>Romance Standard Time</TimeZone>
            </component>
        </settings>
        <settings pass="specialize">
             <component name="Microsoft-Windows-Shell-Setup" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS" xmlns:wcm="http://schemas.microsoft.com/WMIConfig/2002/State" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
                <CopyProfile>true</CopyProfile>
             </component>
        </settings>
        <settings pass="generalize">
            <component name="Microsoft-Windows-Security-SPP" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS" xmlns:wcm="http://schemas.microsoft.com/WMIConfig/2002/State" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
                <SkipRearm>1</SkipRearm>
            </component>
            <component name="Microsoft-Windows-Deployment" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS" xmlns:wcm="http://schemas.microsoft.com/WMIConfig/2002/State" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
                <Generalize>
                    <Mode>VM</Mode>
                    <ForceShutdownNow>false</ForceShutdownNow>
                </Generalize>
            </component>
        </settings>
    </unattend>
    

    Note

    Le mot de passe dans l’exemple (UABzAHMAdwBvAHIAZAAxACEA) correspond à “Password1!” encodé en Base64. Utilisez un mot de passe fort et générez sa version Base64 (par ex. via PowerShell : [Convert]::ToBase64String([System.Text.Encoding]::Unicode.GetBytes("VotreMotDePasseComplexe"))).

2. Préparation KubeVirt

  • Stocker `unattend.xml` dans Kubernetes :

    Utilisez un Secret (recommandé) ou une ConfigMap.

    kubectl create secret generic win11-unattend --from-file=unattend.xml=./unattend.xml
    
  • Rendre les ISOs accessibles à KubeVirt :

    La méthode recommandée est d’utiliser CDI (Containerized Data Importer) pour importer les ISOs dans des PVCs.

    Commande pour importer l’ISO Windows via CDI (adapter URL et storageClass)
    cat <<EOF | kubectl apply -f -
    apiVersion: cdi.kubevirt.io/v1beta1
    kind: DataVolume
    metadata:
      name: win11-iso
    spec:
      source:
          http:
             url: "<URL_VERS_VOTRE_ISO_WINDOWS_11>"
      pvc:
        accessModes: [ "ReadWriteOnce" ] # Ou ReadOnlyMany si supporté/nécessaire
        resources:
          requests: { storage: 7Gi }
        storageClassName: <votre-storage-class>
    EOF
    
    Commande pour importer virtio-win.iso via CDI
    cat <<EOF | kubectl apply -f -
    apiVersion: cdi.kubevirt.io/v1beta1
    kind: DataVolume
    metadata:
      name: virtio-win-iso
    spec:
      source:
          http:
             url: "https://fedorapeople.org/groups/virt/virtio-win/direct-downloads/stable-virtio/virtio-win.iso"
      pvc:
        accessModes: [ "ReadWriteOnce" ] # Ou ReadOnlyMany
        resources:
          requests: { storage: 1Gi }
        storageClassName: <votre-storage-class>
    EOF
    

    Attendez que les DataVolumes soient Succeeded.

  • Créer le PVC pour l’installation Windows :

    Ce PVC deviendra le disque système de la VM temporaire.

    Commande pour créer le PVC d’installation
    cat <<EOF | kubectl apply -f -
    apiVersion: v1
    kind: PersistentVolumeClaim
    metadata:
      name: win11-install-pvc
    spec:
      accessModes: [ "ReadWriteOnce" ] # RW pour l'installation
      resources:
        requests: { storage: 80Gi } # Taille recommandée
      storageClassName: <votre-storage-class-block-ou-disque> # Choisir une classe performante
    EOF
    

3. Création de la VM Temporaire

Définissez la VirtualMachine KubeVirt pour l’installation. Créez un fichier vm-template-install.yaml :

Définition de la VM d’installation (vm-template-install.yaml)
apiVersion: kubevirt.io/v1
kind: VirtualMachine
metadata:
  name: win11-installer
spec:
  runStrategy: Manual # Démarrage manuel
  template:
    metadata:
      labels:
        kubevirt.io/domain: win11-installer
    spec:
      domain:
        cpu: { cores: 4 }
        memory: { guest: 8Gi }
        resources: { requests: { memory: 8Gi } }
        devices:
          disks:
            - name: installpvc
              disk: { bus: virtio } # Pilote VirtIO disque
              # bootOrder: 2
            - name: winiso
              cdrom: { bus: sata }
              # bootOrder: 1 # Booter sur l'ISO Windows
            - name: virtioiso
              cdrom: { bus: sata }
            - name: unattendiso # Monte le Secret/ConfigMap comme CD
              cdrom: { bus: sata }
          interfaces:
            - name: default
              masquerade: {} # Ou autre config réseau
              model: virtio # Pilote VirtIO réseau
          tpm: {} # Émulation TPM pour Win11
        features:
          acpi: {}
          apic: {}
          smm: { enabled: true } # Recommandé pour Windows
        firmware:
          uefi: { secureBoot: false } # UEFI requis pour Win11
      terminationGracePeriodSeconds: 360
      volumes:
        - name: installpvc
          persistentVolumeClaim: { claimName: win11-install-pvc }
        - name: winiso
          persistentVolumeClaim: { claimName: win11-iso } # PVC de l'ISO Win11
        - name: virtioiso
          persistentVolumeClaim: { claimName: virtio-win-iso } # PVC de l'ISO VirtIO
        - name: unattendiso
          secret: { secretName: win11-unattend } # Référence au Secret unattend
          # Si ConfigMap:
          # configMap: { name: win11-unattend-configmap }
  • Appliquer et démarrer :

    kubectl apply -f vm-template-install.yaml
    virtctl start win11-installer
    
  • Se connecter à la console :

    virtctl vnc win11-installer # Ou 'console'
    

4. Installation et Configuration Windows

  1. Installation de Windows : * Suivez l’assistant d’installation Windows. * Lors de la sélection du disque, cliquez sur Charger un pilote. * Naviguez vers le lecteur CD VirtIO -> viostor -> w11 -> amd64 -> chargez le pilote. Le disque PVC doit apparaître. * Terminez l’installation.

  2. Configuration post-installation : * Une fois Windows démarré, connectez-vous. * Installer les pilotes VirtIO : Exécutez virtio-win-gt-x64.msi depuis le CD VirtIO. * Installer QEMU Guest Agent : Exécutez qemu-ga-x86_64.msi depuis le dossier guest-agent du CD VirtIO. C’est essentiel pour l’intégration KubeVirt. * Configurer le réseau, activer RDP si besoin. * Installer les mises à jour Windows via Windows Update. * Installer les logiciels de base souhaités. * Nettoyer les fichiers temporaires (optionnel mais recommandé).

5. Généralisation (Sysprep)

Cette étape prépare l’image à être clonée.

  1. Ouvrir une Invite de commandes (Admin).

  2. Aller dans le répertoire Sysprep :

    cd C:\Windows\System32\Sysprep
    
  3. Identifier la lettre de lecteur du CD contenant unattend.xml (monté depuis le Secret/ConfigMap, ex: E:).

  4. Exécuter Sysprep avec le fichier unattend :

    sysprep.exe /generalize /oobe /shutdown /unattend:E:\unattend.xml
    

    Remplacez ``E:unattend.xml`` par le chemin correct.

    • /generalize : Supprime les informations spécifiques à la machine.

    • /oobe : Lance l’assistant de configuration au prochain démarrage.

    • /shutdown : Arrête la VM après Sysprep. Crucial.

  5. La VM s’éteindra. Ne la redémarrez pas.

6. Création de l’Image de Base

Le PVC win11-install-pvc contient l’image généralisée. Pour la préserver et l’utiliser comme modèle, deux méthodes :

  • Méthode 1: Volume Snapshot (Recommandée)

    Si votre stockage le supporte, créez un VolumeSnapshot du PVC.

    Création d’un VolumeSnapshot (snapshot.yaml)
    apiVersion: snapshot.storage.k8s.io/v1
    kind: VolumeSnapshot
    metadata:
      name: win11-base-snapshot
    spec:
      volumeSnapshotClassName: <votre-snapshot-class> # Nom de la classe de snapshot
      source:
        persistentVolumeClaimName: win11-install-pvc
    

    Appliquez avec kubectl apply -f snapshot.yaml. Ce snapshot servira de dataSource pour les PVCs des futures VMs.

  • Méthode 2: Clonage de PVC

    Créez un nouveau PVC en clonant le PVC d’installation.

    Création d’un PVC par clonage (clone-pvc.yaml)
    apiVersion: v1
    kind: PersistentVolumeClaim
    metadata:
      name: win11-base-image-pvc
    spec:
      accessModes: [ "ReadWriteOnce" ] # Ou ReadOnlyMany si possible
      storageClassName: <votre-storage-class> # Mettre la même que la source
      dataSource:
        kind: PersistentVolumeClaim
        name: win11-install-pvc # PVC source à cloner
      resources:
        requests: { storage: 80Gi } # Taille >= source
    

    Appliquez avec kubectl apply -f clone-pvc.yaml. Attendez que win11-base-image-pvc soit Bound. Ce PVC cloné est votre image de base.

7. Nettoyage

Après avoir sécurisé votre image de base (via Snapshot ou Clone) :

  • Supprimez la VM d’installation :

    kubectl delete vm win11-installer
    
  • Si vous avez utilisé la méthode de clonage, supprimez le PVC d’installation original (une fois le clone terminé) :

    kubectl delete pvc win11-install-pvc
    
  • Si vous utilisez des snapshots, vérifiez si votre provisionneur nécessite de conserver le PVC source.

8. Utilisation

Vous disposez maintenant d’un VolumeSnapshot (win11-base-snapshot) ou d’un PersistentVolumeClaim (win11-base-image-pvc) qui peut être utilisé comme dataSource lors de la création de nouveaux PVCs pour vos VM Windows 11. Chaque nouvelle VM démarrera à l’étape OOBE, prête à être configurée selon les directives de votre unattend.xml ou manuellement.