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 fondateur36a882bne 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 dans1295eeaet jamais chargee par Ansible. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
179 lines
9.1 KiB
Markdown
179 lines
9.1 KiB
Markdown
# 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** :
|
||
|
||
```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-<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`](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`](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.
|