ScuttleBot
| 7bbcd81… | lmata | 1 | # Kubernetes deployment |
| 7bbcd81… | lmata | 2 | |
| 7bbcd81… | lmata | 3 | Production-grade deployment for scuttlebot on Kubernetes. |
| 7bbcd81… | lmata | 4 | |
| 7bbcd81… | lmata | 5 | ## Architecture |
| 7bbcd81… | lmata | 6 | |
| 7bbcd81… | lmata | 7 | ``` |
| 7bbcd81… | lmata | 8 | LoadBalancer |
| 7bbcd81… | lmata | 9 | :6667 (IRC) |
| 7bbcd81… | lmata | 10 | │ |
| 7bbcd81… | lmata | 11 | ┌────────────▼────────────┐ |
| 7bbcd81… | lmata | 12 | │ ergo │ |
| 7bbcd81… | lmata | 13 | │ (single replica) │ |
| 7bbcd81… | lmata | 14 | │ ircd.db on PVC │ |
| 7bbcd81… | lmata | 15 | └────────────┬────────────┘ |
| 7bbcd81… | lmata | 16 | │ ClusterIP :8089 |
| 7bbcd81… | lmata | 17 | ┌────────────▼────────────┐ |
| 7bbcd81… | lmata | 18 | │ scuttlebot │ |
| 7bbcd81… | lmata | 19 | │ REST API :8080 (CIP) │ |
| 7bbcd81… | lmata | 20 | │ MCP :8081 (CIP) │ |
| 7bbcd81… | lmata | 21 | └────────────┬────────────┘ |
| 7bbcd81… | lmata | 22 | │ |
| 7bbcd81… | lmata | 23 | ┌────────────▼────────────┐ |
| 7bbcd81… | lmata | 24 | │ Postgres │ |
| 7bbcd81… | lmata | 25 | │ (external, PaaS) │ |
| 7bbcd81… | lmata | 26 | └─────────────────────────┘ |
| 7bbcd81… | lmata | 27 | ``` |
| 7bbcd81… | lmata | 28 | |
| 7bbcd81… | lmata | 29 | **Ergo is single-instance.** HA = fast pod restart with durable PVC, not horizontal scaling. `strategy: Recreate` is required — Ergo cannot run two pods sharing one `ReadWriteOnce` volume. |
| 7bbcd81… | lmata | 30 | |
| 7bbcd81… | lmata | 31 | **Postgres is external.** Use your cloud provider's managed Postgres (RDS, Cloud SQL, etc.). Scuttlebot expects a `postgres-dsn` secret. |
| 7bbcd81… | lmata | 32 | |
| 7bbcd81… | lmata | 33 | ## Prerequisites |
| 7bbcd81… | lmata | 34 | |
| 7bbcd81… | lmata | 35 | - A running Kubernetes cluster |
| 7bbcd81… | lmata | 36 | - `kubectl` configured |
| 7bbcd81… | lmata | 37 | - A Postgres instance reachable from the cluster |
| 7bbcd81… | lmata | 38 | - Container images built and pushed (see below) |
| 7bbcd81… | lmata | 39 | |
| 7bbcd81… | lmata | 40 | ## Deploying |
| 7bbcd81… | lmata | 41 | |
| 7bbcd81… | lmata | 42 | ### 1. Build and push images |
| 7bbcd81… | lmata | 43 | |
| 7bbcd81… | lmata | 44 | ```sh |
| 7bbcd81… | lmata | 45 | # scuttlebot |
| 7bbcd81… | lmata | 46 | docker build -f deploy/docker/Dockerfile -t ghcr.io/conflicthq/scuttlebot:latest . |
| 7bbcd81… | lmata | 47 | docker push ghcr.io/conflicthq/scuttlebot:latest |
| 7bbcd81… | lmata | 48 | |
| 7bbcd81… | lmata | 49 | # ergo (custom image with envsubst) |
| 7bbcd81… | lmata | 50 | docker build -f deploy/compose/ergo/Dockerfile -t ghcr.io/conflicthq/scuttlebot-ergo:latest deploy/compose/ergo/ |
| 7bbcd81… | lmata | 51 | docker push ghcr.io/conflicthq/scuttlebot-ergo:latest |
| 7bbcd81… | lmata | 52 | ``` |
| 7bbcd81… | lmata | 53 | |
| 7bbcd81… | lmata | 54 | ### 2. Create the secret |
| 7bbcd81… | lmata | 55 | |
| 7bbcd81… | lmata | 56 | ```sh |
| 7bbcd81… | lmata | 57 | kubectl create secret generic scuttlebot-secrets \ |
| 7bbcd81… | lmata | 58 | --from-literal=ergo-api-token=$(openssl rand -hex 32) \ |
| 7bbcd81… | lmata | 59 | --from-literal=postgres-dsn='postgres://scuttlebot:PASSWORD@HOST:5432/scuttlebot?sslmode=require' |
| 7bbcd81… | lmata | 60 | ``` |
| 7bbcd81… | lmata | 61 | |
| 7bbcd81… | lmata | 62 | Do **not** commit `scuttlebot-secret.yaml` with real values. The file in this directory is an example template only. |
| 7bbcd81… | lmata | 63 | |
| 7bbcd81… | lmata | 64 | ### 3. Apply manifests |
| 7bbcd81… | lmata | 65 | |
| 7bbcd81… | lmata | 66 | ```sh |
| 7bbcd81… | lmata | 67 | kubectl apply -f deploy/k8s/ |
| 7bbcd81… | lmata | 68 | ``` |
| 7bbcd81… | lmata | 69 | |
| 7bbcd81… | lmata | 70 | ### 4. Watch rollout |
| 7bbcd81… | lmata | 71 | |
| 7bbcd81… | lmata | 72 | ```sh |
| 7bbcd81… | lmata | 73 | kubectl rollout status deployment/ergo |
| 7bbcd81… | lmata | 74 | kubectl rollout status deployment/scuttlebot |
| 7bbcd81… | lmata | 75 | ``` |
| 7bbcd81… | lmata | 76 | |
| 7bbcd81… | lmata | 77 | ### 5. Get the API token |
| 7bbcd81… | lmata | 78 | |
| 7bbcd81… | lmata | 79 | ```sh |
| 7bbcd81… | lmata | 80 | kubectl logs deployment/scuttlebot | grep "api token" |
| 7bbcd81… | lmata | 81 | ``` |
| 7bbcd81… | lmata | 82 | |
| 7bbcd81… | lmata | 83 | ## Customising |
| 7bbcd81… | lmata | 84 | |
| 7bbcd81… | lmata | 85 | | What | How | |
| 7bbcd81… | lmata | 86 | |------|-----| |
| 7bbcd81… | lmata | 87 | | IRC network name / server name | Edit `scuttlebot-configmap.yaml` | |
| 7bbcd81… | lmata | 88 | | Storage class for Ergo PVC | Uncomment `storageClassName` in `ergo-pvc.yaml` | |
| 7bbcd81… | lmata | 89 | | Expose REST API externally | Change `scuttlebot-api` service type to `LoadBalancer` or add an Ingress | |
| 7bbcd81… | lmata | 90 | | Namespace | Add `namespace:` to all resource metadata | |
| 7bbcd81… | lmata | 91 | |
| 7bbcd81… | lmata | 92 | ## Secrets management |
| 7bbcd81… | lmata | 93 | |
| 7bbcd81… | lmata | 94 | The example uses a plain Kubernetes Secret for simplicity. For production, prefer: |
| 7bbcd81… | lmata | 95 | - [Sealed Secrets](https://github.com/bitnami-labs/sealed-secrets) |
| 7bbcd81… | lmata | 96 | - [External Secrets Operator](https://external-secrets.io/) |
| 7bbcd81… | lmata | 97 | - [HashiCorp Vault](https://www.vaultproject.io/) |