Files
sbbb/docs/deployment.md
Sienna Meridian Satterwhite 2f7785774b docs: add production deployment guide — Serving Looks in Production 👠
Scaleway setup, k3s, kustomize structure, deployment phases, DNS,
cert-manager, backup strategy, image registry.
2026-03-24 11:46:47 +00:00

259 lines
7.1 KiB
Markdown
Raw Permalink Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Serving Looks in Production 👠
The Super Boujee Business Box ✨ runs on a single Scaleway Elastic Metal server in Paris. One box, one bill, European data sovereignty by default. No multi-cloud, no multi-region, no per-seat fees — just a server that belongs to you.
---
## The Server
| Property | Value |
|----------|-------|
| **Provider** | Scaleway Elastic Metal |
| **Region** | Paris (PAR1/PAR2) |
| **RAM** | 64GB minimum |
| **Storage** | Local NVMe |
| **Network** | Public IPv4, configurable reverse DNS |
| **Monthly cost** | ~€5080 (server) + ~€716 (services) |
### External Scaleway Services
| Service | Purpose | Cost |
|---------|---------|------|
| Object Storage | PostgreSQL backups (barman), cold asset overflow | ~€510/mo |
| Transactional Email (TEM) | Outbound SMTP relay | ~€1/mo |
| Generative APIs | AI inference for all components | ~€15/mo |
Total: under €100/month for the entire collaboration suite. That's less than three Slack seats. 💅
---
## k3s Installation
```bash
curl -sfL https://get.k3s.io | INSTALL_K3S_EXEC="--disable=traefik" sh -
```
Traefik is disabled because we use Pingora. k3s gives us single-binary Kubernetes without the overhead of a full cluster setup.
---
## Deployment Flow
### First-Time Setup
```bash
# 1. Install k3s (above)
# 2. Configure sunbeam
sunbeam config set \
--domain sunbeam.pt \
--host admin@{SERVER_IP} \
--infra-dir /path/to/sbbb \
--acme-email ops@sunbeam.pt
# 3. Bring up core infrastructure
sunbeam up # cert-manager, Linkerd, TLS
# 4. Deploy everything
sunbeam apply # all namespaces
# 5. Seed credentials
sunbeam seed # all secrets into OpenBao
# 6. Bootstrap services
sunbeam bootstrap # Gitea orgs, repos, service accounts
# 7. Verify
sunbeam verify # OpenBao + VSO sync test
sunbeam check # functional health probes
```
### Ongoing Deployments
The daily driver. Most deploys are just one command.
```bash
# Deploy all namespaces
sunbeam apply
# Deploy specific namespace
sunbeam apply lasuite
sunbeam apply monitoring
sunbeam apply matrix
# Build, push, and deploy a service
sunbeam build sol --push --deploy
```
---
## Kustomize Structure
```
sbbb/
├── base/ # Canonical manifests (environment-agnostic)
│ ├── data/ # PostgreSQL, Valkey, OpenSearch, OpenBao, SearXNG
│ ├── devtools/ # Gitea
│ ├── ingress/ # Pingora proxy
│ ├── lasuite/ # All La Suite apps + Hive + Postfix
│ ├── matrix/ # Tuwunel + Sol☀
│ ├── media/ # LiveKit
│ ├── mesh/ # Linkerd
│ ├── monitoring/ # Prometheus, Grafana, Loki, Tempo, Alloy
│ ├── ory/ # Kratos + Hydra
│ ├── storage/ # SeaweedFS
│ ├── cert-manager/ # Certificate management
│ ├── longhorn/ # Volume management
│ └── vso/ # Vault Secrets Operator
├── overlays/
│ ├── local/ # Local dev patches (resource limits, mkcert)
│ └── production/ # Production patches (SSL, full resources)
├── scripts/ # Bash automation
└── docs/ # You are here ✨
```
### The Pattern
- **Base** holds canonical config — deployments, services, configmaps, values files, vault secrets, alert rules, service monitors
- **Overlays** hold only patches — resource overrides, domain-specific values, environment differences
- **DOMAIN_SUFFIX** placeholder gets replaced by `sed` at deploy time
```bash
# What sunbeam apply does under the hood
kustomize build overlays/production \
| sed 's/DOMAIN_SUFFIX/sunbeam.pt/g' \
| kubectl apply --server-side -f -
```
---
## Deployment Phases
The stack deploys in order of dependency — foundation first, glamour later:
### Phase 1 — Core Infrastructure
1. Kubernetes & networking (k3s, Linkerd)
2. Secrets (OpenBao, Vault Secrets Operator)
3. Database (CloudNativePG)
4. Cache (Valkey)
5. Storage (SeaweedFS)
### Phase 2 — Identity & Edge
6. Ory Kratos & Hydra
7. Pingora edge proxy
8. cert-manager (Let's Encrypt)
### Phase 3 — Applications
9. Docs (Collabora)
10. Meet (LiveKit)
11. Drive
12. Messages (full email stack)
13. Calendars
14. People
15. Projects
16. Find
17. Integration navbar
### Phase 4 — Connectivity & Sync
18. Hive (Drive ↔ S3 sync)
19. Postfix (outbound SMTP)
### Phase 5 — Matrix & AI
20. Tuwunel (Matrix homeserver)
21. Sol☀ (AI agent)
### Phase 6 — Development Tools
22. Gitea
23. SearXNG
### Phase 7 — Observability
24. Prometheus + Grafana
25. Loki + Alloy
26. Tempo
27. AlertManager
---
## DNS Setup
All subdomains point to the server's public IP via A records:
```
docs.sunbeam.pt → A → {SERVER_IP}
meet.sunbeam.pt → A → {SERVER_IP}
drive.sunbeam.pt → A → {SERVER_IP}
mail.sunbeam.pt → A → {SERVER_IP}
messages.sunbeam.pt → A → {SERVER_IP}
people.sunbeam.pt → A → {SERVER_IP}
src.sunbeam.pt → A → {SERVER_IP}
auth.sunbeam.pt → A → {SERVER_IP}
cal.sunbeam.pt → A → {SERVER_IP}
projects.sunbeam.pt → A → {SERVER_IP}
metrics.sunbeam.pt → A → {SERVER_IP}
livekit.sunbeam.pt → A → {SERVER_IP}
s3.sunbeam.pt → A → {SERVER_IP}
# ... and the rest
```
### Email DNS
Email requires additional records:
| Record | Value |
|--------|-------|
| **MX** | Points to server IP (messages-mta-in listens on port 25) |
| **SPF** | `v=spf1 ip4:{SERVER_IP} include:tem.scaleway.com ~all` |
| **DKIM** | Generated by Postfix/Rspamd, published as TXT record |
| **DMARC** | `v=DMARC1; p=quarantine; rua=mailto:dmarc@sunbeam.pt` |
| **PTR** | Reverse DNS configured in Scaleway console |
---
## TLS Certificates
cert-manager handles Let's Encrypt certificates in production:
- ACME HTTP-01 challenges routed by Pingora itself (watches Ingress objects for solver pods)
- Certificates stored in K8s Secret `pingora-tls`
- Pingora watches the Secret and hot-reloads on renewal (zero downtime)
---
## Backups
### PostgreSQL
- **Tool:** barman (continuous archiving)
- **Destination:** Scaleway Object Storage
- **Retention:** 30 days (see [ops.md](ops.md) for the 7-year cold storage gap)
- **Recovery:** CloudNativePG handles point-in-time recovery
### Secrets
- OpenBao (Vault) data backed up separately
- Root token and unseal keys stored securely offline
### Object Storage
- SeaweedFS volumes on local NVMe
- Game assets also exist in Drive (Hive keeps them synced — bless that fairy)
- Consider periodic snapshots for critical buckets
---
## Image Registry
Container images are built and stored in the Gitea registry at `src.sunbeam.pt`:
```bash
# Build and push
sunbeam build proxy --push
sunbeam build sol --push
# Images tagged as
src.sunbeam.pt/studio/proxy:latest
src.sunbeam.pt/studio/sol:latest
```
For arm64 targets, `sunbeam mirror` rebuilds amd64-only La Suite images for multi-arch support. We don't discriminate against architectures. ✨