You have a CRD. Kubernetes stores it, validates it, and serves it.
The only missing piece is something that watches it and acts on it.
Traditionally that means Go: informers, workqueues, reconcile loops, code generation, Dockerfiles, Helm charts — a software project per operator. Most engineers never start. Teams that do spend weeks before the first CR reconciles.
Orkestra removes that entirely.
apiVersion: orkestra.orkspace.io/v1
kind: Katalog
metadata:
name: website-operator
spec:
crds:
website:
crdFile: ./crd.yaml
crFiles: [./cr.yaml]
operatorBox:
onCreate:
deployments:
- name: "{{ .metadata.name }}"
image: "{{ .spec.image }}"
replicas: "{{ .spec.replicas }}"
reconcile: true
services:
- name: "{{ .metadata.name }}-svc"
port: 80
targetPort: "{{ .spec.port }}"
reconcile: trueThat is the whole operator.
ork runOrkestra reads the Katalog, applies the CRD and CR, starts the operator, creates the Deployment and Service, sets owner references on both, writes status, emits Kubernetes events, corrects drift, and exposes health, metrics, and a control center.
Not a single line of Go.
Your CRD is enough. The rest is just a Katalog.
Every CRD declared in a Katalog becomes a complete, isolated operator. Nothing to configure.
| Informer | Watches your exact GVK. In-memory cache. Zero API calls on read. |
| Workqueue | Per-CRD. Rate-limited. Deduplicated. Isolated from every other CRD. |
| Worker pool | Configurable concurrency. A panic in one CRD does not affect any other. |
| Drift correction | reconcile: true — desired state is enforced on every cycle. |
| Owner references | Child resources deleted when the CR is deleted. No onDelete logic needed. |
| Finalizers | CRs protected from dirty deletion automatically. |
| Events | Every reconcile is a traceable Kubernetes event. |
| Leader election | One active instance. Followers hold warm caches. Failover in under 15s. |
| Status | Ready condition + your own status fields written after every reconcile. |
| Health API | /katalog/{crd}/health, /katalog/{crd}/cr, /metrics — per CRD. |
| Prometheus metrics | Reconcile totals, queue depth, error rate — labeled by GVK. |
| Deletion protection | Orkestra and everything it manages cannot be accidentally kubectl delete. |
| Control Center | Realtime visibility per CRD, per Katalog, across instances. Auto-generated operator docs — overview, reconcile mode, child resources, kubectl reference, access control. |
| Developer portal | idp.enabled: true on any CRD surfaces a self-service form in the Control Center. Users submit CRs through a browser — no kubectl, no YAML. |
# Install (macOS)
brew install orkspace/tap/ork orkspace/tap/orkcc
# Install (Linux)
curl -sSL https://get.orkestra.sh | bashWindows Download
ork_windows_amd64.zipandorkcc_windows_amd64.zipfrom the latest release.
Extract the archives and add the folder containingork.exeandorkcc.exeto yourPATH.
ork init
ork runNo cluster? Add
--devto create a temporary kind cluster. Requires Docker.
ork init scaffolds a katalog.yaml, crd.yaml, and cr.yaml in the current directory — like terraform init.
→ Learning to Orkestrate — the guided path from first operator to full platform. Every capability has a runnable example.
In another terminal:
ork control→ localhost:8081 · username:password → orkestra
Six Runtimes. 75 CRDs. One Control Center.
Live deployment: cc.orkestra.sh
| Traditional (75 operators) | Orkestra | |
|---|---|---|
| Processes | 75 | 6 runtimes + 1 control center |
| Memory | 3.75 GB – 15 GB | ~79 MB per runtime (measured) |
| CRDs under management | 75 | 75 |
| First operator | 3–6 weeks | Under 1 hour |
| Lines of Go | 400+ per operator | 0 |
| Adding a new CRD | Days to weeks | Minutes |
79 MB is a live measurement from a 10-CRD runtime (process_resident_memory_bytes from the /metrics endpoint — raw scrape). The memory reduction works because Orkestra pays the cost of client-go, leader election, and health servers once per runtime. Per-CRD cost is a goroutine pool and an in-memory cache. Isolation works the same way kube-controller-manager isolates Deployment, StatefulSet, and Job controllers — dedicated informer, queue, and worker pool per CRD. A panic in one is caught by safeReconcile; the others keep running. The Control Center aggregates all runtimes into a single dashboard.
Not an operator framework — an operator runtime. A framework gives you libraries and conventions. Orkestra gives you a runtime with platform tools to build, test, evaluate, visualize, and operate operators and control planes.
Not an operator — a runtime for operators. Each CRD in a Katalog becomes its own operator. Orkestra is the runtime that runs them all.
Not an IDP — but every operator can become one. idp.enabled: true on any CRD exposes a self-service form in the Control Center. Users submit CRs through a browser without kubectl or YAML. The IDP is the operator — Orkestra just surfaces it.
Not a replacement for Go. Hooks and constructors exist for exactly this reason. ~90% of operators are declarative; ~10% need code. Orkestra handles the 90% and gives the 10% a clean interface — the same informer, queue, health, and metrics infrastructure, with a single function to implement.
Not GitOps. Katalogs define long-lived API contracts and are resolved at startup. Silently reloading them mid-flight is dangerous. Treat Katalog changes like any other runtime change — deploy through a pipeline.
Not a product — a primitive layer. Notes, autoscaler, IDP mode, Katalogs — none of these are products. They are primitives ready for composition. What you build on top of them is.
| Why Orkestra | What Orkestra is, how it works, and why it’s different |
| Foundations | The decisions that shaped the design — and why they hold |
| Trust and Failure Model | What happens when things go wrong |
| Getting Started | First operator in under an hour |
| Learning to Orkestrate | Every capability, as a runnable example |
| Katalog Reference | Complete field reference |
| Orkestra Registry | OCI distribution for operators |
| Security | How Orkestra is secure by default |
Issues · Discussions · Contributing
Apache 2.0 — see LICENSE



