Appearance
Deploying Sulu on Kubernetes
Sulu ships a Helm chart that installs the backend, frontend, landing site, docs, and all required infrastructure into a Kubernetes cluster. The chart is published to GHCR as an OCI artifact and is versioned in lockstep with the Sulu Docker images.
Prerequisites
- Kubernetes 1.27 or newer
- Helm 3.14 or newer (older versions don't support OCI registries fully)
- An ingress controller (we recommend ingress-nginx)
- A TLS certificate provisioner (we recommend cert-manager)
- A Sulu pull token (issued by your Sulu account team)
Quick start
1. Authenticate to GHCR
bash
# For Docker images
echo "$SULU_PULL_TOKEN" | docker login ghcr.io -u <your-handle> --password-stdin
# For the Helm chart (OCI)
echo "$SULU_PULL_TOKEN" | helm registry login ghcr.io -u <your-handle> --password-stdin2. Create the image-pull secret in your cluster
bash
kubectl create namespace sulu
kubectl create secret docker-registry sulu-ghcr-creds \
--docker-server=ghcr.io \
--docker-username=<your-handle> \
--docker-password=$SULU_PULL_TOKEN \
--namespace sulu3. Create your overrides file
yaml
# my-overrides.yaml
suluSecretKey: "<output of: openssl rand -base64 32>"
bootstrapAdmin:
email: "[email protected]"
password: "<output of: openssl rand -base64 24>"
publicUrl: "https://sulu.yourcompany.example"
ingress:
className: "nginx"
tls:
enabled: true
secretName: "sulu-tls"
hosts:
app: "sulu.yourcompany.example"
api: "api.sulu.yourcompany.example"
landing: "www.yourcompany.example"
docs: "docs.sulu.yourcompany.example"
smtp:
host: "smtp.yourcompany.example"
port: 587
user: "[email protected]"
password: "<smtp-password>"
from: "[email protected]"4. Install the chart
bash
helm install sulu oci://ghcr.io/ellyzz/charts/sulu \
--version 1.0.0 \
--namespace sulu \
-f my-overrides.yamlHelm will:
- Pull the chart from GHCR
- Resolve the bundled Bitnami subcharts (Postgres + RabbitMQ + MinIO)
- Run a pre-install Job that waits for Postgres and applies Flyway migrations
- Roll out backend, frontend, landing, and docs Deployments
- Render an Ingress with the four hosts you configured
Watch the rollout:
bash
kubectl --namespace sulu get pods -l app.kubernetes.io/instance=sulu --watch5. Verify
bash
helm test sulu --namespace suluThis runs a smoke probe against /actuator/health/readiness on the backend.
Bring your own infrastructure
If your platform already provides managed Postgres, RabbitMQ, and S3, disable the bundled subcharts:
bash
helm install sulu oci://ghcr.io/ellyzz/charts/sulu \
--version 1.0.0 \
--namespace sulu \
-f my-overrides.yaml \
-f values-examples/byo-deps.yamlThe values-byo-deps.yaml example wires the backend to external services. You'll need to create Kubernetes Secrets for the credentials beforehand:
bash
kubectl create secret generic sulu-postgres-creds \
--from-literal=password='<your-postgres-password>' \
--namespace suluAutoscaling
Both backend and frontend support horizontal pod autoscaling. Enable in your overrides:
yaml
backend:
autoscaling:
enabled: true
minReplicas: 2
maxReplicas: 10
targetCPUUtilizationPercentage: 70
frontend:
autoscaling:
enabled: true
minReplicas: 2
maxReplicas: 5You'll need the metrics-server running in your cluster for HPA to read pod metrics.
NetworkPolicy
To restrict inter-pod traffic, enable NetworkPolicy:
yaml
networkPolicy:
enabled: trueThis applies two policies:
- Frontend/landing/docs accept ingress only from
namespace ingress-nginx - Backend accepts ingress from frontend pods
You'll need a CNI plugin that enforces NetworkPolicy (Calico, Cilium, etc.).
Upgrades
bash
helm upgrade sulu oci://ghcr.io/ellyzz/charts/sulu \
--version 1.1.0 \
--namespace sulu \
-f my-overrides.yamlThe pre-upgrade hook runs Flyway migrations before any pod restart. If migrations fail, the upgrade aborts cleanly and no pods are recreated.
Uninstall
bash
helm uninstall sulu --namespace sulu
kubectl delete namespace suluPersistentVolumeClaims belonging to the bundled Postgres/RabbitMQ/MinIO are NOT auto-deleted. Delete them explicitly if you want to wipe data:
bash
kubectl delete pvc -l app.kubernetes.io/instance=sulu --namespace suluTroubleshooting
| Symptom | Likely cause | Fix |
|---|---|---|
| Image pull errors | Pull secret missing or wrong | Re-create sulu-ghcr-creds (see step 2). |
| Pre-install Job stuck | Postgres not reachable | Check kubectl logs job/sulu-migrate-<rev> and the Postgres pod. |
| Backend CrashLoopBackOff | suluSecretKey or bootstrapAdmin missing | Re-run with --set values, or fix overrides file. |
| Ingress 502 | Backend not ready yet, or hostname mismatch | kubectl get ingress -n sulu and kubectl describe. |