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/)
98
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!