Kubernetes
Overview
Section titled “Overview”Chart path: helm/garrison/. It deploys API, CRDT merge worker, queue worker, optional scheduler, UI, and optional in-cluster Postgres and Redis. The marketing site (www) is disabled by default (www.enabled: false).
The chart sets NOTE_CRDT_MERGE_URL (and DB_HOST, REDIS_HOST, etc.) in a ConfigMap. Override those only when using external Postgres, Redis, or a CRDT merge worker outside the cluster.
Chart files
Section titled “Chart files”| File | Purpose |
|---|---|
helm/garrison/values.yaml | Default values (safe for local or trial installs) |
helm/garrison/values-production.example.yaml | Production-oriented overrides — copy to a private repo or merge into your install |
helm/garrison/argocd-application.example.yaml | Example Argo CD Application manifest |
helm/garrison/README.md | Quick reference in the repository |
For GitOps with Argo CD, see Argo CD.
Prerequisites
Section titled “Prerequisites”- Kubernetes cluster and
kubectl - Helm 3
- Images in a registry (built by GitLab CI or locally)
- TLS certificate on your Gateway listener (for example cert-manager
Certificatereferenced by the Gateway), or legacy Ingress TLS - Kubernetes Secret with Laravel env for production (recommended via
api.existingSecret; seehelm/garrison/secrets.env.example)
Install
Section titled “Install”Start from helm/garrison/values-production.example.yaml or create your own values file (my-values.yaml):
global: imageRegistry: registry.gitlab.com/churchtechhelp/garrison # When the registry is private: # imagePullSecrets: # - name: garrison-registry
api: image: repository: api tag: latest # pin to $CI_COMMIT_SHORT_SHA after CI build existingSecret: garrison-secrets # Laravel env (APP_URL, MAIL_*, SESSION_*, etc.) — put in garrison-secrets; see helm/garrison/secrets.env.example
crdtMerge: image: repository: crdt-merge tag: latest
ui: image: repository: ui tag: latest
scheduler: enabled: true
postgres: auth: password: "" # use api.existingSecret DB_PASSWORD instead
# Optional marketing site (default false in values.yaml):# www:# enabled: true# image:# repository: www# tag: latest
ingress: enabled: false
httpRoute: enabled: true parentRefs: - name: external-gateway namespace: gateway-system sectionName: https hosts: api: api.garrison.test app: app.garrison.test www: www.garrison.testSet httpRoute.parentRefs to your cluster’s existing Gateway (the chart does not create it). List Gateways with kubectl get gateway -A, then list listener names:
kubectl get gateway <gateway-name> -n <gateway-namespace> \ -o jsonpath='{range .spec.listeners[*]}{.name}{" ("}{.protocol}{" :"}{.port}{")\n"}{end}'Use the HTTPS listener’s name as sectionName. See Argo CD → Gateway API for the full field mapping and Argo parameter names.
Create the Secret before install when using api.existingSecret (copy and customize helm/garrison/secrets.env.example):
kubectl create namespace garrisonkubectl create secret generic garrison-secrets -n garrison \ --from-env-file=secrets.envGenerate APP_KEY with php artisan key:generate --show from a local Laravel install.
Install:
helm upgrade --install garrison ./helm/garrison \ --namespace garrison --create-namespace \ -f my-values.yamlMarketing site (optional)
Section titled “Marketing site (optional)”Set in your values file:
www: enabled: true image: repository: www tag: latestWhen using HTTPRoute or Ingress, set httpRoute.hosts.www or ingress.hosts.www when enabling the marketing site.
External database or Redis
Section titled “External database or Redis”Disable bundled services and point at managed instances:
postgres: enabled: false
externalDatabase: enabled: true host: postgres.example.com port: 5432 database: garrison username: garrison password: "secret"
redis: enabled: false
externalRedis: enabled: true host: redis.example.com port: 6379Prefer api.existingSecret for DB_PASSWORD in production rather than committing passwords in values.
Migrations
Section titled “Migrations”API, queue, and scheduler pods run php artisan migrate --force --isolated in an init container on every rollout, after waiting for Postgres (and Redis where configured). If a migration fails, the new pod does not become ready and the rollout stalls instead of serving traffic against an outdated schema.
To run migrations manually (for example during incident response):
kubectl exec -n garrison deploy/garrison-api -- php artisan migrate --forceStartup ordering
Section titled “Startup ordering”On first install the chart applies resources in order so dependencies are ready:
- Postgres PVC (
-20) - ConfigMap, Secret, and Postgres/Redis Services (
-15) - Postgres and Redis Deployments (
-10) - CRDT merge worker (
5) - API, queue, scheduler, UI, and their Services (
10) — init containers wait for Postgres/Redis, then run migrations - HTTPRoutes or Ingress (
20)
Health checks
Section titled “Health checks”- API readiness and liveness: HTTP
GET /upon port 80 - CRDT merge worker: HTTP
GET /healthon port 3000 - UI and www: HTTP
GET /on port 80
UI API URL
Section titled “UI API URL”Build the UI image with VITE_API_URL matching your public API (docker/ui/Dockerfile ARG). The chart serves the pre-built image; changing API URL requires rebuilding the UI image.
Upgrade
Section titled “Upgrade”helm upgrade garrison ./helm/garrison -f my-values.yamlkubectl rollout status deployment/garrison-api -n garrisonSee also
Section titled “See also”- Argo CD
- Production smoke checklist — verify
/up, GraphQL auth, and CRDT after deploy helm/garrison/README.mdin the repository