Applications that submit work through a UI, run it as Kubernetes jobs, and observe it — built as three tiers plus an async compute plane. The three tiers are a front-end (the UI), a back-end (the business-logic + launcher service), and a receiver (the observability store). The compute plane is a workflow driver and the task pods it spawns. "fe / be / task-launcher" is the colloquial name; the model below is the precise one — the launching is the back-end's job, and the third tier is the receiver, distinct from the compute plane that feeds it. The echo trio + foxfire is the worked reference; new apps copy the shape and swap the contents.
The deploy machinery is workload-agnostic. Every tier uses the same containerized_deployment archetype (wanderland-pipelines-pack) and the same k8s_provisioner deploy boundary (wanderland-k8s-pack). A static nginx bundle, a JVM service, and a Wanderland engine deploy through the identical pipeline — build an image, push it to ECR, point a kustomize overlay at the pushed ref, kubectl apply it, wait for the rollout. The three tiers and the compute plane are abstract deployment slots which can be filled by any application as long as it complies with the required form.
Three tiers (front-end, back-end, receiver) and an async compute plane.
| Tier | Component | Built on | Exposure |
|---|---|---|---|
| 1 — front-end | echo-frontend |
web components (no build) on nginx | public ingress, VPN-whitelisted, CFN DNS + cert-manager TLS |
| 2 — back-end | echo-backend |
Wanderland engine | ClusterIP (reached via the frontend's /api proxy); launches runs + proxies receiver reads |
| 3 — receiver | foxfire |
Wanderland engine | public ingress, VPN-whitelisted; stateful (PVC-backed SQLite) |
The compute plane is not a tier — it is the async fleet that produces data into Tier 3:
| Element | Component | Built on | Lifecycle |
|---|---|---|---|
| driver | nf-driver |
Nextflow + JDK image, nf-foxfire plugin baked in | one-shot k8s Job per run |
| task pods | stock python:3.11-slim (process.container) |
— | ephemeral, driver-spawned |
echo-frontend and echo-backend live in vivarta-examples; foxfire and the nf-driver image live in the foxfire repo. Per-component deployment descriptors: advaita-service-echo-frontend, advaita-service-echo-backend, advaita-service-foxfire, advaita-service-nf-driver.
front-end ──POST /api/runs──▶ back-end (launch_run)
│ applies a k8s Job
▼
driver Job ──(k8s executor)──▶ task pods
│ nf-foxfire signs each event
▼
foxfire (verify + append-only store + GraphQL)
▲
front-end ──POST /api/graphql──▶ back-end (foxfire_graphql) ──┘
A user submits a run in the front-end; the back-end's launch_run boundary renders a Nextflow-driver Job and fires it through the k8s_job launch primitive; the driver runs the workflow with the Kubernetes executor, each process becoming a task pod, and its nf-foxfire plugin signs each lifecycle event and POSTs it to foxfire's /events/signed; the front-end reads run/task/cost data back through the back-end's foxfire_graphql proxy. The three tiers plus the compute plane exercise the whole deploy + observability platform end to end.
Each deployable carries a vivarta.yml on the containerized_deployment archetype with the stages collect → image → deploy:
git_hash, optionally pom_xml / package_json for a version) and, in prod, reads the running image with k8s_live_image for promotion.docker_build → ECR in build environments, noop in prod (promotion reuses the dev image; no rebuild).component iterator. For a workload it runs k8s_provisioner (pin the overlay image with kustomize_set_image, then kubectl_apply). Where a public hostname is needed it also runs a cfn_provisioner component that writes the Route53 A record to the cluster's nginx-ingress IP — a mixed AWS-substrate + Kubernetes-workload deploy in one slot, DNS first so cert-manager's HTTP-01 challenge resolves. The nf-driver image pipeline sets deploy: { type: noop } — build and push only.Environments are a single local → dev → prod ladder, every varying value sourced under !Environment. Images come from one ECR registry across all environments. local targets an OrbStack cluster; dev/prod target the CoreWeave useast13-dev / useast13-prod clusters.
k8s_job (wanderland-k8s-pack) applies a Job manifest through the :kubectl adapter (kubectl apply -f - on stdin), fire-and-forget by default, wait: true to block on completion. It is the kubectl analogue of an ECS run-task — it launches work, where k8s_provisioner deploys a long-lived workload. echo-backend's launch_run composes it.
The Kubernetes-executor substrate is applied once per cluster, outside the app deploys, and referenced by name:
nextflow-runner ServiceAccount + RBAC (create/watch/delete pods + PVCs) for the driver's k8s executor.nextflow-work ReadWriteMany PVC, the shared Nextflow work dir mounted at /work across the driver and task pods. Its storage class is cluster-specific (RWX-capable).nextflow-launcher ServiceAccount + create-Jobs RBAC, the identity echo-backend runs as.These live in foxfire/k8s/infra/ and echo-backend/k8s/infra/.
vivarta-examples/drones/deploy-suite.yml is a vivarta-drones sortie that chains the four pipelines in dependency order through the wanderland drone action (config + route: deploy + chdir + WANDERLAND_ENVIRONMENT), exposing environment and workspace parameters:
bin/drone run vivarta-examples/drones/deploy-suite.yml \
--param environment=dev --no-prompt
drones/local-up.yml brings up the three tiers on OrbStack without the compute plane, and drones/local-bootstrap.yml prepares a cluster (namespace, nginx-ingress, launcher RBAC, ECR pull secret). These kick off the real Wanderland pipelines — the same work a Jenkins job runs, driven from a workstation.
vivarta-examples/echo-frontend, vivarta-examples/echo-backend, vivarta-examples/dronesfoxfire (receiver + driver/ image + k8s/infra/)wanderland-k8s-pack — kustomize_set_image, kubectl_apply, k8s_provisioner, k8s_live_image, k8s_jobwanderland-pipelines-pack — containerized_deployment archetype