feat: add helm chart support (#1)

feat: enhance Helm chart workflows and update image references
This commit is contained in:
sirily11 2026-01-27 11:33:53 +08:00
parent 34653e4baf
commit 6635d70170
No known key found for this signature in database
GPG Key ID: 210EC8A2FB4FB9CB
26 changed files with 2593 additions and 2 deletions

12
.github/labeler.yml vendored
View File

@ -220,3 +220,15 @@
- changed-files:
- any-glob-to-any-file:
- "extensions/qwen-portal-auth/**"
"kubernetes":
- changed-files:
- any-glob-to-any-file:
- "charts/**"
- "docs/install/kubernetes.md"
- ".github/workflows/helm-test.yml"
"helm":
- changed-files:
- any-glob-to-any-file:
- "charts/**"

124
.github/workflows/helm-release.yml vendored Normal file
View File

@ -0,0 +1,124 @@
name: Release Helm Chart
on:
push:
branches:
- main
paths:
- 'charts/**'
tags:
- 'v*'
workflow_dispatch:
env:
REGISTRY: ghcr.io
IMAGE_NAME: ${{ github.repository }}
jobs:
# Validate chart on all triggers
validate:
name: Validate Helm Chart
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Install Helm
uses: azure/setup-helm@v4
with:
version: v3.13.0
- name: Lint chart
run: helm lint charts/clawdbot
- name: Lint with production values
run: helm lint charts/clawdbot -f charts/clawdbot/values.yaml
- name: Template validation
run: helm template test charts/clawdbot --debug
# Release chart only on tag push
release:
name: Release Helm Chart
runs-on: ubuntu-latest
needs: validate
if: startsWith(github.ref, 'refs/tags/')
permissions:
contents: write
pages: write
id-token: write
steps:
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Configure Git
run: |
git config user.name "$GITHUB_ACTOR"
git config user.email "$GITHUB_ACTOR@users.noreply.github.com"
- name: Install Helm
uses: azure/setup-helm@v4
with:
version: v3.13.0
- name: Install yq
uses: mikefarah/yq@v4
- name: Extract version from tag
id: version
run: |
VERSION=${GITHUB_REF#refs/tags/v}
echo "version=$VERSION" >> $GITHUB_OUTPUT
echo "Extracted version: $VERSION"
- name: Update Chart.yaml with version
run: |
VERSION="${{ steps.version.outputs.version }}"
echo "Updating Chart.yaml with version: $VERSION"
yq e '.version = strenv(VERSION)' -i charts/clawdbot/Chart.yaml
yq e '.appVersion = strenv(VERSION)' -i charts/clawdbot/Chart.yaml
cat charts/clawdbot/Chart.yaml
env:
VERSION: ${{ steps.version.outputs.version }}
- name: Update values.yaml with image repository
run: |
echo "Updating image repository to: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}"
yq e '.image.registry = "${{ env.REGISTRY }}"' -i charts/clawdbot/values.yaml
yq e '.image.repository = "${{ env.IMAGE_NAME }}"' -i charts/clawdbot/values.yaml
cat charts/clawdbot/values.yaml | head -20
- name: Package Helm chart
run: |
mkdir -p .cr-release-packages
helm package charts/clawdbot -d .cr-release-packages
ls -la .cr-release-packages
- name: Run chart-releaser
uses: helm/chart-releaser-action@v1.6.0
with:
charts_dir: charts
skip_existing: true
env:
CR_TOKEN: "${{ secrets.GITHUB_TOKEN }}"
# Update GitHub Pages index
publish-pages:
name: Publish to GitHub Pages
runs-on: ubuntu-latest
needs: release
if: startsWith(github.ref, 'refs/tags/')
steps:
- name: Checkout gh-pages branch
uses: actions/checkout@v4
with:
ref: gh-pages
fetch-depth: 0
- name: Verify index updated
run: |
echo "Chart published successfully"
echo "Helm repo: https://clawdbot.github.io/clawdbot"
echo "Install with: helm repo add clawdbot https://clawdbot.github.io/clawdbot"

125
.github/workflows/helm-test.yml vendored Normal file
View File

@ -0,0 +1,125 @@
name: Helm Chart Tests
on:
pull_request:
paths:
- 'charts/**'
- 'Dockerfile'
- '.github/workflows/helm-test.yml'
push:
branches:
- main
paths:
- 'charts/**'
- 'Dockerfile'
jobs:
lint-test:
name: Lint and Test Helm Chart
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v6
- name: Set up Helm
uses: azure/setup-helm@v4
with:
version: v3.13.0
- name: Lint Helm chart
run: |
helm lint charts/clawdbot
helm lint charts/clawdbot --values charts/clawdbot/examples/values-basic.yaml
helm lint charts/clawdbot --values charts/clawdbot/examples/values-production.yaml
- name: Template validation
run: |
helm template test charts/clawdbot \
--values charts/clawdbot/examples/values-basic.yaml \
--set secrets.data.anthropicApiKey=test-key \
> /tmp/manifests.yaml
cat /tmp/manifests.yaml
kind-test:
name: Test on Kind
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v6
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Build Docker image
uses: docker/build-push-action@v6
with:
context: .
file: ./Dockerfile
tags: clawdbot:test
load: true
cache-from: type=gha
cache-to: type=gha,mode=max
- name: Create Kind cluster
uses: helm/kind-action@v1.8.0
with:
cluster_name: clawdbot-test
config: |
kind: Cluster
apiVersion: kind.x-k8s.io/v1alpha4
nodes:
- role: control-plane
- name: Load image into Kind
run: |
kind load docker-image clawdbot:test --name clawdbot-test
- name: Set up Helm
uses: azure/setup-helm@v4
with:
version: v3.13.0
- name: Install Helm chart
run: |
helm install test-clawdbot charts/clawdbot \
--values charts/clawdbot/examples/values-basic.yaml \
--set image.repository=clawdbot \
--set image.tag=test \
--set image.pullPolicy=Never \
--set secrets.data.anthropicApiKey=test-key \
--set secrets.data.gatewayToken=$(openssl rand -hex 32) \
--wait --timeout=3m
- name: Verify deployment
run: |
kubectl get all -l app.kubernetes.io/name=clawdbot
kubectl wait --for=condition=ready pod -l app.kubernetes.io/name=clawdbot --timeout=120s
kubectl get pvc -l app.kubernetes.io/name=clawdbot
- name: Check pod logs
if: always()
run: |
POD_NAME=$(kubectl get pod -l app.kubernetes.io/name=clawdbot -o jsonpath='{.items[0].metadata.name}')
kubectl logs $POD_NAME --tail=100
- name: Run Helm tests
run: |
helm test test-clawdbot
- name: Test health command
run: |
POD_NAME=$(kubectl get pod -l app.kubernetes.io/name=clawdbot -o jsonpath='{.items[0].metadata.name}')
GATEWAY_TOKEN=$(kubectl get secret test-clawdbot -o jsonpath='{.data.gatewayToken}' | base64 -d)
kubectl exec $POD_NAME -- node dist/index.js health --token "$GATEWAY_TOKEN" || true
- name: Verify persistence
run: |
POD_NAME=$(kubectl get pod -l app.kubernetes.io/name=clawdbot -o jsonpath='{.items[0].metadata.name}')
kubectl exec $POD_NAME -- ls -la /home/node/.clawdbot
kubectl exec $POD_NAME -- ls -la /home/node/clawd
- name: Cleanup
if: always()
run: |
helm uninstall test-clawdbot || true
kubectl delete pvc -l app.kubernetes.io/name=clawdbot || true

View File

@ -21,7 +21,7 @@ It answers you on the channels you already use (WhatsApp, Telegram, Slack, Disco
If you want a personal, single-user assistant that feels local, fast, and always-on, this is it.
[Website](https://molt.bot) · [Docs](https://docs.molt.bot) · [Getting Started](https://docs.molt.bot/start/getting-started) · [Updating](https://docs.molt.bot/install/updating) · [Showcase](https://docs.molt.bot/start/showcase) · [FAQ](https://docs.molt.bot/start/faq) · [Wizard](https://docs.molt.bot/start/wizard) · [Nix](https://github.com/moltbot/nix-clawdbot) · [Docker](https://docs.molt.bot/install/docker) · [Discord](https://discord.gg/clawd)
[Website](https://molt.bot) · [Docs](https://docs.molt.bot) · [Getting Started](https://docs.molt.bot/start/getting-started) · [Updating](https://docs.molt.bot/install/updating) · [Showcase](https://docs.molt.bot/start/showcase) · [FAQ](https://docs.molt.bot/start/faq) · [Wizard](https://docs.molt.bot/start/wizard) · [Nix](https://github.com/moltbot/nix-clawdbot) · [Docker](https://docs.molt.bot/install/docker) · [Kubernetes](https://docs.molt.bot/install/kubernetes) · [Discord](https://discord.gg/clawd)
Preferred setup: run the onboarding wizard (`moltbot onboard`). It walks through gateway, workspace, channels, and skills. The CLI wizard is the recommended path and works on **macOS, Linux, and Windows (via WSL2; strongly recommended)**.
Works with npm, pnpm, or bun.
@ -164,7 +164,7 @@ Run `moltbot doctor` to surface risky/misconfigured DM policies.
### Ops + packaging
- [Control UI](https://docs.molt.bot/web) + [WebChat](https://docs.molt.bot/web/webchat) served directly from the Gateway.
- [Tailscale Serve/Funnel](https://docs.molt.bot/gateway/tailscale) or [SSH tunnels](https://docs.molt.bot/gateway/remote) with token/password auth.
- [Nix mode](https://docs.molt.bot/install/nix) for declarative config; [Docker](https://docs.molt.bot/install/docker)-based installs.
- [Nix mode](https://docs.molt.bot/install/nix) for declarative config; [Docker](https://docs.molt.bot/install/docker) and [Kubernetes (Helm)](https://docs.molt.bot/install/kubernetes) deployments.
- [Doctor](https://docs.molt.bot/gateway/doctor) migrations, [logging](https://docs.molt.bot/logging).
## How it works (short)

View File

@ -0,0 +1,23 @@
# Patterns to ignore when building packages.
# This supports shell glob matching, relative path matching, and
# negation (prefixed with !). Only one pattern per line.
.DS_Store
# Common VCS dirs
.git/
.gitignore
.bzr/
.bzrignore
.hg/
.hgignore
.svn/
# Common backup files
*.swp
*.bak
*.tmp
*.orig
*~
# Various IDEs
.project
.idea/
*.tmproj
.vscode/

View File

@ -0,0 +1,21 @@
apiVersion: v2
name: clawdbot
description: Personal AI assistant with multi-channel support
type: application
version: 1.0.0
appVersion: "2026.1.25"
keywords:
- ai
- assistant
- whatsapp
- telegram
- discord
- claude
- chatgpt
home: https://github.com/clawdbot/clawdbot
sources:
- https://github.com/clawdbot/clawdbot
maintainers:
- name: Clawdbot Team
url: https://docs.clawd.bot
icon: https://github.com/clawdbot/clawdbot/raw/main/README-header.png

View File

@ -0,0 +1,253 @@
# Publishing the Clawdbot Helm Chart
This guide covers how to publish the Helm chart to make it available for users.
## Quick Start (Automated)
The chart is automatically published to GitHub Pages when you:
1. Update `charts/clawdbot/Chart.yaml` version
2. Commit and push to `main` branch
3. GitHub Actions automatically packages and publishes
## Publishing Methods
### Option 1: GitHub Pages (Recommended)
#### Initial Setup
1. **Enable GitHub Pages:**
- Go to repository Settings → Pages
- Source: Deploy from a branch
- Branch: `gh-pages``/ (root)`
- Click Save
2. **Create gh-pages branch (first time only):**
```bash
# Create empty gh-pages branch
git checkout --orphan gh-pages
git rm -rf .
echo "# Clawdbot Helm Charts" > README.md
git add README.md
git commit -m "Initial gh-pages"
git push origin gh-pages
git checkout main
```
3. **The workflow will automatically:**
- Package the chart
- Create a GitHub release
- Update the chart repository index
- Publish to GitHub Pages
#### Manual Publishing (if needed)
```bash
# 1. Package the chart
helm package charts/clawdbot -d .cr-release-packages
# 2. Create index
helm repo index .cr-release-packages --url https://clawdbot.github.io/clawdbot
# 3. Commit to gh-pages branch
git checkout gh-pages
cp .cr-release-packages/* .
git add .
git commit -m "Release chart version X.Y.Z"
git push origin gh-pages
git checkout main
```
#### Usage for End Users
Once published, users can install via:
```bash
# Add repo
helm repo add clawdbot https://clawdbot.github.io/clawdbot
helm repo update
# Install
helm install my-clawdbot clawdbot/clawdbot
```
### Option 2: OCI Registry (GitHub Container Registry)
Modern approach using OCI registries:
#### Setup
```bash
# Login to GHCR
echo $GITHUB_TOKEN | helm registry login ghcr.io -u USERNAME --password-stdin
# Package chart
helm package charts/clawdbot
# Push to GHCR
helm push clawdbot-1.0.0.tgz oci://ghcr.io/clawdbot
```
#### Automate in GitHub Actions
```yaml
- name: Login to GHCR
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Push chart to GHCR
run: |
helm package charts/clawdbot
helm push clawdbot-*.tgz oci://ghcr.io/${{ github.repository_owner }}
```
#### Usage for End Users
```bash
# Install directly from OCI
helm install my-clawdbot oci://ghcr.io/clawdbot/clawdbot --version 1.0.0
```
### Option 3: Artifact Hub
Make your chart discoverable on [Artifact Hub](https://artifacthub.io).
#### Prerequisites
- Chart published to GitHub Pages or OCI registry
- Artifact Hub metadata file
#### Add Artifact Hub metadata
Create `charts/clawdbot/artifacthub-repo.yml`:
```yaml
repositoryID: <your-repo-id>
owners:
- name: Clawdbot Team
email: team@clawdbot.com
```
#### Submit to Artifact Hub
1. Go to https://artifacthub.io
2. Sign in with GitHub
3. Add repository
4. Provide repository URL: `https://clawdbot.github.io/clawdbot`
5. Wait for verification
### Option 4: ChartMuseum (Self-Hosted)
For private/internal charts:
```bash
# Run ChartMuseum
docker run -d \
-p 8080:8080 \
-v $(pwd)/charts:/charts \
ghcr.io/helm/chartmuseum:latest \
--storage local \
--storage-local-rootdir /charts
# Upload chart
curl --data-binary "@clawdbot-1.0.0.tgz" http://localhost:8080/api/charts
```
## Versioning
Follow Semantic Versioning:
- **Chart version** (`version` in Chart.yaml): Chart changes
- **App version** (`appVersion` in Chart.yaml): Clawdbot version
### Bumping Versions
```bash
# Update chart version
vim charts/clawdbot/Chart.yaml
# Change version: 1.0.0 → 1.1.0
# Update app version (when clawdbot version changes)
vim charts/clawdbot/Chart.yaml
# Change appVersion: "2026.1.25" → "2026.1.26"
```
### Version Guidelines
- **Major** (1.0.0 → 2.0.0): Breaking changes to values.yaml or behavior
- **Minor** (1.0.0 → 1.1.0): New features, non-breaking changes
- **Patch** (1.0.0 → 1.0.1): Bug fixes, documentation
## Release Checklist
- [ ] Update `version` in `Chart.yaml`
- [ ] Update `appVersion` if clawdbot version changed
- [ ] Update `CHANGELOG.md` (if you have one)
- [ ] Test chart locally: `./scripts/test-helm-local.sh`
- [ ] Lint chart: `helm lint charts/clawdbot`
- [ ] Commit changes
- [ ] Push to main (triggers automated release)
- [ ] Verify GitHub Pages deployment
- [ ] Test installation from published repo
## Testing Published Chart
```bash
# Add your published repo
helm repo add clawdbot https://clawdbot.github.io/clawdbot
helm repo update
# Search for chart
helm search repo clawdbot
# Install from published repo
helm install test clawdbot/clawdbot --dry-run --debug
```
## Troubleshooting
### Chart not appearing after publish
1. Check GitHub Actions logs
2. Verify gh-pages branch exists
3. Check GitHub Pages settings are enabled
4. Wait 5-10 minutes for GitHub Pages to deploy
### Users getting "not found" error
```bash
# Check index.yaml exists
curl https://clawdbot.github.io/clawdbot/index.yaml
# Verify chart package exists
curl https://clawdbot.github.io/clawdbot/clawdbot-1.0.0.tgz
```
### Permission denied during publishing
Ensure GitHub Actions has write permissions:
- Settings → Actions → General → Workflow permissions
- Select "Read and write permissions"
## Advanced: Multi-Chart Repository
If you add more charts:
```
charts/
clawdbot/
clawdbot-operator/
clawdbot-monitoring/
```
The `helm/chart-releaser-action` automatically handles multiple charts.
## References
- [Helm Chart Repository Guide](https://helm.sh/docs/topics/chart_repository/)
- [Chart Releaser Action](https://github.com/helm/chart-releaser-action)
- [Artifact Hub](https://artifacthub.io/docs/topics/repositories/)
- [OCI Registry Support](https://helm.sh/docs/topics/registries/)

302
charts/clawdbot/README.md Normal file
View File

@ -0,0 +1,302 @@
# Clawdbot Helm Chart
Personal AI assistant with multi-channel support (WhatsApp, Telegram, Discord, and more) running on Kubernetes.
## TL;DR
```bash
helm install my-clawdbot ./clawdbot \
--set secrets.data.anthropicApiKey=sk-ant-xxx \
--set secrets.data.gatewayToken=$(openssl rand -hex 32)
```
## Introduction
This chart deploys Clawdbot Gateway on a Kubernetes cluster using the Helm package manager.
**Important:** Clawdbot is designed as a single-user personal assistant. The chart enforces `replicas: 1` and does not support horizontal scaling.
## Prerequisites
- Kubernetes 1.19+
- Helm 3.x
- PV provisioner support in the underlying infrastructure (for persistent storage)
- **Optional:** Ingress controller (NGINX, Traefik, etc.) for external access
- **Optional:** cert-manager for automatic TLS certificates
## Installing the Chart
### Basic Installation
```bash
helm install my-clawdbot ./clawdbot
```
### With Custom Values
```bash
helm install my-clawdbot ./clawdbot \
--values examples/values-production.yaml \
--set secrets.data.anthropicApiKey=sk-ant-xxx \
--set ingress.hosts[0].host=assistant.example.com
```
### From Examples
```bash
# Basic (local testing)
helm install my-clawdbot ./clawdbot -f examples/values-basic.yaml
# Production
helm install my-clawdbot ./clawdbot -f examples/values-production.yaml
# Fly.io-like setup
helm install my-clawdbot ./clawdbot -f examples/values-fly-like.yaml
```
## Uninstalling the Chart
```bash
helm uninstall my-clawdbot
# Also delete PVCs (data will be lost)
kubectl delete pvc -l app.kubernetes.io/instance=my-clawdbot
```
## Configuration
### Key Parameters
| Parameter | Description | Default |
|-----------|-------------|---------|
| `replicaCount` | Number of replicas (must be 1) | `1` |
| `image.repository` | Clawdbot image repository | `clawdbot/clawdbot` |
| `image.tag` | Image tag | Chart appVersion |
| `gateway.bind` | Gateway binding mode (`loopback`, `lan`, `auto`) | `lan` |
| `gateway.port` | Gateway port | `18789` |
| `secrets.data.anthropicApiKey` | Anthropic API key | `""` |
| `secrets.data.openaiApiKey` | OpenAI API key | `""` |
| `secrets.data.gatewayToken` | Gateway authentication token (auto-generated if empty) | `""` |
| `persistence.enabled` | Enable persistent storage | `true` |
| `persistence.size` | PVC size | `10Gi` |
| `ingress.enabled` | Enable Ingress | `false` |
| `ingress.className` | Ingress class | `nginx` |
| `resources.limits.memory` | Memory limit | `2Gi` |
| `resources.requests.memory` | Memory request | `512Mi` |
### Full Values Reference
See [values.yaml](values.yaml) for all available parameters.
## Storage
The chart creates a StatefulSet with a persistent volume claim template that mounts storage at two locations:
- `/home/node/.clawdbot` (subPath: `clawdbot-state`) - Configuration, sessions, device identity, SQLite databases
- `/home/node/clawd` (subPath: `clawdbot-workspace`) - Agent workspace files
**Storage Class:** By default, uses the cluster's default storage class. Override with `persistence.storageClass`.
**Size Recommendations:**
- Development/Testing: 5-10Gi
- Production (single user): 20Gi+
- Depends on session history and workspace usage
## Secrets Management
### Option 1: Inline Secrets (Development Only)
```bash
helm install my-clawdbot ./clawdbot \
--set secrets.data.anthropicApiKey=sk-ant-xxx \
--set secrets.data.gatewayToken=$(openssl rand -hex 32)
```
### Option 2: External Secret (Production)
Create a Kubernetes Secret:
```bash
kubectl create secret generic clawdbot-secrets \
--from-literal=gatewayToken=$(openssl rand -hex 32) \
--from-literal=anthropicApiKey=sk-ant-xxx \
--from-literal=discordBotToken=MTQ...
```
Install with existing secret:
```bash
helm install my-clawdbot ./clawdbot \
--set secrets.create=false \
--set secrets.existingSecret=clawdbot-secrets
```
### Option 3: External Secrets Operator
Use External Secrets Operator to sync from Vault, AWS Secrets Manager, etc.
## Ingress
### NGINX Ingress Controller
```yaml
ingress:
enabled: true
className: nginx
annotations:
cert-manager.io/cluster-issuer: letsencrypt-prod
nginx.ingress.kubernetes.io/proxy-read-timeout: "3600"
nginx.ingress.kubernetes.io/proxy-send-timeout: "3600"
nginx.ingress.kubernetes.io/websocket-services: "{{ include \"clawdbot.fullname\" . }}"
hosts:
- host: assistant.example.com
paths:
- path: /
pathType: Prefix
tls:
- secretName: clawdbot-tls
hosts:
- assistant.example.com
```
**Important:** WebSocket support requires extended timeouts (3600s recommended).
### Traefik
```yaml
ingress:
className: traefik
annotations:
traefik.ingress.kubernetes.io/router.entrypoints: websecure
traefik.ingress.kubernetes.io/router.tls: "true"
```
## Health Checks
The chart uses exec-based probes that run the CLI health command:
```yaml
livenessProbe:
exec:
command:
- sh
- -c
- node dist/index.js health --token "${CLAWDBOT_GATEWAY_TOKEN}" || exit 1
```
## Upgrading
```bash
# Pull latest chart changes
git pull
# Upgrade with current values
helm upgrade my-clawdbot ./clawdbot --reuse-values
# Upgrade with new values
helm upgrade my-clawdbot ./clawdbot -f values-production.yaml
```
## Troubleshooting
### Pod Not Starting
```bash
# Check pod events
kubectl describe pod my-clawdbot-0
# Check logs
kubectl logs my-clawdbot-0
```
### OOM (Out of Memory)
Increase memory limits:
```yaml
resources:
limits:
memory: 4Gi
requests:
memory: 1Gi
```
**Note:** 512MB is too small for production. 2GB recommended minimum.
### PVC Not Binding
```bash
# Check PVC status
kubectl get pvc
# Check storage class
kubectl get storageclass
# Describe for events
kubectl describe pvc data-my-clawdbot-0
```
### WebSocket Connections Timing Out
Ensure Ingress has WebSocket annotations:
```yaml
annotations:
nginx.ingress.kubernetes.io/proxy-read-timeout: "3600"
nginx.ingress.kubernetes.io/proxy-send-timeout: "3600"
```
### Gateway Lock File Issues
If the gateway won't start due to stale lock files:
```bash
kubectl exec my-clawdbot-0 -- rm -f /home/node/.clawdbot/gateway.*.lock
kubectl delete pod my-clawdbot-0 # Restart pod
```
## Examples
### Local Testing (Minikube/Kind/Docker Desktop)
```bash
# Build local image
docker build -t clawdbot:local .
# Load into cluster (example for Minikube)
minikube image load clawdbot:local
# Install chart
helm install test ./clawdbot \
-f examples/values-basic.yaml \
--set image.repository=clawdbot \
--set image.tag=local \
--set image.pullPolicy=Never
```
### Production Deployment
```bash
# Create external secret first
kubectl create secret generic clawdbot-secrets \
--from-literal=gatewayToken=$(openssl rand -hex 32) \
--from-literal=anthropicApiKey=$ANTHROPIC_API_KEY
# Install with production values
helm install my-clawdbot ./clawdbot -f examples/values-production.yaml
```
## Documentation
- [Clawdbot Documentation](https://docs.clawd.bot)
- [Kubernetes Installation Guide](https://docs.clawd.bot/install/kubernetes)
- [GitHub Repository](https://github.com/clawdbot/clawdbot)
## Support
- [GitHub Issues](https://github.com/clawdbot/clawdbot/issues)
- [Documentation](https://docs.clawd.bot)
## License
See [LICENSE](https://github.com/clawdbot/clawdbot/blob/main/LICENSE)

View File

@ -0,0 +1,33 @@
# Basic configuration for local testing or development
image:
repository: clawdbot
tag: local
pullPolicy: Never
gateway:
bind: lan
port: 18789
allowUnconfigured: false
secrets:
create: true
data:
# Set via --set or environment variables
anthropicApiKey: ""
gatewayToken: ""
persistence:
enabled: true
size: 5Gi
ingress:
enabled: false
resources:
limits:
memory: 2Gi
cpu: 1000m
requests:
memory: 512Mi
cpu: 250m

View File

@ -0,0 +1,58 @@
# Configuration similar to Fly.io deployment
# Mimics fly.toml settings
image:
repository: ghcr.io/clawdbot/clawdbot
tag: "2026.1.25"
pullPolicy: IfNotPresent
gateway:
bind: lan
port: 3000 # Fly.io uses port 3000
allowUnconfigured: true
extraArgs: []
env:
NODE_ENV: production
CLAWDBOT_STATE_DIR: /home/node/.clawdbot
CLAWDBOT_WORKSPACE_DIR: /home/node/clawd
NODE_OPTIONS: "--max-old-space-size=1536" # Fly.io recommendation
secrets:
create: false
existingSecret: clawdbot-secrets
persistence:
enabled: true
size: 1Gi # Similar to Fly.io volume size
resources:
limits:
memory: 2Gi # shared-cpu-2x on Fly.io
cpu: 1000m
requests:
memory: 512Mi
cpu: 250m
service:
type: ClusterIP
port: 3000
ingress:
enabled: true
className: nginx
annotations:
cert-manager.io/cluster-issuer: letsencrypt-prod
nginx.ingress.kubernetes.io/force-ssl-redirect: "true"
nginx.ingress.kubernetes.io/proxy-read-timeout: "3600"
nginx.ingress.kubernetes.io/proxy-send-timeout: "3600"
nginx.ingress.kubernetes.io/websocket-services: "clawdbot"
hosts:
- host: my-clawdbot.example.com
paths:
- path: /
pathType: Prefix
tls:
- secretName: clawdbot-tls
hosts:
- my-clawdbot.example.com

View File

@ -0,0 +1,92 @@
# Production configuration with Ingress and external secrets
image:
repository: ghcr.io/clawdbot/clawdbot
tag: "2026.1.25"
pullPolicy: IfNotPresent
gateway:
bind: lan
port: 18789
allowUnconfigured: false
# Use external secret in production
secrets:
create: false
existingSecret: clawdbot-secrets
config:
create: true
data:
agents:
defaults:
model:
primary: "anthropic/claude-opus-4-5"
fallbacks:
- "anthropic/claude-sonnet-4-5"
maxConcurrent: 4
sandbox:
mode: "off"
list:
- id: main
default: true
auth:
profiles:
"anthropic:default":
mode: token
provider: anthropic
gateway:
mode: local
bind: auto
auth:
mode: token
controlUi:
enabled: true
channels:
discord:
enabled: true
meta:
lastTouchedVersion: "2026.1.25"
persistence:
enabled: true
storageClass: fast-ssd
size: 20Gi
accessMode: ReadWriteOnce
resources:
limits:
memory: 4Gi
cpu: 2000m
requests:
memory: 1Gi
cpu: 500m
ingress:
enabled: true
className: nginx
annotations:
cert-manager.io/cluster-issuer: letsencrypt-prod
nginx.ingress.kubernetes.io/proxy-read-timeout: "3600"
nginx.ingress.kubernetes.io/proxy-send-timeout: "3600"
nginx.ingress.kubernetes.io/websocket-services: "clawdbot"
hosts:
- host: assistant.example.com
paths:
- path: /
pathType: Prefix
tls:
- secretName: clawdbot-tls
hosts:
- assistant.example.com
affinity:
nodeAffinity:
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 100
preference:
matchExpressions:
- key: workload-type
operator: In
values:
- stateful

View File

@ -0,0 +1,46 @@
Thank you for installing {{ .Chart.Name }}!
Your Clawdbot gateway is starting up. This may take 1-2 minutes.
1. Check the gateway status:
kubectl get statefulset {{ include "clawdbot.fullname" . }} -n {{ .Release.Namespace }}
kubectl logs -f {{ include "clawdbot.fullname" . }}-0 -n {{ .Release.Namespace }}
2. Access the Control UI:
{{- if .Values.ingress.enabled }}
{{- range .Values.ingress.hosts }}
https://{{ .host }}
{{- end }}
{{- else }}
# Port-forward to access locally:
kubectl port-forward {{ include "clawdbot.fullname" . }}-0 {{ .Values.gateway.port }}:{{ .Values.gateway.port }} -n {{ .Release.Namespace }}
Then visit: http://localhost:{{ .Values.gateway.port }}
{{- end }}
3. Your gateway token (for authentication):
kubectl get secret {{ include "clawdbot.secretName" . }} -n {{ .Release.Namespace }} -o jsonpath='{.data.gatewayToken}' | base64 -d && echo
4. Configure channels:
kubectl exec -it {{ include "clawdbot.fullname" . }}-0 -n {{ .Release.Namespace }} -- node dist/index.js channels add --channel discord --token YOUR_BOT_TOKEN
5. Check health:
kubectl exec -it {{ include "clawdbot.fullname" . }}-0 -n {{ .Release.Namespace }} -- node dist/index.js health
Documentation: https://docs.clawd.bot
Support: https://github.com/clawdbot/clawdbot/issues
{{- if not .Values.persistence.enabled }}
WARNING: Persistence is disabled. State will be lost on pod restart.
{{- end }}
{{- if eq .Values.gateway.bind "loopback" }}
WARNING: Gateway is bound to loopback. External access will not work.
{{- end }}

View File

@ -0,0 +1,84 @@
{{/*
Expand the name of the chart.
*/}}
{{- define "clawdbot.name" -}}
{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }}
{{- end }}
{{/*
Create a default fully qualified app name.
We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec).
If release name contains chart name it will be used as a full name.
*/}}
{{- define "clawdbot.fullname" -}}
{{- if .Values.fullnameOverride }}
{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" }}
{{- else }}
{{- $name := default .Chart.Name .Values.nameOverride }}
{{- if contains $name .Release.Name }}
{{- .Release.Name | trunc 63 | trimSuffix "-" }}
{{- else }}
{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" }}
{{- end }}
{{- end }}
{{- end }}
{{/*
Create chart name and version as used by the chart label.
*/}}
{{- define "clawdbot.chart" -}}
{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }}
{{- end }}
{{/*
Common labels
*/}}
{{- define "clawdbot.labels" -}}
helm.sh/chart: {{ include "clawdbot.chart" . }}
{{ include "clawdbot.selectorLabels" . }}
{{- if .Chart.AppVersion }}
app.kubernetes.io/version: {{ .Chart.AppVersion | quote }}
{{- end }}
app.kubernetes.io/managed-by: {{ .Release.Service }}
{{- end }}
{{/*
Selector labels
*/}}
{{- define "clawdbot.selectorLabels" -}}
app.kubernetes.io/name: {{ include "clawdbot.name" . }}
app.kubernetes.io/instance: {{ .Release.Name }}
{{- end }}
{{/*
Create the name of the service account to use
*/}}
{{- define "clawdbot.serviceAccountName" -}}
{{- if .Values.serviceAccount.create }}
{{- default (include "clawdbot.fullname" .) .Values.serviceAccount.name }}
{{- else }}
{{- default "default" .Values.serviceAccount.name }}
{{- end }}
{{- end }}
{{/*
Create the name of the secret to use
*/}}
{{- define "clawdbot.secretName" -}}
{{- if .Values.secrets.existingSecret }}
{{- .Values.secrets.existingSecret }}
{{- else }}
{{- include "clawdbot.fullname" . }}
{{- end }}
{{- end }}
{{/*
Create the name of the config map to use
*/}}
{{- define "clawdbot.configMapName" -}}
{{- if .Values.config.existingConfigMap }}
{{- .Values.config.existingConfigMap }}
{{- else }}
{{- printf "%s-config" (include "clawdbot.fullname" .) }}
{{- end }}
{{- end }}

View File

@ -0,0 +1,11 @@
{{- if .Values.config.create -}}
apiVersion: v1
kind: ConfigMap
metadata:
name: {{ include "clawdbot.configMapName" . }}
labels:
{{- include "clawdbot.labels" . | nindent 4 }}
data:
clawdbot.json: |
{{ .Values.config.data | toJson | nindent 4 }}
{{- end }}

View File

@ -0,0 +1,41 @@
{{- if .Values.ingress.enabled -}}
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: {{ include "clawdbot.fullname" . }}
labels:
{{- include "clawdbot.labels" . | nindent 4 }}
{{- with .Values.ingress.annotations }}
annotations:
{{- toYaml . | nindent 4 }}
{{- end }}
spec:
{{- if .Values.ingress.className }}
ingressClassName: {{ .Values.ingress.className }}
{{- end }}
{{- if .Values.ingress.tls }}
tls:
{{- range .Values.ingress.tls }}
- hosts:
{{- range .hosts }}
- {{ . | quote }}
{{- end }}
secretName: {{ .secretName }}
{{- end }}
{{- end }}
rules:
{{- range .Values.ingress.hosts }}
- host: {{ .host | quote }}
http:
paths:
{{- range .paths }}
- path: {{ .path }}
pathType: {{ .pathType }}
backend:
service:
name: {{ include "clawdbot.fullname" $ }}
port:
number: {{ $.Values.service.port }}
{{- end }}
{{- end }}
{{- end }}

View File

@ -0,0 +1,23 @@
{{- if .Values.secrets.create -}}
apiVersion: v1
kind: Secret
metadata:
name: {{ include "clawdbot.fullname" . }}
labels:
{{- include "clawdbot.labels" . | nindent 4 }}
type: Opaque
stringData:
gatewayToken: {{ .Values.secrets.data.gatewayToken | default (randAlphaNum 32) | quote }}
{{- with .Values.secrets.data.anthropicApiKey }}
anthropicApiKey: {{ . | quote }}
{{- end }}
{{- with .Values.secrets.data.openaiApiKey }}
openaiApiKey: {{ . | quote }}
{{- end }}
{{- with .Values.secrets.data.discordBotToken }}
discordBotToken: {{ . | quote }}
{{- end }}
{{- with .Values.secrets.data.telegramBotToken }}
telegramBotToken: {{ . | quote }}
{{- end }}
{{- end }}

View File

@ -0,0 +1,19 @@
apiVersion: v1
kind: Service
metadata:
name: {{ include "clawdbot.fullname" . }}
labels:
{{- include "clawdbot.labels" . | nindent 4 }}
{{- with .Values.service.annotations }}
annotations:
{{- toYaml . | nindent 4 }}
{{- end }}
spec:
type: {{ .Values.service.type }}
ports:
- port: {{ .Values.service.port }}
targetPort: gateway
protocol: TCP
name: gateway
selector:
{{- include "clawdbot.selectorLabels" . | nindent 4 }}

View File

@ -0,0 +1,12 @@
{{- if .Values.serviceAccount.create -}}
apiVersion: v1
kind: ServiceAccount
metadata:
name: {{ include "clawdbot.serviceAccountName" . }}
labels:
{{- include "clawdbot.labels" . | nindent 4 }}
{{- with .Values.serviceAccount.annotations }}
annotations:
{{- toYaml . | nindent 4 }}
{{- end }}
{{- end }}

View File

@ -0,0 +1,202 @@
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: {{ include "clawdbot.fullname" . }}
labels:
{{- include "clawdbot.labels" . | nindent 4 }}
spec:
serviceName: {{ include "clawdbot.fullname" . }}
replicas: {{ .Values.replicaCount }}
selector:
matchLabels:
{{- include "clawdbot.selectorLabels" . | nindent 6 }}
template:
metadata:
annotations:
{{- if .Values.config.create }}
checksum/config: {{ include (print $.Template.BasePath "/configmap.yaml") . | sha256sum }}
{{- end }}
{{- if .Values.secrets.create }}
checksum/secret: {{ include (print $.Template.BasePath "/secret.yaml") . | sha256sum }}
{{- end }}
{{- with .Values.podAnnotations }}
{{- toYaml . | nindent 8 }}
{{- end }}
labels:
{{- include "clawdbot.selectorLabels" . | nindent 8 }}
spec:
{{- with .Values.imagePullSecrets }}
imagePullSecrets:
{{- toYaml . | nindent 8 }}
{{- end }}
serviceAccountName: {{ include "clawdbot.serviceAccountName" . }}
securityContext:
{{- toYaml .Values.podSecurityContext | nindent 8 }}
{{- if or .Values.config.create .Values.initContainers }}
initContainers:
{{- if .Values.config.create }}
- name: init-config
image: "{{ .Values.image.registry }}/{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}"
imagePullPolicy: {{ .Values.image.pullPolicy }}
command:
- sh
- -c
- |
echo "Initializing configuration..."
mkdir -p /home/node/.clawdbot
if [ ! -f /home/node/.clawdbot/clawdbot.json ]; then
echo "Copying default config..."
cp /config/clawdbot.json /home/node/.clawdbot/clawdbot.json
echo "Config initialized"
else
echo "Config already exists, skipping"
fi
volumeMounts:
- name: config
mountPath: /config
- name: data
mountPath: /home/node/.clawdbot
subPath: clawdbot-state
securityContext:
{{- toYaml .Values.securityContext | nindent 12 }}
{{- end }}
{{- with .Values.initContainers }}
{{- toYaml . | nindent 8 }}
{{- end }}
{{- end }}
containers:
- name: gateway
image: "{{ .Values.image.registry }}/{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}"
imagePullPolicy: {{ .Values.image.pullPolicy }}
command:
- node
- dist/index.js
- gateway
- --bind
- {{ .Values.gateway.bind }}
- --port
- {{ .Values.gateway.port | quote }}
{{- if .Values.gateway.allowUnconfigured }}
- --allow-unconfigured
{{- end }}
{{- range .Values.gateway.extraArgs }}
- {{ . }}
{{- end }}
env:
{{- range $key, $value := .Values.env }}
- name: {{ $key }}
value: {{ $value | quote }}
{{- end }}
- name: CLAWDBOT_GATEWAY_PORT
value: {{ .Values.gateway.port | quote }}
- name: CLAWDBOT_GATEWAY_TOKEN
valueFrom:
secretKeyRef:
name: {{ include "clawdbot.secretName" . }}
key: gatewayToken
{{- if .Values.secrets.data.anthropicApiKey }}
- name: ANTHROPIC_API_KEY
valueFrom:
secretKeyRef:
name: {{ include "clawdbot.secretName" . }}
key: anthropicApiKey
optional: true
{{- end }}
{{- if .Values.secrets.data.openaiApiKey }}
- name: OPENAI_API_KEY
valueFrom:
secretKeyRef:
name: {{ include "clawdbot.secretName" . }}
key: openaiApiKey
optional: true
{{- end }}
{{- if .Values.secrets.data.discordBotToken }}
- name: DISCORD_BOT_TOKEN
valueFrom:
secretKeyRef:
name: {{ include "clawdbot.secretName" . }}
key: discordBotToken
optional: true
{{- end }}
{{- if .Values.secrets.data.telegramBotToken }}
- name: TELEGRAM_BOT_TOKEN
valueFrom:
secretKeyRef:
name: {{ include "clawdbot.secretName" . }}
key: telegramBotToken
optional: true
{{- end }}
ports:
- name: gateway
containerPort: {{ .Values.gateway.port }}
protocol: TCP
volumeMounts:
- name: data
mountPath: /home/node/.clawdbot
subPath: clawdbot-state
- name: data
mountPath: /home/node/clawd
subPath: clawdbot-workspace
{{- if .Values.livenessProbe.enabled }}
livenessProbe:
{{- omit .Values.livenessProbe "enabled" | toYaml | nindent 12 }}
{{- end }}
{{- if .Values.readinessProbe.enabled }}
readinessProbe:
{{- omit .Values.readinessProbe "enabled" | toYaml | nindent 12 }}
{{- end }}
{{- if .Values.startupProbe.enabled }}
startupProbe:
{{- omit .Values.startupProbe "enabled" | toYaml | nindent 12 }}
{{- end }}
{{- with .Values.lifecycle }}
lifecycle:
{{- toYaml . | nindent 12 }}
{{- end }}
resources:
{{- toYaml .Values.resources | nindent 12 }}
securityContext:
{{- toYaml .Values.securityContext | nindent 12 }}
{{- with .Values.extraContainers }}
{{- toYaml . | nindent 8 }}
{{- end }}
volumes:
{{- if .Values.config.create }}
- name: config
configMap:
name: {{ include "clawdbot.configMapName" . }}
{{- end }}
{{- with .Values.nodeSelector }}
nodeSelector:
{{- toYaml . | nindent 8 }}
{{- end }}
{{- with .Values.affinity }}
affinity:
{{- toYaml . | nindent 8 }}
{{- end }}
{{- with .Values.tolerations }}
tolerations:
{{- toYaml . | nindent 8 }}
{{- end }}
{{- if .Values.persistence.enabled }}
volumeClaimTemplates:
- metadata:
name: data
{{- with .Values.persistence.annotations }}
annotations:
{{- toYaml . | nindent 10 }}
{{- end }}
spec:
accessModes:
- {{ .Values.persistence.accessMode }}
{{- if .Values.persistence.storageClass }}
storageClassName: {{ .Values.persistence.storageClass }}
{{- end }}
resources:
requests:
storage: {{ .Values.persistence.size }}
{{- with .Values.persistence.selector }}
selector:
{{- toYaml . | nindent 10 }}
{{- end }}
{{- end }}

View File

@ -0,0 +1,15 @@
apiVersion: v1
kind: Pod
metadata:
name: "{{ include "clawdbot.fullname" . }}-test-connection"
labels:
{{- include "clawdbot.labels" . | nindent 4 }}
annotations:
"helm.sh/hook": test
spec:
containers:
- name: wget
image: busybox
command: ['wget']
args: ['{{ include "clawdbot.fullname" . }}:{{ .Values.service.port }}']
restartPolicy: Never

View File

@ -0,0 +1,74 @@
{
"$schema": "https://json-schema.org/draft-07/schema#",
"type": "object",
"properties": {
"replicaCount": {
"type": "integer",
"minimum": 1,
"maximum": 1,
"default": 1,
"description": "Must be 1 for single-user architecture. Clawdbot does not support horizontal scaling."
},
"image": {
"type": "object",
"properties": {
"repository": {
"type": "string"
},
"pullPolicy": {
"type": "string",
"enum": ["Always", "IfNotPresent", "Never"]
},
"tag": {
"type": "string"
}
}
},
"gateway": {
"type": "object",
"properties": {
"bind": {
"type": "string",
"enum": ["loopback", "lan", "auto"],
"description": "Gateway binding mode"
},
"port": {
"type": "integer",
"minimum": 1,
"maximum": 65535
}
}
},
"persistence": {
"type": "object",
"properties": {
"enabled": {
"type": "boolean"
},
"size": {
"type": "string",
"pattern": "^[0-9]+(Gi|Mi|Ti)$"
},
"accessMode": {
"type": "string",
"enum": ["ReadWriteOnce", "ReadOnlyMany", "ReadWriteMany"]
}
}
},
"service": {
"type": "object",
"properties": {
"type": {
"type": "string",
"enum": ["ClusterIP", "NodePort", "LoadBalancer"]
},
"port": {
"type": "integer",
"minimum": 1,
"maximum": 65535
}
}
}
},
"required": ["replicaCount"]
}

227
charts/clawdbot/values.yaml Normal file
View File

@ -0,0 +1,227 @@
# Default values for clawdbot.
# This is a YAML-formatted file.
# Declare variables to be passed into your templates.
# Image configuration
image:
registry: ghcr.io
repository: clawdbot/clawdbot
pullPolicy: IfNotPresent
# Overrides the image tag whose default is the chart appVersion.
tag: ""
imagePullSecrets: []
nameOverride: ""
fullnameOverride: ""
# Replica count - MUST be 1 for single-user architecture
replicaCount: 1
# Service account
serviceAccount:
# Specifies whether a service account should be created
create: true
# Annotations to add to the service account
annotations: {}
# The name of the service account to use.
# If not set and create is true, a name is generated using the fullname template
name: ""
# Pod annotations
podAnnotations: {}
# Pod security context
podSecurityContext:
runAsNonRoot: true
runAsUser: 1000
runAsGroup: 1000
fsGroup: 1000
# Container security context
securityContext:
allowPrivilegeEscalation: false
capabilities:
drop:
- ALL
readOnlyRootFilesystem: false # Node needs write access to /tmp
# Gateway configuration
gateway:
# Binding mode: loopback, lan, auto
bind: lan
# Gateway port
port: 18789
# Allow unconfigured startup (creates minimal config)
allowUnconfigured: false
# Additional CLI arguments
extraArgs: []
# Environment variables (non-sensitive)
env:
NODE_ENV: production
CLAWDBOT_STATE_DIR: /home/node/.clawdbot
CLAWDBOT_WORKSPACE_DIR: /home/node/clawd
NODE_OPTIONS: "--max-old-space-size=2048"
# Secrets configuration
secrets:
# Create secret from values (dev/testing only - use existingSecret in production)
create: true
# Use existing secret (production)
existingSecret: ""
# Secret data (only used if create is true)
data:
anthropicApiKey: ""
openaiApiKey: ""
discordBotToken: ""
telegramBotToken: ""
gatewayToken: "" # Auto-generated if empty
# Config file (clawdbot.json)
config:
# Create ConfigMap from inline config
create: true
# Use existing ConfigMap
existingConfigMap: ""
# Config data (JSON5 format)
data:
agents:
defaults:
model:
primary: "anthropic/claude-opus-4-5"
fallbacks:
- "anthropic/claude-sonnet-4-5"
- "openai/gpt-4o"
maxConcurrent: 4
sandbox:
mode: "off" # Disable Docker-in-Docker for Kubernetes
list:
- id: main
default: true
auth:
profiles:
"anthropic:default":
mode: token
provider: anthropic
"openai:default":
mode: token
provider: openai
gateway:
mode: local
bind: auto
auth:
mode: token
controlUi:
enabled: true
channels: {}
meta:
lastTouchedVersion: "2026.1.25"
# Persistence
persistence:
enabled: true
# Storage class (use cluster default if empty)
storageClass: ""
# Access mode
accessMode: ReadWriteOnce
# Volume size
size: 10Gi
# Annotations
annotations: {}
# Selector
selector: {}
# Service configuration
service:
type: ClusterIP
port: 18789
annotations: {}
# Ingress configuration
ingress:
enabled: false
className: nginx
annotations:
# cert-manager.io/cluster-issuer: letsencrypt-prod
# nginx.ingress.kubernetes.io/proxy-read-timeout: "3600"
# nginx.ingress.kubernetes.io/proxy-send-timeout: "3600"
# nginx.ingress.kubernetes.io/websocket-services: "{{ include \"clawdbot.fullname\" . }}"
hosts:
- host: clawdbot.example.com
paths:
- path: /
pathType: Prefix
tls: []
# - secretName: clawdbot-tls
# hosts:
# - clawdbot.example.com
# Resource limits/requests
resources:
limits:
memory: 2Gi
cpu: 1000m
requests:
memory: 512Mi
cpu: 250m
# Node selector
nodeSelector: {}
# Tolerations
tolerations: []
# Affinity rules
affinity: {}
# Init containers (for setup tasks)
initContainers: []
# Extra containers (sidecars)
extraContainers: []
# Lifecycle hooks
lifecycle:
preStop:
exec:
command:
- sh
- -c
- rm -f /home/node/.clawdbot/gateway.*.lock; sleep 10
# Probes
livenessProbe:
enabled: true
exec:
command:
- node
- dist/index.js
- health
initialDelaySeconds: 30
periodSeconds: 30
timeoutSeconds: 10
failureThreshold: 3
readinessProbe:
enabled: true
exec:
command:
- node
- dist/index.js
- health
initialDelaySeconds: 15
periodSeconds: 10
timeoutSeconds: 5
failureThreshold: 3
startupProbe:
enabled: true
exec:
command:
- node
- dist/index.js
- health
initialDelaySeconds: 10
periodSeconds: 5
timeoutSeconds: 5
failureThreshold: 12 # 60 seconds max startup time

View File

@ -101,6 +101,7 @@ Tip: if you dont have a global install yet, run repo commands via `pnpm moltb
### 4) Other install options
- Docker: [Docker](/install/docker)
- Kubernetes: [Kubernetes (Helm)](/install/kubernetes)
- Nix: [Nix](/install/nix)
- Ansible: [Ansible](/install/ansible)
- Bun (CLI only): [Bun](/install/bun)

482
docs/install/kubernetes.md Normal file
View File

@ -0,0 +1,482 @@
---
title: Kubernetes (Helm)
description: Deploy Clawdbot on Kubernetes using Helm charts
---
# Kubernetes Deployment
**Goal:** Clawdbot Gateway running on Kubernetes with Helm, persistent storage, automatic HTTPS, and channel access.
## What you need
- Kubernetes cluster (1.19+)
- kubectl CLI configured
- Helm 3.x
- Model auth: Anthropic API key (or other provider keys)
- Channel credentials: Discord bot token, Telegram token, etc.
- **Optional:** Ingress controller (NGINX, Traefik) for external access
- **Optional:** cert-manager for automatic TLS certificates
## Beginner quick path
1. Install Helm chart from source
2. Configure secrets (API keys)
3. Access Control UI via Ingress or port-forward
4. Configure channels
## Prerequisites
### 1) Kubernetes Cluster
You need a running Kubernetes cluster. Options:
**Local development:**
- Docker Desktop (macOS/Windows) - Enable Kubernetes in settings
- Minikube - `brew install minikube && minikube start`
- Kind - `brew install kind && kind create cluster`
**Cloud providers:**
- GKE (Google Kubernetes Engine)
- EKS (Amazon Elastic Kubernetes Service)
- AKS (Azure Kubernetes Service)
- DigitalOcean Kubernetes
- Linode Kubernetes Engine
### 2) kubectl
Install kubectl:
```bash
# macOS
brew install kubectl
# Linux
curl -LO "https://dl.k8s.io/release/$(curl -L -s https://dl.k8s.io/release/stable.txt)/bin/linux/amd64/kubectl"
sudo install -o root -g root -m 0755 kubectl /usr/local/bin/kubectl
# Verify
kubectl version --client
kubectl cluster-info
```
### 3) Helm
Install Helm 3.x:
```bash
# macOS
brew install helm
# Linux
curl https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3 | bash
# Verify
helm version
```
## Installation
### 1) Clone the repository
```bash
git clone https://github.com/clawdbot/clawdbot.git
cd clawdbot
```
### 2) Install Helm chart
**Basic installation (development):**
```bash
helm install my-clawdbot charts/clawdbot \
--set secrets.data.anthropicApiKey=sk-ant-xxx \
--set secrets.data.gatewayToken=$(openssl rand -hex 32)
```
**With custom values file:**
```bash
helm install my-clawdbot charts/clawdbot \
--values charts/clawdbot/examples/values-production.yaml \
--set secrets.data.anthropicApiKey=sk-ant-xxx \
--set ingress.hosts[0].host=assistant.example.com
```
**Create external secret (recommended for production):**
```bash
# Create secret
kubectl create secret generic clawdbot-secrets \
--from-literal=gatewayToken=$(openssl rand -hex 32) \
--from-literal=anthropicApiKey=sk-ant-xxx \
--from-literal=discordBotToken=YOUR_DISCORD_TOKEN
# Install with external secret
helm install my-clawdbot charts/clawdbot \
--values charts/clawdbot/examples/values-production.yaml \
--set secrets.create=false \
--set secrets.existingSecret=clawdbot-secrets
```
### 3) Verify installation
```bash
# Check deployment status
helm status my-clawdbot
kubectl get all -l app.kubernetes.io/instance=my-clawdbot
# Wait for pod to be ready
kubectl wait --for=condition=ready pod -l app.kubernetes.io/instance=my-clawdbot --timeout=120s
# Check logs
kubectl logs -f my-clawdbot-0
```
## Access the Gateway
### Option 1: Port-forward (local access)
```bash
kubectl port-forward my-clawdbot-0 18789:18789
```
Then visit: http://localhost:18789
### Option 2: Ingress (external access)
**Install NGINX Ingress Controller (if not already installed):**
```bash
# For cloud providers
kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/controller-v1.9.0/deploy/static/provider/cloud/deploy.yaml
# For bare metal/local
kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/controller-v1.9.0/deploy/static/provider/baremetal/deploy.yaml
# For Minikube
minikube addons enable ingress
# For Kind
kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/main/deploy/static/provider/kind/deploy.yaml
```
**Enable Ingress in values:**
```yaml
ingress:
enabled: true
className: nginx
annotations:
cert-manager.io/cluster-issuer: letsencrypt-prod # If using cert-manager
nginx.ingress.kubernetes.io/proxy-read-timeout: "3600"
nginx.ingress.kubernetes.io/proxy-send-timeout: "3600"
nginx.ingress.kubernetes.io/websocket-services: "my-clawdbot"
hosts:
- host: assistant.example.com
paths:
- path: /
pathType: Prefix
tls:
- secretName: clawdbot-tls
hosts:
- assistant.example.com
```
**Upgrade with Ingress:**
```bash
helm upgrade my-clawdbot charts/clawdbot \
--reuse-values \
--set ingress.enabled=true \
--set ingress.hosts[0].host=assistant.example.com \
--set ingress.hosts[0].paths[0].path=/ \
--set ingress.hosts[0].paths[0].pathType=Prefix
```
### 3) Get gateway token
```bash
kubectl get secret my-clawdbot -o jsonpath='{.data.gatewayToken}' | base64 -d && echo
```
Use this token to authenticate in the Control UI.
## Configuration
### Configure channels
#### Discord
```bash
# Exec into pod
kubectl exec -it my-clawdbot-0 -- sh
# Inside pod
node dist/index.js channels add --channel discord --token YOUR_DISCORD_BOT_TOKEN
```
Or set via secret:
```bash
kubectl create secret generic clawdbot-secrets \
--from-literal=discordBotToken=YOUR_DISCORD_BOT_TOKEN \
--dry-run=client -o yaml | kubectl apply -f -
# Restart pod to apply
kubectl delete pod my-clawdbot-0
```
#### Telegram
```bash
kubectl exec -it my-clawdbot-0 -- node dist/index.js channels add \
--channel telegram \
--token YOUR_TELEGRAM_BOT_TOKEN
```
#### WhatsApp (QR code)
```bash
# Exec into pod
kubectl exec -it my-clawdbot-0 -- node dist/index.js channels login
```
Scan the QR code with WhatsApp on your phone.
### Update configuration
Edit the config:
```bash
# Get current config
kubectl get configmap my-clawdbot-config -o yaml > clawdbot-config.yaml
# Edit clawdbot-config.yaml
# Apply changes
kubectl apply -f clawdbot-config.yaml
# Restart gateway to reload config
kubectl delete pod my-clawdbot-0
```
## Storage
The chart creates a persistent volume claim that stores:
- `/home/node/.clawdbot` - Config, sessions, device identity, SQLite databases
- `/home/node/clawd` - Agent workspace files
**Check storage:**
```bash
kubectl get pvc
kubectl describe pvc data-my-clawdbot-0
```
**Increase storage size:**
```yaml
persistence:
size: 20Gi
```
## Upgrading
```bash
# Pull latest changes
cd clawdbot
git pull
# Upgrade with current values
helm upgrade my-clawdbot charts/clawdbot --reuse-values
# Upgrade with new values
helm upgrade my-clawdbot charts/clawdbot -f values-production.yaml
```
## Troubleshooting
### Pod not starting
```bash
# Check events
kubectl describe pod my-clawdbot-0
# Check logs
kubectl logs my-clawdbot-0
# If pod crashed
kubectl logs my-clawdbot-0 --previous
```
### OOM (Out of Memory)
Container keeps restarting. Signs: `SIGABRT`, `v8::internal::Runtime_AllocateInYoungGeneration`, or silent restarts.
**Fix:** Increase memory in values.yaml:
```yaml
resources:
limits:
memory: 4Gi
requests:
memory: 1Gi
```
**Note:** 512MB is too small. 2GB recommended minimum.
### PVC not binding
```bash
# Check PVC status
kubectl get pvc
# Check events
kubectl describe pvc data-my-clawdbot-0
# Check if storage provisioner is available
kubectl get storageclass
```
**Fix for Minikube:**
```bash
minikube addons enable storage-provisioner
minikube addons enable default-storageclass
```
### Gateway lock issues
Gateway refuses to start with "already running" errors.
```bash
# Delete lock file
kubectl exec my-clawdbot-0 -- rm -f /home/node/.clawdbot/gateway.*.lock
# Restart pod
kubectl delete pod my-clawdbot-0
```
### WebSocket connections timing out
Ensure Ingress has proper annotations:
```yaml
annotations:
nginx.ingress.kubernetes.io/proxy-read-timeout: "3600"
nginx.ingress.kubernetes.io/proxy-send-timeout: "3600"
nginx.ingress.kubernetes.io/websocket-services: "my-clawdbot"
```
### Config not being read
If using `--allow-unconfigured`, the gateway creates a minimal config. Your custom config should be read on restart.
```bash
# Verify config exists
kubectl exec my-clawdbot-0 -- cat /home/node/.clawdbot/clawdbot.json
# Verify ConfigMap
kubectl get configmap my-clawdbot-config -o yaml
```
### Image pull errors (local testing)
When testing with local images:
```bash
# Ensure pullPolicy is Never
--set image.pullPolicy=Never
# Load image into cluster
# Docker Desktop: Image already available
# Minikube: minikube image load clawdbot:local
# Kind: kind load docker-image clawdbot:local
```
## Local Testing
Test the Helm chart locally before deploying to production:
### Using Docker Desktop Kubernetes
```bash
# Enable Kubernetes in Docker Desktop settings
# Run automated test script
./scripts/test-helm-local.sh
```
### Using Minikube
```bash
# Start Minikube
minikube start --memory=4096 --cpus=2
# Build and load image
docker build -t clawdbot:local .
minikube image load clawdbot:local
# Install chart
helm install test charts/clawdbot \
-f charts/clawdbot/examples/values-basic.yaml \
--set image.repository=clawdbot \
--set image.tag=local \
--set image.pullPolicy=Never
# Access via port-forward
kubectl port-forward test-clawdbot-0 18789:18789
```
### Using Kind
```bash
# Create cluster
kind create cluster
# Build and load image
docker build -t clawdbot:local .
kind load docker-image clawdbot:local
# Install chart
helm install test charts/clawdbot \
-f charts/clawdbot/examples/values-basic.yaml \
--set image.repository=clawdbot \
--set image.tag=local \
--set image.pullPolicy=Never
```
## Uninstall
```bash
# Uninstall Helm release
helm uninstall my-clawdbot
# Delete PVCs (data will be lost)
kubectl delete pvc -l app.kubernetes.io/instance=my-clawdbot
```
## Notes
- Clawdbot is a **single-user application**. The chart enforces `replicas: 1`.
- WebSocket gateway requires long-lived connections (use proper Ingress timeouts).
- Persistent storage is required to preserve state across restarts.
- Docker-in-Docker sandboxing is disabled by default in Kubernetes deployments.
- For production, use external secret management (Kubernetes Secrets, External Secrets Operator, or Vault).
## Documentation
- [Chart README](https://github.com/clawdbot/clawdbot/tree/main/charts/clawdbot)
- [Clawdbot Documentation](https://docs.clawd.bot)
- [GitHub Repository](https://github.com/clawdbot/clawdbot)
## Cost
Kubernetes cluster costs vary by provider:
- **Local (free):** Docker Desktop, Minikube, Kind
- **Cloud providers:** $50-200/month depending on node size and region
- **Recommended resources:** 2 CPU, 4GB RAM minimum
See your cloud provider's pricing for details.

View File

@ -0,0 +1,144 @@
#!/usr/bin/env bash
# Publish Helm chart to GitHub Pages
set -euo pipefail
# Colors
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m'
log() { echo -e "${GREEN}[PUBLISH]${NC} $*"; }
warn() { echo -e "${YELLOW}[WARN]${NC} $*"; }
error() { echo -e "${RED}[ERROR]${NC} $*"; exit 1; }
info() { echo -e "${BLUE}[INFO]${NC} $*"; }
# Configuration
CHART_PATH="charts/clawdbot"
REPO_URL="https://clawdbot.github.io/clawdbot"
OUTPUT_DIR=".cr-release-packages"
# Check prerequisites
command -v helm >/dev/null 2>&1 || error "helm not found. Install it first."
command -v git >/dev/null 2>&1 || error "git not found."
# Get chart version
CHART_VERSION=$(grep '^version:' "$CHART_PATH/Chart.yaml" | awk '{print $2}')
APP_VERSION=$(grep '^appVersion:' "$CHART_PATH/Chart.yaml" | awk '{print $2}' | tr -d '"')
log "Publishing Helm Chart"
info "Chart version: $CHART_VERSION"
info "App version: $APP_VERSION"
# Confirm
read -p "Continue with publishing? (y/N) " -n 1 -r
echo
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
warn "Publishing cancelled"
exit 0
fi
# Step 1: Lint chart
log "Step 1: Linting chart..."
helm lint "$CHART_PATH" || error "Chart lint failed"
# Step 2: Package chart
log "Step 2: Packaging chart..."
mkdir -p "$OUTPUT_DIR"
helm package "$CHART_PATH" -d "$OUTPUT_DIR" || error "Chart packaging failed"
info "Packaged: $OUTPUT_DIR/clawdbot-${CHART_VERSION}.tgz"
# Step 3: Generate index
log "Step 3: Generating repository index..."
# Check if we're on gh-pages branch
CURRENT_BRANCH=$(git branch --show-current)
if [ "$CURRENT_BRANCH" != "gh-pages" ]; then
warn "Not on gh-pages branch. Switching..."
# Stash current changes if any
if ! git diff-index --quiet HEAD --; then
log "Stashing current changes..."
git stash push -m "publish-helm-chart: stash before gh-pages"
fi
# Switch to gh-pages
git checkout gh-pages || {
error "Failed to checkout gh-pages branch. Create it first:
git checkout --orphan gh-pages
git rm -rf .
echo '# Clawdbot Helm Charts' > README.md
git add README.md
git commit -m 'Initial gh-pages'
git push origin gh-pages
git checkout main"
}
fi
# Copy package to gh-pages root
log "Step 4: Copying package to gh-pages..."
cp "$OUTPUT_DIR/clawdbot-${CHART_VERSION}.tgz" .
# Update or create index.yaml
if [ -f "index.yaml" ]; then
log "Updating existing index.yaml..."
helm repo index . --url "$REPO_URL" --merge index.yaml
else
log "Creating new index.yaml..."
helm repo index . --url "$REPO_URL"
fi
# Step 5: Commit and push
log "Step 5: Committing to gh-pages..."
git add "clawdbot-${CHART_VERSION}.tgz" index.yaml
if git diff --staged --quiet; then
warn "No changes to commit. Chart version $CHART_VERSION may already be published."
else
git commit -m "Release chart version ${CHART_VERSION}
Chart: clawdbot ${CHART_VERSION}
App: ${APP_VERSION}
Published via scripts/publish-helm-chart.sh"
log "Step 6: Pushing to origin/gh-pages..."
git push origin gh-pages || error "Failed to push to gh-pages"
log "✓ Chart published successfully!"
info "Version: $CHART_VERSION"
info "URL: $REPO_URL/clawdbot-${CHART_VERSION}.tgz"
fi
# Step 7: Switch back to original branch
log "Switching back to $CURRENT_BRANCH..."
git checkout "$CURRENT_BRANCH"
# Restore stash if we created one
if git stash list | grep -q "publish-helm-chart: stash before gh-pages"; then
log "Restoring stashed changes..."
git stash pop
fi
# Clean up
rm -rf "$OUTPUT_DIR"
echo
log "============================================"
log "Chart published successfully! ✓"
log "============================================"
echo
info "Users can now install with:"
echo
echo " helm repo add clawdbot $REPO_URL"
echo " helm repo update"
echo " helm install my-clawdbot clawdbot/clawdbot"
echo
info "Chart URL: $REPO_URL/clawdbot-${CHART_VERSION}.tgz"
info "Wait 5-10 minutes for GitHub Pages to deploy"
echo
info "Verify deployment:"
echo " curl $REPO_URL/index.yaml"

167
scripts/test-helm-local.sh Executable file
View File

@ -0,0 +1,167 @@
#!/usr/bin/env bash
# Test Helm chart locally on Docker Desktop K8s, Minikube, or Kind
set -euo pipefail
# Colors for output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color
log() { echo -e "${GREEN}[TEST]${NC} $*"; }
warn() { echo -e "${YELLOW}[WARN]${NC} $*"; }
error() { echo -e "${RED}[ERROR]${NC} $*"; exit 1; }
info() { echo -e "${BLUE}[INFO]${NC} $*"; }
# Configuration
CHART_PATH="${CHART_PATH:-charts/clawdbot}"
IMAGE_NAME="${IMAGE_NAME:-clawdbot}"
IMAGE_TAG="${IMAGE_TAG:-local-test}"
RELEASE_NAME="${RELEASE_NAME:-test-clawdbot}"
NAMESPACE="${NAMESPACE:-default}"
ANTHROPIC_API_KEY="${ANTHROPIC_API_KEY:-sk-ant-test-dummy}"
GATEWAY_TOKEN="${GATEWAY_TOKEN:-$(openssl rand -hex 32)}"
# Detect K8s environment
detect_k8s() {
if kubectl config current-context | grep -q docker-desktop 2>/dev/null; then
echo "docker-desktop"
elif kubectl config current-context | grep -q minikube 2>/dev/null; then
echo "minikube"
elif kubectl config current-context | grep -q kind 2>/dev/null; then
echo "kind"
else
echo "unknown"
fi
}
K8S_ENV=$(detect_k8s)
info "Detected Kubernetes environment: $K8S_ENV"
# Step 1: Lint chart
log "Step 1: Linting Helm chart..."
helm lint "$CHART_PATH" || error "Helm lint failed"
helm lint "$CHART_PATH" --values "$CHART_PATH/examples/values-basic.yaml" || error "Helm lint with values-basic.yaml failed"
log "✓ Lint passed"
# Step 2: Template validation
log "Step 2: Validating templates..."
helm template test "$CHART_PATH" \
--values "$CHART_PATH/examples/values-basic.yaml" \
--set image.repository="$IMAGE_NAME" \
--set image.tag="$IMAGE_TAG" \
--set secrets.data.anthropicApiKey="$ANTHROPIC_API_KEY" \
> /tmp/clawdbot-manifests.yaml || error "Template validation failed"
log "✓ Template validation passed"
# Step 3: Build Docker image
log "Step 3: Building Docker image..."
docker build -t "$IMAGE_NAME:$IMAGE_TAG" -f Dockerfile . || error "Docker build failed"
log "✓ Image built: $IMAGE_NAME:$IMAGE_TAG"
# Step 4: Load image into cluster
log "Step 4: Loading image into cluster..."
case "$K8S_ENV" in
docker-desktop)
info "Docker Desktop: Image already available"
;;
minikube)
minikube image load "$IMAGE_NAME:$IMAGE_TAG" || error "Failed to load image into Minikube"
;;
kind)
kind load docker-image "$IMAGE_NAME:$IMAGE_TAG" || error "Failed to load image into Kind"
;;
*)
warn "Unknown K8s environment, skipping image load (may fail if image not available)"
;;
esac
log "✓ Image loaded"
# Step 5: Install Helm chart
log "Step 5: Installing Helm chart..."
helm install "$RELEASE_NAME" "$CHART_PATH" \
--namespace "$NAMESPACE" \
--values "$CHART_PATH/examples/values-basic.yaml" \
--set image.repository="$IMAGE_NAME" \
--set image.tag="$IMAGE_TAG" \
--set image.pullPolicy=Never \
--set secrets.data.anthropicApiKey="$ANTHROPIC_API_KEY" \
--set secrets.data.gatewayToken="$GATEWAY_TOKEN" \
--wait --timeout=3m || error "Helm install failed"
log "✓ Chart installed"
# Step 6: Verify deployment
log "Step 6: Verifying deployment..."
# Check StatefulSet
info "Checking StatefulSet..."
kubectl get statefulset -l app.kubernetes.io/instance="$RELEASE_NAME" -n "$NAMESPACE"
# Check Pod
info "Waiting for pod to be ready..."
kubectl wait --for=condition=ready pod -l app.kubernetes.io/instance="$RELEASE_NAME" \
-n "$NAMESPACE" --timeout=120s || error "Pod did not become ready"
log "✓ Pod is ready"
# Check PVC
info "Checking PVC..."
kubectl get pvc -l app.kubernetes.io/instance="$RELEASE_NAME" -n "$NAMESPACE"
log "✓ PVC created"
# Step 7: Health check
log "Step 7: Running health check..."
POD_NAME=$(kubectl get pod -l app.kubernetes.io/instance="$RELEASE_NAME" -n "$NAMESPACE" -o jsonpath='{.items[0].metadata.name}')
kubectl exec "$POD_NAME" -n "$NAMESPACE" -- node dist/index.js health --token "$GATEWAY_TOKEN" && log "✓ Health check passed" || warn "Health check failed (may be OK for test env)"
# Step 8: Check logs
log "Step 8: Checking logs (last 50 lines)..."
kubectl logs "$POD_NAME" -n "$NAMESPACE" --tail=50
# Step 9: Run Helm tests
log "Step 9: Running Helm tests..."
helm test "$RELEASE_NAME" -n "$NAMESPACE" && log "✓ Helm tests passed" || warn "Helm tests failed"
# Step 10: Verify persistence
log "Step 10: Testing persistence..."
info "Checking state directory..."
kubectl exec "$POD_NAME" -n "$NAMESPACE" -- ls -la /home/node/.clawdbot
info "Checking workspace directory..."
kubectl exec "$POD_NAME" -n "$NAMESPACE" -- ls -la /home/node/clawd
info "Checking config file..."
kubectl exec "$POD_NAME" -n "$NAMESPACE" -- cat /home/node/.clawdbot/clawdbot.json || warn "Config file not found (may be OK)"
log "✓ Persistence verified"
# Step 11: Port-forward test
log "Step 11: Testing port-forward (5 seconds)..."
kubectl port-forward "$POD_NAME" -n "$NAMESPACE" 18789:18789 &
PF_PID=$!
sleep 5
kill $PF_PID 2>/dev/null || true
log "✓ Port-forward test complete"
# Success summary
echo
log "============================================"
log "All tests passed! ✓"
log "============================================"
info "Release: $RELEASE_NAME"
info "Namespace: $NAMESPACE"
info "Pod: $POD_NAME"
info "Gateway token: $GATEWAY_TOKEN"
echo
# Cleanup prompt
read -p "Clean up resources? (y/N) " -n 1 -r
echo
if [[ $REPLY =~ ^[Yy]$ ]]; then
log "Cleaning up..."
helm uninstall "$RELEASE_NAME" -n "$NAMESPACE"
kubectl delete pvc -l app.kubernetes.io/instance="$RELEASE_NAME" -n "$NAMESPACE"
log "✓ Cleanup complete"
else
info "Skipping cleanup. To clean up later, run:"
echo " helm uninstall $RELEASE_NAME -n $NAMESPACE"
echo " kubectl delete pvc -l app.kubernetes.io/instance=$RELEASE_NAME -n $NAMESPACE"
fi