From 921c528cc3b86aa08ef19a8bc2dd04a6df5fc385 Mon Sep 17 00:00:00 2001 From: Miguel Date: Mon, 29 Jun 2026 13:00:42 +0200 Subject: [PATCH] feat(helm): add nodeSelector, tolerations and DNS overrides to server and worker (#22233) Closes #22250 ## What Adds four standard pod spec fields to both server and worker Deployments of the Helm chart, exposed under `server.*` and `worker.*` in `values.yaml`: - `nodeSelector` - `tolerations` - `dnsPolicy` - `dnsConfig` ## Why Self-hosters who run Twenty on clusters with dedicated nodes, taints, or custom DNS requirements currently need to fork the chart or patch rendered manifests with Kustomize. These are the standard pod spec fields supported by virtually every other community chart (Bitnami, prometheus-community, cert-manager, etc.) and are commonly needed in production setups. ## How Uses the same `{{- with }}` pattern already present in the chart (e.g. `extraEnv`, `extraVolumeMounts`), so empty defaults skip rendering entirely: ```yaml {{- with .Values.server.nodeSelector }} nodeSelector: {{- toYaml . | nindent 8 }} {{- end }} ``` ## Backward compatibility Fully backward compatible. Defaults are empty: ```yaml server: nodeSelector: {} tolerations: [] dnsPolicy: ~ dnsConfig: {} ``` `helm template` output is bit-identical to the previous version for any existing install. ## Schema note `dnsPolicy` is typed as `[string, null]` and the enum includes `null` so the empty default (`dnsPolicy: ~`) passes validation. The `{{- with }}` guard treats null as falsy and renders nothing. ## Validation - `helm lint` passes - `helm template` with default values produces bit-identical output to before this PR - `helm template` with values set renders the four fields correctly on both server and worker - Live install validated on a multi-node Kubernetes cluster, pinning Twenty to a dedicated tainted node with custom DNS (`ndots: 1`); server and worker scheduled and started successfully Review in cubic --------- Co-authored-by: Charles Bochet --- .../twenty/templates/deployment-server.yaml | 19 ++++++++++++++++++ .../twenty/templates/deployment-worker.yaml | 19 ++++++++++++++++++ .../helm/twenty/values.schema.json | 20 +++++++++++++++++-- .../twenty-docker/helm/twenty/values.yaml | 14 +++++++++++++ 4 files changed, 70 insertions(+), 2 deletions(-) diff --git a/packages/twenty-docker/helm/twenty/templates/deployment-server.yaml b/packages/twenty-docker/helm/twenty/templates/deployment-server.yaml index e262422099..5f9cde4344 100644 --- a/packages/twenty-docker/helm/twenty/templates/deployment-server.yaml +++ b/packages/twenty-docker/helm/twenty/templates/deployment-server.yaml @@ -32,6 +32,25 @@ spec: spec: securityContext: {{- toYaml .Values.securityContext | nindent 8 }} + {{- with .Values.server.nodeSelector }} + nodeSelector: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.server.tolerations }} + tolerations: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.server.affinity }} + affinity: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.server.dnsPolicy }} + dnsPolicy: {{ . }} + {{- end }} + {{- with .Values.server.dnsConfig }} + dnsConfig: + {{- toYaml . | nindent 8 }} + {{- end }} volumes: {{- if .Values.server.dockerDataPersistence.enabled }} - name: docker-data diff --git a/packages/twenty-docker/helm/twenty/templates/deployment-worker.yaml b/packages/twenty-docker/helm/twenty/templates/deployment-worker.yaml index 50fe02e7c9..287ff085bb 100644 --- a/packages/twenty-docker/helm/twenty/templates/deployment-worker.yaml +++ b/packages/twenty-docker/helm/twenty/templates/deployment-worker.yaml @@ -28,6 +28,25 @@ spec: spec: securityContext: {{- toYaml .Values.securityContext | nindent 8 }} + {{- with .Values.worker.nodeSelector }} + nodeSelector: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.worker.tolerations }} + tolerations: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.worker.affinity }} + affinity: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.worker.dnsPolicy }} + dnsPolicy: {{ . }} + {{- end }} + {{- with .Values.worker.dnsConfig }} + dnsConfig: + {{- toYaml . | nindent 8 }} + {{- end }} initContainers: - name: wait-for-db image: postgres:16-alpine diff --git a/packages/twenty-docker/helm/twenty/values.schema.json b/packages/twenty-docker/helm/twenty/values.schema.json index 48db9817d1..9bfe0eebdd 100644 --- a/packages/twenty-docker/helm/twenty/values.schema.json +++ b/packages/twenty-docker/helm/twenty/values.schema.json @@ -138,7 +138,15 @@ "accessModes": { "type": "array", "items": { "type": "string" } }, "size": { "type": "string" } } - } + }, + "nodeSelector": { "type": "object" }, + "tolerations": { + "type": "array", + "items": { "type": "object" } + }, + "affinity": { "type": "object" }, + "dnsPolicy": { "type": ["string", "null"], "enum": ["ClusterFirst", "ClusterFirstWithHostNet", "Default", "None", null] }, + "dnsConfig": { "type": "object" } } }, @@ -173,7 +181,15 @@ { "required": ["valueFrom"] } ] } - } + }, + "nodeSelector": { "type": "object" }, + "tolerations": { + "type": "array", + "items": { "type": "object" } + }, + "affinity": { "type": "object" }, + "dnsPolicy": { "type": ["string", "null"], "enum": ["ClusterFirst", "ClusterFirstWithHostNet", "Default", "None", null] }, + "dnsConfig": { "type": "object" } } }, diff --git a/packages/twenty-docker/helm/twenty/values.yaml b/packages/twenty-docker/helm/twenty/values.yaml index 088c9e5a9c..633426ac46 100644 --- a/packages/twenty-docker/helm/twenty/values.yaml +++ b/packages/twenty-docker/helm/twenty/values.yaml @@ -98,6 +98,13 @@ server: extraVolumeMounts: [] + # Pod scheduling and DNS + nodeSelector: {} + tolerations: [] + affinity: {} + dnsPolicy: ~ + dnsConfig: {} + # Worker deployment worker: enabled: true @@ -115,6 +122,13 @@ worker: extraEnv: [] + # Pod scheduling and DNS + nodeSelector: {} + tolerations: [] + affinity: {} + dnsPolicy: ~ + dnsConfig: {} + # PostgreSQL db: enabled: true