Skip to content

Arquitetura

O Ongrid é um sistema de quatro camadas. O edge roda em todo host monitorado; o manager é a nuvem. Eles se comunicam por um tunnel outbound (o control plane) mais um caminho de upload direto auth-gated separado para telemetria (o data plane).

O modelo de 4 camadas

text
┌──────────────────────────────────────────────────────────────────┐
│ L4  Alerta / notificação                                         │
│      regras built-in + kinds custom → canais (Slack / TG / IM)   │
├──────────────────────────────────────────────────────────────────┤
│ L3  Inteligência (agent ReAct de graph-kernel)                   │
│      coordinator → specialist sub-agents → ~30 skills            │
├──────────────────────────────────────────────────────────────────┤
│ L2  Tríade de observabilidade + caminho direto do edge           │
│      Prometheus · Loki · Tempo  +  RPC push_host_metrics         │
├──────────────────────────────────────────────────────────────────┤
│ L1  Cluster (coleta de sinal)                                    │
│      ongrid-edge + plugins em cada host                          │
└──────────────────────────────────────────────────────────────────┘
  • L1 — Cluster. De onde os sinais vêm. Um ongrid-edge por host, mais seus plugins subprocess (promtail, node_exporter, process_exporter, otelcol-contrib).
  • L2 — Tríade de observabilidade. Prometheus / Loki / Tempo armazenam os sinais. Vêm no docker-compose; a mesma UI funciona contra equivalentes externos gerenciados (Grafana Cloud, Mimir, VictoriaMetrics) se você trocar a partir de Settings. Um caminho direto do edge separado carrega push_host_metrics pelo tunnel para métricas de host de baixa cardinalidade de conjunto fechado (é o que alimenta os alertas built-in de CPU / mem / disco / load mesmo antes do Prom ser configurado).
  • L3 — Inteligência. O agent ReAct de graph-kernel: coordinator decompõe a pergunta, despacha a sub-agents specialist, chama skills, sintetiza uma resposta.
  • L4 — Alertas & notificações. Regras built-in + kinds custom avaliam contra streams L2 / L1, disparam em canais (Slack, Telegram, Larksuite, DingTalk, WeCom, webhook cru).

A aposta estratégica é L1 + caminho direto L2: um único tarball, um tunnel outbound, métricas de host fluindo sem um round-trip do Prom. É o que faz a instalação de 10 minutos ser de fato 10 minutos.

Edge → frontier → manager

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


                                       Prom / Loki / Tempo /
                                       MySQL / Qdrant /
                                       SearXNG / Grafana
  • Uma conexão TCP por host. ongrid-edge disca para frontier:40012 outbound. Nada inbound. Sem port-forward, sem jumpbox, sem reverse-tunnel SaaS.
  • Multiplex Geminio. Muitos streams RPC lógicos rodam em uma conexão TCP. Bidirecional: o manager pode chamar para dentro do edge (bash, host_probe_*, query_processes) e o edge pode chamar para dentro do manager (push_host_metrics, report_register).
  • Frontier é o broker. Upstream singchia/frontier, distribuído no tarball de release. ADR-007 é a justificativa (não reimplementamos o que um broker externo já faz).
  • Manager é um único binário Go. Cerca de dez bounded contexts (edges, alerts, incidents, agent, knowledge, channels, identity, audit…), todos atrás da porta da frente do nginx.

Data plane vs control plane

Edges têm dois caminhos de egress distintos para a nuvem, por design:

text
 ┌──────── ongrid-edge ────────┐
 │                              │
 │  ┌──────── runtime ────────┐ │     ── control plane ──▶ frontier:40012
 │  │ geminio client (RPC)    │ │       (TLS-por-padrão se cert fornecido)
 │  └─────────────────────────┘ │       multiplex, bidirecional, low rate
 │                              │
 │  ┌──────── plugins ────────┐ │     ── data plane ──▶ nginx :443
 │  │ promtail   → Loki push  │ │       https POST por batch
 │  │ otelcol    → OTLP push  │ │       auth_request → manager edgeauth
 │  │ exporters  → /metrics   │ │       high rate, payloads grandes
 │  └─────────────────────────┘ │
 │                              │
 └──────────────────────────────┘

Por que o split? ADR-014. Logs + traces são de alto volume, batch grande, naturalmente HTTP. Multiplexá-los no tunnel mata o throughput sob carga. Push direto sobre nginx auth_request mantém a postura de segurança (só edges enrolled podem fazer push) mantendo o data plane rápido.

O que ainda anda pelo tunnel?

  • Métricas — atualmente ainda RPC push_host_metrics por geminio. remote_write direto de edge a Prometheus está no roadmap quando tamanhos de cluster justificarem. Até lá o volume de métrica é tolerável.
  • Todos os RPCs — query_processes, bash, query_logs_tail, host_probe_*, expand_topology, leituras de arquivo, WebShell.

Mapa de containers (docker-compose)

O que sudo ./install.sh sobe no host manager:

