gabarit : modeleChezlepro -> modeleSetOPS, et une porte pour l'hebergeur
Le gabarit portait le nom du mauvais proprietaire. Les TROIS instances (Chezlepro, Technolibre, lab) le declaraient et pointaient deja toutes sur le MEME VMID 99998 — alors que le commentaire affirmait « chaque tenant a SON golden template ». Faux depuis longtemps, et invisible en lisant un seul fichier. Renomme sur le cluster et dans les trois instances. Le gabarit est un artefact du MOTEUR, pas d'un tenant ; le nom d'un tenant sur le gabarit d'un autre etait un piege qui n'attendait qu'un troisieme hebergeur. model_creer.py et config_proxmox.py proposaient encore modele-debian13 : alignes. Sans risque : le clonage se fait par VMID depuis le 2026-08-10, le nom ne sert plus qu'a l'affichage. NOUVELLE PORTE dans l'aiguillage : docs/preparer-un-site-hebergeur.md, pour quelqu'un qui prete son materiel sans rien connaitre de Set-OPS. Ecrit a partir du depot — VLAN et MTU d'underlay.yml, bloc par tenant de inventory_rules.supernet_de(), privileges du jeton de config-proxmox.md, dimensionnement (~460 Go, ~37 Go de RAM) mesure sur la flotte vivante. Deux avertissements y figurent parce qu'ils ont deja coute cher ici : un gabarit personnalise recopie son identite dans chaque clone, et un blocage contourne en silence se paie en heures. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
parent
f802e96b42
commit
77809477b2
6 changed files with 213 additions and 4 deletions
39
CHANGELOG.md
39
CHANGELOG.md
|
|
@ -1,5 +1,44 @@
|
||||||
# CHANGELOG — Set-OPS
|
# CHANGELOG — Set-OPS
|
||||||
|
|
||||||
|
## 2026-08-12 — `modeleSetOPS`, et une porte pour l'hébergeur
|
||||||
|
|
||||||
|
### Le gabarit portait le nom du mauvais propriétaire
|
||||||
|
|
||||||
|
`modeleChezlepro` était déclaré par les **trois** instances — Chezlepro, Technolibre et le
|
||||||
|
lab — qui pointaient déjà toutes sur le **même** VMID 99998. Le commentaire du rôle
|
||||||
|
affirmait pourtant « chaque tenant a SON golden template » : c'était faux depuis
|
||||||
|
longtemps, et personne ne pouvait le voir en lisant un seul fichier.
|
||||||
|
|
||||||
|
Renommé **`modeleSetOPS`** — sur le cluster et dans les trois instances. Le gabarit est un
|
||||||
|
artefact du **moteur**, pas d'un tenant, et le nom d'un tenant sur le gabarit d'un autre
|
||||||
|
était un piège qui n'attendait qu'un troisième hébergeur pour se refermer. Les scripts
|
||||||
|
d'amorçage (`model_creer.py`, `config_proxmox.py`) proposaient encore
|
||||||
|
`modele-debian13` : alignés eux aussi.
|
||||||
|
|
||||||
|
Sans risque : le clonage se fait **par VMID** depuis la correction du 2026-08-10 — le nom
|
||||||
|
ne sert plus qu'à l'affichage et aux vérifications. Rien n'empêche un tenant d'en désigner
|
||||||
|
un autre ; il change le champ **et** le VMID.
|
||||||
|
|
||||||
|
### Une porte de plus dans l'aiguillage : l'hébergeur
|
||||||
|
|
||||||
|
`docs/preparer-un-site-hebergeur.md` — pour quelqu'un qui **prête son matériel** sans rien
|
||||||
|
connaître de Set-OPS. Il ne décrit que ce que la machine ne peut pas deviner : le plan
|
||||||
|
d'adressage à respecter, la frontière, le stockage, l'hyperviseur, le gabarit, et la liste
|
||||||
|
exacte de ce qu'il doit transmettre en retour.
|
||||||
|
|
||||||
|
Écrit à partir du dépôt, pas de conventions générales : les VLAN et MTU viennent
|
||||||
|
d'`underlay.yml`, le bloc par tenant de `inventory_rules.supernet_de()`, les privilèges du
|
||||||
|
jeton de `config-proxmox.md`, et le dimensionnement (**~460 Go, ~37 Go de RAM pour
|
||||||
|
quatorze VM**) d'une mesure sur la flotte vivante.
|
||||||
|
|
||||||
|
Deux avertissements y sont écrits parce qu'ils ont déjà coûté cher ici : **un gabarit
|
||||||
|
personnalisé recopie son identité dans chaque clone**, et **un blocage contourné en
|
||||||
|
silence se paie en heures** — la panne est alors cherchée au mauvais endroit.
|
||||||
|
|
||||||
|
Le rôle `Administrator` sur le jeton Proxmox y est recommandé **et signalé comme tel**,
|
||||||
|
avec le minimum documenté en regard : mieux vaut un privilège large assumé et resserré
|
||||||
|
ensuite qu'un privilège serré qu'on élargit en panique au milieu d'un déploiement.
|
||||||
|
|
||||||
## 2026-08-12 — La donnée revient : restauration éprouvée, pas seulement sauvegarde
|
## 2026-08-12 — La donnée revient : restauration éprouvée, pas seulement sauvegarde
|
||||||
|
|
||||||
On savait que la donnée partait et arrivait. On ne savait pas qu'elle **revenait** — et
|
On savait que la donnée partait et arrivait. On ne savait pas qu'elle **revenait** — et
|
||||||
|
|
|
||||||
|
|
@ -6,11 +6,12 @@ Le dépôt est le **moteur** (générique, partageable). Chaque déploiement ré
|
||||||
|
|
||||||
## Par où entrer — selon ce que tu viens faire
|
## Par où entrer — selon ce que tu viens faire
|
||||||
|
|
||||||
On n'arrive pas avec un *sujet*, on arrive avec une **situation**. Il y en a quatre :
|
On n'arrive pas avec un *sujet*, on arrive avec une **situation**. Il y en a cinq :
|
||||||
|
|
||||||
| Ta situation | Ta porte |
|
| Ta situation | Ta porte |
|
||||||
|---|---|
|
|---|---|
|
||||||
| « Je veux **monter** mon écosystème sur ma grappe Proxmox » | [`QUICKSTART.md`](QUICKSTART.md) |
|
| « Je veux **monter** mon écosystème sur ma grappe Proxmox » | [`QUICKSTART.md`](QUICKSTART.md) |
|
||||||
|
| « Je **prête mon matériel** à quelqu'un qui déploiera dessus » | [`docs/preparer-un-site-hebergeur.md`](docs/preparer-un-site-hebergeur.md) |
|
||||||
| « Je viens d'**hériter** d'un écosystème déjà déployé, je dois l'exploiter » | [`wiki/Reprendre-l-écosystème.md`](wiki/Reprendre-l-%C3%A9cosyst%C3%A8me.md) |
|
| « Je viens d'**hériter** d'un écosystème déjà déployé, je dois l'exploiter » | [`wiki/Reprendre-l-écosystème.md`](wiki/Reprendre-l-%C3%A9cosyst%C3%A8me.md) |
|
||||||
| « Je dois **modifier** le moteur » | [`docs/carte-set-ops.md`](docs/carte-set-ops.md) |
|
| « Je dois **modifier** le moteur » | [`docs/carte-set-ops.md`](docs/carte-set-ops.md) |
|
||||||
| « J'**apprends** le métier » | [`wiki/Home.md`](wiki/Home.md) |
|
| « J'**apprends** le métier » | [`wiki/Home.md`](wiki/Home.md) |
|
||||||
|
|
|
||||||
|
|
@ -46,7 +46,7 @@
|
||||||
| P31 | Documentation : tout ce que le depot FAIT est nomme | — | ✅ OK | 44 scripts expliques et atteignables, 92 cibles make documentees, 54 roles avec README. |
|
| P31 | Documentation : tout ce que le depot FAIT est nomme | — | ✅ OK | 44 scripts expliques et atteignables, 92 cibles make documentees, 54 roles avec README. |
|
||||||
| P32 | Intrants exiges par les roles : tous fournis | — | ✅ OK | CONFORME : 35 exigence(s) de role, toutes satisfaites (126 cle(s) declaree(s) par l'instance). |
|
| P32 | Intrants exiges par les roles : tous fournis | — | ✅ OK | CONFORME : 35 exigence(s) de role, toutes satisfaites (126 cle(s) declaree(s) par l'instance). |
|
||||||
| P33 | Aucune collision de port entre roles co-localises | — | ✅ OK | CONFORME : 32 revendication(s) de port, aucune collision entre roles co-localises (33 groupes). |
|
| P33 | Aucune collision de port entre roles co-localises | — | ✅ OK | CONFORME : 32 revendication(s) de port, aucune collision entre roles co-localises (33 groupes). |
|
||||||
| P34 | Chaque document declare son lecteur | — | ✅ OK | 38 document(s) declarent leur lecteur (15 genere(s) exempte(s)). |
|
| P34 | Chaque document declare son lecteur | — | ✅ OK | 39 document(s) declarent leur lecteur (15 genere(s) exempte(s)). |
|
||||||
| P35 | Toute application exigeant une base en a une au plan | — | ✅ OK | 5 application(s) exigeant une base l'ont toutes (4 entree(s) au registre). |
|
| P35 | Toute application exigeant une base en a une au plan | — | ✅ OK | 5 application(s) exigeant une base l'ont toutes (4 entree(s) au registre). |
|
||||||
| P36 | Tout detenteur d'etat porte une sauvegarde | — | ✅ OK | 9 hote(s) detiennent de l'etat, tous porteurs de `client_backup` (9 groupe(s) au catalogue). |
|
| P36 | Tout detenteur d'etat porte une sauvegarde | — | ✅ OK | 9 hote(s) detiennent de l'etat, tous porteurs de `client_backup` (9 groupe(s) au catalogue). |
|
||||||
|
|
||||||
|
|
|
||||||
169
docs/preparer-un-site-hebergeur.md
Normal file
169
docs/preparer-un-site-hebergeur.md
Normal file
|
|
@ -0,0 +1,169 @@
|
||||||
|
# Préparer un site hébergeur
|
||||||
|
|
||||||
|
> **Pour qui :** l'**hébergeur** qui met son matériel à disposition — il n'a pas besoin de
|
||||||
|
> connaître Set-OPS. L'exploitant du tenant lui transmet ce document, puis relit §7 pour
|
||||||
|
> savoir ce qu'il doit recevoir en retour.
|
||||||
|
|
||||||
|
Set-OPS déploie un écosystème complet (annuaire, SSO, courriel, forge, nuage
|
||||||
|
collaboratif, supervision, sauvegardes) à partir d'un plan. Tout cet adressage se
|
||||||
|
**dérive** d'un seul chiffre — l'`index` du tenant.
|
||||||
|
|
||||||
|
Ce que la machine ne peut pas deviner, c'est le **matériel** : le câblage, le nom des
|
||||||
|
stockages, le chemin de sortie vers Internet. C'est l'objet de ce document, et c'est tout
|
||||||
|
ce qui est demandé à l'hébergeur.
|
||||||
|
|
||||||
|
## 1. Le partage des rôles
|
||||||
|
|
||||||
|
| | Décide quoi | Où ça vit |
|
||||||
|
|---|---|---|
|
||||||
|
| **Hébergeur** | réseau physique, pare-feu de bordure, stockage, hyperviseur | `underlay.yml` et `proxmox-hebergeur.yml`, dans **son** dépôt |
|
||||||
|
| **Tenant** | quels services, sur quel nœud/stockage/pont les poser | `inventories/*/group_vars/`, dans le dépôt du tenant |
|
||||||
|
|
||||||
|
Cette séparation n'est pas cosmétique. Tant que ces valeurs étaient recopiées chez chaque
|
||||||
|
tenant, elles ont **divergé** : deux inventaires contradictoires du même cluster, avec des
|
||||||
|
listes de stockages et de ponts différentes. Un hébergeur décrit son matériel **une fois**.
|
||||||
|
|
||||||
|
## 2. Le plan d'adressage — la seule chose à respecter à la lettre
|
||||||
|
|
||||||
|
| Rôle | VLAN | Sous-réseau | MTU | Qui y vit |
|
||||||
|
|---|---|---|---|---|
|
||||||
|
| Gestion | 10 | `10.0.0.0/24` | 1500 | frontière `.1`, commutateurs, OOB/IPMI, admin hyperviseur |
|
||||||
|
| Transport VXLAN | 11 | `10.0.5.0/24` | 1500 | hyperviseurs seulement |
|
||||||
|
| Stockage iSCSI | 20 | `10.0.1.0/24` | 9000 | baie ↔ hyperviseurs |
|
||||||
|
| Sortie des tenants | 40 | `10.0.4.0/24` | 1500 | frontière `.1`, nœuds de sortie |
|
||||||
|
|
||||||
|
Deux invariants portés par la preuve `P23` :
|
||||||
|
|
||||||
|
- **Un point de routage porte le même dernier octet partout** : `.1`. La passerelle d'un
|
||||||
|
sous-réseau garde cette adresse, quel que soit l'équipement qui l'assure.
|
||||||
|
- **Chaque tenant occupe `10.(10+index).0.0/16`.** Index 11 → `10.21.0.0/16`, index 17 →
|
||||||
|
`10.27.0.0/16`. Aucun réseau de l'hébergeur ne doit chevaucher ces blocs : le symptôme
|
||||||
|
d'une collision est un service qui « ne répond pas » sans aucune erreur nulle part.
|
||||||
|
|
||||||
|
### Le MTU n'est pas un détail
|
||||||
|
|
||||||
|
Le trafic des VM voyage encapsulé en VXLAN, ce qui coûte **50 octets**. Avec un transport
|
||||||
|
à 1500, les VM tournent à **1450** — automatiquement, mais à condition que 1500 passe
|
||||||
|
réellement de bout en bout sur les VLAN 11 et 40. Un MTU rogné en chemin donne le pire des
|
||||||
|
symptômes : les petites requêtes passent, les grosses meurent, et rien n'est signalé.
|
||||||
|
|
||||||
|
Le jumbo (9000) sur le stockage est facultatif. **À moitié configuré, il ne fonctionne
|
||||||
|
pas du tout** — mieux vaut rester à 1500 que le poser sur un seul des trois maillons.
|
||||||
|
|
||||||
|
## 3. La frontière (pare-feu de bordure)
|
||||||
|
|
||||||
|
C'est le seul équipement qui route, et l'unique point de passage entre l'extérieur et
|
||||||
|
l'intérieur. Set-OPS **pilote ses règles par API** : le boîtier reste à l'hébergeur, rien
|
||||||
|
n'y est installé.
|
||||||
|
|
||||||
|
**Interfaces :** le WAN (noter l'IP publique) ; la gestion en `10.0.0.1/24` ; le transit
|
||||||
|
en `10.0.4.1/24`, par où sortent les machines du tenant.
|
||||||
|
|
||||||
|
**Un compte pour l'exploitant :** un utilisateur `ansible` avec sa clé publique.
|
||||||
|
**Aucun `sudo` n'est nécessaire** — l'outil lit et appelle l'API. Un compte qui ne peut
|
||||||
|
pas devenir root ne peut pas casser le pare-feu par accident.
|
||||||
|
|
||||||
|
**Une clé d'API :** sur OPNsense, *System → Access → Users → `ansible` → API keys → « + »*.
|
||||||
|
Le **secret n'est affiché qu'une seule fois**.
|
||||||
|
|
||||||
|
## 4. Le stockage
|
||||||
|
|
||||||
|
Rien de spécifique à Set-OPS : il faut que l'hyperviseur puisse y poser des disques de VM
|
||||||
|
(NFS ou iSCSI). Seuls comptent les stockages qui acceptent le contenu **`images`**.
|
||||||
|
|
||||||
|
**Dimensionnement**, mesuré sur un écosystème complet de quatorze machines :
|
||||||
|
|
||||||
|
| | Mesuré | À prévoir |
|
||||||
|
|---|---|---|
|
||||||
|
| Disques provisionnés | ~460 Go | 600 Go |
|
||||||
|
| RAM allouée | ~37 Go | 48 Go (32 à la rigueur, en démarrant par vagues) |
|
||||||
|
|
||||||
|
## 5. L'hyperviseur (Proxmox VE)
|
||||||
|
|
||||||
|
**À noter et transmettre :** le **nom exact du nœud** tel qu'il apparaît dans l'interface,
|
||||||
|
les **noms exacts** des stockages, et les **ponts** (`vmbrN`). Pas les descriptions : les
|
||||||
|
noms, tels qu'ils seront lus par l'API.
|
||||||
|
|
||||||
|
Sur un cluster de plusieurs nœuds, un pont doit exister **sur tous** — un pont partiel est
|
||||||
|
un piège : la VM ne démarre que sur certains nœuds, et l'erreur ne le dit pas.
|
||||||
|
|
||||||
|
**Le SDN n'est pas à configurer par l'hébergeur.** Set-OPS crée le contrôleur EVPN, la
|
||||||
|
zone (un VRF par tenant) et les réseaux. Il faut seulement que le SDN soit disponible et
|
||||||
|
le VLAN de transport en place.
|
||||||
|
|
||||||
|
### Le compte d'API
|
||||||
|
|
||||||
|
```
|
||||||
|
pveum user add ansible@pve
|
||||||
|
pveum aclmod / -user ansible@pve -role Administrator
|
||||||
|
pveum user token add ansible@pve set-ops --privsep 0
|
||||||
|
```
|
||||||
|
|
||||||
|
Le **Token ID** et le **secret** sont à noter — le secret n'est affiché qu'une fois.
|
||||||
|
|
||||||
|
> **Sur `Administrator`, autant le dire franchement.** Le minimum documenté est
|
||||||
|
> `VM.Allocate`, `VM.Clone`, `VM.Config.*`, `Datastore.AllocateSpace` et les droits SDN.
|
||||||
|
> Mais l'outil crée aussi des objets réseau et détruit des VM : partir large le premier
|
||||||
|
> jour évite de courir après des `403` pendant le déploiement. **Le resserrer ensuite est
|
||||||
|
> un rôle sur mesure, dix minutes** — et c'est un geste à faire, pas une intention.
|
||||||
|
|
||||||
|
## 6. Le gabarit — et le piège qu'il porte
|
||||||
|
|
||||||
|
Toutes les VM sont clonées depuis un même modèle Debian, nommé **`modeleSetOPS`** : c'est
|
||||||
|
un artefact du **moteur**, pas d'un tenant. Une VM Debian minimale avec
|
||||||
|
`qemu-guest-agent` et `cloud-init`, convertie en template, suffit.
|
||||||
|
|
||||||
|
> **Ne pas le personnaliser.** Un gabarit qui porte une clé privée d'hôte SSH, un
|
||||||
|
> `/etc/resolv.conf` figé ou un compte nominatif recopie tout cela dans **chaque** clone.
|
||||||
|
> C'est arrivé, et il a fallu recapturer le gabarit puis reconstruire pour s'en défaire.
|
||||||
|
|
||||||
|
En cas de doute, laisser l'exploitant le fabriquer : c'est une demi-heure, et la procédure
|
||||||
|
est écrite (`docs/procedure-template-debian13-proxmox.md`).
|
||||||
|
|
||||||
|
## 7. Ce que l'exploitant doit recevoir
|
||||||
|
|
||||||
|
| Élément | Exemple |
|
||||||
|
|---|---|
|
||||||
|
| IP publique (WAN) | `203.0.113.10` |
|
||||||
|
| Nom du nœud hyperviseur | `asgard` |
|
||||||
|
| Stockages (noms exacts) | `TrueNAS`, `local-lvm` |
|
||||||
|
| Ponts | `vmbr0`, `vmbr3` |
|
||||||
|
| RAM et disque disponibles | 64 Go / 2 To |
|
||||||
|
| Modèle du commutateur | dicte le dialecte de CLI (`cisco` \| `binardat`) |
|
||||||
|
| Domaine public prévu | `exemple.ca` |
|
||||||
|
| Gabarit | fait, ou à faire |
|
||||||
|
| Accès | sur place, ou VPN débouchant sur le VLAN 10 |
|
||||||
|
|
||||||
|
**Et deux paires de secrets**, par un canal chiffré et séparément du reste : le Token ID +
|
||||||
|
secret de l'hyperviseur, la clé + secret de l'API de la frontière. Ils n'entrent **jamais**
|
||||||
|
dans un dépôt git : leur place est la voûte chiffrée de l'instance.
|
||||||
|
|
||||||
|
### Les accès réseau nécessaires
|
||||||
|
|
||||||
|
| Cible | Port | Pour quoi |
|
||||||
|
|---|---|---|
|
||||||
|
| Hyperviseur | 8006 | créer et détruire les VM |
|
||||||
|
| Frontière | 443 | poser les règles par API |
|
||||||
|
| Frontière | 22 | SSH, compte `ansible` |
|
||||||
|
| Réseau du tenant | 22 | SSH vers les VM une fois créées |
|
||||||
|
|
||||||
|
Les VM ont besoin de sortir sur Internet pour leurs paquets système. Le reste — les
|
||||||
|
artefacts applicatifs — est **poussé depuis le poste de l'exploitant**, pas téléchargé par
|
||||||
|
les machines.
|
||||||
|
|
||||||
|
## 8. Ce qu'il ne faut pas faire
|
||||||
|
|
||||||
|
- **Ne pas créer de VM à la main** pour le tenant. Elles sont toutes dérivées du plan ;
|
||||||
|
une VM créée à côté est invisible pour l'outil, qui la détruira sans le savoir.
|
||||||
|
- **Ne pas configurer le SDN** : l'outil le fait entièrement.
|
||||||
|
- **Ne pas écrire les secrets** dans un fichier partagé ni dans un dépôt git.
|
||||||
|
- **Ne pas contourner un blocage en silence.** Un point resté ouvert et *signalé* se règle
|
||||||
|
en dix minutes ; un contournement non dit se paie en heures, parce que la panne sera
|
||||||
|
cherchée au mauvais endroit.
|
||||||
|
|
||||||
|
## Voir aussi
|
||||||
|
|
||||||
|
- [`sdn-evpn.md`](sdn-evpn.md) — pourquoi une zone EVPN par tenant.
|
||||||
|
- [`config-proxmox.md`](config-proxmox.md) — les intrants côté hyperviseur, et le token.
|
||||||
|
- [`frontiere-opnsense.md`](frontiere-opnsense.md) — la frontière, hors flotte Ansible.
|
||||||
|
- [`procedure-template-debian13-proxmox.md`](procedure-template-debian13-proxmox.md) — fabriquer `modeleSetOPS`.
|
||||||
|
|
@ -53,7 +53,7 @@ VALEURS_DEFAUT = {
|
||||||
"proxmox_validate_certs": False,
|
"proxmox_validate_certs": False,
|
||||||
"proxmox_clone_noeud": "",
|
"proxmox_clone_noeud": "",
|
||||||
"proxmox_clone_vmid_modele": 9000,
|
"proxmox_clone_vmid_modele": 9000,
|
||||||
"proxmox_clone_source_nom": "modele-debian13",
|
"proxmox_clone_source_nom": "modeleSetOPS",
|
||||||
"proxmox_clone_stockage": "",
|
"proxmox_clone_stockage": "",
|
||||||
"proxmox_clone_format": "",
|
"proxmox_clone_format": "",
|
||||||
"proxmox_clone_complet": True,
|
"proxmox_clone_complet": True,
|
||||||
|
|
|
||||||
|
|
@ -163,7 +163,7 @@ def _generaliser(modele: Path, source: Path) -> None:
|
||||||
for cle in PROXMOX_A_VIDER:
|
for cle in PROXMOX_A_VIDER:
|
||||||
_sub_champ(px_f, rf'(?m)^{cle}:.*$', f'{cle}: ""')
|
_sub_champ(px_f, rf'(?m)^{cle}:.*$', f'{cle}: ""')
|
||||||
_sub_champ(px_f, r'(?m)^proxmox_clone_source_nom:.*$',
|
_sub_champ(px_f, r'(?m)^proxmox_clone_source_nom:.*$',
|
||||||
'proxmox_clone_source_nom: "modele-debian13"')
|
'proxmox_clone_source_nom: "modeleSetOPS"')
|
||||||
|
|
||||||
|
|
||||||
def creer(mode: str, nom: str, base: str | None, source: str | None, dest: str | None) -> Path:
|
def creer(mode: str, nom: str, base: str | None, source: str | None, dest: str | None) -> Path:
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue