Local Cluster (k3d)
Run the full platform locally with k3d and DevSpace.
For day-to-day development the full platform runs on a local k3d cluster — real k3s inside Docker — with images built locally and no registry, GCP, or Terraform involved. One task brings the whole stack up; a second adds a hot-reload dev loop via DevSpace.
Prerequisites
You need docker, k3d, and devspace on your PATH, plus
task to run the targets and kubectl to poke at the
cluster. Verify the tools:
task cluster:preflightIf anything is missing, the task prints install hints (brew install k3d,
brew install devspace, Docker Desktop).
Bring up the cluster
task cluster:deployThis single target:
- Runs the preflight check.
- Creates a k3d cluster named
octofromdeploy/k3d/cluster.yaml(one server, no agents), mounting./datafrom the repo root into the node so Postgres data persists on your disk. - Builds the five images locally (
task cluster:images):octo-platform,octo-orchestrator,octo-logs,octo-schema, andocto-runtime, all tagged:dev, and loads them straight into the cluster's containerd withk3d image import— no registry needed. - Applies the raw manifests in
deploy/k8s/viadevspace deploy, in order: theocto-devnamespace, Postgres, the schema Job (appliessql/schema.sql), NATS, the platform, orchestrator RBAC, runtime RBAC, the orchestrator, and the log aggregator. - Restarts the platform and orchestrator Deployments so they pick up freshly
imported images (the
:devtag never changes between runs).
The target is idempotent — re-run it after code changes to rebuild the images and roll the pods.
This path uses the raw manifests in deploy/k8s/, not the Helm chart. Every
cluster:* task pins the kube context to k3d-octo, so a stray
current-context pointing at a remote cluster can never be the target of a
deploy or purge.
Access the stack
The k3d load balancer maps localhost ports to NodePort services, so nothing needs a long-running port-forward:
- Editor UI — http://localhost:3000
- Orchestrator — http://localhost:8090/healthz
(and
/db-version)
Check pod status with:
kubectl --context k3d-octo get pods -n octo-devHot-reload dev loop
task cluster:devThis ensures the cluster is up (cluster:deploy), builds the dev-flavored
images (cluster:images:dev, from the Dockerfile.dev files), then hands off
to devspace dev, which:
- Swaps the platform pod for a
next devimage and live-syncsapps/platform/into it — edits hot-reload in the browser. - Swaps the orchestrator and logs pods for
go runimages, syncingorchestrator/andlogs/and restarting the container on each upload so Go recompiles. - Tails the platform, orchestrator, logs, Postgres, and NATS logs to your terminal.
The session stays attached until you press Ctrl-C. The NodePort mappings keep
working during dev mode, so the editor stays on localhost:3000. To restore
the production-image pods afterwards:
devspace reset pods -n octo-devTear down
task cluster:stopThis purges the DevSpace deployment and deletes the k3d cluster, reclaiming
Docker memory — but keeps ./data, so Postgres comes back with its data on
the next task cluster:deploy.
To wipe the database as well:
task cluster:db:resetThe task refuses to run while the cluster is up (Postgres holds the data
directory open), prompts for confirmation, then deletes ./data. The next
task cluster:deploy recreates Postgres and re-applies the schema fresh.
task cluster:db:reset permanently deletes all local Postgres data —
integrations, deployments, logs, and KV contents.