Ce document décrit l'architecture, la configuration réseau et stockage, ainsi que les procédures d'exploitation pour faire tourner des machines virtuelles (VMs) d'entreprise sur notre cluster de serveurs physiques HPE ProLiant DL360.
L'infrastructure repose sur un modèle de virtualisation hybride combinant serveurs physiques et stockage partagé centralisé :
dl360g9-3 actif, et bientôt dl360g9-4) sous Red Hat Enterprise Linux CoreOS (RHCOS) avec support KVM.10.194.16.14).ens1f1) avec tagging 802.1Q dynamique géré par OVN-Kubernetes.La configuration du stockage est le pilier central de l'architecture. Elle permet d'assurer la persistance des disques virtuels et d'autoriser la migration à chaud (Live Migration) des VMs entre nos hyperviseurs.
Pour que les processus de virtualisation d'OpenShift (les pods d'importation et le runtime QEMU s'exécutant avec l'UID 107) puissent lire et écrire sur le partage, les permissions NFS doivent être configurées comme suit sur TrueNAS :
/mnt/pool1/nfs/mtrllabocpRead/Write).chmod -R 777 pour éviter les redémarrages en boucle de l'importateur CDI avec l'erreur Permission denied).
Nous utilisons le provisionneur de sous-répertoires NFS d'OpenShift pour structurer nos fichiers de disques durs virtuels. Nous configurons onDelete: “delete” conjointement au pathPattern pour s'assurer que les dossiers temporaires ou disques supprimés soient nettoyés proprement sur TrueNAS.
apiVersion: storage.k8s.io/v1 kind: StorageClass metadata: name: nfs-csi-rwx provisioner: k8s-sigs.io/nfs-subdir-external-provisioner parameters: # 1. Regroupe et préfixe tous les PVCs proprement dans le dossier /vms pathPattern: "vms/\${.PVC.namespace}-\${.PVC.name}" # 2. Supprime proprement les sous-dossiers lors de la suppression d'une VM (pas d'archivage parasite) onDelete: "delete" reclaimPolicy: Delete volumeBindingMode: Immediate mountOptions: - nfsvers=4.2
Pour isoler hermétiquement le trafic réseau de nos VMs tout en leur permettant de communiquer directement avec nos switchs physiques externes, nous utilisons une interface dédiée ens1f1 rattachée à un pont Open vSwitch.
[ VM Fedora (vlan217-nic / vlan218-nic) ]
|
[ Bridge OVS interne: br-int ]
|
[ OVN localnet bridge-mapping ]
|
[ Bridge OVS physique: br-vms ]
|
[ Interface Physique: ens1f1 ] ===> [ Switch Physique Trunk ]
Nous utilisons l'opérateur Kubernetes NMState pour provisionner de manière déclarative l'infrastructure réseau. Ce profil cible uniquement les serveurs physiques étiquetés avec le label physicalworker: “true”.
apiVersion: nmstate.io/v1 kind: NodeNetworkConfigurationPolicy metadata: name: ovs-vm-traffic-policy spec: nodeSelector: physicalworker: "true" desiredState: interfaces: # 1. Interface physique Trunk - name: ens1f1 type: ethernet state: up ipv4: enabled: false ipv6: enabled: false # 2. Création du pont OVS dédié - name: br-vms description: "Dedicated OVS Bridge for Virtual Machines on ens1f1" type: ovs-bridge state: up bridge: options: stp: false port: - name: ens1f1 # 3. Association logique du pont OVS au moteur OVN-Kubernetes ovn: bridge-mappings: - localnet: vms-localnet bridge: br-vms state: present
L'intégration des VLANs se fait de manière dynamique à l'aide de définitions de réseaux secondaires basées sur le pilote officiel d'OpenShift ovn-k8s-cni-overlay. Cette méthode évite de devoir créer des sous-interfaces étiquetées complexes sur chaque nœud hôte.
Règle d'or de DokuWiki / Multus : La configuration config doit être déclarée à plat (sans tableau plugins: […]), sous forme de chaîne de caractères YAML (config: |-), et contenir impérativement les clés d'identification réseau netAttachDefName et nadName.
apiVersion: k8s.cni.cncf.io/v1 kind: NetworkAttachmentDefinition metadata: name: ovs-vlan217-net namespace: default spec: config: |- { "cniVersion": "0.3.1", "name": "ovs-vlan217-net", "type": "ovn-k8s-cni-overlay", "topology": "localnet", "netAttachDefName": "default/ovs-vlan217-net", "nadName": "default/ovs-vlan217-net", "physicalNetworkName": "vms-localnet", "vlanID": 217 }
apiVersion: k8s.cni.cncf.io/v1 kind: NetworkAttachmentDefinition metadata: name: ovs-vlan218-net namespace: default spec: config: |- { "cniVersion": "0.3.1", "name": "ovs-vlan218-net", "type": "ovn-k8s-cni-overlay", "topology": "localnet", "netAttachDefName": "default/ovs-vlan218-net", "nadName": "default/ovs-vlan218-net", "physicalNetworkName": "vms-localnet", "vlanID": 218 }
Voici le manifest complet à utiliser pour instancier notre VM Fedora de référence. Elle est configurée avec 3 interfaces réseau (1 réseau de pod par défaut pour OpenShift, 1 carte sur le VLAN 217 et 1 carte sur le VLAN 218).
Le stockage utilise le mode de téléchargement fiable source: registry depuis Quay.io pour éliminer définitivement les instabilités liées aux téléchargements d'URLs HTTP.
apiVersion: kubevirt.io/v1 kind: VirtualMachine metadata: name: fedora-nfs-vm namespace: default spec: runStrategy: Always dataVolumeTemplates: - metadata: name: fedora-nfs-disk spec: pvc: accessModes: - ReadWriteMany resources: requests: storage: 20Gi storageClassName: nfs-csi-rwx volumeMode: Filesystem source: registry: url: "docker://quay.io/containerdisks/fedora:40" template: metadata: labels: kubevirt.io/vm: fedora-nfs-vm spec: nodeSelector: physicalworker: "true" domain: cpu: cores: 2 sockets: 1 threads: 1 resources: requests: memory: 2Gi devices: disks: - name: rootdisk disk: bus: virtio - name: cloudinitdisk disk: bus: virtio # ================= MULTI-NIC CONFIGURATION ================= interfaces: # NIC 1 : Réseau interne SDN OpenShift - name: default masquerade: {} # NIC 2 : Patte VLAN 217 (OVS Bridge br-vms) - name: vlan217-nic bridge: {} # NIC 3 : Patte VLAN 218 (OVS Bridge br-vms) - name: vlan218-nic bridge: {} # ========================================================== networks: - name: default pod: {} - name: vlan217-nic multus: networkName: default/ovs-vlan217-net - name: vlan218-nic multus: networkName: default/ovs-vlan218-net volumes: - name: rootdisk dataVolume: name: fedora-nfs-disk - name: cloudinitdisk cloudInitNoCloud: userData: |- #cloud-config user: fedora password: fedora_password chpasswd: { expire: False } ssh_pwauth: True
Par défaut, KubeVirt attribue une adresse MAC aléatoire aux interfaces réseau de la VM à chaque démarrage complet (transition de l'état Stopped à Running).
Pour des VMs d'entreprise, cette variation peut perturber l'attribution de baux DHCP statiques ou corrompre les configurations réseau gérées par des outils invités (comme NetworkManager sous Fedora/RHEL ou Netplan sous Ubuntu/Debian).
Pour figer une adresse MAC de manière persistante sur une interface réseau, il suffit de rajouter le paramètre macAddress sous la carte virtuelle concernée dans la section interfaces de la VM :
# ================= CONFIGURATION DES CARTES RÉSEAU (NICs) ================= interfaces: # NIC 1 : Réseau par défaut (Kubernetes SDN interne) - name: default masquerade: {} # NIC 2 : VLAN 217 avec une adresse MAC fixe - name: vlan217-nic bridge: {} macAddress: "02:00:00:00:02:17" # <--- Adresse MAC Statique ! # NIC 3 : VLAN 218 avec une adresse MAC fixe - name: vlan218-nic bridge: {} macAddress: "02:00:00:00:02:18" # <--- Adresse MAC Statique !
Lors de l'attribution manuelle de vos adresses MAC, respectez impérativement ces trois règles d'ingénierie réseau :
02:xx:xx…, 06:xx:xx…, 0A:xx:xx…, 0E:xx:xx…).ovn-k8s-cni-overlay et le standard linux-bridge gèrent nativement et de manière transparente le pass-through de ces adresses MAC personnalisées.Pour un déploiement de VMs à grande échelle, la gestion manuelle des adresses MAC devient complexe. OpenShift Virtualization intègre par défaut KubeMacPool, un contrôleur qui alloue et réserve automatiquement un pool d'adresses MAC uniques et persistantes pour chaque carte réseau secondaire créée.
Vous pouvez vérifier que KubeMacPool est actif et inspecter sa plage d'adresses MAC globale avec cette commande :
oc get hco kubevirt-hyperconverged -n openshift-cnv -o jsonpath='{.spec.kubeMacPoolConfiguration}'
Pour administrer la VM depuis la console de ton terminal local sous Xubuntu, l'outil dédié virtctl est indispensable.
# Téléchargement depuis les utilitaires CLI exposés par ton propre cluster OCP curl -kO https://hyperconverged-cluster-cli-download-openshift-cnv.apps.<CLUSTER>.<FQDN>/amd64/linux/virtctl.tar.gz # Extraction et installation dans le PATH système tar xzvf virtctl.tar.gz chmod +x virtctl sudo mv virtctl /usr/local/bin/
# Lancement de la console interactive virtctl console fedora-nfs-vm -n default
fedorafedora_passwordCtrl + ].Conserve ces commandes à portée de main dans ton DokuWiki pour diagnostiquer rapidement les anomalies sur ton lab.
# Vérifier l'état global du DataVolume de disque virtuel oc get dv -n default # Consulter les logs de l'importateur CDI si le disque reste bloqué oc logs -n default -l cdi.kubevirt.io/testing=manifest-test-pvc # Lister les fichiers physiquement écrits sur le montage TrueNAS sudo mount 10.194.16.14:/mnt/pool1/nfs/mtrllabocp /tmp/nfs && ls -la /tmp/nfs/vms/ && sudo umount /tmp/nfs
# Visualiser la configuration et les interfaces logiques en temps réel sur le nœud physique oc debug node/dl360g9-3 -- chroot /host ovs-vsctl show # Inspecter l'état réseau configuré et appliqué par NMState sur l'hôte physique oc get nodenetworkstate dl360g9-3 -o yaml # Inspecter les événements d'initialisation réseau ou d'attribution d'interfaces sur le pod oc describe pod -l kubevirt.io/vm=fedora-nfs-vm -n default | grep -A 10 Events:
Cette section décrit la procédure d'ingénierie standard pour provisionner un nouveau disque dur virtuel vierge et l'attacher à chaud (sans aucune coupure de service) à une machine virtuelle existante en cours d'exécution.
Dans un stockage de type NFS (mode Filesystem), le moteur de virtualisation KubeVirt requiert impérativement un fichier image structuré nommé disk.img à la racine du volume pour émuler un disque physique brut (périphérique de bloc) à la VM.
disk.img: no such file or directory) et place la VM en CrashLoopBackOff.DataVolume avec l'instruction blank: {} délègue à l'importateur CDI d'OpenShift le provisionnement automatique du dossier NFS ET la création du fichier disk.img à la taille spécifiée.Créez le fichier de configuration suivant :
apiVersion: cdi.kubevirt.io/v1beta1 kind: DataVolume metadata: name: extra-data-disk namespace: default spec: source: # Force l'importateur CDI à générer le fichier disk.img requis par QEMU/KVM blank: {} pvc: accessModes: # RWX requis pour supporter la Live Migration de la VM vers un autre hyperviseur - ReadWriteMany resources: requests: storage: 15Gi storageClassName: nfs-csi-rwx volumeMode: Filesystem
Appliquez le manifest pour lancer la création sur TrueNAS :
oc apply -f create-hotplug-volume.yaml
Avant de rattacher le disque à la VM, assurez-vous que l'importateur d'OpenShift a terminé la création et le formatage physique du fichier image sur le stockage NFS (le statut doit afficher Succeeded) :
oc get dv extra-data-disk -n default
| NAME | PHASE | PROGRESS | OWNER |
|---|---|---|---|
| extra-data-disk | Succeeded | 100.0% |
Une fois le volume prêt, utilisez virtctl pour connecter le disque en direct. L'argument –persist garantit que l'association de ce disque est écrite définitivement dans la configuration YAML de la VM (survivant aux reboots et aux migrations) :
virtctl addvolume fedora-nfs-vm --volume-name=extra-data-disk --persist -n default ==== Diagnostics Généraux d'Exploitation ==== <code bash> # Suivre l'historique complet des événements du namespace par ordre chronologique oc get events -n default --sort-by='.metadata.creationTimestamp' # Forcer l'étiquetage correct d'un nœud physique oc label node dl360g9-4 physicalworker=true --overwrite
archived-. Ils occupent de l'espace disque inutilement. Tu peux supprimer en toute sécurité tous les dossiers commençant par archived- directement depuis ton partage TrueNAS.openshift-virtualization-os-images à la main : Ces volumes NFS hébergent les sources de démarrage standard de l'opérateur (Golden Images). Si tu les effaces sur TrueNAS, OpenShift lancera instantanément des c