Remote — Zero Build

2 min read

The same WebApp operator. The reconciler is a bash script.

No Go. No image build. No Kubernetes SDK. No kubeconfig. Orkestra owns the queue, backoff, informer, owner references, SSA apply, and health. The script owns the Deployment and Service specs.

cd from-controller-runtime/01-remote
RECONCILER_TOKEN=orkestra-demo-token ./reconciler/reconciler.sh &
ork run

What changed

controller-runtimeRemote
LanguageGoanything that speaks HTTP
Kubernetes clientcontroller-runtime/clientnone
Owner referencesmetav1.NewControllerRef(...)automatic
RBAChand-written markersautomatic
Drift correctionnot implementedautomatic (SSA)
Garbage collectionOwns() in SetupWithManagerowner refs set by Orkestra
Build & deployDockerfile, image push./reconciler.sh

The contract

Orkestra POSTs to your endpoint on every watch event:

{
  "key":    "default/my-webapp",
  "gvk":    { "Group": "...", "Version": "v1alpha1", "Kind": "WebApp" },
  "object": { ...WebApp CR... },
  "args":   { "logLevel": "info", "environment": "development" }
}

args are declared in the Katalog and evaluated against the CR — no raw object parsing needed for common values.

Your endpoint returns:

{
  "result":  "ok",
  "status":  { "phase": "Running", "endpoint": "...", "replicas": 1 },
  "resources": [
    { "type": "deployment", "fields": { "name": "my-webapp", "image": "nginx:latest", "replicas": 1 } },
    { "type": "service",    "fields": { "name": "my-webapp-svc", "port": 80, "targetPort": 80 } }
  ]
}

Resources use the intent form — type names the built-in kind, fields is a flat map. Orkestra constructs the full Kubernetes object, sets owner references, and SSA-applies it. The reconciler never writes Kubernetes schema.

That is the entire interface. Any language, any runtime, any host that can receive HTTP and return JSON is a valid operator.


Endpoint selection

The Katalog uses a note to pick the right URL depending on where Orkestra is running:

notes:
  functions:
    - name: reconcilerEndpoint
      expression: '{{ if .ork.inPod }}http://webapp-reconciler.default.svc.cluster.local:8025/reconcile{{ else }}http://localhost:8025/reconcile{{ end }}'

.ork.inPod is false locally and true inside a pod. One Katalog file — no separate variant for local vs. in-cluster.


Same operator, any language

The bash reconciler, a Python version, and a Go version all ship in the example. Swap them without touching the Katalog or the CR:

# Python
RECONCILER_TOKEN=orkestra-demo-token python3 reconciler/main.py

# Go (no controller-runtime, no kubeconfig)
RECONCILER_TOKEN=orkestra-demo-token go run reconciler/main.go

When to use this

Pick remote when:

  • The reconcile logic already exists as a service, a script, or a function
  • You want to use a language other than Go
  • You want to iterate on reconcile logic without a rebuild or redeploy cycle
  • The operator’s behaviour is simple enough that the HTTP overhead is irrelevant