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