The chart default killed zitadel-setup at ~5.5 minutes while it was still replaying projections.projects4, which failed the whole PreSync and left the Application OutOfSync/Missing. 1200s leaves room for a cold database without masking a genuine hang.
143 lines
5.8 KiB
YAML
143 lines
5.8 KiB
YAML
# k8s/infra/iam/zitadel-values.yaml
|
|
# ZITADEL — Authentik replacement. Coexistence is deliberate: Authentik keeps
|
|
# running, read-only, in the same `iam` namespace until the last consumer moves.
|
|
# Migration plan: ~/workplace/homelab-doc/ZITADEL_MIGRATION.html (outside git).
|
|
#
|
|
# Chart: zitadel/zitadel 10.4.0, app v4.19.2. The plan cites v4.19.4; the chart
|
|
# has not published it yet. Pin the chart, never `*`, until the v4.19.4 chart
|
|
# exists — a silent app bump invalidates the verified masterkey/passwap facts.
|
|
#
|
|
# URL: https://zitadel.riotpiao.com. TLS terminates at ingress-nginx, which
|
|
# serves the wildcard riotpiao-com-tls as its default-ssl-certificate, so
|
|
# ExternalSecure=true and TLS.Enabled=false (no per-rule tls: block needed).
|
|
#
|
|
# Database: CNPG cluster zitadel-db (wave 2). The DSN comes from CNPG's
|
|
# generated `zitadel-db-app` secret. When ZITADEL_DATABASE_POSTGRES_DSN is set,
|
|
# ZITADEL ignores the discrete Database.Postgres.* fields, so neither a
|
|
# password nor a host is written into this file.
|
|
#
|
|
# Masterkey: Secret `zitadel-masterkey` (k8s/argocd/secrets/
|
|
# zitadel-masterkey.enc.yaml), key `masterkey`, exactly 32 bytes. It wraps the
|
|
# rows in system.encryption_keys, which encrypt every client secret and private
|
|
# key. Losing it makes those values unreadable: keep the offline sealed copy.
|
|
#
|
|
# Ingress uses the chart's own objects (controller: nginx adds the gRPC backend
|
|
# annotation ZITADEL needs for its HTTP/2 API). Do not hand-write a second
|
|
# Ingress for this host.
|
|
|
|
zitadel:
|
|
configmapConfig:
|
|
ExternalSecure: true
|
|
ExternalDomain: zitadel.riotpiao.com
|
|
TLS:
|
|
Enabled: false
|
|
|
|
# Rendered into a Secret by the chart; read by pods and init jobs alike.
|
|
masterkeySecretName: zitadel-masterkey
|
|
|
|
resources:
|
|
requests: { memory: "512Mi", cpu: "250m" }
|
|
limits: { memory: "2Gi", cpu: "1" }
|
|
|
|
# FirstInstance defaults stay for the FIRST sync: the chart creates org
|
|
# `zitadel` plus the `iam-admin` machine user and its machine-key Secret.
|
|
# Terraform consumes that key to declare projects, roles, OIDC apps and the
|
|
# groups action.
|
|
#
|
|
# SECOND-SYNC HAZARD — read before enabling automated sync.
|
|
# The chart marks eight objects as `pre-install,pre-upgrade` hooks (two
|
|
# ServiceAccounts, two ConfigMaps, Role, RoleBinding, zitadel-init,
|
|
# zitadel-setup), and one cleanup Job as `post-delete`. ArgoCD maps the first
|
|
# eight to PreSync with `before-hook-creation`: it deletes and re-creates them
|
|
# on EVERY sync, not only on a chart change.
|
|
# - zitadel-init (`init zitadel`) — schema step
|
|
# - zitadel-setup (`setup`) — first instance + iam-admin machine key
|
|
# On an initialized instance the setup step can fail, which aborts the sync
|
|
# before the Deployment is applied. If it succeeds instead, its
|
|
# machinekeyWriter container re-applies the iam-admin key Secret that
|
|
# Terraform reads, which silently rotates a credential in use.
|
|
# After the first sync reports healthy:
|
|
# 1. set configmapConfig.FirstInstance.Skip: true here — permanently: the
|
|
# setup steps are schema-only once the instance exists, and Skip alone
|
|
# stops the machinekeyWriter rotation
|
|
# 2. set initJob.enabled: false below
|
|
# 3. commit, sync once, then enable automated+selfHeal on the Application
|
|
# For a later schema upgrade, re-enable initJob.enabled only — never set
|
|
# FirstInstance.Skip back to false.
|
|
# ArgoCD never prunes a hook Job, so a Job that failed before step 2 stays and
|
|
# keeps ZitadelSetupJobFailed firing until a human deletes it.
|
|
|
|
# DSN mode (chart renders this through the zitadel.dbEnv helper). CNPG's `uri`
|
|
# key is a postgresql:// URL, which ZITADEL accepts as a DSN.
|
|
env:
|
|
- name: ZITADEL_DATABASE_POSTGRES_DSN
|
|
valueFrom:
|
|
secretKeyRef:
|
|
name: zitadel-db-app
|
|
key: uri
|
|
|
|
# Bundled Bitnami Postgres is disabled: the CNPG cluster above is the system of
|
|
# record. Enabling it would create a second, unmanaged database.
|
|
postgresql:
|
|
enabled: false
|
|
|
|
# CNPG already created the database, the `app` user and its grants, so the init
|
|
# job runs only the ZITADEL-internal step. Running the full default command
|
|
# would try to create a database and a superuser it does not own.
|
|
initJob:
|
|
command: "zitadel"
|
|
activeDeadlineSeconds: 600
|
|
|
|
# The setup job runs the full first-instance creation: schema migrations, the
|
|
# system org, the iam-admin machine key, and 13 projection replays. The chart
|
|
# default killed it at ~5.5 minutes on 2026-10-25 while it was still replaying
|
|
# projections.projects4, which failed the whole sync. 20 minutes leaves room for
|
|
# a cold database without masking a genuine hang.
|
|
setupJob:
|
|
activeDeadlineSeconds: 1200
|
|
|
|
# Two API replicas: the read path survives one node drain, and both share the
|
|
# same masterkey and database. The login UI stays at one replica — a session
|
|
# cookie is not shared, so a second pod buys nothing.
|
|
replicaCount: 2
|
|
revisionHistoryLimit: 3
|
|
|
|
ingress:
|
|
enabled: true
|
|
className: nginx
|
|
controller: nginx
|
|
|
|
login:
|
|
enabled: true
|
|
replicaCount: 1
|
|
ingress:
|
|
enabled: true
|
|
className: nginx
|
|
|
|
# Chart-owned ServiceMonitor. The cluster's Prometheus runs with
|
|
# serviceMonitorSelectorNilUsesHelmValues=false, so the release label is not
|
|
# required for discovery. Endpoint is /debug/metrics on port http2-server.
|
|
metrics:
|
|
enabled: true
|
|
serviceMonitor:
|
|
enabled: true
|
|
scrapeInterval: 30s
|
|
scrapeTimeout: 10s
|
|
|
|
# The 3-CP / 2-worker cluster mixes control-plane taints with worker capacity.
|
|
# Without the toleration a rolling upgrade can leave both replicas Pending.
|
|
tolerations:
|
|
- key: node-role.kubernetes.io/control-plane
|
|
operator: Exists
|
|
effect: NoSchedule
|
|
|
|
affinity:
|
|
podAntiAffinity:
|
|
preferredDuringSchedulingIgnoredDuringExecution:
|
|
- weight: 100
|
|
podAffinityTerm:
|
|
topologyKey: kubernetes.io/hostname
|
|
labelSelector:
|
|
matchLabels:
|
|
app.kubernetes.io/name: zitadel
|