{"id":617,"date":"2026-03-21T22:52:57","date_gmt":"2026-03-21T14:52:57","guid":{"rendered":"https:\/\/pa.yingzhi8.cn\/index.php\/2026\/03\/21\/install-kubernetes\/"},"modified":"2026-03-21T23:23:48","modified_gmt":"2026-03-21T15:23:48","slug":"install-kubernetes","status":"publish","type":"post","link":"https:\/\/pa.yingzhi8.cn\/index.php\/2026\/03\/21\/install-kubernetes\/","title":{"rendered":"Kubernetes"},"content":{"rendered":"<h1>Kubernetes<\/h1>\n<h1>OpenClaw on Kubernetes<\/h1>\n<p>A minimal starting point for running OpenClaw on Kubernetes &mdash; not a production-ready deployment. It covers the core resources and is meant to be adapted to your environment.<\/p>\n<h2>Why not Helm?<\/h2>\n<p>OpenClaw is a single container with some config files. The interesting customization is in agent content (markdown files, skills, config overrides), not infrastructure templating. Kustomize handles overlays without the overhead of a Helm chart. If your deployment grows more complex, a Helm chart can be layered on top of these manifests.<\/p>\n<h2>What you need<\/h2>\n<ul>\n<li>A running Kubernetes cluster (AKS, EKS, GKE, k3s, kind, OpenShift, etc.)<\/li>\n<li><code>kubectl<\/code> connected to your cluster<\/li>\n<li>An API key for at least one model provider<\/li>\n<\/ul>\n<h2>&#24555;&#36895;&#24320;&#22987;<\/h2>\n<p>&#8220;`bash  theme={&#8220;theme&#8221;:{&#8220;light&#8221;:&#8221;min-light&#8221;,&#8221;dark&#8221;:&#8221;min-dark&#8221;}}<\/p>\n<h1>Replace with your provider: ANTHROPIC, GEMINI, OPENAI, or OPENROUTER<\/h1>\n<p>export _API_KEY=&#8221;&#8230;&#8221;<br \/>\n.\/scripts\/k8s\/deploy.sh<\/p>\n<p>kubectl port-forward svc\/openclaw 18789:18789 -n openclaw<br \/>\nopen http:\/\/localhost:18789<\/p>\n<pre><code>\nRetrieve the gateway token and paste it into the Control UI:\n\n```bash  theme={\"theme\":{\"light\":\"min-light\",\"dark\":\"min-dark\"}}\nkubectl get secret openclaw-secrets -n openclaw -o jsonpath='{.data.OPENCLAW_GATEWAY_TOKEN}' | base64 -d\n<\/code><\/pre>\n<p>For local debugging, <code>.\/scripts\/k8s\/deploy.sh --show-token<\/code> prints the token after deploy.<\/p>\n<h2>Local testing with Kind<\/h2>\n<p>If you don&#8217;t have a cluster, create one locally with <a href=\"https:\/\/kind.sigs.k8s.io\/\">Kind<\/a>:<\/p>\n<p>&#8220;`bash  theme={&#8220;theme&#8221;:{&#8220;light&#8221;:&#8221;min-light&#8221;,&#8221;dark&#8221;:&#8221;min-dark&#8221;}}<br \/>\n.\/scripts\/k8s\/create-kind.sh           # auto-detects docker or podman<br \/>\n.\/scripts\/k8s\/create-kind.sh &#8211;delete  # tear down<\/p>\n<pre><code>\nThen deploy as usual with `.\/scripts\/k8s\/deploy.sh`.\n\n## Step by step\n\n### 1) Deploy\n\n**Option A** &mdash; API key in environment (one step):\n\n```bash  theme={\"theme\":{\"light\":\"min-light\",\"dark\":\"min-dark\"}}\n# Replace with your provider: ANTHROPIC, GEMINI, OPENAI, or OPENROUTER\nexport &lt;PROVIDER&gt;_API_KEY=\"...\"\n.\/scripts\/k8s\/deploy.sh\n<\/code><\/pre>\n<p>The script creates a Kubernetes Secret with the API key and an auto-generated gateway token, then deploys. If the Secret already exists, it preserves the current gateway token and any provider keys not being changed.<\/p>\n<p><strong>Option B<\/strong> &mdash; create the secret separately:<\/p>\n<p>&#8220;`bash  theme={&#8220;theme&#8221;:{&#8220;light&#8221;:&#8221;min-light&#8221;,&#8221;dark&#8221;:&#8221;min-dark&#8221;}}<br \/>\nexport _API_KEY=&#8221;&#8230;&#8221;<br \/>\n.\/scripts\/k8s\/deploy.sh &#8211;create-secret<br \/>\n.\/scripts\/k8s\/deploy.sh<\/p>\n<pre><code>\nUse `--show-token` with either command if you want the token printed to stdout for local testing.\n\n### 2) Access the gateway\n\n```bash  theme={\"theme\":{\"light\":\"min-light\",\"dark\":\"min-dark\"}}\nkubectl port-forward svc\/openclaw 18789:18789 -n openclaw\nopen http:\/\/localhost:18789\n<\/code><\/pre>\n<h2>What gets deployed<\/h2>\n<pre><code>Namespace: openclaw (configurable via OPENCLAW_NAMESPACE)\n&#9500;&#9472;&#9472; Deployment\/openclaw        # Single pod, init container + gateway\n&#9500;&#9472;&#9472; Service\/openclaw           # ClusterIP on port 18789\n&#9500;&#9472;&#9472; PersistentVolumeClaim      # 10Gi for agent state and config\n&#9500;&#9472;&#9472; ConfigMap\/openclaw-config  # openclaw.json + AGENTS.md\n&#9492;&#9472;&#9472; Secret\/openclaw-secrets    # Gateway token + API keys\n<\/code><\/pre>\n<h2>Customization<\/h2>\n<h3>Agent instructions<\/h3>\n<p>Edit the <code>AGENTS.md<\/code> in <code>scripts\/k8s\/manifests\/configmap.yaml<\/code> and redeploy:<\/p>\n<p>&#8220;`bash  theme={&#8220;theme&#8221;:{&#8220;light&#8221;:&#8221;min-light&#8221;,&#8221;dark&#8221;:&#8221;min-dark&#8221;}}<br \/>\n.\/scripts\/k8s\/deploy.sh<\/p>\n<pre><code>\n### Gateway config\n\nEdit `openclaw.json` in `scripts\/k8s\/manifests\/configmap.yaml`. See [Gateway configuration](\/gateway\/configuration) for the full reference.\n\n### Add providers\n\nRe-run with additional keys exported:\n\n```bash  theme={\"theme\":{\"light\":\"min-light\",\"dark\":\"min-dark\"}}\nexport ANTHROPIC_API_KEY=\"...\"\nexport OPENAI_API_KEY=\"...\"\n.\/scripts\/k8s\/deploy.sh --create-secret\n.\/scripts\/k8s\/deploy.sh\n<\/code><\/pre>\n<p>Existing provider keys stay in the Secret unless you overwrite them.<\/p>\n<p>Or patch the Secret directly:<\/p>\n<p>&#8220;`bash  theme={&#8220;theme&#8221;:{&#8220;light&#8221;:&#8221;min-light&#8221;,&#8221;dark&#8221;:&#8221;min-dark&#8221;}}<br \/>\nkubectl patch secret openclaw-secrets -n openclaw<br \/>\n  -p &#8216;{&#8220;stringData&#8221;:{&#8220;_API_KEY&#8221;:&#8221;&#8230;&#8221;}}&#8217;<br \/>\nkubectl rollout restart deployment\/openclaw -n openclaw<\/p>\n<pre><code>\n### Custom namespace\n\n```bash  theme={\"theme\":{\"light\":\"min-light\",\"dark\":\"min-dark\"}}\nOPENCLAW_NAMESPACE=my-namespace .\/scripts\/k8s\/deploy.sh\n<\/code><\/pre>\n<h3>Custom image<\/h3>\n<p>Edit the <code>image<\/code> field in <code>scripts\/k8s\/manifests\/deployment.yaml<\/code>:<\/p>\n<p>&#8220;`yaml  theme={&#8220;theme&#8221;:{&#8220;light&#8221;:&#8221;min-light&#8221;,&#8221;dark&#8221;:&#8221;min-dark&#8221;}}<br \/>\nimage: ghcr.io\/openclaw\/openclaw:latest # or pin to a specific version from https:\/\/github.com\/openclaw\/openclaw\/releases<\/p>\n<pre><code>\n### Expose beyond port-forward\n\nThe default manifests bind the gateway to loopback inside the pod. That works with `kubectl port-forward`, but it does not work with a Kubernetes `Service` or Ingress path that needs to reach the pod IP.\n\nIf you want to expose the gateway through an Ingress or load balancer:\n\n* Change the gateway bind in `scripts\/k8s\/manifests\/configmap.yaml` from `loopback` to a non-loopback bind that matches your deployment model\n* Keep gateway auth enabled and use a proper TLS-terminated entrypoint\n* Configure the Control UI for remote access using the supported web security model (for example HTTPS\/Tailscale Serve and explicit allowed origins when needed)\n\n## Re-deploy\n\n```bash  theme={\"theme\":{\"light\":\"min-light\",\"dark\":\"min-dark\"}}\n.\/scripts\/k8s\/deploy.sh\n<\/code><\/pre>\n<p>This applies all manifests and restarts the pod to pick up any config or secret changes.<\/p>\n<h2>Teardown<\/h2>\n<p>&#8220;`bash  theme={&#8220;theme&#8221;:{&#8220;light&#8221;:&#8221;min-light&#8221;,&#8221;dark&#8221;:&#8221;min-dark&#8221;}}<br \/>\n.\/scripts\/k8s\/deploy.sh &#8211;delete<\/p>\n<pre><code>\nThis deletes the namespace and all resources in it, including the PVC.\n\n## Architecture notes\n\n* The gateway binds to loopback inside the pod by default, so the included setup is for `kubectl port-forward`\n* No cluster-scoped resources &mdash; everything lives in a single namespace\n* Security: `readOnlyRootFilesystem`, `drop: ALL` capabilities, non-root user (UID 1000)\n* The default config keeps the Control UI on the safer local-access path: loopback bind plus `kubectl port-forward` to `http:\/\/127.0.0.1:18789`\n* If you move beyond localhost access, use the supported remote model: HTTPS\/Tailscale plus the appropriate gateway bind and Control UI origin settings\n* Secrets are generated in a temp directory and applied directly to the cluster &mdash; no secret material is written to the repo checkout\n\n## File structure\n\n<\/code><\/pre>\n<p>scripts\/k8s\/<br \/>\n&#9500;&#9472;&#9472; deploy.sh                   # Creates namespace + secret, deploys via kustomize<br \/>\n&#9500;&#9472;&#9472; create-kind.sh              # Local Kind cluster (auto-detects docker\/podman)<br \/>\n&#9492;&#9472;&#9472; manifests\/<br \/>\n    &#9500;&#9472;&#9472; kustomization.yaml      # Kustomize base<br \/>\n    &#9500;&#9472;&#9472; configmap.yaml          # openclaw.json + AGENTS.md<br \/>\n    &#9500;&#9472;&#9472; deployment.yaml         # Pod spec with security hardening<br \/>\n    &#9500;&#9472;&#9472; pvc.yaml                # 10Gi persistent storage<br \/>\n    &#9492;&#9472;&#9472; service.yaml            # ClusterIP on 18789<br \/>\n&#8220;`<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Kubernetes OpenClaw on Kubernetes A minimal starting po [&hellip;]<\/p>\n","protected":false},"author":0,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[2],"tags":[],"class_list":["post-617","post","type-post","status-publish","format-standard","hentry","category-docs"],"_links":{"self":[{"href":"https:\/\/pa.yingzhi8.cn\/index.php\/wp-json\/wp\/v2\/posts\/617","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/pa.yingzhi8.cn\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/pa.yingzhi8.cn\/index.php\/wp-json\/wp\/v2\/types\/post"}],"replies":[{"embeddable":true,"href":"https:\/\/pa.yingzhi8.cn\/index.php\/wp-json\/wp\/v2\/comments?post=617"}],"version-history":[{"count":3,"href":"https:\/\/pa.yingzhi8.cn\/index.php\/wp-json\/wp\/v2\/posts\/617\/revisions"}],"predecessor-version":[{"id":771,"href":"https:\/\/pa.yingzhi8.cn\/index.php\/wp-json\/wp\/v2\/posts\/617\/revisions\/771"}],"wp:attachment":[{"href":"https:\/\/pa.yingzhi8.cn\/index.php\/wp-json\/wp\/v2\/media?parent=617"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/pa.yingzhi8.cn\/index.php\/wp-json\/wp\/v2\/categories?post=617"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/pa.yingzhi8.cn\/index.php\/wp-json\/wp\/v2\/tags?post=617"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}