Set-OPS-Public/docs/implanter-un-tenant-sur-un-site.md
Daniel Allaire 3445ccb836 portee : les trois devis d'un site partagent enfin la meme regle
Le commit du 2026-08-14 nommait lui-meme ce qui restait : « meme hypothese ailleurs, non
corrigee — devis_sdn et devis_reseau partent du meme decouvrir(). A traiter quand ils
serviront sur un second site. » C'est fait AVANT, pas pendant la visite.

Les trois devis equipent le MATERIEL d'un site : la frontiere (regles, routes), le
commutateur (VLAN, SVI, routes) et le SDN de l'hyperviseur (zones, VNets). Un tenant
d'ailleurs y ajoutait des objets que le materiel accepte, qui ne correspondent jamais a
rien, et que rien ne signale.

UNE SEULE FONCTION AU LIEU D'UN FILTRE RECOPIE TROIS FOIS :
`devis_reseau.decouvrir_du_site()` = decouvrir() restreint par `underlay.tenants`, la
doctrine ecrite une fois. Le filtre inline de devis_opnsense est retire au profit d'elle.
`admin_tous_tenants()` la suit : le routeur d'un site n'a pas a savoir revenir vers le
plan de gestion d'un tenant qu'il ne porte pas.

EPROUVE dans les trois situations : underlay sans la cle -> les deux tenants, comme avant ;
underlay du second site -> OPS-Technolibre seul ; nom declare qu'aucun dossier ne fournit
-> ATTENTION et le reste est retenu ; filtre qui ne retient rien -> refus, code 1.

SANS EFFET SUR LE SITE ACTUEL : l'underlay de Chezlepro ne declare pas `tenants`, et cle
absente = toute la federation (verifie : decouvrir() et decouvrir_du_site() rendent la
meme liste ici).

ET LA CLE EST ENFIN DOCUMENTEE — c'etait le vrai trou. `underlay.tenants` existait depuis
le 14 sans figurer ni dans underlay.yml.example ni dans l'annexe du runbook
d'implantation : indecouvrable pour qui monte un second site.

prouver 37 OK, 0 echec, 0 saute ; make test inchange.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-18 16:38:30 -04:00

13 KiB

Implanter un tenant sur un site hébergeur neuf

Pour qui : l'exploitant, sur place, le jour de l'intervention. Le tenant existe déjà (son plan est écrit, éprouvé) ; le site, lui, n'a jamais rien porté. Rien à migrer, rien à interrompre.

Trois documents voisins, à ne pas confondre :

Situation Document
L'hébergeur prépare son matériel, avant qu'on arrive preparer-un-site-hebergeur.md
Un tenant vivant change d'hébergeur, sans coupure migration-tenant.md
Ce document — un tenant existant prend corps sur un site vierge (ici)

La règle qui commande tout l'ordre

Rien n'est fait tant que ce n'est pas mesuré sur place. Une valeur transmise par courriel, une liste relevée dans l'interface web, un vmbr cité de mémoire : chacun de ces trois a déjà produit une panne dans ce dépôt. Chaque phase ci-dessous se termine donc par une commande qui interroge le système, jamais par une conviction.

Le piège qui revient le plus souvent : le chèque vert sur un périmètre vide. Une sauvegarde qui réussit sur zéro fichier, un devis qui lit un intrant périmé, une preuve qui ne peut pas échouer. À chaque « ✅ », se demander sur quoi il a porté.


Phase 0 — au bureau, avant de partir

  • Recevoir la fiche de l'hébergeur — les huit lignes du §7 de preparer-un-site-hebergeur.md. Sans le nom exact du nœud et des stockages, la journée s'arrête à la phase 1.
  • Fixer l'index du site = l'index de son tenant. Il n'y a pas de second registre : la gestion du site est 10.<index>.0.0/24, dérivée du même seed que les zones du tenant. (Technolibre → index 23 → gestion 10.23.0.0/24.)
  • Créer le dépôt de l'hébergeur — un dossier frère, avec deux fichiers : underlay.yml et proxmox-hebergeur.yml (squelettes en annexe).
  • Emporter le gabarit modeleSetOPS sur disque (vzdump), et la procédure de fabrication en repli : procedure-template-debian13-proxmox.md.
  • Préparer la voûte de l'instance à recevoir les deux paires de secrets (hyperviseur, frontière). Jamais dans un dépôt git, jamais dans une conversation.
  • Vérifier la version de Proxmox. Tout ce dépôt a été éprouvé sur PVE 8. Sur PVE 9, traiter chaque écart comme inconnu jusqu'à mesure — en particulier le SDN EVPN et le moteur de pare-feu.

Un site neuf se construit d'emblée dans l'adressage cible — gestion en 10.<index>.0.0/24, chemins en 192.168.<vlan>.0/24 (D-77, D-78). Le site historique est encore en 10.0.x et migrera par runbooks-exploitation.md §6. Sur un site vierge, la cible ne coûte rien — et deux sites en 10.0.0.0/24 rendraient la reprise mutuelle impossible : deux plans de gestion identiques ne peuvent pas s'atteindre.


Phase 1 — reconnaissance du cluster (aucune écriture)

  • Relever le cluster par son API, pas par son interface : nœuds, stockages qui acceptent images, ponts présents.
  • Écrire proxmox-hebergeur.yml depuis ce relevé — jamais depuis une union devinée. C'est en recopiant des listes chez chaque tenant qu'elles ont divergé.
  • Décider le nom du contrôleur EVPN : EVPN00<index> (site 23 → EVPN0023). Un seul contrôleur par site sert tous ses tenants ; chaque tenant n'a que sa zone.
  • Sur un site à un seul nœud : ce nœud est aussi le nœud de sortie et la sortie primaire. Aucun pont ne peut être « partiel », et il n'y a pas de haute disponibilité — le dire à l'hébergeur plutôt que le laisser supposer.
make underlay          # affiche et valide la fabric — preuve P23
make placement-plan    # nœud, stockage, pont, gabarit : existent-ils VRAIMENT ?

placement-plan est la commande qui sauve la journée : elle confronte les quatre objets au cluster avant quarante minutes de déploiement. C'est elle qui a trouvé un pont déclaré mais disparu depuis dix jours.


Phase 2 — la frontière

  • Interfaces : WAN (noter l'IP publique) ; gestion 10.<index>.0.1/24 ; transit 192.168.40.1/24. Un point de routage porte .1 partout — invariant P23.
  • Compte ansible avec clé publique. Aucun sudo : l'outil lit et appelle l'API.
  • Clé d'API (System → Access → Users → API keys). Le secret n'est affiché qu'une fois.
  • Poser la clé dans la voûte, puis :
make frontiere-plan                        # écart, sans rien écrire
make frontiere-appliquer CONFIRMER=true    # écrit ET retire le périmé

Phase 3 — le gabarit

  • qmrestore de l'archive, puis convertir en template. Une VM ordinaire se clonerait aussi — et produirait quatorze copies d'une machine vivante.
  • Noter son VMID sur ce cluster et le porter dans le group_vars/proxmox.yml du tenant (proxmox_clone_vmid_modele).
  • Ne pas le personnaliser. Une clé d'hôte SSH, un /etc/resolv.conf figé ou un compte nominatif se recopient dans chaque clone. C'est arrivé ; il a fallu recapturer puis reconstruire.

Transférer un binaire est le geste rapide, pas le geste juste : D-76 vise à construire le gabarit depuis le dépôt. À faire une fois, pas à ériger en méthode.


Phase 4 — composer le moteur sur ce site

Les deux symlinks sont des axes indépendants (D-80) : le tenant ne sait rien de la fabric qui le porte.

  • instance → le dépôt du tenant (make instance-utiliser NOM=<dossier>)
  • underlay.yml → le fichier du site : ln -sfn ../<depot-hebergeur>/underlay.yml underlay.yml (proxmox-hebergeur.yml est trouvé par dérivation de ce symlink — rien d'autre à déclarer.)
  • Les quatre valeurs de placement du tenant, dans son inventories/*/group_vars/proxmox.yml : proxmox_clone_noeud, proxmox_clone_stockage, proxmox_clone_pont, proxmox_clone_vmid_modele.
  • Le jeton d'API de ce cluster dans la voûte de l'instance.
make instancier && make instancier-appliquer   # FORCE=1 si le plan a changé exprès
make prouver && make test
make placement-plan                            # re-mesurer : les valeurs ont changé

Phase 5 — matérialiser

  • Le SDN d'abord :
make sdn-plan                        # écart
make sdn-appliquer CONFIRMER=true    # crée ce qui manque, RETIRE ce qui est périmé
  • Puis la flotte, en une commande :
make reconstruire CONFIRMER=true

Elle enchaîne, dans cet ordre et pour de bonnes raisons :

Pourquoi cet ordre
1 make flux Sans lui, flux-genere/ est vide et le socle pose nftables en policy drop sans aucune règle. La flotte monte, SSH répond depuis l'administration, et tout le reste est mur. Trouvé le 2026-08-10 en montant un tenant depuis zéro : l'AC était debout, son port 8443 en écoute, et step ca bootstrap expirait depuis le même sous-réseau.
2 flotte-creer clone les VM manquantes ; une VM déjà présente est sautée
3 _amorcer-socle PKI et DNS complètement debout d'abord (D-71), hôte par hôte. Sinon chaque VM réclame un certificat à une autorité absente — et l'échec se lit comme un défaut du rôle, pas comme un défaut d'ordre.
4 deployer-tout le reste, par couches
  • Si les clones expirent : proxmox_clone_timeout est court sous clonage parallèle. Le relever, ou baisser PARALLELE=n.

Phase 6 — la recette (rien n'est « prêt » avant)

  • make valider — la recette sur la flotte
  • Les devis, qui interrogent le système en marche, pas le dépôt :
make certificats-plan   make identite-plan     make courriel-plan
make expositions-plan   make postgresql-plan   make devis-reseau
make frontiere-plan     make sdn-plan          make placement-plan
  • La sauvegarde emporte-t-elle quelque chose ? Compter les fichiers, pas les succès. Une sauvegarde verte sur zéro fichier a tenu six semaines ici.
  • Éprouver une restauration — runbooks-exploitation.md §5. Une sauvegarde jamais restaurée n'est pas une sauvegarde.
  • La supervision voit-elle l'unité de sauvegarde ? Sans vault_icinga_api_depot, personne ne surveille les sauvegardes — et rien ne le dit.
  • make prouver (toutes les preuves) et make test.

Ce qui n'est PAS fait en repartant

À dire à l'hébergeur, explicitement, plutôt que de le laisser supposer :

  • Le resserrement du compte d'API. Administrator le premier jour évite de courir après des 403 ; le réduire est un rôle sur mesure, dix minutes — un geste, pas une intention.
  • Le lien inter-sites, si la reprise mutuelle est prévue : il doit tenir sans qu'aucun poste soit allumé, et sa politique (allowed-ips) est l'isolation.
  • Le gabarit des deux côtés — une reprise sans gabarit chez le survivant n'est pas une reprise.
  • La voûte de l'instance conservée hors de son propre site. Les sauvegardes sont chiffrées côté client : le site d'accueil héberge du chiffré qu'il ne peut pas lire.

Annexe — les deux fichiers du site

underlay.yml — squelette d'un site à un nœud, dans l'adressage cible :

---
underlay:
  # LE SEED DU SITE — le même que celui de son tenant, et la clé qu'on oublie.
  # C'est elle qui dit au validateur que 10.<index>.0.0/16 est SON supernet, donc que
  # la bande basse lui appartient. Sans elle, `make underlay` refuse le réseau de
  # gestion en le prenant pour celui d'un AUTRE site — message déroutant, cause triviale.
  index: <index>
  # LES TENANTS QUE CE SITE PORTE — noms de dossier, pas de fantaisie. Les trois devis
  # d'équipement (frontière, commutateur, SDN) découvrent TOUTE la fédération : sans
  # cette clé, le second site se voit proposer les règles, les VLAN et les zones du
  # premier. Le matériel les accepte, aucune ne correspond jamais à un paquet, et rien
  # ne le signale. Un site UNIQUE n'a rien à déclarer ; c'est le second qui se nomme.
  tenants: [OPS-<tenant>]
  routeur: <nom-du-commutateur>     # racine du spanning-tree, pas un routeur
  # `stp` exige `routeur` : ne pas le déclarer tant qu'aucun commutateur ne l'est.
  routage_tenants: sdn              # le routage inter-zone vit sur l'hyperviseur
  mtu_overlay: 1450                 # 1450 + 50 de VXLAN = 1500 de transport
  acl_inter_tenant: false           # true seulement si le matériel sait lier une ACL à un SVI
  dialecte: cisco                   # cisco | binardat — propriété du MATÉRIEL
  stp: { mode: mstp, topologie: etoile }
  reseaux:
    - { nom: management,        vlan: 10, sous_reseau: 10.<index>.0.0/24, passerelle: 10.<index>.0.1, mtu: 1500 }
    - { nom: transit-frontiere, vlan: 40, sous_reseau: 192.168.40.0/24, passerelle_sortie: 192.168.40.1, mtu: 1500 }
    - { nom: underlay-vxlan,    vlan: 50, sous_reseau: 192.168.50.0/24, mtu: 1500 }
    # Stockage : uniquement les réseaux réellement câblés (fabric: stockage, mtu 9000).
  hotes:
    - { nom: <frontiere>, reseau: management,        ip: 10.<index>.0.1,  role: frontiere }
    - { nom: <frontiere>, reseau: transit-frontiere, ip: 192.168.40.1,    role: frontiere }
    - { nom: <noeud>,     reseau: management,        ip: 10.<index>.0.41, role: hyperviseur, via: vmbr0 }
    - { nom: <noeud>,     reseau: underlay-vxlan,    ip: 192.168.50.41,   role: hyperviseur, via: <bond> }
    - { nom: <noeud>,     reseau: transit-frontiere, ip: 192.168.40.41,   role: hyperviseur, via: <bond> }

proxmox-hebergeur.yml — rempli depuis la reconnaissance, jamais de mémoire :

---
proxmox_api_host: <noeud>
proxmox_api_port: '8006'
proxmox_api_user: ansible@pve
proxmox_validate_certs: false
proxmox_noeuds:    [<noeud>]
proxmox_stockages: [<ceux qui portent `images`>]
proxmox_ponts:     [<présents sur TOUS les nœuds>]
proxmox_sdn:
  controleur: EVPN00<index>
  asn: 65000
  noeuds_de_sortie: [<noeud>]
  sortie_primaire: <noeud>

Le MTU n'est pas un détail : à moitié configuré, le jumbo ne fonctionne pas du tout. Un MTU rogné en chemin donne le pire des symptômes — les petites requêtes passent, les grosses meurent, et rien n'est signalé. make mtu-mesurer tranche.

Voir aussi