diff --git a/apps/docs/content/self-hosting/deploy/kubernetes/index.mdx b/apps/docs/content/self-hosting/deploy/kubernetes/index.mdx index 3dd9f1df3..95cb14e9b 100644 --- a/apps/docs/content/self-hosting/deploy/kubernetes/index.mdx +++ b/apps/docs/content/self-hosting/deploy/kubernetes/index.mdx @@ -8,12 +8,12 @@ This guide takes you from zero to a running ZITADEL instance on Kubernetes and t ## Stage 1 — Quickstart -The ZITADEL chart ships with an optional PostgreSQL subchart so a single `helm install` deploys the database alongside ZITADEL. You still need an ingress controller running in your cluster. +The ZITADEL chart ships with an optional PostgreSQL subchart so a single `helm install` deploys the database alongside ZITADEL. You still need a routing controller running in your cluster to expose the service. ### Prerequisites - A Kubernetes cluster (1.30+) -- An ingress controller (e.g. Traefik, NGINX) +- An Ingress controller (e.g., Traefik, NGINX) **OR** a Gateway API controller - [kubectl](https://kubernetes.io/docs/tasks/tools/) - [Helm](https://helm.sh/docs/intro/install/) 3.x or 4.x @@ -31,7 +31,7 @@ mkdir zitadel-helm && cd zitadel-helm && curl -fsSLO https://raw.githubusercontent.com/zitadel/zitadel-charts/main/examples/0-quickstart/quickstart-values.yaml ``` -Edit `quickstart-values.yaml` before installing. For a local k3d or k3s cluster, these values usually work as-is: +Edit `quickstart-values.yaml` before installing. For a local k3d or k3s cluster, these standard Ingress values usually work as-is: ```yaml zitadel: @@ -47,7 +47,7 @@ login: className: traefik ``` -If you are using a different ingress controller, replace both `className` values with that controller's IngressClass name. +If you are using a different ingress controller, replace both `className` values with that controller's IngressClass name. ```bash helm repo add zitadel https://charts.zitadel.com && @@ -66,8 +66,8 @@ Once ZITADEL has been initialized with a masterkey, it **cannot be changed** wit -The stack runs: your ingress controller → **ZITADEL API** (Go) + **ZITADEL Login** (Next.js) → **PostgreSQL** (bundled). -See [HTTP/2](/self-hosting/manage/http2) for requirements on how the ingress controller must forward traffic to ZITADEL pods. +The stack runs: your ingress/gateway controller → **ZITADEL API** (Go) + **ZITADEL Login** (Next.js) → **PostgreSQL** (bundled). +See [HTTP/2](/self-hosting/manage/http2) for requirements on how traffic must be forwarded to ZITADEL pods via h2c. ### Swap out components @@ -76,16 +76,16 @@ The bundled PostgreSQL subchart is for quickstart use only. You can replace it i | Component | How to replace | |-----------|---------------| -| **Database** | Set `postgresql.enabled: false` and configure `ZITADEL_DATABASE_POSTGRES_DSN` pointing to your own PostgreSQL. Use the `postgres` maintenance database so ZITADEL can create its own database during initialization | -| **Ingress controller** | Update `ingress.className` (and `login.ingress.className`) to match your controller's IngressClass | -| **Caching** | Add Redis by configuring `zitadel.configmapConfig.Caches` (see [Caching](/self-hosting/deploy/kubernetes/caching)) | +| **Database** | Set `postgresql.enabled: false` and configure `ZITADEL_DATABASE_POSTGRES_DSN` pointing to your own PostgreSQL. Use the `postgres` maintenance database so ZITADEL can create its own database during initialization. | +| **Routing / Ingress** | Update `ingress.className` to match your controller, or disable the Helm ingress (`ingress.enabled: false`) to manage your own Gateway API `HTTPRoute` resources. | +| **Caching** | Add Redis by configuring `zitadel.configmapConfig.Caches` (see [Caching](/self-hosting/deploy/kubernetes/caching)). | ## Stage 2 — Production Cluster For production you need: - A Kubernetes cluster (1.30+) -- An ingress controller (Traefik, NGINX, or cloud-native) +- A routing solution: Ingress controller (Traefik, NGINX) or a Gateway API implementation - A domain with DNS configured - TLS certificates (via cert-manager, ACME, or manually) - PostgreSQL 14+ (managed service or in-cluster) @@ -96,7 +96,7 @@ For production you need: -The ZITADEL management console [requires end-to-end HTTP/2 support](/self-hosting/manage/http2). Ensure your ingress controller is configured to forward HTTP/2 (h2c) traffic to ZITADEL pods. +The ZITADEL management console [requires end-to-end HTTP/2 support](/self-hosting/manage/http2). Ensure your routing controller is configured to forward HTTP/2 (h2c) traffic to ZITADEL pods. ### Create secrets @@ -113,7 +113,7 @@ kubectl create secret generic zitadel-db-credentials \ ### Configure values -Save the following as `values.yaml`. Replace `zitadel.example.com` with your domain: +Save the base configuration below as `values.yaml`. Replace `zitadel.example.com` with your domain: ```yaml replicaCount: 2 @@ -140,6 +140,20 @@ zitadel: Password: "YourSecurePassword123!" PasswordChangeRequired: true +podDisruptionBudget: + enabled: true + minAvailable: 1 +``` + +### Exposing ZITADEL (Choose your routing method) + +ZITADEL can be exposed using standard Kubernetes **Ingress** or the newer **Gateway API**. Choose the method that matches your cluster's architecture. + +#### Option A: Using Standard Ingress (e.g., Traefik) + +Append the following routing block to your `values.yaml` to have Helm automatically generate standard `Ingress` objects: + +```yaml ingress: enabled: true className: traefik @@ -174,12 +188,44 @@ login: - secretName: zitadel-tls hosts: - zitadel.example.com - -podDisruptionBudget: - enabled: true - minAvailable: 1 ``` +#### Option B: Using Gateway API + +If your cluster utilizes the Kubernetes Gateway API, disable the Helm chart's built-in ingress generation by ensuring both `ingress.enabled: false` and `login.ingress.enabled: false` are set (which is the default). + +After deploying the Helm chart, apply an `HTTPRoute` resource to route traffic to the ZITADEL services via your `Gateway`: + +```yaml +apiVersion: gateway.networking.k8s.io/v1 +kind: HTTPRoute +metadata: + name: zitadel-route + namespace: zitadel +spec: + parentRefs: + - name: your-cluster-gateway + namespace: gateway-system + hostnames: + - "zitadel.example.com" + rules: + - matches: + - path: + type: PathPrefix + value: /ui/v2/login + backendRefs: + - name: zitadel-login + port: 8080 + - matches: + - path: + type: PathPrefix + value: / + backendRefs: + - name: zitadel + port: 8080 +``` +*(Note: Ensure your Gateway controller supports h2c/HTTP2 backend connections).* + ### Install ```bash @@ -213,9 +259,9 @@ Review the [Production Checklist](/self-hosting/manage/productionchecklist) befo | Guide | Description | |-------|-------------| | [Configuration](/self-hosting/deploy/kubernetes/configuration) | All configmap and secret options, autoscaling, security contexts | -| [Ingress](/self-hosting/deploy/kubernetes/ingress) | Traefik, NGINX, and cloud-native ingress setup | +| [Routing](/self-hosting/deploy/kubernetes/ingress) | Ingress, Gateway API, and cloud-native setup | | [Database](/self-hosting/deploy/kubernetes/database) | PostgreSQL TLS modes, credentials, and connection pooling | | [Operations](/self-hosting/deploy/kubernetes/operations) | Upgrades, manual and automatic scaling, resource limits | | [Caching](/self-hosting/deploy/kubernetes/caching) | Redis/Valkey caching configuration | | [Observability](/self-hosting/deploy/kubernetes/observability) | Traces (OTLP), Prometheus metrics, and log collection | -| [Uninstalling](/self-hosting/deploy/kubernetes/uninstalling) | Remove ZITADEL from your cluster | +| [Uninstalling](/self-hosting/deploy/kubernetes/uninstalling) | Remove ZITADEL from your cluster | \ No newline at end of file