ContainerImagemPortas no hostPapel
ongridongrid:<version>9100 (metrics)O manager. Binário Go; API HTTP em :8080 proxiada pelo nginx.
ongrid-nginxongrid-web:<version>443, 80Terminador TLS + SPA + reverse proxy. Serve /api/*, /grafana/*, /install.sh, /edge/*.
ongrid-mysqlmysql:8.03306Todo estado operacional (edges, alerts, users, audit log, configs de canal).
ongrid-frontiersingchia/frontier:1.2.540012Broker geminio. Edges discam 40012; manager disca 40011 pela rede do compose.
ongrid-prometheusprom/prometheus:v2.54.0(nenhuma)TSDB. Recebe remote_write do manager, queries da skill query_promql.
ongrid-lokigrafana/loki:3.4.0(nenhuma)Backend de logs. Push em /loki/api/v1/push via auth-gate do nginx.
ongrid-tempografana/tempo:2.5.0(nenhuma)Backend de traces. Push OTLP em /v1/traces via auth-gate do nginx.
ongrid-grafanagrafana/grafana-oss:11.1.43000Dashboards. Embarcados como iframes sob /grafana/ no SPA.
ongrid-qdrantqdrant/qdrant(nenhuma)Vector store para a base de conhecimento.
ongrid-searxngsearxng/searxng(nenhuma)Meta-search self-hosted para a skill web_search.

Todos os serviços com estado fazem bind-mount em paths do host sob /var/lib/ongrid/, não em volumes nomeados do docker — operadores podem fazer backup e inspecionar arquivos sem ginástica de docker. Override do data root com ONGRID_DATA_DIR e o log root com ONGRID_LOG_DIR.

Manager — bounded contexts

O binário do manager é um único processo Go. Internamente é dividido em bounded contexts (cada um detém seu próprio schema de DB, suas próprias rotas HTTP, seus próprios background workers). Aproximadamente:

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│   │          │   │         │
└─────────┘   └──────────┘   └─────────┘   └──────────┘   └─────────┘

Tráfego inter-BC é por chamadas de função Go (camada biz) — não há RPC dentro do binário. O arch lint (make arch-lint) impõe a direção de dependência (cmd → service → biz → data, sem ciclos).

Edge — plugin runtime

ongrid-edge é um binário Go que supervisiona uma pequena frota de subprocessos. Cada subprocesso é um collector off-the-shelf reskinado como um "plugin":

text
ongrid-edge (PID 1)
 ├─ geminio runtime  ← control plane para frontier
 ├─ plugin: logs
 │   └─ subprocess promtail
 │       config: /etc/ongrid-edge/promtail.yaml
 │       data plane: https://<manager>/loki/api/v1/push
 ├─ plugin: traces
 │   └─ subprocess otelcol-contrib
 │       config: /etc/ongrid-edge/otelcol.yaml
 │       data plane: https://<manager>/v1/traces
 ├─ plugin: hostmetrics
 │   └─ subprocess node_exporter
 │       /metrics raspado pelo Prometheus dentro do manager
 └─ plugin: procmetrics
     └─ subprocess process_exporter

ADR-015 é a justificativa: cada collector é best-of-breed em seu próprio ecossistema; reinventá-los como libs Go é desesperançoso. Então o edge detém o contrato de runtime (entrega de config, healthcheck, captura de log, upgrade) e shell out para o trabalho de dado real.

Upgrades — stage-then-swap

ADR-024 governa upgrades de bundle inteiro. O fluxo:

  1. Operador joga edge-bundle-<arch>-<ver>.tar.gz + .sha256 em /opt/ongrid/edge/ no manager (o install.sh e o upgrade.sh do tarball de release fazem isso).
  2. Operador dispara "upgrade all edges" da UI. O manager envia MethodFetchPackage pelo tunnel.
  3. Edge baixa o bundle, verifica o sha256, faz stage dos arquivos em /var/lib/ongrid-edge/.upgrade/incoming/.
  4. Edge escreve um marker, sai limpo. systemd reinicia.
  5. Em restart, apply-pending-upgrade.sh roda como root (via ExecStartPre com +) — verifica o sha de cada arquivo, faz backup de <dest> em <dest>.previous, faz mv atômico do arquivo novo para o lugar.
  6. Se o agent novo não escreve um healthy_marker antes do próximo restart, apply-pending-upgrade.sh rolla back cada .previous automaticamente.

É por isso que um upgrade de edge é só "restart a unit" — sem rewire frágil in-process.

Onde as coisas vivem em disco

No manager:

PathO que
/opt/ongrid/Compose file, configs, certs, .env, artefatos de edge.
/opt/ongrid/.envSecrets + tunables (mode 0600).
/opt/ongrid/certs/tls.crt, tls.key para nginx. Substitua para prod.
/opt/ongrid/edge/Bundles de upgrade de edge + binários soltos por arch.
/var/lib/ongrid/Root de bind-mount para containers com estado.
/var/log/ongrid/Arquivos de log do manager e nginx.

No edge:

PathO que
/usr/local/bin/ongrid-edgeO binário do agent.
/usr/local/lib/ongrid-edge/Binários de plugin + apply-pending-upgrade.sh.
/etc/ongrid-edge/ongrid-edge.env (access/secret keys), configs de plugin.
/var/lib/ongrid-edge/.upgrade/Incoming de upgrade staged + markers.
/var/log/ongrid-edge/Captura de stdout/stderr de plugin. Journal detém logs do agent.
/etc/systemd/system/ongrid-edge.serviceUnit do Systemd.

Onde ler mais