--- title: Operations description: "Manage and scale ZITADEL on Kubernetes, covering upgrades, manual and automated scaling, and database considerations" sidebar_label: Operations --- This guide covers day-2 operations for Zitadel on Kubernetes. ## Upgrades ### General Upgrade Process 1. Review the release notes for your target version 2. Back up your database 3. Update your `values.yaml` with any required changes 4. Upgrade the Helm release: ```bash helm repo update helm upgrade my-zitadel zitadel/zitadel --values values.yaml --version ``` 5. Monitor the upgrade. Watch the pods: ```bash kubectl get pods --watch ``` Check the Helm release status: ```bash helm status my-zitadel ``` ### Upgrading to ZITADEL v4 If you are moving from ZITADEL v3 to v4 (for example via a chart version that ships ZITADEL v4), follow [Upgrade from ZITADEL v3 to v4](/self-hosting/manage/upgrade-v3-to-v4) and technical advisory [A-10017](/support/advisory/a10017) for the recommended OIDC web key staging path. Newer charts may deploy a Login V2 workload by default. That does **not** enable Login V2 for existing instances. If you are not adopting Login V2 yet, set `login.enabled: false`. When you are ready to cut over, see [Adopt Login V2 on an existing installation](/self-hosting/manage/adopt-login-v2). For chart-specific breaking changes (for example chart v8 → v9 or v9 → v10), always check the [Helm chart README](https://github.com/zitadel/zitadel-charts/blob/main/charts/zitadel/README.md) upgrade notes as well. ## Scaling ### Manual Scaling Adjust the replica count in your values: ```yaml replicaCount: 3 ``` Or scale directly: ```bash kubectl scale deployment my-zitadel --replicas=3 ``` ### Horizontal Pod Autoscaler Enable HPA for automatic scaling based on resource utilization: ```yaml zitadel: autoscaling: enabled: true minReplicas: 2 maxReplicas: 10 targetCPUUtilizationPercentage: 80 targetMemoryUtilizationPercentage: 80 ``` This creates an HPA that: - Maintains at least 2 replicas - Scales up to 10 replicas - Targets 80% CPU and memory utilization View HPA status: ```bash kubectl get hpa ``` Get detailed HPA information: ```bash kubectl describe hpa my-zitadel ``` ### Resource Requests and Limits Configure appropriate resource allocations: ```yaml resources: requests: cpu: 100m memory: 256Mi limits: cpu: 1000m memory: 1Gi ``` **Recommendations by deployment size:** | Size | CPU Request | CPU Limit | Memory Request | Memory Limit | |------|-------------|-----------|----------------|--------------| | Small (dev) | 100m | 500m | 256Mi | 512Mi | | Medium | 250m | 1000m | 512Mi | 1Gi | | Large | 500m | 2000m | 1Gi | 2Gi | ### Pod Disruption Budget Ensure availability during voluntary disruptions by using `minAvailable`: ```yaml podDisruptionBudget: enabled: true minAvailable: 1 ``` Alternatively, use `maxUnavailable`: ```yaml podDisruptionBudget: enabled: true maxUnavailable: 1 ``` This ensures at least one pod remains available during node drains, upgrades, or other voluntary disruptions. ### Database Scaling Considerations When scaling Zitadel horizontally, ensure your PostgreSQL database can handle the increased connection load: - Each Zitadel pod opens multiple connections - Consider using PgBouncer for connection pooling - Monitor database connection usage Example connection pooling setup with PgBouncer: ```bash kubectl create secret generic zitadel-db-credentials \ --from-literal=dsn="postgresql://zitadel:password@pgbouncer.database.svc.cluster.local:6432/zitadel?sslmode=disable" ``` ```yaml zitadel: env: - name: ZITADEL_DATABASE_POSTGRES_DSN valueFrom: secretKeyRef: name: zitadel-db-credentials key: dsn configmapConfig: Database: Postgres: MaxOpenConns: 20 MaxIdleConns: 10 ``` ## Next Steps - [Configuration](./configuration) — Review all configuration options - [Uninstalling](./uninstalling) — Remove Zitadel from your cluster