- New namespace grist with in-namespace PostgreSQL 16 - Ingress grist.basicstack.de + letsencrypt-prod (DNS-01 via Hetzner) - Pocket ID OIDC login (client "Grist", group "grist") - All PVCs on hcloud-volumes-encrypted - ArgoCD application via apps/app-grist.yaml Co-Authored-By: Paperclip <noreply@paperclip.ing>
94 lines
3 KiB
Markdown
94 lines
3 KiB
Markdown
# Grist Deployment
|
|
|
|
This directory contains the Kubernetes manifests for the Grist deployment at https://grist.basicstack.de
|
|
|
|
Grist is an open-source, self-hostable spreadsheet / database hybrid ([grist-core](https://github.com/gristlabs/grist-core)).
|
|
|
|
## Components
|
|
|
|
- **grist-deployment.yaml**: Main Grist application deployment
|
|
- Image: `gristlabs/grist:1.7.7`
|
|
- Port: 8484
|
|
- OIDC login via Pocket ID (`https://auth.basicstack.de`)
|
|
- Data persisted at `/persist`
|
|
|
|
- **grist-service.yaml**: ClusterIP service exposing port 80 -> 8484
|
|
|
|
- **grist-data-pvc.yaml**: PVC for Grist app data (`/persist`), 20 GiB on `hcloud-volumes-encrypted`
|
|
|
|
- **grist-postgres-deployment.yaml** / **grist-postgres-service.yaml**: In-namespace PostgreSQL 16 for the Grist home database (TypeORM connection)
|
|
|
|
- **grist-db-pvc.yaml**: PVC for PostgreSQL data, 20 GiB on `hcloud-volumes-encrypted`
|
|
|
|
- **grist-ingress.yaml**: Traefik ingress with TLS
|
|
- Host: `grist.basicstack.de`
|
|
- TLS via cert-manager (`letsencrypt-prod`, DNS-01 via Hetzner webhook)
|
|
|
|
- **grist-db-credentials-sealed.yaml**: SealedSecret for PostgreSQL user password
|
|
- **grist-app-secrets-sealed.yaml**: SealedSecret with `GRIST_SESSION_SECRET`
|
|
- **grist-oidc-secret-sealed.yaml**: SealedSecret with Pocket ID OIDC client credentials
|
|
|
|
## OIDC Configuration (Pocket ID)
|
|
|
|
- Pocket ID group: `grist`
|
|
- Client name in Pocket ID: `Grist`
|
|
- Callback URL: `https://grist.basicstack.de/oauth2/callback`
|
|
- Client is restricted to members of the `grist` group
|
|
|
|
Grist environment variables driving OIDC (from https://pocket-id.org/docs/client-examples/grist):
|
|
|
|
```
|
|
GRIST_OIDC_IDP_ISSUER=https://auth.basicstack.de
|
|
GRIST_OIDC_IDP_CLIENT_ID=<from secret>
|
|
GRIST_OIDC_IDP_CLIENT_SECRET=<from secret>
|
|
GRIST_OIDC_SP_HOST=https://grist.basicstack.de
|
|
GRIST_OIDC_IDP_SCOPES="openid email profile"
|
|
GRIST_OIDC_IDP_END_SESSION_ENDPOINT=https://auth.basicstack.de/api/oidc/end-session
|
|
GRIST_OIDC_SP_IGNORE_EMAIL_VERIFIED=true
|
|
GRIST_DEFAULT_EMAIL=andreas.leinen@basicstack.de
|
|
GRIST_FORCE_LOGIN=true
|
|
```
|
|
|
|
`GRIST_DEFAULT_EMAIL` is used by Grist as the primary admin identity - the value must be a valid Pocket ID user.
|
|
|
|
## Storage
|
|
|
|
Both PVCs (`grist-data`, `grist-db`) use `hcloud-volumes-encrypted` (Retain reclaim policy) as required for
|
|
sensitive workload data on Hetzner.
|
|
|
|
## GitOps
|
|
|
|
Managed by Argo CD via `apps/app-grist.yaml`:
|
|
|
|
```yaml
|
|
apiVersion: argoproj.io/v1alpha1
|
|
kind: Application
|
|
metadata:
|
|
name: grist
|
|
namespace: argocd
|
|
spec:
|
|
project: default
|
|
source:
|
|
repoURL: git@forgejo.forgejo.svc.cluster.local:basicstack/stack.basicstack.de.git
|
|
targetRevision: main
|
|
path: apps/grist
|
|
destination:
|
|
server: https://kubernetes.default.svc
|
|
namespace: grist
|
|
syncPolicy:
|
|
syncOptions:
|
|
- CreateNamespace=true
|
|
```
|
|
|
|
## Verification
|
|
|
|
```
|
|
kubectl -n grist get pods
|
|
kubectl -n grist get pvc
|
|
kubectl -n grist get ingress
|
|
curl -I https://grist.basicstack.de
|
|
```
|
|
|
|
## Backup
|
|
|
|
The PostgreSQL PVC uses reclaim policy `Retain`. For scheduled logical backups add a `CronJob` like the one in `apps/directus/directus-backup-cronjob.yaml`.
|