Files
orca-platform/clusters/README.md
T
Sharang Parnerkar 8971152da0
ci / shared (pull_request) Successful in 23s
ci / validate (pull_request) Successful in 4s
refactor(iac): cluster split — 1 cluster per plane, breakpilot-* naming
Restructures the draft to reflect the 2026-06-30 cluster decision:

Three Orca clusters, each becoming its own Gitea repo at migration time:
- breakpilot-edge   → vm-edge       (Identity + Infra: KC, Gitea, Infisical, PowerDNS, Orca-Proxy)
- breakpilot-control → vm-control   (Portal, tenant-registry, ERPNext, MariaDB, Stalwart)
- breakpilot-app    → vm-app-prod + vm-app-stage (CERTifAI, compliance-*, Mongo, MinIO, Qdrant, LiteLLM)

Key model points encoded:
- Identity (Keycloak) co-tenant with Infra on vm-edge (1 VM core), per
  INFRASTRUCTURE.md §6 — heap pinned so it cannot starve PowerDNS/Infisical
- Stage and prod live in the same breakpilot-app cluster on different
  VMs. Stage authenticates via prod Keycloak under tenant.kind = "stage";
  no duplicated identity, no duplicated control plane (per §5).
- The existing CERTifAI Keycloak will be repurposed for breakpilot-edge
  rather than standing up a fresh one — same realm, same users.
- Multi-VM rollout gated on legal entity being established so we can sign
  SysEleven / Hetzner business contracts. Until then, single-VM ops
  continues via ~/workspace/orca-infra; this repo is design-only.

Mechanical changes:
- manifests/{vm-edge,vm-control,vm-data,stage}/ → clusters/{breakpilot-edge,breakpilot-control,breakpilot-app/services/{prod,stage}}/services/
- vm-data → vm-app-prod, stage → vm-app-stage in node references and headers
- overlays/{stage,prod}/overlay.toml point at the new cluster paths
- scripts/validate.sh now enforces a per-cluster node whitelist
  (breakpilot-edge → vm-edge, breakpilot-control → vm-control,
  breakpilot-app → {vm-app-prod, vm-app-stage}) instead of dir-name equality
- New READMEs at clusters/, clusters/breakpilot-edge/,
  clusters/breakpilot-control/, clusters/breakpilot-app/ documenting
  scope, SLA targets, co-tenant notes, and the future-repo split
- Top README rewritten to lead with the cluster-split decision and the
  legal-entity gate; per-milestone fill-in table re-pathed

Validation:
- make validate → 38 files OK (35 manifests + 3 overlays)
- make plan ENV=stage → 11 resolved manifests in .orca-out/stage/
- make plan ENV=prod  → 24 resolved manifests in .orca-out/prod/
2026-06-30 22:14:51 +02:00

86 lines
3.9 KiB
Markdown

# Clusters
Each subdirectory under `clusters/` is the manifest set for one Orca cluster.
At migration time each will become its own Gitea repository under
`platform/` so the cluster boundary doubles as a repository boundary.
| Subdir | Future repo | VMs | Plane |
|---|---|---|---|
| [`breakpilot-edge/`](./breakpilot-edge/) | `platform/breakpilot-edge` | `vm-edge` (1) | Identity + Infra |
| [`breakpilot-control/`](./breakpilot-control/) | `platform/breakpilot-control` | `vm-control` (1) | Control |
| [`breakpilot-app/`](./breakpilot-app/) | `platform/breakpilot-app` | `vm-app-prod` + `vm-app-stage` (2) | App (was "Data") |
## Why one cluster per plane
- **Independent failure domain.** A runaway reconcile loop in `breakpilot-app`
cannot restart Keycloak. An ERPNext migration on `breakpilot-control` does
not stall portal logins.
- **Independent backup policy.** Each cluster has its own `[backup]` block
and its own S3 bucket so RPO targets in `INFRASTRUCTURE.md §6` can be set
per plane without cross-talk.
- **Independent IaC.** Each future repo has its own CI, CODEOWNERS, and
reconcile cadence. Touching identity does not gate a portal hotfix.
- **Same Orca everywhere.** Per-node ingress (every Orca node binds 80/443
with its own ACME) means each cluster's services get A records pointing
at their own VM. No central proxy SPOF.
## Why this is still a single repo today
We hold the three-cluster design in this one staging repo until the legal
entity is established and we can sign SysEleven / Hetzner business
contracts to provision actual VMs. Until then, everything runs on the
existing single VM under `orca-infra` and these manifests are
design-only — `make validate` keeps them honest, `make apply` is a no-op
for now.
When the entity lands the migration is mechanical: split each subdir into
its own Gitea repo, point its `cluster.toml` at a real VM, run
`orca deploy`.
## VM topology after migration
```
breakpilot-edge cluster → vm-edge (Keycloak + Gitea + Infisical + PowerDNS + Orca-Proxy)
breakpilot-control cluster → vm-control (Portal + Tenant-Registry + ERPNext + MariaDB + Stalwart)
breakpilot-app cluster → vm-app-prod (CERTifAI + compliance-* + Mongo + MinIO + Qdrant + LiteLLM)
\→ vm-app-stage (slim parallel set for staging)
```
`vm-app-stage` lives in the same Orca cluster as `vm-app-prod` and points
at PROD `breakpilot-edge` Keycloak + PROD `breakpilot-control`
tenant-registry, isolated by `tenant.kind = "stage"` per
`INFRASTRUCTURE.md §5`. No duplicated identity, no duplicated control plane.
## Identity is part of the core (single VM)
The May 18 `INFRASTRUCTURE.md` had Identity (Keycloak) co-tenant with Infra
on `vm-edge`, with JVM heap pinned at 1.5 GB so it cannot starve PowerDNS
/ Infisical. That decision stands — Identity lives in `breakpilot-edge` on
the same VM as the rest of infra. We will revisit splitting Keycloak onto
its own VM only if the JVM vs. infra fight actually shows up in alerts.
## Repurposing the existing Keycloak
`benjamin_boenisch/certifai` already runs a Keycloak instance. Plan is to
**repurpose that instance into `breakpilot-edge/services/keycloak.toml`**
rather than stand up a fresh one — same realm exports, same client
configurations, same user database. Migration is a hostname swap and a
realm export/import, not a re-bootstrap.
## Adding a new service
Pick the plane, then drop the manifest into the right `services/` dir:
```bash
clusters/breakpilot-<plane>/services/<service>.toml
# breakpilot-app extras:
clusters/breakpilot-app/services/{prod,stage}/<service>.toml
```
`scripts/validate.sh` enforces:
- `placement.node` must match one of the cluster's declared VMs
(`vm-edge` / `vm-control` / `vm-app-prod` / `vm-app-stage`)
- `resources.memory` is mandatory (§8 rule 5)
- no nested `depends_on` / `extra_ports` / `cmd` / `mounts` under
`[service.placement|resources|env|volume]`