Files
orca-platform/clusters/README.md
T
sharang 6be727d404
ci / shared (push) Successful in 9s
ci / validate (push) Successful in 4s
refactor(iac): cluster split — 1 cluster per plane, breakpilot-* naming (#6)
3 Orca clusters (breakpilot-edge / breakpilot-control / breakpilot-app), 1 plane each. Single-VM core with Keycloak co-tenant on vm-edge. App cluster gets prod + stage VMs. Manifests reorganized into clusters/<name>/services/; validator now enforces per-cluster node whitelist. Multi-VM rollout gated on legal entity.
2026-06-30 20:30:14 +00:00

3.9 KiB

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/ platform/breakpilot-edge vm-edge (1) Identity + Infra
breakpilot-control/ platform/breakpilot-control vm-control (1) Control
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:

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]