SPB Git forge
29commits 1branches 0releases
684.0 KBsize
maindefault branch
2 days agolast push
Python 95.8% Shell 4.2%
ZIP tar.gz
NameLast commitUpdated
assets ngrok → MacLustr Tunnel intégré à mld ; mld heal (auto-réparation) ;... 13 days ago
bin maclustr-dispatch v1.0.0 — mld : découverte LAN, scan, picker,... 19 days ago
mld registry : résoudre l IP live du nœud avant l IP figée au déploiement... 2 days ago
.gitignore maclustr-dispatch v1.0.0 — mld : découverte LAN, scan, picker,... 19 days ago
README.md README : FileVault désactivé sur M3U96a/b, auto-login partout 13 days ago
README.md source

# maclustr-dispatch — mld

Orchestrateur de déploiement du cluster MacLustr. Il tourne sur la passerelle M1M32 et déploie chaque application sur le nœud le plus efficient du cluster, via le LAN (192.168.2.x, clé SSH maclustr-m1m32 autorisée sur tous les nœuds).

text
laptop ──ssh──▶ M1M32 (passerelle : spbgit + mld + staging ~/dispatch/stage)
                  │  scan live (RAM libre, charge, disque, ports, runtimes)
                  │  choix du nœud (score) → rsync LAN → PM2/launchd → santé locale → route MacLustr Tunnel → santé publique → registre

        M3U96a · M3U96b · M2U64 · M4M64a · M4M64b · M4M36 · M2M32 · …
                  │  wg1 (WireGuard)

        BHS64 (OVH Québec) : Caddy https://<domaine> → 10.67.0.x:<port>   ← `tunnelctl`, piloté par mld/tunnel.py

Depuis le 2026-09-10, plus aucun ngrok : l'exposition publique est une route Caddy sur la passerelle du MacLustr Tunnel (tunnel.domain dans le manifeste), que mld deploy/move repointent vers le nœud courant (rollback compris) et que mld retire supprime. mld heal (LaunchDaemon io.maclustr.mld-heal sur M1M32, toutes les 5 min) relance ce qui manque après une coupure ; mld harden rend chaque nœud capable de revenir seul (auto-login, pas de veille, MAJ off).

# Depuis le laptop

~/Desktop/cluster-skill/mld <commande> relaie à la passerelle et rapatrie le registre (cluster-skill/cluster-registry.json).

Commande Effet
mld scan / mld nodes sonde (ou relit) ressources + runtimes des nœuds
mld apps / mld show <app> manifestes et emplacement courant
mld pick <app> · mld pick --ram 4 --runtime node classement des nœuds pour une app / un besoin
mld plan [apps…] plan de placement global (glouton, projection des ressources)
mld stage <dir-local> <app> pousse un dossier du laptop dans le staging de la passerelle
mld deploy <app> [--node X] staging → nœud choisi (auto sans --node), démarrage, santé, registre
mld move <app> [--to X] [--from Y] migration : pré-copie à chaud, arrêt, delta final, déploiement, santé, retrait (rollback auto)
mld stop/start/restart <app> · mld logs <app> · mld health <app> cycle de vie
mld status [--live] · mld registry registre (~/dispatch/registry.json sur M1M32)
mld subscribers [--add app|node NOM CHEMIN] [--remove …] · mld registry --push abonnés du registre (copie poussée à chaque sauvegarde) · rediffusion manuelle
mld retire <app> arrête et efface la copie du nœud
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
mld bootstrap <nœud> Xcode CLT + Homebrew sur un Mac vierge (sudo NOPASSWD temporaire)
mld import <nœud> brouillons de manifestes depuis les PM2 vivants d'un nœud (~/dispatch/apps/_drafts/)
mld tunnel status [-g R9128] pairs WireGuard (handshake, trafic) + routes Caddy de la passerelle
mld tunnel peer <nœud>… raccorde un Mac au hub (wireguard-tools + LaunchDaemon io.maclustr.wireguard-wg1, IP fixe de /etc/maclustr-tunnel/ipmap)
mld tunnel route <app>… · mld tunnel rm <app>… (re)pointe / retire la route publique d'une app (normalement fait par deploy/retire)
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)
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

# Manifestes (~/dispatch/apps/<app>.json, mode 600)

