vCenter et hôtes ESXi

Rôle

vcenter.infra.indio (VMware vCenter Server 8.0.3) est le plan de contrôle central de toute la plateforme de virtualisation Indio. Il gouverne le cluster à 2 hôtes ESXi qui porte le datastore vSAN (voir vsan.md), l'ensemble des groupes de ports du DVS (dont les segments overlay NSX, voir nsx.md), et sert de cible de placement à toute VM déployée par le module Terraform /root/vmware (indio/iac/vmware) ainsi qu'au template doré produit par /root/packer (voir packer-template.md).

Point important, déjà établi et reconfirmé dans cette page : vCenter/ESXi et la formation du cluster vSAN lui-même (2 nœuds + witness) sont hors Terraform — construits et administrés à la main via l'UI vCenter/govc. Le dépôt /root/vmware ne fait que consommer ces objets déjà existants (data sources) pour y cloner des VM.

Architecture

vCenter

Élément Valeur
FQDN vcenter.infra.indio
Produit VMware vCenter Server 8.0.3, build 25413364
Compte admin administrator@infra.indio (domaine SSO = infra.indio, pas le défaut vsphere.local)
Datacenter Datacenter
Cluster de calcul Cluster

Les 2 hôtes ESXi + le witness

Cluster vSAN à 2 nœuds, topologie standard VMware (2 hôtes de données + 1 appliance witness tierce pour le quorum) :

Hôte IP Rôle CPU RAM Version
esxi-node01.infra.indio 10.15.100.11 Nœud de données 1 Dell, Xeon Gold 6144 @3.50GHz, 16 CPU logiques 785 029 MB VMware ESXi 8.0.3, build 25429389
esxi-node02.infra.indio 10.15.100.12 Nœud de données 2 Dell, Xeon Gold 6144 @3.50GHz, 16 CPU logiques 458 113 MB VMware ESXi 8.0.3, build 25429389
witness.infra.indio Appliance witness (quorum vSAN) Objet /Datacenter/host/witness.infra.indio, hors du conteneur Cluster

Vérifié en direct (2026-07-19)

govc host.info esxi-node01.infra.indio esxi-node02.infra.indio confirme les deux hôtes connected, même build ESXi, même heure de boot (2026-07-18 09:30:4x — redémarrage coordonné récent, cohérent avec une fenêtre de maintenance/patch commune). L'écart de RAM entre les deux hôtes (785 Go vs 458 Go) est réel et observé tel quel — voir Points d'attention.

Le witness n'est pas un nœud de calcul : il ne porte aucune VM applicative, il stocke uniquement les composants "witness" (métadonnées de quorum) des objets vSAN, ce qui permet à un cluster à seulement 2 nœuds de données de survivre à la perte d'un des deux sans split-brain.

Réseau : le DVS DSwitch et ses groupes de ports

Le cluster est raccordé à un unique Distributed Virtual Switch (DSwitch), avec :

  • des groupes de ports d'infrastructure vSphere : DPortGroup-MGMT, DPortGroup-vSAN, DPortGroup-vMotion, DPortGroup-Front, DPortGroup-workload, DSwitch-DVUplinks-28 ;
  • les segments overlay NSX attachés au même DVS (un groupe de ports par segment créé côté NSX Manager, consommé ici comme cible de network_interface par les VM) : seg-admin, seg-service, seg-data, seg-supervision, seg-identite, seg-soc, seg-soc-admin, seg-proxy, seg-proxy-dns, seg-storage, seg-sauvegarde, seg-t0-uplink, seg-edge-uplinks — détail complet (CIDR, DHCP, rôle) dans nsx.md.

dvportgroup-2002 = seg-storage (vérifié par govc find/object.collect) : c'est ce groupe de ports que consomme le vSAN File Service (voir vsan-file-service.md).

Dossiers VM (rangement par segment)

Convention posée le 2026-07-05 (voir la note "renommage" dans les autres pages) : chaque projet Terraform place ses VM dans un dossier vCenter nommé d'après le segment réseau NSX cible, pas le rôle applicatif — vsphere_folder = "seg-xxx" (valeur relative, le provider vsphere préfixe lui-même /Datacenter/vm/).

Constaté en direct (govc ls /Datacenter/vm) : dossiers seg-supervision, seg-proxy-dns, seg-data, seg-service, seg-identite, seg-soc, seg-proxy présents, plus Templates, Admin, ESX Agents (VM système, voir vsan-file-service.md) et veeam (VM Veeam existantes, hors IaC). D'autres objets à la racine (nutanix, haproxy-v0.2.0, nsx, vCLS, VMware vCenter Server, Discovered virtual machine) ne relèvent pas de ce module et sont hors périmètre de cette page.

Comptes de service vCenter

Quatre comptes de service AD dédiés à l'automatisation, tous assignés au même rôle custom svc-vm-automation au niveau /Datacenter (propagate = Yes) :

Compte Consommateur
svc-packer@infra.indio /root/packer (build du template)
svc-terraform@infra.indio Modules Terraform (dont /root/vmware)
svc-veeam@infra.indio Sauvegarde Veeam (hors IaC)
svc-horizon@infra.indio Horizon (hors IaC)

Vérifié en direct (2026-07-19)

govc permissions.ls /Datacenter confirme les 4 comptes liés au rôle svc-vm-automation avec propagate=Yes. govc role.ls svc-vm-automation confirme la présence du privilège VirtualMachine.Interact.PutUsbScanCodes (voir Points d'attention) au milieu d'un ensemble classique de privilèges VirtualMachine.*/Datastore.*/Resource.*/Network.Assign — un rôle taillé pour cloner, configurer et piloter des VM, rien de plus large (pas de droit sur les hôtes, le cluster ou le réseau physique).

Schéma — topologie du cluster

flowchart TD
    subgraph VC["vCenter Server 8.0.3 (vcenter.infra.indio)"]
        DC["Datacenter"]
    end
    DC --> CL["Cluster (vSAN 2 nœuds)"]
    DC --> WIT["witness.infra.indio<br/>(hors conteneur Cluster)"]
    CL --> N1["esxi-node01.infra.indio<br/>10.15.100.11 · 785 Go RAM"]
    CL --> N2["esxi-node02.infra.indio<br/>10.15.100.12 · 458 Go RAM"]
    N1 & N2 --> DVS["DVS DSwitch"]
    DVS --> PG1["DPortGroup-MGMT / vSAN / vMotion / Front / workload"]
    DVS --> PG2["Segments overlay NSX<br/>(seg-admin, seg-service, seg-storage, ...)"]
    N1 & N2 -.contribuent des disques.-> VSAN[("vsanDatastore")]
    WIT -.quorum uniquement, pas de données.-> VSAN

    style WIT stroke-dasharray: 5 5

Schéma — du template au clonage (module /root/vmware)

sequenceDiagram
    participant TF as Terraform (/root/vmware)
    participant VC as vCenter
    participant VM as VM clonée

    TF->>VC: data sources (datacenter, cluster,<br/>datastore, network, template)
    TF->>VC: vsphere_virtual_machine.vm (clone du template)
    VC->>VM: clone + customize (hostname, IP statique, DNS)
    VM-->>VM: 1er boot (config réseau appliquée)
    TF->>VM: provisioner file (add_disk_lvm.sh + mdp sudo temporaire)
    TF->>VM: provisioner remote-exec (user applicatif, LVM, cleanup)
    Note over VM: Baseline OS déjà présente (RPM indio-baseline-config,<br/>voir baseline-config.md) — héritée du template, pas de ce module

Structure du dépôt /root/vmware

vmware/
├── versions.tf               # provider vsphere >= 2.6.0, terraform >= 1.5.0
├── variables.tf              # connexion vCenter, placement, définition VM, réseau, disque, SSH
├── main.tf                   # data sources + resource vsphere_virtual_machine
├── outputs.tf                # vm_name, vm_ip, vm_uuid, data_disk, app_user
├── terraform.tfvars.example  # à copier en terraform.tfvars (secrets réels, jamais commité)
└── scripts/
    └── add_disk_lvm.sh       # PV/VG/LV + montage fstab durci, exécuté par un provisioner

Le dépôt déclare une seule VM par état (pas de for_each/map sur une liste de nœuds) : c'est un module générique, destiné à être dupliqué ou paramétré par projet consommateur plutôt qu'à décrire toute la flotte dans un seul état.

Provisioning Terraform

main.tf s'articule en deux parties :

  • Data sources : vsphere_datacenter, vsphere_compute_cluster, vsphere_datastore, vsphere_network, vsphere_virtual_machine (le template tmpl-rocky96-hardened). Aucune de ces ressources n'est créée par ce module — uniquement lue. C'est le mécanisme technique qui matérialise la règle "ce module ne provisionne pas le cluster" : toute tentative de déployer sans que ces objets existent déjà échoue au plan.
  • Resource vsphere_virtual_machine.vm :
  • Clone du template (clone.template_uuid) ; CPU/RAM/firmware/scsi_type définis par variable, disque système hérité du template (taille, thin provisioning, eager scrub copiés depuis les données du template via la data source).
  • Disque de données optionnel (dynamic "disk", piloté par var.add_data_disk, unit_number = 1).
  • clone.customize : hostname, domaine, IP statique, masque, passerelle et serveurs DNS pour la VM — customization VMware Tools au clonage, c'est ce bloc qui pose une IP différente de l'IP figée du template au build (voir packer-template.md).
  • lifecycle.ignore_changes sur annotation, clone[0].template_uuid et disk[0].io_share_count — évite un diff/redéploiement accidentel si le template doré change de version (nouveau build Packer) ou si l'annotation vSphere est modifiée manuellement.

Variables principales (variables.tf) : connexion vCenter (vsphere_server/user/password marquée sensitive, vsphere_insecure), placement (vsphere_datacenter/cluster/datastore/ network/folder), caractéristiques VM (vm_cpu défaut 2, vm_ram défaut 4096 Mo), réseau (vm_ip, vm_netmask, vm_gateway, vm_dns), utilisateur applicatif (app_user, app_user_pubkey, app_user_sudo), disque de données (add_data_disk, data_disk_size_gb défaut 50, data_lvm_vg/data_lvm_lv/data_mount_point/data_fs_type), et accès SSH pour les provisioners (ssh_username défaut indio-adm, ssh_password marquée sensitive).

outputs.tf expose vm_name, vm_ip, vm_uuid, un résumé du disque de données (data_disk) et app_user.

Configuration Ansible

Ce dépôt n'utilise pas Ansible. Le provisioning post-clonage est fait directement par des provisioners Terraform natifs, exécutés en SSH juste après la customization :

  1. provisioner "file" (×2) : dépose scripts/add_disk_lvm.sh sur la VM, puis le mot de passe sudo dans un fichier temporaire /tmp/.tf_sudo_pass (permissions 600) plutôt qu'en argument de commande — il n'apparaît donc ni dans les logs Terraform/CI ni dans la table des processus (ps) de la VM.
  2. provisioner "remote-exec" : chmod 600 sur le fichier de mot de passe, création idempotente de l'utilisateur applicatif (id ... || useradd), ajout au groupe wheel si app_user_sudo, dépôt de la clé publique SSH si app_user_pubkey est fournie, exécution de add_disk_lvm.sh si add_data_disk, puis suppression des fichiers temporaires.

scripts/add_disk_lvm.sh : rescanne les hôtes SCSI, détecte le premier disque sans partition ni PV LVM existant, crée PV/VG/LV, formate (XFS par défaut), monte sur le point demandé avec des options durcies (nodev,nosuid), et ajoute une entrée /etc/fstab idempotente basée sur l'UUID du volume. Idempotent : si aucun disque libre n'est trouvé mais que le LV attendu existe déjà, il vérifie seulement le montage.

La configuration OS plus large de la flotte (comptes, proxy, DNS, dépôts internes, NTP) est prise en charge en amont par le template Packer et en aval par /root/baseline (Ansible) — voir baseline-config.md. Ce module ne s'occupe que du strict nécessaire au placement/réseau/disque de données.

Procédure manuelle

Le cluster vSAN (hôtes + witness) et le rangement vCenter sont construits/maintenus hors Terraform. Aucun log détaillé pas-à-pas de la construction initiale du cluster n'a été conservé ; les procédures ci-dessous sont soit des runbooks déjà exécutés et vérifiés (2, 3, 4), soit la méthode standard VMware reproductible pour reconstruire l'élément concerné (1) — cohérente avec la topologie réellement observée dans cette page.

1. Formation du cluster vSAN à 2 nœuds + witness (procédure standard VMware, à suivre en cas de reconstruction complète — pas un journal vérifié de l'exécution initiale) :

  1. Créer le cluster dans le Datacenter, y ajouter esxi-node01/esxi-node02.
  2. Activer vSAN sur le cluster en topologie 2 nœuds (pas stretched, pas de fault domain custom).
  3. Déployer l'appliance witness (OVA VMware fourni) sur un site/hyperviseur tiers, la configurer avec son propre réseau de management, puis la désigner comme witness du cluster depuis l'assistant vSAN.
  4. Réclamer les disques de chaque hôte en groupes de disques (cache tier + capacity tier).
  5. Vérifier vSAN Health (Skyline) avant de considérer le cluster prêt à recevoir des VM.

2. Rattachement d'un hôte au DVS après un incident de préparation NSX (exécuté et vérifié le 2026-07-11, cf. nsx.md pour le contexte transport node) :

govc host.maintenance.enter -host.ip=<ip-esxi>   # laisser tourner sans annuler, peut prendre plusieurs minutes
# ... nettoyage/reconfiguration DVS interne à vSphere ...
govc dvs.add -dvs=DSwitch -pnic=vmnic1,vmnic2,vmnic3 esxi-node02.infra.indio
govc host.maintenance.exit -host.ip=<ip-esxi>

Effet de bord vérifié, pas une hypothèse

Mettre un hôte portant des VM agents système (vSAN File Service, nsx-manager, vCenter lui-même) en mode maintenance peut déclencher un nettoyage EAM qui désactive des services cluster entiers en plus d'évacuer les VM concernées. C'est exactement ce qui est arrivé au vSAN File Service ce jour-là — postmortem complet dans vsan-file-service.md. Avant toute mise en maintenance d'un hôte de ce cluster, vérifier quelles VM agents/système y tournent.

3. Rangement des VM par dossier vCenter (segment NSX) :

govc folder.create /Datacenter/vm/seg-xxx
govc object.mv /Datacenter/vm/NOM-VM /Datacenter/vm/seg-xxx

Puis déclarer vsphere_folder = "seg-xxx" (valeur relative) côté Terraform pour que les futurs clones y atterrissent directement.

4. Comptes de service et rôle svc-vm-automation : la création initiale des 4 comptes AD et du rôle custom n'est pas détaillée dans un log conservé (probablement faite via l'UI vCenter — Menu Administration > Rôles, puis Utilisateurs et groupes AD > attribution de permission sur /Datacenter). Le correctif suivant, lui, est vérifié et directement reproductible :

govc role.update -a svc-vm-automation VirtualMachine.Interact.PutUsbScanCodes

Nécessaire pour que le boot_command de Packer (voir packer-template.md) fonctionne — sans ce privilège précis (distinct de ConsoleInteract), l'injection de touches clavier via l'API échoue avec Permission to perform this operation was denied. Le rôle étant partagé par les 4 comptes, le correctif bénéficie aux quatre simultanément.

5. Bascule du template canonique : après un nouveau build Packer réussi (nom temporaire type tmpl-rocky96-hardened-v3), renommage manuel pour que tmpl-rocky96-hardened (le nom attendu par var.template_name de tous les projets Terraform consommateurs) pointe sur le nouveau build :

govc object.rename /Datacenter/vm/tmpl-rocky96-hardened tmpl-rocky96-hardened-old
govc object.rename /Datacenter/vm/tmpl-rocky96-hardened-v3 tmpl-rocky96-hardened

Grâce à lifecycle.ignore_changes sur clone[0].template_uuid (voir plus haut), cette bascule ne provoque aucun diff sur les VM déjà déployées — seuls les futurs clones héritent du nouveau template.

Procédure de déploiement

cp terraform.tfvars.example terraform.tfvars   # éditer les valeurs réelles (jamais commité)
terraform init
terraform plan
terraform apply

Le mot de passe SSH utilisé par les provisioners est celui du compte indio-adm déjà en place sur le template (hérité du build Packer, éventuellement changé depuis par une rotation fleet-wide) ; il ne doit être renseigné qu'en local dans terraform.tfvars, jamais versionné.

Pour un usage en équipe, le README recommande un backend d'état distant (ex. state Terraform géré par GitLab) plutôt que le state local actuellement utilisé — non implémenté dans ce dépôt à ce jour.

Contrôle de santé / Vérification

Commandes read-only utilisées pour vérifier cette page (2026-07-19), réutilisables comme runbook :

export GOVC_URL=https://vcenter.infra.indio GOVC_USERNAME=administrator@infra.indio \
       GOVC_PASSWORD='...' GOVC_INSECURE=1

govc about                                          # version/build vCenter
govc ls /Datacenter/host/Cluster                     # hôtes + réseaux du cluster
govc host.info esxi-node01.infra.indio esxi-node02.infra.indio   # état connected/build
govc permissions.ls /Datacenter                      # comptes de service + rôles assignés
govc role.ls svc-vm-automation                        # privilèges du rôle partagé

Résultat au moment de la vérification : les deux hôtes connected, même build ESXi (25429389), rôle svc-vm-automation bien assigné aux 4 comptes de service avec PutUsbScanCodes présent.

Points d'attention

  • Ce module ne crée pas le cluster vSAN. Le Datacenter, le Cluster (2 nœuds ESXi + witness) et vsanDatastore sont gérés hors Terraform, au niveau vSphere/ESXi. Le dépôt se contente de les référencer par data source pour y déployer des VM.
  • Asymétrie de RAM entre les deux hôtes (785 Go sur esxi-node01 contre 458 Go sur esxi-node02, observée en direct) : à vérifier si volontaire (contrainte matérielle/budget) ou à corriger — une asymétrie de capacité entre nœuds d'un cluster vSAN à 2 nœuds peut limiter la capacité de bascule complète d'un hôte vers l'autre en cas de panne.
  • Le template tmpl-rocky96-hardened est observé directement à la racine de /Datacenter/vm, pas dans le dossier Templates (qui existe mais n'est pas utilisé en pratique malgré vsphere_folder par défaut de Packer valant "Templates") — écart mineur, sans impact fonctionnel.
  • terraform.tfvars et terraform.tfstate* sont gitignorés (identifiants vCenter réels + état) : ne jamais les committer ni les recopier dans une documentation.
  • ssh_password et vsphere_password sont marquées sensitive = true côté Terraform mais restent transmises en clair aux provisioners (authentification SSH par mot de passe) — choix cohérent avec l'activation de PasswordAuthentication yes sur le template doré (voir packer-template.md), à ne pas reproduire tel quel si une politique clé-uniquement est adoptée plus tard.
  • lifecycle.ignore_changes sur clone[0].template_uuid : un changement de version du template doré n'entraîne pas de diff sur les VM déjà déployées — seuls les futurs clones héritent du nouveau template.
  • Pas de backend d'état distant configuré : un usage multi-opérateur nécessiterait de migrer le state hors du disque local.
  • Le rôle svc-vm-automation est partagé par 4 comptes (svc-packer/svc-veeam/ svc-horizon/svc-terraform) : tout ajustement de privilège (ex. le correctif PutUsbScanCodes) impacte simultanément les quatre usages, à garder en tête avant toute modification.
  • Toute mise en maintenance d'un des deux hôtes doit être précédée d'un inventaire des VM agents/système qui y tournent (nsx-manager, vCenter, vSAN File Service) — voir l'encadré danger ci-dessus et le postmortem détaillé dans vsan-file-service.md.