SPB Git

README : MacLustr Tunnel, mld heal/harden/tunnel, section Résilience

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Simon-Pierre Boucher committed (Sep 10, 2026) parent 3918d4d Browse files

1 changed file +31 −5

Unified Split
modified README.md +31 −5
@@ -7,11 +7,19 @@ déploie chaque application sur le **nœud le plus efficient** du cluster, via l
7 ``` 7 ```
8 laptop ──ssh──▶ M1M32 (passerelle : spbgit + mld + staging ~/dispatch/stage) 8 laptop ──ssh──▶ M1M32 (passerelle : spbgit + mld + staging ~/dispatch/stage)
9 │ scan live (RAM libre, charge, disque, ports, runtimes) 9 │ scan live (RAM libre, charge, disque, ports, runtimes)
10− │ choix du nœud (score) → rsync LAN → PM2/launchd → ngrok → healthcheck → registre 10+ │ choix du nœud (score) → rsync LAN → PM2/launchd → santé locale → route MacLustr Tunnel → santé publique → registre
11 ▼ 11 ▼
12 M3U96a · M3U96b · M2U64 · M4M64a · M4M64b · M4M36 · M2M32 · … 12 M3U96a · M3U96b · M2U64 · M4M64a · M4M64b · M4M36 · M2M32 · …
13+ │ wg1 (WireGuard)
14+ ▼
15+ BHS64 (OVH Québec) : Caddy https://<domaine> → 10.67.0.x:<port> ← `tunnelctl`, piloté par mld/tunnel.py
13 ``` 16 ```
14 17
18+Depuis le **2026-09-10**, plus aucun ngrok : l'exposition publique est une route Caddy sur la passerelle du MacLustr Tunnel
19+(`tunnel.domain` dans le manifeste), que `mld deploy`/`move` **repointent vers le nœud courant** (rollback compris) et que
20+`mld retire` supprime. `mld heal` (LaunchDaemon `io.maclustr.mld-heal` sur M1M32, toutes les 5 min) relance ce qui manque
21+après une coupure ; `mld harden` rend chaque nœud capable de revenir seul (auto-login, pas de veille, MAJ off).
22+
15 ## Depuis le laptop 23 ## Depuis le laptop
16 24
17 `~/Desktop/cluster-skill/mld <commande>` relaie à la passerelle et rapatrie le registre 25 `~/Desktop/cluster-skill/mld <commande>` relaie à la passerelle et rapatrie le registre
@@ -30,15 +38,21 @@ laptop ──ssh──▶ M1M32 (passerelle : spbgit + mld + staging ~/dispatch/
30 | `mld status [--live]` · `mld registry` | registre (`~/dispatch/registry.json` sur M1M32) | 38 | `mld status [--live]` · `mld registry` | registre (`~/dispatch/registry.json` sur M1M32) |
31 | `mld subscribers [--add app\|node NOM CHEMIN] [--remove …]` · `mld registry --push` | abonnés du registre (copie poussée à chaque sauvegarde) · rediffusion manuelle | 39 | `mld subscribers [--add app\|node NOM CHEMIN] [--remove …]` · `mld registry --push` | abonnés du registre (copie poussée à chaque sauvegarde) · rediffusion manuelle |
32 | `mld retire <app>` | arrête et efface la copie du nœud | 40 | `mld retire <app>` | arrête et efface la copie du nœud |
33−| `mld prepare <nœud> [--ka-helpers]` | installe node/pnpm/pm2/ngrok/python via Homebrew, config ngrok, pm2 startup, marqueur ; `--ka-helpers` = pousseur Ka + alias `gitsrv` + clé autorisée sur la passerelle | 41+| `mld prepare <nœud> [--ka-helpers] [--no-tunnel] [--no-harden]` | installe node/pnpm/pm2/python via Homebrew, pm2 startup, marqueur, raccordement wg1 au tunnel, `harden` ; `--ka-helpers` = pousseur Ka + alias `gitsrv` + clé autorisée sur la passerelle |
34 | `mld bootstrap <nœud>` | Xcode CLT + Homebrew sur un Mac vierge (sudo NOPASSWD temporaire) | 42 | `mld bootstrap <nœud>` | Xcode CLT + Homebrew sur un Mac vierge (sudo NOPASSWD temporaire) |
35 | `mld import <nœud>` | brouillons de manifestes depuis les PM2 vivants d'un nœud (`~/dispatch/apps/_drafts/`) | 43 | `mld import <nœud>` | brouillons de manifestes depuis les PM2 vivants d'un nœud (`~/dispatch/apps/_drafts/`) |
44+| `mld tunnel status [-g R9128]` | pairs WireGuard (handshake, trafic) + routes Caddy de la passerelle |
45+| `mld tunnel peer <nœud>…` | raccorde un Mac au hub (wireguard-tools + LaunchDaemon `io.maclustr.wireguard-wg1`, IP fixe de `/etc/maclustr-tunnel/ipmap`) |
46+| `mld tunnel route <app>…` · `mld tunnel rm <app>…` | (re)pointe / retire la route publique d'une app (normalement fait par deploy/retire) |
47+| `mld heal [--dry-run] [--apps …] [--nodes …]` | auto-réparation : 1 SSH par nœud (PM2, launchd, wg1, HTTP local) puis resurrect/start/restart/kickstart/route ; `--install` pose le LaunchDaemon (5 min) |
48+| `mld harden <nœud>… \| --all [--autologin\|--no-autologin]` | résilience : autorestart + restartfreeze + sleep 0 + womp, MAJ macOS/App Store off, Tailscale auto-update off, auto-login (kcpassword) sauf FileVault/nœud loué, vérif pm2 startup + wg1 |
36 49
37 ## Manifestes (`~/dispatch/apps/<app>.json`, mode 600) 50 ## Manifestes (`~/dispatch/apps/<app>.json`, mode 600)
38 51
39 Un manifeste décrit *comment* tourne une app : `dir` (même chemin absolu sur tous les nœuds), 52 Un manifeste décrit *comment* tourne une app : `dir` (même chemin absolu sur tous les nœuds),
40−`processes` (PM2 : script, args, interpreter, cwd, env, cron_restart…), `ngrok` (domaine réservé → 53+`processes` (PM2 : script, args, interpreter, cwd, env, cron_restart…), `tunnel` (`domain`, `gateway`
41−processus `<app>-ngrok`), `launchd` (plists générés), `requires` (runtimes, RAM, ports), 54+BHS64|R9128, `redirects` apex, `websocket` : route publique https://domain → nœud courant:port ; l'ancien bloc `ngrok`
55+est converti automatiquement et les vieux processus `<app>-ngrok` supprimés au start), `launchd` (plists générés), `requires` (runtimes, RAM, ports),
42 `placement` (`pin`, `prefer`, `avoid` + raison), `sync_excludes`, `extra_paths`, `env_overrides` 56 `placement` (`pin`, `prefer`, `avoid` + raison), `sync_excludes`, `extra_paths`, `env_overrides`
43 (réécriture de `.env` au déploiement), `hooks.post_sync` / `post_start`, `ka_repo` (inscription au pousseur). 57 (réécriture de `.env` au déploiement), `hooks.post_sync` / `post_start`, `ka_repo` (inscription au pousseur).
44 Gabarits : `{{HOME}}`, `{{NODE}}`, `{{LAN_IP}}`, `{{IP:<alias>}}`. 58 Gabarits : `{{HOME}}`, `{{NODE}}`, `{{LAN_IP}}`, `{{IP:<alias>}}`.
@@ -87,6 +101,18 @@ fournisseur a `AllowUsers` (ex. `/etc/ssh/sshd_config.d/100-rental.conf`), ajout
87 - `mld/config.py` inventaire statique, rôles, chemins, détection des runtimes 101 - `mld/config.py` inventaire statique, rôles, chemins, détection des runtimes
88 - `mld/nodes.py` découverte LAN, sonde · `mld/picker.py` score/plan · `mld/deploy.py` fetch/deploy/move/health 102 - `mld/nodes.py` découverte LAN, sonde · `mld/picker.py` score/plan · `mld/deploy.py` fetch/deploy/move/health
89 - `mld/render.py` ecosystem PM2 + plists · `mld/prepare.py` runtimes/bootstrap/ka-helpers · `mld/importer.py` 103 - `mld/render.py` ecosystem PM2 + plists · `mld/prepare.py` runtimes/bootstrap/ka-helpers · `mld/importer.py`
90−- `assets/` pousseur Ka (script + plist) 104+- `mld/tunnel.py` MacLustr Tunnel (tunnelctl : routes, pairs) · `mld/heal.py` auto-réparation + LaunchDaemon · `mld/harden.py` résilience des nœuds
105+- `assets/` pousseur Ka (script + plist), `wg-node-setup.sh` (raccordement WireGuard d'un Mac, copie de cluster-skill/maclustr-tunnel)
106+
107+## Résilience (coupure de courant, mise à jour, redémarrage)
108+
109+Chaîne de retour à la vie d'un nœud : `autorestart` (rallumage après coupure) → boot → **ouverture de session automatique**
110+(`/etc/kcpassword` + `autoLoginUser`, posés par `mld harden`) → LaunchAgents (`pm2.<user>.plist` → `pm2 resurrect`, gardiens,
111+pousseur) + LaunchDaemons (`io.maclustr.wireguard-wg1`, PM2 en daemon sur M2U64 et les nœuds loués) → apps up → route Caddy
112+inchangée sur BHS64. Filet : `mld heal` toutes les 5 min depuis M1M32 (délai de grâce 3 min après un boot, 6 actions max
113+par app et par heure, journal `~/dispatch/logs/heal.log`, état `heal-state.json`). Limite connue : **FileVault** (M3U96a,
114+M3U96b) bloque le démarrage jusqu'à la saisie du mot de passe — aucun auto-login possible tant qu'il est actif.
115+Les mises à jour macOS / App Store / Tailscale sont désactivées partout (une MAJ Tailscale relance tailscaled et fait
116+disparaître le nœud de `*.maclustr.io`, dont les noms résolvent vers l'IP Tailscale).
91 117
92 Pas de dépendance : Python 3 système (3.9) + ssh/rsync (GNU rsync via Homebrew sur la passerelle). 118 Pas de dépendance : Python 3 système (3.9) + ssh/rsync (GNU rsync via Homebrew sur la passerelle).
93 119
Menu

Theme