Set-OPS-Public/docs/multi-instances.md
Daniel Allaire 5ace6bdb95 adressage : le decalage de +10 est retire, l'index se lit dans l'adresse
supernet_de rendait 10.(10+index).0.0/16. Personne ne savait plus pourquoi : ni le
commentaire de la constante, ni le wiki, ni le commit fondateur 36a882b ne le
justifiaient. Trois endroits consultes, zero raison ecrite.

Ses deux effets constates :
  - il reservait 10.0-10.9 sous la plage tenant. Utile tant que l'underlay vivait
    la — mais D-77 l'a fait entrer dans la bande basse de son propre /16, ce qui a
    vide cette reserve de son role la veille ;
  - il eloignait le premier tenant de 10.0.0.0/16, la plage la plus repandue en
    reseau domestique. Ce risque revient donc aux index bas, et c'est ASSUME.

En echange l'index se lit directement dans l'adresse (17 -> 10.17.x.x) et le
plafond passe de 245 a 255 ecosystemes federes.

  Chezlepro (17)   10.27.0.0/16 -> 10.17.0.0/16
  Technolibre (11) 10.21.0.0/16 -> 10.11.0.0/16
  lab (1)          10.11.0.0/16 -> 10.1.0.0/16

Doc alignee : les trois pages du wiki, multi-instances.md (plafond et exemple
devenus faux arithmetiquement), sdn-evpn.md, le libelle de la GUI, la docstring
d'underlay.py, D-77, et le document de preparation d'un site hebergeur. Les
CONSTATS DE TERRAIN dates sont laisses tels quels : ce sont des mesures.

CE COMMIT NE RENUMEROTE RIEN. Il change ce que le plan DERIVE ; l'inventaire
applique porte toujours 10.27.x.x et les quatorze VM tournent dessus. Appliquer
sans reconstruire rendrait la flotte injoignable — le renumerotage est une
operation a part, a mener a froid.

Au passage, retire un debris : une copie de conflit Nextcloud de
serveur_powerdns/defaults/main.yml, IDENTIQUE a l'original, commitee par accident
dans 1295eea et jamais chargee par Ansible.

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

9.1 KiB
Raw Blame History

Multi-instances — un moteur, N écosystèmes

Pour qui : le mainteneur — la séparation entre le moteur et une instance.

Set-OPS sépare le moteur (ce dépôt : rôles, playbooks, scripts, GUI) de l'instance (un dépôt distinct : le plan d'un écosystème + son inventaire généré + ses secrets). Un seul moteur pilote autant d'instances que voulu.

« lab vs prod » n'est qu'un cas particulier : ce sont deux instances. Le même mécanisme sert un bac à sable, une production, ou les écosystèmes de plusieurs tenants — c'est le socle multi-tenant souverain.

Une instance = un écosystème autonome

Chaque instance est un dépôt séparé, monté dans le moteur par symlink (instance →). Elle possède tout ce qui lui est propre :

<instance>/
├── plan/                         ← la « méta-classe » (cf. meta-classe.md)
│   ├── nomenclature.yml          réseau, VLAN, fonctions
│   ├── serveurs.yml              VM = fonction + état + overrides
│   ├── applications.yml
│   ├── bases-donnees.yml
│   └── domaines.yml
└── inventories/principal/        ← un seul inventaire par instance
    ├── hosts.yml                 généré (make instancier-appliquer)
    └── group_vars/
        ├── all/
        │   ├── 00-instance.yml   setops_plan_dir, setops_production
        │   ├── 10-intrants.yml   identité (domaine_interne, fuseau)
        │   └── vault.yml         🔒 voûte UNIQUE de l'instance (chiffrée)
        ├── proxmox.yml           cible Proxmox de l'instance
        └── modeles_vm.yml        construction du golden template

Isolation totale entre instances : plan, inventaire, voûte, identité (domaine_interne), réseau (seed index → adressage dérivé distinct) et cible Proxmox distincts. Une instance ne peut pas toucher l'infra d'une autre.

Gérer la flotte

Une seule instance est active à la fois — celle que pointe le symlink instance. Toutes les commandes make (instancier, deployer, creer-vm, prouver…) visent l'active.

Voir la flotte — qui existe, laquelle est active (), leur index, plage VLAN, statut fédéré/local et production ; signale toute collision d'index :

make instances
★ OPS-Chezlepro      13   1131-1136   fédérée  prod
  OPS-Technolibre     2   1021-1026   fédérée
  OPS-Chezlepro-lab   1   1011-1016   local

Basculer l'active — le symlink, avec garde-fous (le dossier existe, instance est bien un symlink) :

make instance-courante                          # quelle instance est montée ?
make instance-utiliser NOM=OPS-Technolibre      # bascule (l'inventaire suit le lien)

Rien à « recharger » : l'inventaire vit dans le dépôt de l'instance, il suit le lien. Le GUI (onglet Réseau) montre la même flotte et les collisions ; la bascule reste au CLI (chirurgie de symlink, mal placée dans une interface web).

Deux réflexes. (1) Avant tout déploiement, make instance-courante : la seule vraie façon de se tromper est de déployer sur la mauvaise flotte (la colonne prod est là pour ça). (2) Un index unique par instance fédérée — make instances le crie, la preuve P21 le refuse dans le harnais, mais choisis-le distinct dès la création.

Sans toucher au symlink (utile en CI ou pour du parallèle) :

