Skip to content

feat(substrate): render BYO extraContainers in the SandboxAgent ActorTemplate - #2691

Open
carlochessamp wants to merge 1 commit into
kagent-dev:release/v0.10.xfrom
carlochessamp:feat/substrate-extra-containers
Open

feat(substrate): render BYO extraContainers in the SandboxAgent ActorTemplate#2691
carlochessamp wants to merge 1 commit into
kagent-dev:release/v0.10.xfrom
carlochessamp:feat/substrate-extra-containers

Conversation

@carlochessamp

Copy link
Copy Markdown

What

buildSandboxAgentActorTemplate only ever emitted the agent container, so byo.deployment.extraContainers (and the declarative deployment.extraContainers) silently disappeared for SandboxAgents on substrate. The translator's pod template carries them, but on 0.10 every SandboxAgent reconciles through the substrate backend — there is no pod — so extra containers were dropped on the floor.

This renders them as additional ActorTemplate containers. The gVisor sandbox gives them the sidecar semantics a Kubernetes pod would: one shared loopback network namespace, separate rootfs/mount namespaces per container. Sidecars like a credential-brokering forward proxy listening on 127.0.0.1:<port> work unchanged.

Why

A sidecar is the standard way to attach e.g. a credential broker, log shipper, or local proxy to a workload. byo.deployment.extraContainers already exists in the CRD and works on the agent-sandbox platform; on substrate the same field currently no-ops, which is the worst failure mode: the CR validates, syncs, and the sidecar just never runs.

How

Substrate containers are a strict subset of corev1.Container, so the conversion is explicit and fail-closed:

  • image must be digest-pinned (pinImageRef, applied per container)
  • command must be explicit — same rule ValidateSubstrateSandboxAgentSpec already enforces for the BYO agent cmd (substrate copies Command verbatim into the OCI Process.Args, no image-entrypoint fallback)
  • env keeps literals and secretKeyRef (the ate control plane resolves the latter server-side, per container); envFrom and configMapKeyRef drop, as sanitizeActorTemplateEnvVar already does for the agent container
  • an HTTP readiness probe maps to Readyz so actor readiness keeps gating on the sidecar; named ports resolve against the extra container's own containerPorts (the translator only registers the agent container's http port). TCP/exec probes have no substrate equivalent and are ignored
  • volumeMounts are rejected: ActorTemplate volumes only support a single durableDir, already consumed by the agent's /data session store — silently ignoring mounts would misconfigure sidecars that depend on them
  • at most 10 containers (CRD MaxItems)

Extras append after the agent container; applyDurableDirSessionStore keeps mounting /data on Containers[0]. The shape hash covers the whole spec, so adding/removing a sidecar fans out blue-green like any other spec change (asserted in tests).

Testing

go test ./core/pkg/sandboxbackend/substrate/... — new TestBuildSandboxAgentActorTemplateExtraContainers covers: rendering alongside the agent (env literal + secretKeyRef preserved, configMapKeyRef dropped, no volume mounts, readyz mapped, image stays pinned, shape-hash/template-name change), named readiness-port resolution, and the failure modes (unpinned image, missing command, volume mounts, unresolvable named port, >10 containers). All pre-existing substrate/translator/api tests pass unchanged.

Verified end to end against a real rendered SandboxAgent (helm-rendered values carrying an agent-vault credential-brokering sidecar): the CR → translator pod template → patched builder produces the expected two-container ActorTemplate with per-container env isolation.

…Template

buildSandboxAgentActorTemplate only ever emitted the agent container, so
byo.deployment.extraContainers (and the declarative equivalent) silently
disappeared for SandboxAgents on substrate — the translator pod template
carries them, but every SandboxAgent reconciles through substrate on 0.10,
where there is no pod.

Render them as additional ActorTemplate containers. The gVisor sandbox
gives them the sidecar semantics a Kubernetes pod would: one shared
loopback network namespace, separate rootfs/mount namespaces. Sidecars
like a credential-brokering forward proxy (127.0.0.1:<port>) work
unchanged.

Substrate containers are a strict subset of corev1.Container, so the
conversion is explicit and fail-closed:
- image must be digest-pinned (pinImageRef, per container)
- command must be explicit (same rule as the BYO agent cmd)
- env keeps literals and secretKeyRef; envFrom/configMapKeyRef drop
- an HTTP readiness probe maps to Readyz (named ports resolve against
  the container's own containerPorts)
- volumeMounts are rejected: ActorTemplate volumes only support a single
  durableDir, already consumed by the agent's /data session store
- at most 10 containers (CRD MaxItems)

Extras append after the agent container; applyDurableDirSessionStore
keeps mounting /data on Containers[0].
@carlochessamp
carlochessamp requested a review from a team as a code owner September 4, 2026 02:31
@github-actions github-actions Bot added the enhancement New feature or request label Sep 4, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant