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.
8.6 KiB
orca-platform
IaC staging for the Breakpilot Platform: per-cluster Orca service manifests, per-env overlays, DNS zones, backup/restore tooling, and the make plan / make apply wrappers.
Part of the Breakpilot Platform. For the big picture see
platform/docs: Architecture · Infrastructure · Implementation Plan
What this is
The staging area for the future per-cluster Gitea repos. Every change to prod infrastructure will eventually flow through one of platform/breakpilot-{edge,control,app} — until those repos exist, every change to the design flows through this one.
Plane: Infra (design only — no live cluster yet) Owner: @sharang Status: pre-alpha — manifests reflect the 2026-06-30 cluster-split decision; real values land per the milestone schedule below
The cluster split (decided 2026-06-30)
Three Orca clusters, each becoming its own Gitea repo at migration time:
| Cluster | Future repo | VMs (steady state) | 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 |
Identity (Keycloak) is part of breakpilot-edge on the same VM as the
rest of infra — single-VM core, JVM heap pinned so it cannot starve
PowerDNS/Infisical. The Keycloak instance already running for CERTifAI
will be repurposed for breakpilot-edge rather than standing up a new
one.
Stage and prod share the same breakpilot-app cluster but live on
different VMs (vm-app-stage is a small Hetzner CX22-class box).
Same orca config, no config drift; physically isolated, no "oops touched
prod" accidents. Stage authenticates via prod Keycloak and reads tenant
config from prod tenant-registry under tenant.kind = "stage" —
no duplicated identity, no duplicated control plane.
Gate: legal entity
Multi-VM rollout is gated on the legal entity being established so we
can sign SysEleven / Hetzner business contracts. Until then, everything
runs on the existing single VM via the ~/workspace/orca-infra repo and
the manifests in this repo are design-only. make validate keeps the
design honest; make apply is a no-op for now.
When the entity lands the migration is mechanical: split each
clusters/<name>/ subdir into its own Gitea repo, point its
cluster.toml at a real VM, run orca deploy. See
clusters/README.md for the migration order.
Directory layout
.
├── clusters/ # one subdir per future cluster repo
│ ├── README.md the cluster split + migration plan
│ ├── breakpilot-edge/ Identity + Infra (vm-edge)
│ │ ├── README.md
│ │ └── services/ (8 services)
│ ├── breakpilot-control/ Control plane (vm-control)
│ │ ├── README.md
│ │ └── services/ (7 services)
│ └── breakpilot-app/ App plane (vm-app-prod + vm-app-stage)
│ ├── README.md
│ └── services/
│ ├── prod/ (9 services on vm-app-prod)
│ └── stage/ (11 services on vm-app-stage)
├── overlays/ # per-env sparse deltas
│ ├── dev/overlay.toml no-op; dev runs docker-compose per-service
│ ├── stage/overlay.toml → clusters/breakpilot-app/services/stage
│ └── prod/overlay.toml → all three clusters' prod paths
├── dns/
│ └── breakpilot.com.zone.template PowerDNS zone — body lands in M0.3
├── cluster.toml.tmpl # cluster-level template (acme_email, backup, ai)
├── scripts/
│ ├── validate.sh # `make validate` — TOML + per-cluster node check
│ ├── plan.sh # `make plan ENV=<env>` → .orca-out/<env>/
│ ├── apply.sh # `make apply ENV=<env>` (no-op until M1.2)
│ └── restore-drill.sh.template # M1.3 placeholder
├── dev/ # local docker-compose for product devs
└── Makefile # validate / plan / apply / diff / clean
scripts/validate.sh enforces that every service's placement.node
matches one of the cluster's declared VMs:
breakpilot-edge→vm-edgebreakpilot-control→vm-controlbreakpilot-app→vm-app-prodorvm-app-stage
Run locally
IaC validation
make validate # check all manifests parse + have required fields + cluster-correct nodes
make plan ENV=stage # resolve manifests for stage → .orca-out/stage/
make plan ENV=prod # same for prod
make apply ENV=stage # no-op until M1.2 stands up the Orca controller
make validate runs in CI on every PR.
Dev stack
platform/orca-platform doubles as the home for the local-dev compose stack so a developer can clone this repo, run make dev-up, and immediately work against a real Keycloak realm + Postgres / Redis / Mongo / MinIO. See dev/README.md for the full picture.
make dev-up # Keycloak (:8080) + Postgres (:5432) + Redis (:6379) + Mongo (:27017) + MinIO (:9000)
make dev-down # stop, keep volumes
make dev-reset # stop, wipe, fresh
Seed user: test@breakpilot.dev / test (tenant acme, products certifai + compliance).
Per-milestone fill-in schedule
Each stub manifest carries a header comment naming the milestone that finalises its real values. Summary:
| Milestone | What it fills in |
|---|---|
| M0.3 | breakpilot-edge/services/powerdns-auth.toml, DNS zone body, orca-proxy routes |
| M1.2 | VM provisioning (Terraform/OpenStack in a separate repo); brings make apply online |
| M1.3 | Backup cron services + scripts/restore-drill.sh |
| M2.1 | breakpilot-edge/services/{keycloak,pg-keycloak}.toml (repurposed from CERTifAI Keycloak) |
| M3.1 | breakpilot-edge/services/{infisical,pg-infisical,redis-infisical}.toml |
| M3.2 | breakpilot-control/services/stalwart.toml |
| M4.1 | breakpilot-control/services/tenant-registry.toml + breakpilot-app/services/prod/pg-app.toml |
| M5.1 | breakpilot-control/services/customer-portal.toml + stage equivalents |
| M6.x | breakpilot-app/services/prod/{certifai-dashboard,mongodb,litellm}.toml |
| M7.x | compliance services on breakpilot-app/services/{prod,stage}/ |
| M8.1 | breakpilot-control/services/{erpnext,mariadb,redis-erpnext}.toml |
| M9.1 | breakpilot-control/services/frappe-hd.toml |
Until the milestone PR lands, the stub still parses and make validate stays green — but apply will refuse a stub that hasn't replaced its placeholder image tag (gate to be added with the first real image).
Endpoints / surface
| Target | What it does |
|---|---|
make validate |
Parse + structural check + per-cluster node check (no cluster contact) |
make plan ENV=<env> |
Resolve manifests + overlay → .orca-out/<env>/ |
make apply ENV=<env> |
Push to Orca controller at $ORCA_API_URL (M1.2 brings this online) |
make diff ENV=<env> |
Alias for plan |
make clean |
Remove .orca-out/ |
Deployment
| Env | Apply path | Trigger |
|---|---|---|
| dev | docker-compose in each product repo |
dev's machine |
| stage | make apply ENV=stage against the breakpilot-app Orca controller |
CI on merge to main + image build |
| prod | make apply ENV=prod against the breakpilot-app Orca controller |
release tag vX.Y.Z + sign-off |
apply for prod will be gated by the production-promotion gate (24h stage soak + manual sign-off) per IMPLEMENTATION_PLAN.md §1.6. Wiring lands in M1.2.
Observability
- Traces, logs, metrics: SigNoz — service name per individual container
- On-call:
oncall@breakpilot.com· runbooks atplatform/docs/runbooks/
Contributing
See CONTRIBUTING.md. Every PR touching clusters/ MUST keep make validate green; CI enforces it.
License
Proprietary — all rights reserved. Copyright (c) 2026 Sharang Parnerkar and Benjamin Boenisch. See LICENSE.