make inventaire-ui SETOPS_INSTANCE=../OPS-ClientX
# ou viser un inventaire précis :
make deployer SETOPS_INVENTAIRE=../OPS-ClientX/inventories/principal/hosts.yml HOTE=

L'inventaire est détecté de façon rétro-compatible : principal > production > lab (les anciennes instances à double inventaire continuent de marcher).

Comment le moteur découvre les instances

Par convention de disposition, pas par un registre. Il n'y a ni base de données ni fichier qui liste les instances. scripts/instances.py et scripts/devis_reseau.py font simplement :

FRERES = RACINE.parent                    # le dossier qui CONTIENT Set-OPS-public
FRERES.glob("*/plan/nomenclature.yml")    # tout dépôt frère ayant un plan

Une instance est donc un dossier : (1) frère du moteur (../OPS-Chezlepro, ../OPS-Technolibre…), (2) portant un plan/nomenclature.yml, (3) avec un index. De là : active = ce que résout le symlink instance ; fédérée = index présent et federe ≠ false. Les modèles (Set-OPS-Modeles/integral/…) sont un cran plus profond — le glob ne les attrape pas, volontairement.

Conséquence : « inscrire » une instance = la déposer à côté des autres. Rien à éditer, aucune synchronisation, donc aucune dérive « inscrite mais absente ». Le revers — la flotte étant « ce qui est là » — est qu'un simple dossier frère (le bac à sable) y apparaît : d'où le drapeau federe: false pour l'écarter du réseau convergé, et make instances + P21 pour garder un regard et un filet.

setops_production — un attribut, pas une catégorie

Le déploiement réel est permis sur toute instance (un bac à sable déploie sur son infra). Le drapeau setops_production (dans group_vars/all/) ne bloque rien : il marque la PRODUCTION pour exiger une confirmation renforcée au déploiement (badge rouge « PROD », bouton Déployer rouge, re-saisie du nom d'hôte). Une instance bac à sable met false et affiche « bac à sable ».

Créer une nouvelle instance

  1. Créer un dépôt d'instance frère de Set-OPS-public/ (ex. ../OPS-ClientX), avec la structure ci-dessus. Le plus simple : copier un modèle de exemples/modeles/ ou l'instance bac à sable comme point de départ.
  2. Régler l'identité (10-intrants.yml : domaine distinct), le réseau (nomenclature.yml : index distinct — tout l'adressage en dérive, cf. plus bas) et la cible Proxmox (proxmox.yml).
  3. Créer la voûte unique depuis le gabarit (cf. config-proxmox.md) : cp exemples/vault.exemple.yml …/group_vars/all/vault.yml puis ansible-vault encrypt.
  4. make instance-utiliser NOM=OPS-ClientX puis make instancier-appliquer, make inventaire-ui.

Multi-tenant

Chaque tenant est simplement une instance de plus. Un client = make instance-utiliser NOM=OPS-<Client>, tout son écosystème instancié par le même moteur, isolé. C'est la base concrète de la portabilité des tenants.

Garde-fou de positionnement : si le nombre d'instances explose, le besoin d'un registre (lister/choisir, IPAM, secrets centralisés) relève d'outils établis (NetBox, AWX, un coffre type Vault HashiCorp) à adopter aux seuils, pas à réimplémenter dans le moteur. Cf. positionnement.md.

Adressage fédéré : tout dérive du seed index

Pour que plusieurs écosystèmes coexistent sur une même fabric sans collision, chaque instance reçoit un index (unique champ d'adressage de plan/nomenclature.yml : index: N). Rien d'autre n'est écrit à la main — la nomenclature ne garde que le modèle (libellés de zones + placement des fonctions) ; supernet, sous-réseaux, passerelles, VLAN et VMID se dérivent (scripts/inventory_rules : supernet_de, base3_de, passerelle_de, vlan_de). Changer index rederive tout le réseau — et la preuve P20 interdit tout adressage stocké.

Ce que index dérive (modèle à 6 zones) :

Élément Formule Exemple (index 13)
Supernet 10.<index>.0.0/16 10.13.0.0/16
Sous-réseau de zone 10.<index>.(15+zone).0/24 10.13.16.0/24 (Frontière)
Passerelle …(15+zone).1 10.13.16.1
VLAN sur le trunk 1000 + index×10 + zone 1131-1136
VMID (ip-miroir) VLAN · octet-hôte · séq (9 chiffres) 113102101

Les VLAN de deux index différents ne peuvent mathématiquement pas se chevaucher (l'espacement ×10 laisse de la marge). Deux instances de même index, elles, ont les mêmes VLAN/VMID : c'est la collision que make instances et P21 attrapent.

Bacs à sable. Un bac à sable local (labo) a lui aussi un index, mais on le marque federe: false : il est alors exclu du réseau convergé (devis, make instances le montre « local »). Il garde son adressage dérivé et reste déployable sur son infra.

Plafond théorique : 255 écosystèmes fédérés (index 1 à 255), borné par l'IPv4 10.<index> (2ᵉ octet 1→255). Le décalage de +10, retiré le 2026-08-12, en confisquait dix — et surtout, il empêchait de lire l'index directement dans l'adresse. Le VLAN (≤ 4094) autorise jusqu'à 308, le VMID bien plus — c'est donc l'adressage IP qui plafonne. Au-delà d'une poignée d'instances co-localisées, confier l'allocation à un IPAM (NetBox) plutôt qu'au moteur — cf. positionnement.md.

Voir aussi