Un manifeste décrit comment tourne une app : dir (même chemin absolu sur tous les nœuds), processes (PM2 : script, args, interpreter, cwd, env, cron_restart…), tunnel (domain, gateway BHS64|R9128, redirects apex, websocket : route publique https://domain → nœud courant:port ; l'ancien bloc ngrok est converti automatiquement et les vieux processus <app>-ngrok supprimés au start), launchd (plists générés), requires (runtimes, RAM, ports), placement (pin, prefer, avoid + raison), sync_excludes, extra_paths, env_overrides (réécriture de .env au déploiement), hooks.post_sync / post_start, ka_repo (inscription au pousseur). Gabarits : {{HOME}}, {{NODE}}, {{LAN_IP}}, {{IP:<alias>}}.

# Scoring

0.45·RAM libre après placement + 0.25·cœurs idle + 0.10·disque + 0.15·cœurs − 0.04·apps hébergées (+0.15 prefer, +0.05 si déjà sur ce nœud). Inéligible : hors ligne, rôle gateway (sauf épingle), runtime manquant, RAM libre < besoin + 2 Go, disque, port occupé (hors nœud d'origine).

# Registre = source de vérité des emplacements (consommateurs)

~/dispatch/registry.json (M1M32) est la seule référence « quelle app tourne sur quel nœud ». Personne ne code plus d'emplacement en dur : les consommateurs lisent le registre.

  • Push : à chaque sauvegarde (deploy/move/stop/start/retire), registry.save() pousse une copie atomique chez chaque abonné de ~/dispatch/subscribers.json (mld subscribers pour lister/ajouter). Un abonné {"app": X, "path": P} est résolu dans le registre lui-même (nœud + dir de X) — il suit les migrations. Abonnés au 2026-09-04 : admin-kadata/registry.json (console administration-ka.com : sites, projets Claude Code, sweep des nœuds, CLAUDE.md de l'orchestrateur multi-sites) et ka2~/ka-guardian-spool/registry.json (gardiens ka2/ka4/ka6 : nœud, dir, port, process PM2 de chaque service surveillé).
  • Pull : tout nœud peut aussi tirer ssh gitsrv cat ~/dispatch/registry.json (alias gitsrv = M1M32, clé ka_guardian_ed25519 autorisée). admin-ka le fait toutes les 2 min, le service launchd com.ka.registry-sync de M4M36 toutes les 2 min (chaîne zsh pure : macOS 26 LNP interdit le LAN aux descendants de python).
  • Champs consommés : node, ip, port, domain, dir, processes (PM2), launchd, status, updated. Garder ces noms stables.

# Ajouter un nœud

  1. Activer Session à distance sur le Mac, autoriser la clé de la passerelle (~/.ssh/id_ed25519.pub de M1M32) et celle du laptop dans ~/.ssh/authorized_keys.
  2. echo <alias> > ~/.maclustr-node sur le nœud ; ajouter l'alias dans mld/config.py (NODES).
  3. mld discovermld bootstrap <alias> (si Mac vierge) → mld prepare <alias>.

Nœud hors LAN (IP publique, autre utilisateur — ex. M1M64, Mac Studio loué, 2026-09-08) : le déclarer aussi dans REMOTE_NODES (host, user, sudo_pw_file) ; discover s'y connecte directement au lieu de balayer 192.168.2.x, ssh.target/home_of/sudo_pw_file suivent l'utilisateur du nœud. Ces nœuds sont RESERVED (pas de LAN vers les apps sœurs, pas de gardiens Ka) : déploiement seulement avec --node. Si le sshd du fournisseur a AllowUsers (ex. /etc/ssh/sshd_config.d/100-rental.conf), ajouter un fichier 000-maclustr.conf avec AllowUsers <user> (les directives se cumulent).

# Fichiers

  • mld/config.py inventaire statique, rôles, chemins, détection des runtimes
  • mld/nodes.py découverte LAN, sonde · mld/picker.py score/plan · mld/deploy.py fetch/deploy/move/health
  • mld/render.py ecosystem PM2 + plists · mld/prepare.py runtimes/bootstrap/ka-helpers · mld/importer.py
  • mld/tunnel.py MacLustr Tunnel (tunnelctl : routes, pairs) · mld/heal.py auto-réparation + LaunchDaemon · mld/harden.py résilience des nœuds
  • assets/ pousseur Ka (script + plist), wg-node-setup.sh (raccordement WireGuard d'un Mac, copie de cluster-skill/maclustr-tunnel)

# Résilience (coupure de courant, mise à jour, redémarrage)

Chaîne de retour à la vie d'un nœud : autorestart (rallumage après coupure) → boot → ouverture de session automatique (/etc/kcpassword + autoLoginUser, posés par mld harden) → LaunchAgents (pm2.<user>.plistpm2 resurrect, gardiens, pousseur) + LaunchDaemons (io.maclustr.wireguard-wg1, PM2 en daemon sur M2U64 et les nœuds loués) → apps up → route Caddy 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 par app et par heure, journal ~/dispatch/logs/heal.log, état heal-state.json). Attention : FileVault (désactivé le 2026-09-10 sur M3U96a et M3U96b via fdesetup disable -inputplist, sudo pré-authentifié) bloque le démarrage jusqu'à la saisie du mot de passe : ne jamais le réactiver sur un nœud d'apps. Les mises à jour macOS / App Store / Tailscale sont désactivées partout (une MAJ Tailscale relance tailscaled et fait disparaître le nœud de *.maclustr.io, dont les noms résolvent vers l'IP Tailscale).

Pas de dépendance : Python 3 système (3.9) + ssh/rsync (GNU rsync via Homebrew sur la passerelle).