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).
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 → ngrok → healthcheck → registre
▼
M3U96a · M3U96b · M2U64 · M4M64a · M4M64b · M4M36 · M2M32 · …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] |
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 |
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/) |
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…), ngrok (domaine réservé →
processus <app>-ngrok), 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 subscriberspour 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-ka→data/registry.json(console administration-ka.com : sites, projets Claude Code, sweep des nœuds, CLAUDE.md de l'orchestrateur multi-sites) etka2→~/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(aliasgitsrv= M1M32, cléka_guardian_ed25519autorisée). admin-ka le fait toutes les 2 min, le service launchdcom.ka.registry-syncde 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
- Activer Session à distance sur le Mac, autoriser la clé de la passerelle
(
~/.ssh/id_ed25519.pubde M1M32) et celle du laptop dans~/.ssh/authorized_keys. echo <alias> > ~/.maclustr-nodesur le nœud ; ajouter l'alias dansmld/config.py(NODES).mld discover→mld 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.pyinventaire statique, rôles, chemins, détection des runtimesmld/nodes.pydécouverte LAN, sonde ·mld/picker.pyscore/plan ·mld/deploy.pyfetch/deploy/move/healthmld/render.pyecosystem PM2 + plists ·mld/prepare.pyruntimes/bootstrap/ka-helpers ·mld/importer.pyassets/pousseur Ka (script + plist)
Pas de dépendance : Python 3 système (3.9) + ssh/rsync (GNU rsync via Homebrew sur la passerelle).