Vai al contenuto

Cluster master/slave (impianti con più box)

Analisi del codice del 28/10/2026, in sola lettura. Autore di tutto il codice: Franco, tra il 15/05 e il 04/06/2026. Mai provato sul campo e senza documentazione d'uso oltre a quella nel repository.

A cosa serve

Un solo box non ha abbastanza risorse hardware per analizzare molte telecamere. Nel cluster il carico si divide su più box nello stesso impianto: un master e uno o più slave. Ogni box fa girare il proprio Frigate sulle proprie telecamere. Dall'esterno (pannello, midserver) l'impianto resta uno solo: il master coordina, e gli slave seguono.

Due modi diversi, da non confondere

Siti multi-box "vecchi" Cluster della linea stage
Dove già in produzione su alcuni impianti (numero e quali: da censire) solo nel codice, linea stage dalla 3.7.0 (15/05/2026); nessun box in prod
Come funziona ogni box è uno stack completo e indipendente (Frigate, Mosquitto, wrapper, internal_server), registrato separatamente sul midserver i box si coordinano tra loro: il master riceve i comandi e li distribuisce agli slave
Rete gli slave sono raggiungibili solo attraverso il proxy nginx del master, su una porta per nodo gli slave parlano con il master tramite un broker MQTT del cluster
Identificativo degli slave <MAC>-01, <MAC>-02 (una chiave Redis per box; in BSQ c'è solo la riga del master) <MAC>-01, <MAC>-02: stesso formato
Fonte commento di Franco in mdm_frigate_wrapper/dev_scripts/analyze_review_volume.py (classe Target) codice mdm_installation branch stage

Conseguenza pratica: gli slave dei siti vecchi non hanno un IP VPN proprio, quindi non compaiono nel database del Raspberry né nel censimento. Possono spiegare parte della differenza tra i 33 box raggiungibili e i 38 del registro Redis.

Le porte 10101–10106 del box sono un proxy verso la rete del cliente: sulla maggior parte dei box portano ad apparati locali (trombe "IP Speaker", NVR/telecamere, verificato il 28/10). Nei siti con più box servono anche a raggiungere in SSH gli slave, allo stesso IP VPN del master (guida "Procedura Nuova Installazione GANZ", p. 2: "sulla porta 22 c'è il master, gli slave avranno altre porte (10101, ecc.)").

Come si installa un impianto con più box

Script Dove Gestisce master/slave?
installer.sh servito dal midserver (mdm_mid_server/app/static/installer.sh, uguale in main, dev, refactor/v1) quello usato oggi no: chiede solo detector (Frigate o GANZ) e ambiente (prod o stage)
installer.sh del box, linea stage (mdm_installation) non servito dal midserver sì: ruolo Standalone, Master o Slave; broker MQTT del cluster; token per lo slave; poi uv run mdm node init --role ...
  • Siti multi-box di oggi: si fanno a mano. Lo slave si installa come un box normale e, al completamento della registrazione dal pannello, gli si assegna come MAC il codice <MAC>-01, dove <MAC> è il codice del master. In BSQ si registra solo il master: gli slave non hanno una riga. Il collegamento con il midserver passa dal master (sotto).
  • Cluster della linea stage: lo script con i ruoli esiste, ma va reso disponibile al posto di quello servito dal midserver, che non ha i ruoli.

Siti multi-box di oggi: come sono collegati

Spiegazione di Michele (30/10):

  • Nginx Proxy Manager è installato su tutte le macchine (preparazione-pc-ubuntu.md).
  • Sul master si creano degli stream dedicati al midserver: uno per la porta MQTT e uno per le API del midserver.
  • Sullo slave, che non ha VPN, si modifica a mano il JSON di configurazione dell'installation: gli endpoint del midserver diventano quelli del master, con le porte esposte dagli stream.

Conseguenze: - gli slave dipendono dal master anche per parlare con il midserver: se il master è fermo, lo slave è isolato; - la configurazione modificata a mano non è in nessun repository e un aggiornamento che riscrive il JSON la cancella; - porte e nome del file non sono documentati: vanno letti su un sito reale (M-11).

Cluster della linea stage: come funziona

Ruoli e configurazione

  • Ogni box ha una modalità: standalone (predefinita), master o slave (ClusterSettingsModel, app/core/db/models/db_models/cluster_settings_model.py, salvata nel database SQLite del box).
  • Impostazioni: node_id, indirizzo, porta e credenziali del broker MQTT del cluster, registration_token (segreto condiviso tra master e slave), intervalli di heartbeat (30 s), stato (60 s) e timeout (90 s).
  • Il cluster è attivo solo se la modalità non è standalone e ci sono broker e token.
  • L'IP del nodo viene preso dall'interfaccia VPN MyVPN, altrimenti dalla prima interfaccia fisica.
  • Configurazione all'installazione: installer.sh chiede il ruolo (1 Standalone, 2 Master, 3 Slave), il broker e, per lo slave, il token. Comando equivalente: uv run mdm node init --role master|slave ... (dev_scripts/commands/node.py).

Canali MQTT del cluster

Sotto mdm/cluster/v1/ (app/services/cluster_manager/transport/topics.py), con QoS 2:

Messaggio Topic Direzione
registrazione, richiesta di registrazione nodes/<node_id>/register, .../register-request slave → master
heartbeat, stato nodes/<node_id>/heartbeat, .../state slave → master
risposta alla registrazione nodes/<node_id>/register-response master → slave
sincronizzazione inserito/disinserito .../state-sync-request / -response slave ↔ master
comando a un nodo, comando a tutti nodes/<node_id>/command, broadcast/command master → slave
conferma di esecuzione nodes/<node_id>/ack slave → master

Ogni messaggio porta il registration_token: il master scarta quelli con token sbagliato.

Registrazione di uno slave

  1. Lo slave si avvia in modalità slave e pubblica la registrazione con le proprie informazioni.
  2. Il master (ClusterMasterHandler, registration/master_handler.py) controlla il token, rifiuta auto-registrazioni e nodi non slave, salva il nodo nella tabella cluster_nodes.
  3. Il master risponde con la configurazione da copiare (SlaveRegistrationExportService): impostazioni, notifiche, pianificazione degli inserimenti, controlli di salute, configurazione IO degli allarmi, configurazione di Frigate e del wrapper.
  4. Il MAC dello slave viene ricavato da quello del master: <mac_master>-01, -02… (next_slave_mac, f"{master_mac}-{slave_index:02d}"). È la stessa convenzione usata negli impianti esistenti e nei codici BSQ.
  5. Lo slave applica la configurazione (SlaveRegistrationApplyService): toglie le trombe dalla propria configurazione (le trombe restano del master) e si riavvia.
  6. Poi invia heartbeat e stato periodici. Un nodo sconosciuto che manda un heartbeat con il token giusto viene registrato automaticamente.

Comandi dal midserver

Il midserver manda il comando come sempre. Ogni box decide cosa farne in base alla propria modalità e al destinatario, indicato da mac e/o node_id nel messaggio (command/routing.py, routing_states.py):

Modalità del box Comando per sé Comando per uno slave Comando senza destinatario
standalone esegue ignora esegue
slave esegue ignora rifiuta
master esegue; se il comando è "da propagare", lo manda anche a tutti gli slave inoltra allo slave, se la politica lo permette; se è "da propagare", esegue e propaga esegue

La politica (command/policy/command_policy.py) definisce: - comandi propagati a tutti gli slave: inserimento/disinserimento, aggiornamento della pianificazione, aggiornamento del sistema, riavvio, panico, privacy mode, volume e riproduzione/stop dei suoni; - comandi inoltrabili a un singolo slave: letture di stato, informazioni, log, configurazione IO, salute, versione, snapshot, configurazione e maschere/zone di Frigate, riavvio di Frigate/wrapper, live stream, configurazione del cluster.

Il master aspetta le conferme (ack) degli slave e restituisce al midserver un esito complessivo, con l'elenco dei nodi falliti. La pianificazione automatica degli inserimenti gira solo sul master, che la propaga agli slave.

Cosa vede il midserver

  • Lo stato del master include gli slave (node_info.slaves). Il midserver v3 lo legge nel modello di stato (InstallationNodeInfoEntity) e aggiunge il node_id ai comandi (installation_command_publish_router.py).
  • Per i box sotto la versione 10.0.0, quindi anche la nuova versione, il midserver usa i topic MQTT "vecchi" condivisi da tutti i box: è il routing dentro il box a scartare i comandi non suoi.
  • API v3: GET /cluster/config/{mac} (configurazione del cluster di un box). Anche il Flask dev (2.3.0) passa il node_id in molti controller.

Cosa vede il pannello

mdm_web_panel branch dev: pagina Cluster Settings (ruolo, node ID, IP, broker, token, intervalli) e sezione Cluster Nodes nel dettaglio di un master, con gli slave come installazioni separate collegate tramite il loro MAC.

Punti deboli e rischi

  • Mai provato sul campo: il test a casa di un collega non è stato fatto e l'autore non è più in azienda.
  • Un solo segreto condiviso (registration_token) per autenticare tutto il cluster, ed è salvato in chiaro nel database del box. Con il token, qualsiasi macchina che raggiunge il broker si registra come slave e riceve la configurazione dell'impianto.
  • Il master è un punto critico: inserimenti, pianificazione e comandi agli slave passano da lui.
  • La configurazione dello slave è una copia di quella del master al momento della registrazione: le modifiche successive al master vanno ripropagate.
  • Il MAC dello slave è un valore derivato (<mac>-01), non quello della scheda di rete: attenzione a qualsiasi logica che usa il MAC come identificativo fisico.
  • I siti multi-box vecchi già in produzione non usano questo codice: passare alla nuova versione significa riconfigurarli come cluster (procedura non scritta).

Da fare

  1. Censire i siti multi-box già in produzione (T0.5): quali impianti, quanti nodi, su quali porte del proxy, con quale MAC sono registrati in Redis. Domanda per Michele (A9).
  2. Provare il cluster in laboratorio con almeno 2 box della linea stage (caso 2.13 del piano di test).
  3. Scrivere la procedura per convertire un sito multi-box vecchio in cluster della linea stage.