Skip to content

K8s driver (ADR #63 slice 3) — sub-slice tracking #97

Description

@brettchien

Context

ADR #63 (agent-deployment-templates, Accepted) already scoped slice 3 = K8s driver as the second provider behind the same RuntimeDriver-shaped seam as ECS (slice 2, PR #65). This issue tracks that slice, broken into independently-shippable sub-slices, per Brett's ask (orbstack-local k8s cluster as a Studio-managed target).

Full deployment scope confirmed: compose → bundle → k8s apply, on par with ECS provision — not a read-only/observe-first MVP.

Relevant ADRs: deployment-control-plane (ADR-2, §6-state ⇄ k8s mapping), agent-lifecycle (ADR-1), runtime-identity-context (ADR-19, FleetBinding k8s fields), agent-deployment-templates (#63).

Correction after re-reading the code (self-review, 2026-08-21): the k8s schema shape is not net-new. manifest.rs has carried Runtime::Kubernetes(KubernetesRuntime { node_selector, service_account, tolerations }) since slice-0 (c17bf7d, both here and in the upstream openab/operator source) — it's currently hard-rejected by two explicit guards: apply.rs:239-244 and create.rs:56-58 (bail!("Kubernetes runtime not yet implemented")). 3b's job is to implement behind this existing enum arm and delete those two guards, not design new schema. KubernetesRuntime has no context/namespace/cluster field — confirms the original intent was for cluster targeting to live at the FleetBinding level (ADR-19), not per-manifest; carry that assumption forward unless there's a reason to override per-agent.

Sub-slices

  • 3a — Provisioning driver trait extraction (prerequisite, no ADR yet). apply/scale/delete/get are inline aws_sdk_ecs calls with no trait boundary — ADR-2's "RuntimeDriver is the only layer with vendor terms" is only true for state classification (project() in agent-lifecycle) today, not CRUD. Extract a trait, EcsDriver becomes the first impl. Pure refactor, behavior unchanged, existing tests must stay green.
    • Also in scope for 3a (missed in the first pass): create.rs's interactive wizard is AWS-coupled starting at step 3 (Discord secret → Secrets Manager SmClient constructed unconditionally), before runtime is even asked at step 4 — VPC/subnet/security-group prompts (steps 6-8) are ECS-only concepts. The wizard needs restructuring so runtime selection happens early and branches: k8s path skips VPC/SG entirely and prompts kubeconfig context/namespace instead.
    • status.rs/studio_api.rs (Studio-local additions, not upstream) call ECS describe_* directly with no driver branching — the read-model needs a k8s-observe counterpart. This is separate from agent-lifecycle's RuntimeDriver::project() (that only classifies a native observation Studio already fetched; something has to fetch the k8s-native observation first).
  • 3b — K8sDriver skeleton. kubeconfig context resolution (principal_source/scope/location per ADR-19), apply → Deployment, observe → Pod list → 4-discriminator → 6-state (ADR-2's k8s mapping table + traps). Removes the two not yet implemented guards. Adds kube + k8s-openapi crate deps.
  • 3c — Bundle carrier. bundle_from (manifest.rs) currently only resolves to an S3 state prefix; add ConfigMap/volume (or init-container pull) carrier for k8s.
  • 3d — Secrets. Corrected: not just a new URI scheme. secrets.rs::resolve_value_from's output contract is the ECS-native valueFrom shape ({arn}:{key}::) — a k8s target needs a different output (a Secret key selector), so this needs a driver-parameterized result type (e.g. SecretRef::Ecs(String) | SecretRef::K8s{ name, key }), with k8s-secret://<name>#<key> as the new input shorthand alongside the existing aws-sm://.
  • 3e — Identity context panel. Wire k8s fields (context user/SA, cluster/namespace, kubectl auth whoami) into RuntimeContext per ADR-19's table.
  • 3f — Console wiring. FleetBinding gains a k8s driver option + kubeconfig context selector; orbstack's local cluster is just another context, no special-casing.

Explicit non-goals / open questions

  • ingress.rs (Cloud Map + VPC Link + API Gateway) stays ECS-only, permanently. manifest.validate() already enforces this: spec.ingress is rejected for non-ECS runtimes with "use native Kubernetes Ingress otherwise." Not a gap — a deliberate boundary from slice-0. k8s operators manage ingress with native k8s objects.
  • bootstrap.rs k8s equivalent (namespace/RBAC/ServiceAccount one-time setup) — open question, leaning out of scope for v1. ECS bootstrap provisions cluster/IAM/SG/S3/log-group account-wide; for orbstack (operator already has cluster-admin on their own local cluster) this is plausibly unnecessary — assume namespace/RBAC pre-exist as an operator prerequisite (kubectl create namespace oab), revisit only if a shared/multi-tenant k8s target shows up later.

Starting with 3a.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions