Skip to content

Kubernetes Deployment

Cluster

Kubernetes 1.24+, kubectl context with admin rights, and working Ingress or LoadBalancer.

Tooling

Helm 3.x, access to a container registry for custom images, and openssl (or pwgen) for secrets.

LeafLock ships a Helm chart under helm/. All examples assume the repo root as working directory.

The backend refuses to boot without strong secrets. Generate them once per cluster:

kubectl create namespace leaflock
kubectl create secret generic leaflock-secrets \
--namespace leaflock \
--from-literal=postgres-password=$(openssl rand -base64 32) \
--from-literal=redis-password=$(openssl rand -base64 32) \
--from-literal=jwt-secret=$(openssl rand -base64 64) \
--from-literal=encryption-key=$(openssl rand -base64 32) \
--from-literal=admin-password=$(openssl rand -base64 32)

Secrets map directly to config.LoadConfig() fields (JWT_SECRET, SERVER_ENCRYPTION_KEY, etc.). Weak values trigger startup failures—check backend logs if pods restart.

helm upgrade --install leaflock ./helm \
--namespace leaflock \
--set ingress.host=leaflock.example.com \
--set backend.jwtSecretFromSecret=leaflock-secrets:jwt-secret \
--set backend.encryptionKeyFromSecret=leaflock-secrets:encryption-key \
--set database.passwordFromSecret=leaflock-secrets:postgres-password \
--set redis.passwordFromSecret=leaflock-secrets:redis-password

Key chart values:

  • backend.replicaCount: default 2; enable HPA via backend.autoscaling.enabled=true.
  • frontend.corsOrigins: must match your HTTPS origin; defaults to https://leaflock.example.com.
  • ingress.className: align with your ingress controller (e.g., nginx, alb).
  • metrics.enabled: set to true to expose /metrics from the backend (requires Prometheus scrape config).

Refer to helm/values.yaml for additional flags like share-link TTLs and default admin behaviour.

  • Backend liveness/api/v1/health/live; readiness → /api/v1/health/ready (checks PostgreSQL + Redis via server/ReadyState).
  • Frontend health/health served by Caddy.
  • LoadBalancer/Ingress terminates TLS; backend is never exposed publicly.
kubectl get pods -n leaflock
kubectl port-forward svc/backend 8080:8080 -n leaflock
curl http://localhost:8080/api/v1/health/ready
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: leaflock
namespace: leaflock
annotations:
cert-manager.io/cluster-issuer: letsencrypt
spec:
ingressClassName: nginx
rules:
- host: leaflock.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: frontend
port:
number: 80
tls:
- hosts:
- leaflock.example.com
secretName: leaflock-tls
  • helm upgrade leaflock ./helm --set image.tag=v1.6.0 triggers a zero-downtime rolling deployment.
  • Horizontal Pod Autoscaler (HPA) targets CPU by default; tune backend.autoscaling.targetCPUUtilizationPercentage to match workload.
  • For bursty WebSocket usage, increase backend.resources.requests.cpu to avoid throttling collaboration broadcasts.
kubectl rollout status deploy/backend -n leaflock
kubectl autoscale deploy backend --cpu-percent=60 --min=2 --max=10 -n leaflock
  • Enable metrics: --set metrics.enabled=true and configure your Prometheus scrape.
  • Logs: kubectl logs deploy/backend -n leaflock --tail=200 -f for Go request logs with X-Request-ID.
  • Audit database health: kubectl exec deploy/postgres -n leaflock -- pg_isready -U postgres.

Hooking the backend into Grafana Loki? Use the existing structured JSON logs emitted by utils.InfoLogger.

  • Pods crashloop with “fatal: JWT_SECRET required”: secret keys missing or blank; re-create leaflock-secrets.
  • Ingress shows 502: backend readiness likely failing—verify database connectivity and Redis password alignment.
  • WebSocket disconnects: ensure sticky sessions (or consistent hashing) on the ingress controller; collaboration uses /ws upgrades routed to the backend service.
  • Slow migrations: large databases may exceed default readiness timeout; increase backend.readinessProbe.initialDelaySeconds.