Automation Platform > Deployment & hosting
Managed: Kubernetes backend
# Managed: Kubernetes backend Deploy the `oz-agent-worker` daemon into a Kubernetes cluster using the included Helm chart. Each agent task runs as a Kubernetes Job in your cluster. The Automation Platform orchestrates runs end to end (Slack, Linear, schedules, API, `oz agent run-cloud`); your cluster provides the compute, scheduling, and policy enforcement. ## When to use the Kubernetes backend * You already operate a Kubernetes cluster and want agents to run there. * You need Kubernetes-native scheduling, resource management, or policy enforcement. * You want to use Kubernetes Secrets, ServiceAccounts, and admission policies to control task behavior. --- ## How it works 1. The worker connects to the Kubernetes API server (using in-cluster auth by default, or an explicit kubeconfig). 2. On startup, the worker runs a short-lived **preflight Job** to verify that cluster permissions, admission policies, and Pod Security Standards are compatible. If the preflight fails, the worker exits with a diagnostic error before accepting any tasks. 3. For each assigned task, the worker creates a Kubernetes Job in the configured namespace. 4. The worker monitors the Job and Pod status via Kubernetes Watch (with a 30-second safety-net poll for watch disconnects). 5. The worker deletes successful Jobs. Failed Jobs remain until Kubernetes TTL cleanup. Set `--no-cleanup` to disable worker-managed cleanup. --- ## Prerequisites * **Enterprise plan with self-hosting enabled** — [Contact sales](https://www.warp.dev/contact-sales) if self-hosting is not yet enabled for your team. * **A Kubernetes cluster** with the worker process able to reach the API server. The cluster must: * Allow the worker's namespace to create Jobs with a **root init container** (sidecar materialization depends on this pattern). * Grant the worker these namespace-scoped permissions: `create`, `get`, `list`, `watch`, `delete` on `jobs`; `get`, `list`, `watch` on `pods`; `get` on `pods/log`; `list` on `events`. * **[Helm](https://helm.sh/docs/intro/install/)** installed locally, plus `kubectl` authenticated against the target cluster. * **An agent API key** — Create one in the <a href={`https://oz.warp.dev/settings`}>Oz web app</a> so the worker can authenticate to the Automation Platform. You can bind the key to any cloud agent — that choice doesn't restrict which agents can run on the worker. See [API Keys](/reference/cli/api-keys/) for the full creation flow. --- ## Install with the Helm chart The `oz-agent-worker` repository includes a namespace-scoped Helm chart at `charts/oz-agent-worker`. This is the recommended way to deploy the worker into a cluster. ### What the chart deploys * A long-lived `Deployment` running `oz-agent-worker` with the Kubernetes backend. * A namespaced `ServiceAccount` for the worker. * A namespaced `Role` / `RoleBinding` with the minimum permissions needed to manage task Jobs and Pods. * A `ConfigMap` containing the worker config YAML. * An optional `Secret` for `WARP_API_KEY` (or a reference to an existing Secret). The chart does not create CRDs or cluster-scoped RBAC resources. ### 1. Set your API key and namespace ```bash export WARP_API_KEY="your_agent_api_key" ``` Create the namespace if it doesn't exist: ```bash kubectl create namespace warp-oz ``` ### 2. Create the API key Secret If you're not using an existing Secret, create one with the API key: ```bash kubectl create secret generic oz-agent-worker \ --from-literal=WARP_API_KEY="$WARP_API_KEY" \ --namespace warp-oz ``` **Expected outcome:** `kubectl get secret -n warp-oz oz-agent-worker` shows the Secret. ### 3. Install the chart Clone the worker repo and install the chart: ```bash git clone https://github.com/warpdotdev/oz-agent-worker.git helm install oz-agent-worker ./oz-agent-worker/charts/oz-agent-worker \ --namespace warp-oz \ --set worker.workerId=oz-k8s-worker \ --set image.tag=<version> ``` :::caution Set `image.tag` explicitly to pin the worker image. Check the [oz-agent-worker releases](https://github.com/warpdotdev/oz-agent-worker/releases) for the latest version. Do not rely on `latest`. ::: **Expected outcome:** `kubectl get pods -n warp-oz` shows the worker Deployment pod as `Running`, and the worker logs show `Connected to Oz` / `Listening for tasks`. To scale horizontally, deploy multiple Helm releases with distinct worker IDs rather than increasing replicas on a single release. --- ## Key chart values Set `worker.workerId` and `image.tag` for each installation. These values affect capacity and task placement: * `worker.resources` — CPU and memory for the worker Deployment, not task Jobs. The chart requests `100m` CPU and `128Mi` memory by default and sets no limits. * `worker.maxConcurrentTasks` — Maximum concurrent tasks. The default `0` allows unlimited tasks. * `kubernetesBackend.podTemplate` — Raw PodSpec YAML for task Jobs. See the [self-hosted worker reference](/platform/self-hosting/reference/#kubernetes-backend-config) for every worker, backend, API key, and metrics value. --- ## Cluster selection Cluster selection follows Kubernetes client config conventions: * Set `backend.kubernetes.kubeconfig` to use an explicit kubeconfig file. * If `kubeconfig` is omitted and the worker runs inside a Kubernetes pod, the worker uses in-cluster config automatically. * Otherwise, the worker falls back to the default kubeconfig loading rules and uses the current context. `namespace` selects the namespace inside the chosen cluster. It defaults to `default` when omitted. --- ## Pod template The `pod_template` field accepts standard Kubernetes PodSpec YAML and is the declarative way to configure task pod scheduling, service accounts, image pull secrets, resources, and environment variables. When using `pod_template`, define a container named `task` to customize the main task container directly. Otherwise, the worker appends its own `task` container to the PodSpec. ### Size task workloads The worker does not set default CPU or memory resources on task containers. Configure task resources in either of these places: * **Pod template** — Set `resources.requests` and `resources.limits` on the container named `task`. Use the rest of the PodSpec for node selectors, affinity, and tolerations. * **Runner instance shape** — Assign a [runner](/platform/runners/) with the vCPUs and memory needed for a workload. An explicit shape sets the `task` container's CPU and memory requests equal to its limits and overrides matching `pod_template` values. A runner instance shape sizes only `task`. A `pod_template` resource setting applies only to a container you define in the template; it does not alter worker-generated setup or materialization init containers. Requests determine Pod placement, while limits constrain a running container. Account for concurrent Jobs and node headroom. Use workload-specific runners for occasional heavy builds or tests instead of increasing every task's baseline. Use `valueFrom.secretKeyRef` to inject Kubernetes Secret values into task container environment variables: ```yaml pod_template: serviceAccountName: agent-task-sa imagePullSecrets: - name: my-registry-creds containers: - name: task resources: requests: cpu: "2" memory: 4Gi limits: memory: 8Gi env: - name: GITHUB_TOKEN valueFrom: secretKeyRef: name: my-k8s-secret key: github-token tolerations: - key: "dedicated" operator: "Equal" value: "agents" effect: "NoSchedule" ``` The task Job's `serviceAccountName` controls runtime access. It is separate from the worker Deployment's ServiceAccount, which manages Jobs and Pods. --- ## Preflight check On startup, the worker creates a short-lived preflight Job to verify that: * The worker has sufficient RBAC permissions in the target namespace. * Cluster admission policies (Pod Security Standards, OPA Gatekeeper, Kyverno, etc.) allow the worker's task pod shape. * The preflight image can be pulled. If the preflight fails, the worker logs a diagnostic error and exits before accepting any tasks. This surfaces policy and configuration issues at deploy time rather than at task execution time. The preflight image defaults to `busybox:1.36`. If your cluster restricts allowed registries or images, set `preflight_image` to an allowlisted image. When `imagePullSecrets` is configured in `pod_template`, those secrets apply to the preflight Job as well, so you can point `preflight_image` at an image in your private registry. --- ## Environment variables for Kubernetes tasks There are two ways to pass environment variables to Kubernetes task containers: 1. **`pod_template`** (recommended for Kubernetes-native config) — Use standard Kubernetes `env` syntax in the `task` container, including `valueFrom.secretKeyRef` for Kubernetes Secrets. 2. **`-e` / `--env` flags** — Backend-agnostic runtime overrides that work across all managed backends. When configuring the Kubernetes backend via YAML or Helm, declarative task-container env belongs in `pod_template` rather than a separate top-level list. :::note If your organization uses an external secrets manager (HashiCorp Vault, AWS Secrets Manager, GCP Secret Manager, etc.), you can inject secrets into task pods via the CSI Secrets Store Driver or a similar operator. Configure the required `volumes`, `volumeMounts`, and annotations in `pod_template` just as you would for any other Kubernetes workload. See your secrets provider's documentation for details. ::: --- ## Setup and teardown commands Use `kubernetesBackend.setupCommand` (Helm value) or `backend.kubernetes.setup_command` ([config file](/platform/self-hosting/reference/#kubernetes-backend-config)) to run a shell command before each task. Use `teardownCommand` / `teardown_command` for cleanup after the task finishes. These run inside the task Pod and are useful for workspace bootstrapping or post-run reporting. --- ## Metrics Enable worker OpenTelemetry metrics with `metrics.enabled=true`. See [Monitoring](/platform/self-hosting/monitoring/) for Helm values, the metric catalog, and sample PromQL queries. --- ## Related pages * [Self-hosted worker reference](/platform/self-hosting/reference/) — Full CLI flag and config file schema, including every Kubernetes backend field. * [Self-hosting overview](/platform/self-hosting/) — Managed vs unmanaged and the backend decision guide. * [Routing runs to this worker](/platform/self-hosting/#routing-runs-to-self-hosted-workers) — How to send tasks to your connected worker from the CLI, schedules, integrations, the API, and the web UI. * [Environments](/platform/environments/) — Define the task image, repos, and setup commands. * [Monitoring](/platform/self-hosting/monitoring/) — OpenTelemetry metrics, including Helm chart metrics values. * [Security and networking](/platform/self-hosting/security-and-networking/) — RBAC, admission policies, and data boundaries. * [Troubleshooting](/platform/self-hosting/troubleshooting/#kubernetes-backend) — Common Kubernetes-backend issues.Tell me about this feature: https://docs.warp.dev/platform/self-hosting/managed-kubernetes/Deploy the Automation Platform managed worker into a Kubernetes cluster with the included Helm chart. Each agent task runs as a Kubernetes Job in your cluster.
Deploy the oz-agent-worker daemon into a Kubernetes cluster using the included Helm chart. Each agent task runs as a Kubernetes Job in your cluster. The Automation Platform orchestrates runs end to end (Slack, Linear, schedules, API, oz agent run-cloud); your cluster provides the compute, scheduling, and policy enforcement.
When to use the Kubernetes backend
Section titled “When to use the Kubernetes backend”- You already operate a Kubernetes cluster and want agents to run there.
- You need Kubernetes-native scheduling, resource management, or policy enforcement.
- You want to use Kubernetes Secrets, ServiceAccounts, and admission policies to control task behavior.
How it works
Section titled “How it works”- The worker connects to the Kubernetes API server (using in-cluster auth by default, or an explicit kubeconfig).
- On startup, the worker runs a short-lived preflight Job to verify that cluster permissions, admission policies, and Pod Security Standards are compatible. If the preflight fails, the worker exits with a diagnostic error before accepting any tasks.
- For each assigned task, the worker creates a Kubernetes Job in the configured namespace.
- The worker monitors the Job and Pod status via Kubernetes Watch (with a 30-second safety-net poll for watch disconnects).
- The worker deletes successful Jobs. Failed Jobs remain until Kubernetes TTL cleanup. Set
--no-cleanupto disable worker-managed cleanup.
Prerequisites
Section titled “Prerequisites”- Enterprise plan with self-hosting enabled — Contact sales if self-hosting is not yet enabled for your team.
- A Kubernetes cluster with the worker process able to reach the API server. The cluster must:
- Allow the worker’s namespace to create Jobs with a root init container (sidecar materialization depends on this pattern).
- Grant the worker these namespace-scoped permissions:
create,get,list,watch,deleteonjobs;get,list,watchonpods;getonpods/log;listonevents.
- Helm installed locally, plus
kubectlauthenticated against the target cluster. - An agent API key — Create one in the Oz web app so the worker can authenticate to the Automation Platform. You can bind the key to any cloud agent — that choice doesn’t restrict which agents can run on the worker. See API Keys for the full creation flow.
Install with the Helm chart
Section titled “Install with the Helm chart”The oz-agent-worker repository includes a namespace-scoped Helm chart at charts/oz-agent-worker. This is the recommended way to deploy the worker into a cluster.
What the chart deploys
Section titled “What the chart deploys”- A long-lived
Deploymentrunningoz-agent-workerwith the Kubernetes backend. - A namespaced
ServiceAccountfor the worker. - A namespaced
Role/RoleBindingwith the minimum permissions needed to manage task Jobs and Pods. - A
ConfigMapcontaining the worker config YAML. - An optional
SecretforWARP_API_KEY(or a reference to an existing Secret).
The chart does not create CRDs or cluster-scoped RBAC resources.
1. Set your API key and namespace
Section titled “1. Set your API key and namespace”export WARP_API_KEY="your_agent_api_key"Create the namespace if it doesn’t exist:
kubectl create namespace warp-oz2. Create the API key Secret
Section titled “2. Create the API key Secret”If you’re not using an existing Secret, create one with the API key:
kubectl create secret generic oz-agent-worker \ --from-literal=WARP_API_KEY="$WARP_API_KEY" \ --namespace warp-ozExpected outcome: kubectl get secret -n warp-oz oz-agent-worker shows the Secret.
3. Install the chart
Section titled “3. Install the chart”Clone the worker repo and install the chart:
git clone https://github.com/warpdotdev/oz-agent-worker.git
helm install oz-agent-worker ./oz-agent-worker/charts/oz-agent-worker \ --namespace warp-oz \ --set worker.workerId=oz-k8s-worker \ --set image.tag=<version>Expected outcome: kubectl get pods -n warp-oz shows the worker Deployment pod as Running, and the worker logs show Connected to Oz / Listening for tasks.
To scale horizontally, deploy multiple Helm releases with distinct worker IDs rather than increasing replicas on a single release.
Key chart values
Section titled “Key chart values”Set worker.workerId and image.tag for each installation. These values affect capacity and task placement:
worker.resources— CPU and memory for the worker Deployment, not task Jobs. The chart requests100mCPU and128Mimemory by default and sets no limits.worker.maxConcurrentTasks— Maximum concurrent tasks. The default0allows unlimited tasks.kubernetesBackend.podTemplate— Raw PodSpec YAML for task Jobs.
See the self-hosted worker reference for every worker, backend, API key, and metrics value.
Cluster selection
Section titled “Cluster selection”Cluster selection follows Kubernetes client config conventions:
- Set
backend.kubernetes.kubeconfigto use an explicit kubeconfig file. - If
kubeconfigis omitted and the worker runs inside a Kubernetes pod, the worker uses in-cluster config automatically. - Otherwise, the worker falls back to the default kubeconfig loading rules and uses the current context.
namespace selects the namespace inside the chosen cluster. It defaults to default when omitted.
Pod template
Section titled “Pod template”The pod_template field accepts standard Kubernetes PodSpec YAML and is the declarative way to configure task pod scheduling, service accounts, image pull secrets, resources, and environment variables.
When using pod_template, define a container named task to customize the main task container directly. Otherwise, the worker appends its own task container to the PodSpec.
Size task workloads
Section titled “Size task workloads”The worker does not set default CPU or memory resources on task containers. Configure task resources in either of these places:
- Pod template — Set
resources.requestsandresources.limitson the container namedtask. Use the rest of the PodSpec for node selectors, affinity, and tolerations. - Runner instance shape — Assign a runner with the vCPUs and memory needed for a workload. An explicit shape sets the
taskcontainer’s CPU and memory requests equal to its limits and overrides matchingpod_templatevalues.
A runner instance shape sizes only task. A pod_template resource setting applies only to a container you define in the template; it does not alter worker-generated setup or materialization init containers.
Requests determine Pod placement, while limits constrain a running container. Account for concurrent Jobs and node headroom. Use workload-specific runners for occasional heavy builds or tests instead of increasing every task’s baseline.
Use valueFrom.secretKeyRef to inject Kubernetes Secret values into task container environment variables:
pod_template: serviceAccountName: agent-task-sa imagePullSecrets: - name: my-registry-creds containers: - name: task resources: requests: cpu: "2" memory: 4Gi limits: memory: 8Gi env: - name: GITHUB_TOKEN valueFrom: secretKeyRef: name: my-k8s-secret key: github-token tolerations: - key: "dedicated" operator: "Equal" value: "agents" effect: "NoSchedule"The task Job’s serviceAccountName controls runtime access. It is separate from the worker Deployment’s ServiceAccount, which manages Jobs and Pods.
Preflight check
Section titled “Preflight check”On startup, the worker creates a short-lived preflight Job to verify that:
- The worker has sufficient RBAC permissions in the target namespace.
- Cluster admission policies (Pod Security Standards, OPA Gatekeeper, Kyverno, etc.) allow the worker’s task pod shape.
- The preflight image can be pulled.
If the preflight fails, the worker logs a diagnostic error and exits before accepting any tasks. This surfaces policy and configuration issues at deploy time rather than at task execution time.
The preflight image defaults to busybox:1.36. If your cluster restricts allowed registries or images, set preflight_image to an allowlisted image. When imagePullSecrets is configured in pod_template, those secrets apply to the preflight Job as well, so you can point preflight_image at an image in your private registry.
Environment variables for Kubernetes tasks
Section titled “Environment variables for Kubernetes tasks”There are two ways to pass environment variables to Kubernetes task containers:
pod_template(recommended for Kubernetes-native config) — Use standard Kubernetesenvsyntax in thetaskcontainer, includingvalueFrom.secretKeyReffor Kubernetes Secrets.-e/--envflags — Backend-agnostic runtime overrides that work across all managed backends.
When configuring the Kubernetes backend via YAML or Helm, declarative task-container env belongs in pod_template rather than a separate top-level list.
Setup and teardown commands
Section titled “Setup and teardown commands”Use kubernetesBackend.setupCommand (Helm value) or backend.kubernetes.setup_command (config file) to run a shell command before each task. Use teardownCommand / teardown_command for cleanup after the task finishes. These run inside the task Pod and are useful for workspace bootstrapping or post-run reporting.
Metrics
Section titled “Metrics”Enable worker OpenTelemetry metrics with metrics.enabled=true. See Monitoring for Helm values, the metric catalog, and sample PromQL queries.
Related pages
Section titled “Related pages”- Self-hosted worker reference — Full CLI flag and config file schema, including every Kubernetes backend field.
- Self-hosting overview — Managed vs unmanaged and the backend decision guide.
- Routing runs to this worker — How to send tasks to your connected worker from the CLI, schedules, integrations, the API, and the web UI.
- Environments — Define the task image, repos, and setup commands.
- Monitoring — OpenTelemetry metrics, including Helm chart metrics values.
- Security and networking — RBAC, admission policies, and data boundaries.
- Troubleshooting — Common Kubernetes-backend issues.