docs: add local dev setup guide — Setting Up Your Vanity 💄
Lima VM, k3s, mkcert, sslip.io, sunbeam CLI setup, resource budget, differences from production, common commands, troubleshooting.
This commit is contained in:
214
docs/local-dev.md
Normal file
214
docs/local-dev.md
Normal file
@@ -0,0 +1,214 @@
|
|||||||
|
# Setting Up Your Vanity 💄
|
||||||
|
|
||||||
|
Local development for The Super Boujee Business Box ✨ runs on a Lima VM with k3s. The whole stack — every app, every service — runs on your laptop. It's the same architecture as production, just with smaller resource limits and self-signed TLS.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Prerequisites
|
||||||
|
|
||||||
|
- macOS (Apple Silicon or Intel)
|
||||||
|
- [Lima](https://lima-vm.io/) — lightweight Linux VMs on Apple Virtualization.framework
|
||||||
|
- [mkcert](https://github.com/FiloSottile/mkcert) — local TLS certificates
|
||||||
|
- [Sunbeam CLI](cli.md) — the remote control
|
||||||
|
|
||||||
|
```bash
|
||||||
|
brew install lima mkcert
|
||||||
|
```
|
||||||
|
|
||||||
|
And install sunbeam:
|
||||||
|
```bash
|
||||||
|
git clone https://src.sunbeam.pt/studio/cli.git
|
||||||
|
cd cli && cargo install --path sunbeam
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Create the VM
|
||||||
|
|
||||||
|
```bash
|
||||||
|
limactl start --name=sunbeam --memory=12 --cpus=6 --disk=60 template://k3s
|
||||||
|
```
|
||||||
|
|
||||||
|
This gives you a k3s cluster inside a Lima VM with:
|
||||||
|
- 12GB RAM (enough for the full stack)
|
||||||
|
- 6 CPUs
|
||||||
|
- 60GB disk
|
||||||
|
|
||||||
|
Lima uses Apple's Virtualization.framework — native performance, no emulation overhead.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Configure Sunbeam
|
||||||
|
|
||||||
|
Get the Lima VM IP and set up your context:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
LIMA_IP=$(limactl shell sunbeam -- hostname -I | awk '{print $1}')
|
||||||
|
|
||||||
|
sunbeam config set \
|
||||||
|
--domain "${LIMA_IP}.sslip.io" \
|
||||||
|
--infra-dir /path/to/sbbb \
|
||||||
|
--acme-email dev@localhost
|
||||||
|
```
|
||||||
|
|
||||||
|
### sslip.io DNS
|
||||||
|
|
||||||
|
No DNS configuration needed. [sslip.io](https://sslip.io) provides wildcard DNS resolution — any subdomain of `{IP}.sslip.io` resolves to that IP:
|
||||||
|
|
||||||
|
```
|
||||||
|
docs.192.168.5.2.sslip.io → 192.168.5.2
|
||||||
|
meet.192.168.5.2.sslip.io → 192.168.5.2
|
||||||
|
src.192.168.5.2.sslip.io → 192.168.5.2
|
||||||
|
```
|
||||||
|
|
||||||
|
Every app just works.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## TLS with mkcert
|
||||||
|
|
||||||
|
Generate a wildcard certificate for your local domain:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
mkcert "*.${LIMA_IP}.sslip.io"
|
||||||
|
```
|
||||||
|
|
||||||
|
This creates `_wildcard.{IP}.sslip.io.pem` + `_wildcard.{IP}.sslip.io-key.pem`. The sunbeam CLI handles mounting these into the cluster as a K8s Secret for Pingora.
|
||||||
|
|
||||||
|
mkcert's root CA is already trusted by your system — no browser warnings.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Bring Up the Cluster
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Install cert-manager, Linkerd, TLS
|
||||||
|
sunbeam up
|
||||||
|
|
||||||
|
# Deploy everything
|
||||||
|
sunbeam apply
|
||||||
|
|
||||||
|
# Seed all credentials in OpenBao
|
||||||
|
sunbeam seed
|
||||||
|
|
||||||
|
# Bootstrap Gitea orgs and repos
|
||||||
|
sunbeam bootstrap
|
||||||
|
```
|
||||||
|
|
||||||
|
That's it. Go get a coffee — or a mimosa, we don't judge. When you come back:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
sunbeam status # check everything's running
|
||||||
|
sunbeam check # functional health probes
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Access Your Stack
|
||||||
|
|
||||||
|
Open in your browser:
|
||||||
|
|
||||||
|
| App | URL |
|
||||||
|
|-----|-----|
|
||||||
|
| Docs | `https://docs.{LIMA_IP}.sslip.io` |
|
||||||
|
| Drive | `https://drive.{LIMA_IP}.sslip.io` |
|
||||||
|
| Mail | `https://mail.{LIMA_IP}.sslip.io` |
|
||||||
|
| Messages (Matrix) | `https://messages.{LIMA_IP}.sslip.io` |
|
||||||
|
| Meet | `https://meet.{LIMA_IP}.sslip.io` |
|
||||||
|
| Calendar | `https://cal.{LIMA_IP}.sslip.io` |
|
||||||
|
| Projects | `https://projects.{LIMA_IP}.sslip.io` |
|
||||||
|
| Gitea | `https://src.{LIMA_IP}.sslip.io` |
|
||||||
|
| Grafana | `https://metrics.{LIMA_IP}.sslip.io` |
|
||||||
|
| Auth | `https://auth.{LIMA_IP}.sslip.io` |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Resource Budget
|
||||||
|
|
||||||
|
Target: ~5.5–6GB total for pods, plus OS overhead.
|
||||||
|
|
||||||
|
| Component | Memory |
|
||||||
|
|-----------|--------|
|
||||||
|
| Linkerd (control + 20 sidecars) | ~300MB |
|
||||||
|
| PostgreSQL | 512MB |
|
||||||
|
| Valkey | 64MB |
|
||||||
|
| OpenSearch | 512MB |
|
||||||
|
| SeaweedFS (master + volume + filer) | ~576MB |
|
||||||
|
| Ory (Kratos + Hydra) | ~128MB |
|
||||||
|
| La Suite apps (7 × ~256MB) | ~1.8GB |
|
||||||
|
| Gitea | 256MB |
|
||||||
|
| Sol☀️ | 256–512MB |
|
||||||
|
| Hive | 64MB |
|
||||||
|
| Pingora | 256MB |
|
||||||
|
| Monitoring (Prometheus + Grafana + Loki + Tempo + Alloy) | ~1GB |
|
||||||
|
|
||||||
|
12GB VM gives comfortable headroom.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Differences from Production
|
||||||
|
|
||||||
|
| Aspect | Production | Local |
|
||||||
|
|--------|-----------|-------|
|
||||||
|
| Domain | `sunbeam.pt` | `{LIMA_IP}.sslip.io` |
|
||||||
|
| TLS | cert-manager + Let's Encrypt | mkcert self-signed wildcard |
|
||||||
|
| Server | 64GB Scaleway Elastic Metal | 12GB Lima VM |
|
||||||
|
| Backups | barman → Scaleway Object Storage | Disabled |
|
||||||
|
| Email DNS | MX, SPF, DKIM, DMARC, PTR | N/A (no inbound email) |
|
||||||
|
| Email relay | Scaleway TEM | Local Postfix (or disabled) |
|
||||||
|
|
||||||
|
The stack is architecturally identical — same manifests, same overlays, just different resource limits and TLS.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Common Commands
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Rebuild and deploy a service
|
||||||
|
sunbeam build sol --push --deploy
|
||||||
|
|
||||||
|
# Watch logs
|
||||||
|
sunbeam logs matrix/sol -f
|
||||||
|
|
||||||
|
# Restart something that's misbehaving
|
||||||
|
sunbeam restart lasuite/drive
|
||||||
|
|
||||||
|
# Apply changes to just one namespace
|
||||||
|
sunbeam apply lasuite
|
||||||
|
|
||||||
|
# Check service health
|
||||||
|
sunbeam check
|
||||||
|
|
||||||
|
# Access raw kubectl
|
||||||
|
sunbeam k8s get pods -A
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Troubleshooting
|
||||||
|
|
||||||
|
**Pod stuck in CrashLoopBackOff:**
|
||||||
|
```bash
|
||||||
|
sunbeam logs {namespace}/{service} # check the logs
|
||||||
|
sunbeam restart {namespace}/{service} # try a restart
|
||||||
|
```
|
||||||
|
|
||||||
|
**Database connection errors:**
|
||||||
|
```bash
|
||||||
|
sunbeam check data # check PostgreSQL health
|
||||||
|
sunbeam vault status # is OpenBao sealed?
|
||||||
|
sunbeam vault unseal <key> # unseal if needed
|
||||||
|
```
|
||||||
|
|
||||||
|
**TLS certificate errors:**
|
||||||
|
```bash
|
||||||
|
# Regenerate mkcert certs
|
||||||
|
mkcert "*.${LIMA_IP}.sslip.io"
|
||||||
|
sunbeam apply ingress # redeploy with new cert
|
||||||
|
```
|
||||||
|
|
||||||
|
**Everything's broken (we've all been there):**
|
||||||
|
```bash
|
||||||
|
sunbeam status # what's actually running?
|
||||||
|
sunbeam mon loki logs '{namespace="monitoring"}' # check the watchers
|
||||||
|
```
|
||||||
Reference in New Issue
Block a user