Skip to main content
2501 runs on any Kubernetes distribution — vanilla k8s, OpenShift, k3s, EKS, GKE, AKS, Minikube. The engine runs each tool executor in its own isolated sandbox. On Docker and Docker Swarm that sandbox is a container; on Kubernetes the engine creates a short-lived Kubernetes Pod instead — a pod is created when work starts, the engine attaches to it over stdin and stdout, and the pod is deleted when the task ends. This page covers how to generate the deployment manifests with the 2501 CLI, how the Kubernetes backend selects itself, and the RBAC the engine needs.
Docker Swarm remains the default deployment target, with a fully managed deploy lifecycle. The Kubernetes target is generate-only: the CLI renders a complete manifest tree and you apply it with kubectl (or your distribution’s equivalent CLI). This keeps you in control of how changes reach the cluster, including through GitOps tooling.

Generating the manifests

Run the deploy command with the Kubernetes target:
2501 infra deploy --target kubernetes
The CLI prompts for a stack name, namespace, image tag, Command Center public URL, and your Elasticsearch and AWS (registry pull) values, then renders a ready-to-apply manifest tree under <configDir>/kubernetes/:
kubernetes/
├── namespace.yml
├── configmap/        # engine, command-center
├── secret/           # engine, command-center, postgres, ecr-pull-secret, license-public-key
├── deployment/       # engine, command-center, postgres
├── service/          # engine, command-center, postgres
├── pvc/              # postgres
└── rbac/             # executor ServiceAccount, Role, RoleBinding
For non-interactive use, pass the values as flags:
2501 infra deploy --target kubernetes --image-tag <tag> \
  --stack-name ai-2501 --namespace ai-2501 --yes
--image-tag (alias --tag) is required with --yes. --stack-name and --namespace both default to ai-2501, and both are validated as DNS-1123 labels.

Flags

2501 infra deploy -h
Usage: 2501 infra deploy [options]

Deploy 2501 stack

Options:
  --remove                       Remove the deployed stack
  --stop                         Stop the deployed stack
  -t, --tag <tag>                Image tag to deploy (overrides config, e.g. for
                                 testing a build)
  --target <target>              Deployment target: swarm or kubernetes
                                 (overrides config)
  --stack-name <name>            Kubernetes: stack name for Service names/labels
                                 (default: ai-2501)
  --namespace <name>             Kubernetes: target namespace (default: ai-2501)
  --image-tag <tag>              Kubernetes: image tag to deploy (required for
                                 --target kubernetes; alias of --tag)
  -r, --restart [service]        Restart with env reload (optional: engine,
                                 command-center)
  --history                      Show deployment history
  -d, --dir <path>               Config directory (default: /etc/2501)
  -y, --yes                      Non-interactive mode - skip prompts and
                                 seeding, fail on errors
  --cleanup-resources            Clean up unused images and resources before
                                 deployment
  --cleanup-docker-resources     Alias for --cleanup-resources (deprecated)
  --disable-services [services]  Disable services (comma-separated: engine,
                                 command-center, or omit to disable all)
  -h, --help                     display help for command
--remove, --stop, --restart, --history, --cleanup-resources, and --disable-services drive the Swarm lifecycle; on the Kubernetes target the relevant options are --target, --stack-name, --namespace, --image-tag, -d, --dir, and -y, --yes.

Filling in secrets

Secret manifests use stringData, so every value is plain text and the cluster encodes it server-side on apply. Before applying, fill in any blank values directly in the YAML:
  • AWS_* and ELASTICSEARCH_* in secret/engine.yml and secret/command-center.yml
  • BASE_URL in configmap/command-center.yml (your real ingress hostname)
  • The license public key in secret/license-public-key.yml, unless a PEM file already exists at <configDir>/license.public.pem
Generation is safe to re-run. Auto-generated secrets (the PostgreSQL password, credential encryption key, engine API key, auth secret, and log encryption key) are created once and read back from the existing YAML on subsequent runs, and values you typed into the files by hand are preserved. An empty prompt answer never overwrites a previously supplied value.

Applying

kubectl apply -f <configDir>/kubernetes/ -R
(Substitute your distribution’s CLI if you don’t use kubectloc, k3s kubectl, etc.)
The registry pull secret is a short-lived ECR token that expires after roughly 12 hours. Recreate it before each apply:
kubectl create secret docker-registry ecr-pull-secret \
  --docker-server=<registry> --docker-username=AWS \
  --docker-password=$(aws ecr get-login-password --region <region>) \
  -n <namespace> --dry-run=client -o yaml | kubectl apply -f -

Executor backend selection

The engine picks an executor backend automatically:
  • When it detects that it is running inside a Kubernetes cluster, it uses the Kubernetes pod backend.
  • Otherwise it falls back to Docker / Swarm.
You can force a backend with the EXECUTOR_MCP_BACKEND environment variable, set to kube or docker.
The engine talks to the in-cluster Kubernetes API directly using the pod’s auto-mounted service-account token. It does not shell out to kubectl, and you do not supply a kubeconfig.

Required access (RBAC)

The generated rbac/executor.yml provisions a dedicated engine-executor ServiceAccount with a namespace-scoped Role and RoleBinding granting:
ResourceVerbs
podscreate, get, list, watch, delete
pods/attachcreate, get
pods/statusget
pods/logget
Executor pods spawn in the same namespace as the engine. To use a separate sandbox namespace, change the RoleBinding’s namespace and override EXECUTOR_MCP_K8S_NAMESPACE on the engine pod, which is otherwise set to the engine’s own namespace via the Downward API.
gMSA-bound Windows targets are not supported on the Kubernetes executor backend. They depend on a Docker-volume Kerberos sidecar that this backend does not provide. Use the Docker or Swarm backend for those targets. See Docker Swarm.
For the full set of engine and Command Center environment variables (database, security keys, LLM providers, optional integrations), see Configuration.