Skip to content

Architecture

Ongrid est un système à quatre couches. L'edge tourne sur chaque host monitoré ; le manager est le cloud. Ils communiquent sur un tunnel sortant (le plan de contrôle) plus un chemin d'upload direct auth-gaté séparé pour la télémétrie (le plan de données).

Le modèle à 4 couches

text
┌──────────────────────────────────────────────────────────────────┐
│ L4  Alerte / notification                                        │
│      règles intégrées + types personnalisés → canaux (Slack / TG / IM) │
├──────────────────────────────────────────────────────────────────┤
│ L3  Intelligence (agent ReAct graph-kernel)                      │
│      coordinator → sous-agents specialist → ~30 skills           │
├──────────────────────────────────────────────────────────────────┤
│ L2  Triade d'observabilité + chemin direct edge                  │
│      Prometheus · Loki · Tempo  +  RPC push_host_metrics         │
├──────────────────────────────────────────────────────────────────┤
│ L1  Cluster (collecte de signaux)                                │
│      ongrid-edge + plugins sur chaque host                       │
└──────────────────────────────────────────────────────────────────┘
  • L1 — Cluster. D'où viennent les signaux. Un ongrid-edge par host, plus ses plugins en sous-processus (promtail, node_exporter, process_exporter, otelcol-contrib).
  • L2 — Triade d'observabilité. Prometheus / Loki / Tempo stockent les signaux. Ils sont livrés dans le docker-compose ; la même UI fonctionne contre des équivalents managés externes (Grafana Cloud, Mimir, VictoriaMetrics) si vous les remplacez depuis Settings. Un chemin direct edge séparé porte push_host_metrics sur le tunnel pour les métriques host à cardinalité basse et ensemble fermé (c'est ce qui alimente les alertes CPU / mem / disk / load intégrées même avant que Prom soit configuré).
  • L3 — Intelligence. L'agent ReAct graph-kernel : le coordinator décompose la question, dispatche vers des sous-agents specialist, appelle des skills, synthétise une réponse.
  • L4 — Alertes & notifications. Règles intégrées + types personnalisés évaluent contre les streams L2 / L1, partent dans les canaux (Slack, Telegram, Larksuite, DingTalk, WeCom, webhook brut).

Le pari stratégique est L1 + chemin direct edge L2 : un seul tarball, un seul tunnel sortant, métriques host coulant sans aller-retour Prom. C'est ce qui fait que l'install de 10 minutes prend réellement 10 minutes.

Edge → frontier → manager

