Vai al contenuto principale

OpenClaw su Kubernetes

Un punto di partenza minimale per eseguire OpenClaw su Kubernetes — non un deployment pronto per la produzione. Copre le risorse principali ed è pensato per essere adattato al tuo ambiente.

Perché non Helm?

OpenClaw è un singolo container con alcuni file di configurazione. La personalizzazione interessante è nel contenuto dell’agente (file markdown, Skills, override di configurazione), non nel templating dell’infrastruttura. Kustomize gestisce gli overlay senza l’overhead di un chart Helm. Se il tuo deployment diventa più complesso, un chart Helm può essere aggiunto sopra questi manifest.

Cosa ti serve

  • Un cluster Kubernetes in esecuzione (AKS, EKS, GKE, k3s, kind, OpenShift, ecc.)
  • kubectl collegato al tuo cluster
  • Una API key per almeno un provider di modelli

Avvio rapido

# Sostituisci con il tuo provider: ANTHROPIC, GEMINI, OPENAI o OPENROUTER
export <PROVIDER>_API_KEY="..."
./scripts/k8s/deploy.sh

kubectl port-forward svc/openclaw 18789:18789 -n openclaw
open http://localhost:18789
Recupera il segreto condiviso configurato per la UI di controllo. Questo script di deployment crea per impostazione predefinita l’autenticazione con token:
kubectl get secret openclaw-secrets -n openclaw -o jsonpath='{.data.OPENCLAW_GATEWAY_TOKEN}' | base64 -d
Per il debug locale, ./scripts/k8s/deploy.sh --show-token stampa il token dopo il deployment.

Test locali con Kind

Se non hai un cluster, creane uno localmente con Kind:
./scripts/k8s/create-kind.sh           # rileva automaticamente docker o podman
./scripts/k8s/create-kind.sh --delete  # smantella
Poi esegui il deployment come al solito con ./scripts/k8s/deploy.sh.

Passo dopo passo

1) Deployment

Opzione A — API key nell’ambiente (un solo passaggio):
# Sostituisci con il tuo provider: ANTHROPIC, GEMINI, OPENAI o OPENROUTER
export <PROVIDER>_API_KEY="..."
./scripts/k8s/deploy.sh
Lo script crea un Secret Kubernetes con la API key e un token gateway generato automaticamente, poi esegue il deployment. Se il Secret esiste già, conserva il token gateway corrente e tutte le chiavi provider che non vengono modificate. Opzione B — crea il secret separatamente:
export <PROVIDER>_API_KEY="..."
./scripts/k8s/deploy.sh --create-secret
./scripts/k8s/deploy.sh
Usa --show-token con uno dei due comandi se vuoi che il token venga stampato su stdout per test locali.

2) Accedi al gateway

kubectl port-forward svc/openclaw 18789:18789 -n openclaw
open http://localhost:18789

Cosa viene distribuito

Namespace: openclaw (configurabile tramite OPENCLAW_NAMESPACE)
├── Deployment/openclaw        # Singolo pod, init container + gateway
├── Service/openclaw           # ClusterIP sulla porta 18789
├── PersistentVolumeClaim      # 10Gi per stato e configurazione dell'agente
├── ConfigMap/openclaw-config  # openclaw.json + AGENTS.md
└── Secret/openclaw-secrets    # Token gateway + API key

Personalizzazione

Istruzioni dell’agente

Modifica AGENTS.md in scripts/k8s/manifests/configmap.yaml ed esegui di nuovo il deployment:
./scripts/k8s/deploy.sh

Configurazione del Gateway

Modifica openclaw.json in scripts/k8s/manifests/configmap.yaml. Vedi Configurazione del Gateway per il riferimento completo.

Aggiungi provider

Esegui di nuovo con chiavi aggiuntive esportate:
export ANTHROPIC_API_KEY="..."
export OPENAI_API_KEY="..."
./scripts/k8s/deploy.sh --create-secret
./scripts/k8s/deploy.sh
Le chiavi provider esistenti restano nel Secret a meno che tu non le sovrascriva. Oppure applica una patch direttamente al Secret:
kubectl patch secret openclaw-secrets -n openclaw \
  -p '{"stringData":{"<PROVIDER>_API_KEY":"..."}}'
kubectl rollout restart deployment/openclaw -n openclaw

Namespace personalizzato

OPENCLAW_NAMESPACE=my-namespace ./scripts/k8s/deploy.sh

Immagine personalizzata

Modifica il campo image in scripts/k8s/manifests/deployment.yaml:
image: ghcr.io/openclaw/openclaw:latest # oppure fissalo a una versione specifica da https://github.com/openclaw/openclaw/releases

Esposizione oltre port-forward

I manifest predefiniti effettuano il bind del gateway al loopback all’interno del pod. Questo funziona con kubectl port-forward, ma non funziona con un Service Kubernetes o un percorso Ingress che deve raggiungere l’IP del pod. Se vuoi esporre il gateway tramite un Ingress o un load balancer:
  • Modifica il bind del gateway in scripts/k8s/manifests/configmap.yaml da loopback a un bind non loopback che corrisponda al tuo modello di deployment
  • Mantieni abilitata l’autenticazione del gateway e usa un entrypoint con terminazione TLS corretta
  • Configura la UI di controllo per l’accesso remoto usando il modello di sicurezza web supportato (ad esempio HTTPS/Tailscale Serve e origini consentite esplicite quando necessario)

Esegui nuovamente il deployment

./scripts/k8s/deploy.sh
Questo applica tutti i manifest e riavvia il pod per recepire eventuali modifiche a configurazione o secret.

Smantellamento

./scripts/k8s/deploy.sh --delete
Questo elimina il namespace e tutte le risorse al suo interno, incluso il PVC.

Note sull’architettura

  • Per impostazione predefinita, il gateway effettua il bind al loopback all’interno del pod, quindi la configurazione inclusa è pensata per kubectl port-forward
  • Nessuna risorsa con scope cluster — tutto vive in un singolo namespace
  • Sicurezza: readOnlyRootFilesystem, capability drop: ALL, utente non root (UID 1000)
  • La configurazione predefinita mantiene la UI di controllo sul percorso di accesso locale più sicuro: bind loopback più kubectl port-forward verso http://127.0.0.1:18789
  • Se vai oltre l’accesso localhost, usa il modello remoto supportato: HTTPS/Tailscale più il bind gateway appropriato e le impostazioni di origine della UI di controllo
  • I secret vengono generati in una directory temporanea e applicati direttamente al cluster — nessun materiale segreto viene scritto nel checkout del repo

Struttura dei file

scripts/k8s/
├── deploy.sh                   # Crea namespace + secret, esegue il deployment tramite kustomize
├── create-kind.sh              # Cluster Kind locale (rileva automaticamente docker/podman)
└── manifests/
    ├── kustomization.yaml      # Base Kustomize
    ├── configmap.yaml          # openclaw.json + AGENTS.md
    ├── deployment.yaml         # Specifica del pod con hardening di sicurezza
    ├── pvc.yaml                # Storage persistente da 10Gi
    └── service.yaml            # ClusterIP su 18789