# Multi-instances — un moteur, N écosystèmes 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** : ``` / ├── 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** : ```bash 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) : ```bash 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) : ```bash 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 : ```python 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`](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-`, 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`](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.(10+index).0.0/16` | `10.23.0.0/16` | | Sous-réseau de zone | `10.(10+index).(15+zone).0/24` | `10.23.16.0/24` (Frontière) | | Passerelle | `…(15+zone).1` | `10.23.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 : 245 écosystèmes fédérés** (index 1 à 245), borné par l'IPv4 `10.(10+index)` (2ᵉ octet 11→255). 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`](positionnement.md). ## Voir aussi - [`meta-classe.md`](meta-classe.md) — le plan d'une instance instancie sa flotte. - [`config-proxmox.md`](config-proxmox.md) — voûte unique + cible Proxmox par instance. - [`intrants-communs.md`](intrants-communs.md) — intrants de base d'une instance.