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

179 lines
9.1 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 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.