106 lines
3.5 KiB
Markdown
106 lines
3.5 KiB
Markdown
# Deployment
|
|
|
|
Fuller command reference: [`deploy/README.md`](../deploy/README.md). This document covers deployment models and production requirements.
|
|
|
|
## Options
|
|
|
|
| Environment | Tooling | TLS | Data |
|
|
|-------------|---------|-----|------|
|
|
| Laptop | Compose + `compose.dev.yaml` | Traefik default cert | Postgres/Redis/RustFS in compose |
|
|
| Single-host VPS | Compose + `compose.prod.yaml` | Let's Encrypt HTTP-01 | Same + no published DB ports |
|
|
| Local k3s | Helm `values-k3s.yaml` | Chart self-signed | In-cluster |
|
|
| Production K8s | Helm `values-prod.yaml` | cert-manager | Usually external DB/Redis/S3 |
|
|
|
|
## Routing
|
|
|
|
| Path | Service |
|
|
|------|---------|
|
|
| `/api/*`, `/media/*` | backend |
|
|
| `/api/certificates/*`, `/c/*` | backend (+ noindex middleware) |
|
|
| everything else | frontend |
|
|
| `/api/ws` | backend WebSocket via Traefik |
|
|
|
|
## Compose — development
|
|
|
|
```bash
|
|
cp .env.example .env
|
|
./scripts/compose-dev.sh up -d --build
|
|
```
|
|
|
|
- App: https://localhost
|
|
- Traefik dashboard: http://127.0.0.1:8088
|
|
- DB ports only on `127.0.0.1`
|
|
|
|
## Compose — production
|
|
|
|
```bash
|
|
cp .env.prod.example .env.prod
|
|
./scripts/compose-prod.sh up -d --build
|
|
```
|
|
|
|
DNS must point at the host. `DOMAIN`, `ACME_EMAIL`, and strong secrets are required.
|
|
|
|
## k3s + Helm
|
|
|
|
```bash
|
|
# Install k3s and kubeconfig once (see deploy/README.md)
|
|
./scripts/k3s-load-images.sh # build and import local images
|
|
./scripts/helm-k3s.sh # upgrade --install with values-k3s.yaml
|
|
echo "127.0.0.1 pargar.local" | sudo tee -a /etc/hosts # if needed
|
|
curl -k https://pargar.local/api/health
|
|
```
|
|
|
|
### Values
|
|
|
|
| File | Purpose |
|
|
|------|---------|
|
|
| `deploy/helm/pargar/values.yaml` | Defaults |
|
|
| `values-k3s.yaml` | Local: seed, backup CronJob, self-signed TLS |
|
|
| `values-prod.yaml` | Registry, HPA, PDB, NetworkPolicy, `existingSecret` |
|
|
|
|
```bash
|
|
helm lint ./deploy/helm/pargar -f ./deploy/helm/pargar/values-k3s.yaml
|
|
helm template pargar ./deploy/helm/pargar -f ./deploy/helm/pargar/values-k3s.yaml
|
|
```
|
|
|
|
Helm 4 rejects negation patterns in `.helmignore` (`!…`); do not add them.
|
|
|
|
### Chart secrets
|
|
|
|
- Without `backend.existingSecret`: the chart generate-once via `lookup` + `randAlphaNum` and keeps values across upgrades.
|
|
- `change-me-*` placeholders in values are ignored.
|
|
- An existing Postgres password is **never rotated** (data depends on it).
|
|
- Production: always pre-create the Secret and set `backend.existingSecret`.
|
|
|
|
Read a generated admin password:
|
|
|
|
```bash
|
|
kubectl -n pargar get secret pargar-app -o jsonpath='{.data.admin-password}' | base64 -d; echo
|
|
```
|
|
|
|
### DB/Redis wiring in Helm
|
|
|
|
Instead of a raw URL with an unencoded password, the backend builds from parts:
|
|
|
|
- `POSTGRES_USER` / `POSTGRES_PASSWORD` / `POSTGRES_HOST` / `POSTGRES_DB` / `POSTGRES_SSLMODE`
|
|
- `REDIS_HOST` / `REDIS_PASSWORD`
|
|
|
|
Or for external production: `DATABASE_URL` / `REDIS_URL` inside the Secret.
|
|
|
|
### In-cluster backup
|
|
|
|
With `postgres.enabled` and `backup.enabled=true` (on for k3s): daily CronJob `pg_dump | gzip` onto a PVC with retention. For managed Postgres in production, set `backup.enabled=false`.
|
|
|
|
## Production checklist
|
|
|
|
1. `DEV_MODE=false`
|
|
2. Strong `JWT_SECRET` and `ADMIN_PASSWORD` (no placeholders) — otherwise `config.Validate()` refuses to boot
|
|
3. Exact public `PUBLIC_URL` and `FRONTEND_ORIGINS`
|
|
4. `TRUSTED_PROXY_CIDRS` limited to the proxy network
|
|
5. `METRICS_TOKEN` to expose `/metrics`
|
|
6. Images from a private registry + `imagePullSecrets`
|
|
7. cert-manager / real TLS
|
|
8. DB and object-storage backups defined
|
|
9. `PHYSICAL_CERT_ENABLED` only if the offline payment process is ready
|
|
10. NetworkPolicy / HPA per `values-prod.yaml`
|