text
   host (le vôtre)               cloud (le vôtre, self-hosted)
 ┌──────────────────┐
 │ ongrid-edge      │
 │ ├─ plugins/      │           ┌─────────────────────────────┐
 │ │  promtail      │           │ frontier (broker, port 40012)│
 │ │  node_exporter │           │  · multiplex geminio         │
 │ │  process_exp.  │── un ────▶│  · auth : access/secret key  │
 │ │  otelcol       │  sortant  │  · service-end → manager     │
 │ └─ runtime       │   TCP     └──────────────┬──────────────┘
 │    geminio client│   :40012                 │ service-end (40011)
 └──────────────────┘                          ▼
                                 ┌─────────────────────────────┐
                                 │ ongrid (manager)            │
                                 │  · API http (nginx 443)     │
                                 │  · bounded contexts         │
                                 │  · runtime d'agent          │
                                 └──────────────┬──────────────┘


                                       Prom / Loki / Tempo /
                                       MySQL / Qdrant /
                                       SearXNG / Grafana
  • Une connexion TCP par host. ongrid-edge compose frontier:40012 en sortant. Rien en entrant. Pas de port-forward, pas de jumpbox, pas de SaaS de tunnel inversé.
  • Multiplex geminio. De nombreux streams RPC logiques chevauchent une seule connexion TCP. Bidirectionnel : le manager peut appeler dans l'edge (bash, host_probe_*, query_processes) et l'edge peut appeler dans le manager (push_host_metrics, report_register).
  • Frontier est le broker. Upstream singchia/frontier, livré dans le tarball de release. ADR-007 est le rationnel (on ne réimplémente pas ce qu'un broker externe fait déjà).
  • Le manager est un binaire Go unique. Une dizaine de bounded contexts (edges, alerts, incidents, agent, knowledge, channels, identity, audit…), tous derrière la porte d'entrée nginx.

Plan de données vs. plan de contrôle

Les edges ont deux chemins d'egress distincts vers le cloud, par design :

text
 ┌──────── ongrid-edge ────────┐
 │                              │
 │  ┌──────── runtime ────────┐ │     ── plan de contrôle ──▶ frontier:40012
 │  │ geminio client (RPC)    │ │       (TLS par défaut si cert fourni)
 │  └─────────────────────────┘ │       multiplex, bidirectionnel, basse cadence
 │                              │
 │  ┌──────── plugins ────────┐ │     ── plan de données ──▶ nginx :443
 │  │ promtail   → Loki push  │ │       POST https par batch
 │  │ otelcol    → OTLP push  │ │       auth_request → edgeauth manager
 │  │ exporters  → /metrics   │ │       haute cadence, gros payloads
 │  └─────────────────────────┘ │
 │                              │
 └──────────────────────────────┘

Pourquoi le découpage ? ADR-014. Logs + traces sont à haut volume, gros batch, naturellement HTTP. Les multiplexer sur le tunnel tue le débit sous charge. Le push direct sur nginx auth_request garde la posture de sécurité (seuls les edges enrôlés peuvent pousser) tout en gardant le plan de données rapide.

Qu'est-ce qui chevauche encore le tunnel ?

  • Métriques — actuellement encore RPC push_host_metrics sur geminio. Le remote_write direct de l'edge vers Prometheus est sur la roadmap une fois que les tailles de cluster le justifient. Jusque-là, le volume de métriques est tolérable.
  • Tous les RPCs — query_processes, bash, query_logs_tail, host_probe_*, expand_topology, lectures de fichiers, WebShell.

Carte des conteneurs (docker-compose)

Ce que sudo ./install.sh monte sur le host manager :

ConteneurImagePorts hostRôle
ongridongrid:<version>9100 (métriques)Le manager. Binaire Go ; API HTTP sur :8080 proxifiée par nginx.
ongrid-nginxongrid-web:<version>443, 80Terminateur TLS + SPA + reverse proxy. Sert /api/*, /grafana/*, /install.sh, /edge/*.
ongrid-mysqlmysql:8.03306Tout l'état opérationnel (edges, alertes, utilisateurs, log d'audit, configs de canaux).
ongrid-frontiersingchia/frontier:1.2.540012Broker geminio. Les edges composent 40012 ; le manager compose 40011 sur le net compose.
ongrid-prometheusprom/prometheus:v2.54.0(aucun)TSDB. Reçoit remote_write du manager, queries du skill query_promql.
ongrid-lokigrafana/loki:3.4.0(aucun)Backend de logs. Push à /loki/api/v1/push via auth-gate nginx.
ongrid-tempografana/tempo:2.5.0(aucun)Backend de traces. Push OTLP à /v1/traces via auth-gate nginx.
ongrid-grafanagrafana/grafana-oss:11.1.43000Dashboards. Embarqué comme iframes sous /grafana/ dans la SPA.
ongrid-qdrantqdrant/qdrant(aucun)Vector store pour la base de connaissances.
ongrid-searxngsearxng/searxng(aucun)Méta-recherche self-hostée pour le skill web_search.

Tous les services à état bind-mountent vers des chemins host sous /var/lib/ongrid/, pas vers des volumes docker nommés — les opérateurs peuvent sauvegarder et inspecter les fichiers sans gymnastique docker. Surchargez la racine de données avec ONGRID_DATA_DIR et la racine de logs avec ONGRID_LOG_DIR.

Manager — bounded contexts

Le binaire manager est un seul processus Go. En interne il est découpé en bounded contexts (chacun possède son propre schéma DB, ses propres routes HTTP, ses propres workers d'arrière-plan). Grosso modo :

text
┌─────────┐   ┌─────────┐   ┌─────────────┐   ┌──────────────┐
│ identity│   │ edge    │   │ alert       │   │ incident     │
│ ┌─────┐ │   │ ┌─────┐ │   │ ┌─────────┐ │   │ ┌──────────┐ │
│ │users│ │   │ │edges│ │   │ │rules    │ │   │ │incidents │ │
│ │roles│ │   │ │tnls │ │   │ │events   │ │   │ │timeline  │ │
│ │JWT  │ │   │ │keys │ │   │ │evaluator│ │   │ │investig. │ │
│ └─────┘ │   │ └─────┘ │   │ └─────────┘ │   │ └──────────┘ │
└─────────┘   └─────────┘   └─────────────┘   └──────────────┘

┌─────────┐   ┌──────────┐   ┌─────────┐   ┌──────────┐   ┌─────────┐
│ agent   │   │ knowledge│   │ channels│   │ audit    │   │ skills  │
│ kernel  │   │ vault+   │   │ slack/  │   │ events / │   │ registry│
│ + sub-  │   │ embed+   │   │ telegram│   │ chains   │   │ marketp.│
│ agents  │   │ search   │   │ /lark/dt│   │          │   │         │
└─────────┘   └──────────┘   └─────────┘   └──────────┘   └─────────┘

Le trafic inter-BC est via des appels de fonction Go (couche biz) — il n'y a pas de RPC à l'intérieur du binaire. Le lint d'archi (make arch-lint) impose la direction de dépendance (cmd → service → biz → data, pas de cycles).

Edge — runtime de plugins

ongrid-edge est un binaire Go unique qui supervise une petite flotte de sous-processus. Chaque sous-processus est un collecteur sur étagère retravaillé en « plugin » :

text
ongrid-edge (PID 1)
 ├─ runtime geminio  ← plan de contrôle vers frontier
 ├─ plugin: logs
 │   └─ sous-processus promtail
 │       config: /etc/ongrid-edge/promtail.yaml
 │       plan de données: https://<manager>/loki/api/v1/push
 ├─ plugin: traces
 │   └─ sous-processus otelcol-contrib
 │       config: /etc/ongrid-edge/otelcol.yaml
 │       plan de données: https://<manager>/v1/traces
 ├─ plugin: hostmetrics
 │   └─ sous-processus node_exporter
 │       /metrics scrapé par Prometheus à l'intérieur du manager
 └─ plugin: procmetrics
     └─ sous-processus process_exporter

ADR-015 est le rationnel : chaque collecteur est best-of-breed dans son propre écosystème ; les réinventer en libs Go est désespéré. Donc l'edge possède le contrat de runtime (livraison de config, healthcheck, capture de logs, upgrade) et shell out pour le vrai travail de données.

Upgrades — stage-then-swap

ADR-024 gouverne les upgrades de bundle entier. Le flux :

  1. L'opérateur dépose edge-bundle-<arch>-<ver>.tar.gz + .sha256 dans /opt/ongrid/edge/ sur le manager (les install.sh et upgrade.sh du tarball de release le font tous les deux).
  2. L'opérateur déclenche « upgrade all edges » depuis l'UI. Le manager envoie MethodFetchPackage sur le tunnel.
  3. L'edge télécharge le bundle, vérifie le sha256, stage les fichiers dans /var/lib/ongrid-edge/.upgrade/incoming/.
  4. L'edge écrit un marqueur, sort proprement. systemd le redémarre.
  5. Au redémarrage, apply-pending-upgrade.sh tourne comme root (via ExecStartPre avec +) — vérifie le sha de chaque fichier, sauvegarde <dest> vers <dest>.previous, mv atomiquement le nouveau fichier en place.
  6. Si le nouvel agent n'écrit pas un healthy_marker avant le redémarrage suivant, apply-pending-upgrade.sh rollback chaque .previous automatiquement.

C'est pourquoi un upgrade edge est juste « redémarrer l'unit » — pas de recâblage fragile in-process.

Où vivent les choses sur disque

Sur le manager :

CheminQuoi
/opt/ongrid/Fichier compose, configs, certs, .env, artefacts edge.
/opt/ongrid/.envSecrets + ajustables (mode 0600).
/opt/ongrid/certs/tls.crt, tls.key pour nginx. Remplacez pour la prod.
/opt/ongrid/edge/Bundles d'upgrade edge + binaires en vrac par arch.
/var/lib/ongrid/Racine de bind-mount pour les conteneurs à état.
/var/log/ongrid/Fichiers de log manager et nginx.

Sur l'edge :

CheminQuoi
/usr/local/bin/ongrid-edgeLe binaire agent.
/usr/local/lib/ongrid-edge/Binaires de plugin + apply-pending-upgrade.sh.
/etc/ongrid-edge/ongrid-edge.env (clés access/secret), configs de plugin.
/var/lib/ongrid-edge/.upgrade/Upgrade staged en entrant + marqueurs.
/var/log/ongrid-edge/Capture stdout/stderr des plugins. Le journal possède les logs d'agent.
/etc/systemd/system/ongrid-edge.serviceUnit systemd.

Où en lire plus

  • Concepts — glossaire des noms.
  • Installation serveur — le chemin docker-compose.
  • Installation edge — curl-pipe + vérification.
  • Upgradeapply-pending-upgrade.sh, invariants de bundle, rollback.
  • Plan de données de télémétrie (Référence) — endpoints exacts, auth et limites.