feat: add helm chart support (#1)
feat: enhance Helm chart workflows and update image references
This commit is contained in:
parent
34653e4baf
commit
6635d70170
12
.github/labeler.yml
vendored
12
.github/labeler.yml
vendored
@ -220,3 +220,15 @@
|
|||||||
- changed-files:
|
- changed-files:
|
||||||
- any-glob-to-any-file:
|
- any-glob-to-any-file:
|
||||||
- "extensions/qwen-portal-auth/**"
|
- "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
124
.github/workflows/helm-release.yml
vendored
Normal 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
125
.github/workflows/helm-test.yml
vendored
Normal 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
|
||||||
@ -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.
|
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)**.
|
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.
|
Works with npm, pnpm, or bun.
|
||||||
@ -164,7 +164,7 @@ Run `moltbot doctor` to surface risky/misconfigured DM policies.
|
|||||||
### Ops + packaging
|
### Ops + packaging
|
||||||
- [Control UI](https://docs.molt.bot/web) + [WebChat](https://docs.molt.bot/web/webchat) served directly from the Gateway.
|
- [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.
|
- [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).
|
- [Doctor](https://docs.molt.bot/gateway/doctor) migrations, [logging](https://docs.molt.bot/logging).
|
||||||
|
|
||||||
## How it works (short)
|
## How it works (short)
|
||||||
|
|||||||
23
charts/clawdbot/.helmignore
Normal file
23
charts/clawdbot/.helmignore
Normal 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/
|
||||||
21
charts/clawdbot/Chart.yaml
Normal file
21
charts/clawdbot/Chart.yaml
Normal 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
|
||||||
253
charts/clawdbot/PUBLISHING.md
Normal file
253
charts/clawdbot/PUBLISHING.md
Normal 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
302
charts/clawdbot/README.md
Normal 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)
|
||||||
33
charts/clawdbot/examples/values-basic.yaml
Normal file
33
charts/clawdbot/examples/values-basic.yaml
Normal 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
|
||||||
58
charts/clawdbot/examples/values-fly-like.yaml
Normal file
58
charts/clawdbot/examples/values-fly-like.yaml
Normal 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
|
||||||
92
charts/clawdbot/examples/values-production.yaml
Normal file
92
charts/clawdbot/examples/values-production.yaml
Normal 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
|
||||||
46
charts/clawdbot/templates/NOTES.txt
Normal file
46
charts/clawdbot/templates/NOTES.txt
Normal 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 }}
|
||||||
84
charts/clawdbot/templates/_helpers.tpl
Normal file
84
charts/clawdbot/templates/_helpers.tpl
Normal 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 }}
|
||||||
11
charts/clawdbot/templates/configmap.yaml
Normal file
11
charts/clawdbot/templates/configmap.yaml
Normal 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 }}
|
||||||
41
charts/clawdbot/templates/ingress.yaml
Normal file
41
charts/clawdbot/templates/ingress.yaml
Normal 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 }}
|
||||||
23
charts/clawdbot/templates/secret.yaml
Normal file
23
charts/clawdbot/templates/secret.yaml
Normal 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 }}
|
||||||
19
charts/clawdbot/templates/service.yaml
Normal file
19
charts/clawdbot/templates/service.yaml
Normal 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 }}
|
||||||
12
charts/clawdbot/templates/serviceaccount.yaml
Normal file
12
charts/clawdbot/templates/serviceaccount.yaml
Normal 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 }}
|
||||||
202
charts/clawdbot/templates/statefulset.yaml
Normal file
202
charts/clawdbot/templates/statefulset.yaml
Normal 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 }}
|
||||||
15
charts/clawdbot/templates/tests/test-connection.yaml
Normal file
15
charts/clawdbot/templates/tests/test-connection.yaml
Normal 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
|
||||||
74
charts/clawdbot/values.schema.json
Normal file
74
charts/clawdbot/values.schema.json
Normal 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
227
charts/clawdbot/values.yaml
Normal 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
|
||||||
@ -101,6 +101,7 @@ Tip: if you don’t have a global install yet, run repo commands via `pnpm moltb
|
|||||||
### 4) Other install options
|
### 4) Other install options
|
||||||
|
|
||||||
- Docker: [Docker](/install/docker)
|
- Docker: [Docker](/install/docker)
|
||||||
|
- Kubernetes: [Kubernetes (Helm)](/install/kubernetes)
|
||||||
- Nix: [Nix](/install/nix)
|
- Nix: [Nix](/install/nix)
|
||||||
- Ansible: [Ansible](/install/ansible)
|
- Ansible: [Ansible](/install/ansible)
|
||||||
- Bun (CLI only): [Bun](/install/bun)
|
- Bun (CLI only): [Bun](/install/bun)
|
||||||
|
|||||||
482
docs/install/kubernetes.md
Normal file
482
docs/install/kubernetes.md
Normal 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.
|
||||||
144
scripts/publish-helm-chart.sh
Normal file
144
scripts/publish-helm-chart.sh
Normal 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
167
scripts/test-helm-local.sh
Executable 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
|
||||||
Loading…
Reference in New Issue
Block a user