Deploying Colden to a cluster
What a Kubernetes cluster needs before the first Colden release, how to prepare a namespace, the first deployment and the checks that prove it works.
One Helm release per environment runs the whole kit (infra/helm/colden). This guide takes an empty cluster to a working release; the pipeline repeats steps 2 and 3 on every deployment (docs/guides/ci.md).
1. What the cluster needs
The cluster's owner installs these once; the chart expects them and creates none of them.
| Prerequisite | Why | How the chart uses it |
|---|---|---|
| Kubernetes 1.29 or later | The chart's API versions (autoscaling/v2, policy/v1, networking.k8s.io/v1) | kubeVersion in Chart.yaml |
| An ingress controller (ingress-nginx by default, Traefik or any other) | The web and api hosts | ingress.className |
| cert-manager with an issuer | TLS certificates for the hosts | either ingress.certificate.issuer (the chart requests a Certificate per host) or ingress.annotations (cert-manager.io/cluster-issuer), and ingress.tls.*SecretName |
| DNS records pointing at the ingress: the web's host, and the api's when it has its own | The public addresses | hosts.web, hosts.api (empty: the api's /v1 and /webhooks on the web's host) |
| A default storage class | The in-cluster PostgreSQL's volume (dev and staging) | postgresql.persistence.* |
| metrics-server | The autoscalers, where they are on | <host>.autoscaling |
| The OTLP endpoint reachable from the pods | Traces, metrics and logs | config.Telemetry__OtlpEndpoint, the Secret's Telemetry__OtlpHeaders |
A GitLab deploy token with read_registry | Pulling the kit's images | the pull secret in global.imagePullSecrets (gitlab-registry unless COLDEN_PULL_SECRET_NAME names another) |
| An external PostgreSQL and Redis (prod) | The kit's and the identity server's data, the cache | the Secret's ConnectionStrings__Postgres, KRATOS_DSN, ConnectionStrings__Redis |
For an external PostgreSQL, create the two databases first, each owned by its own login role, as infra/compose/postgres/init.sh does: colden for the kit and kratos for the identity server.
2. Prepare the namespace
Export the Secret's keys (infra/helm/colden/README.md lists them) and the registry credential in your shell, from your password manager, never from a file in the repository; then:
export COLDEN_REGISTRY_USER=<deploy token user> COLDEN_REGISTRY_PASSWORD=<deploy token>
export COLDEN_IN_CLUSTER_POSTGRESQL=true # dev and staging, which run the chart's PostgreSQL
tools/bootstrap-namespace.sh colden-dev --dry-run # checks the variables and lists the keys; needs no cluster
tools/bootstrap-namespace.sh colden-dev # Windows: tools/bootstrap-namespace.ps1 colden-dev
The script applies the namespace, the pull secret gitlab-registry and the Secret colden-secrets with server-side apply. It stops before touching the cluster when a required key is missing or has the wrong length, and it never prints a value. Where the cluster's operator creates namespaces, COLDEN_CREATE_NAMESPACE=false makes the script check that the namespace exists instead. COLDEN_PULL_SECRET_NAME gives the pull secret another name, the one the environment's global.imagePullSecrets uses.
3. Install the release
helm upgrade --install colden infra/helm/colden -n colden-dev -f infra/helm/colden/values-dev.yaml \
--set global.image.tag=sha-<commit> --wait --timeout 10m --atomic
Before the first install, set the environment's real hosts in its values file; an environment of your own keeps its values in infra/helm/environments/<owner>/<environment>.yaml, which tools/helm-check.sh validates. On a first install the in-cluster PostgreSQL starts first, then both migrations run (kubectl -n colden-dev logs job/colden-migrate and job/colden-kratos-migrate), then the api, the worker, the web, the identity server and its courier start. --atomic removes a failed first install and rolls back a failed upgrade.
4. Check the deployment
kubectl -n colden-dev get deploy,job,ingress # every Deployment ready, both Jobs complete
curl -fsS https://<api host>/health/ready # the api and its dependencies (with an api host of its own)
curl -fsS https://<web host>/.ory/health/ready # the identity server, through the web
curl -fsS https://<web host>/api/health # the web
Then sign up on the web host: the verification code arrives by email through the kit's sender, and the first organization opens its dashboard. A span from the api in the telemetry backend confirms the OTLP export.
Changing a secret
Update the variable, rerun tools/bootstrap-namespace.sh <namespace> (the pipeline does it on every deployment), then restart the pods, since nothing reloads at runtime:
kubectl -n colden-dev rollout restart deploy -l app.kubernetes.io/instance=colden
Removing an environment
helm -n colden-dev uninstall colden removes the release and keeps the migration Jobs' last runs, the in-cluster PostgreSQL and its volume. Delete the namespace to remove everything, including the data.