Files
twenty/packages/twenty-docker/helm/twenty/values.yaml
T
Miguel 921c528cc3 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

<!-- This is an auto-generated description by cubic. -->
<a
href="https://cubic.dev/pr/twentyhq/twenty/pull/22233?utm_source=github"
target="_blank" rel="noopener noreferrer"
data-no-image-dialog="true"><picture><source
media="(prefers-color-scheme: dark)"
srcset="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"><source
media="(prefers-color-scheme: light)"
srcset="https://www.cubic.dev/buttons/review-in-cubic-light.svg"><img
alt="Review in cubic"
src="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"></picture></a>
<!-- End of auto-generated description by cubic. -->

---------

Co-authored-by: Charles Bochet <charles@twenty.com>
2026-06-29 13:00:42 +02:00

204 lines
3.6 KiB
YAML

# Default image used by all components
image:
repository: twentycrm/twenty
tag: "" # defaults to Chart.yaml appVersion
pullPolicy: IfNotPresent
nameOverride: ""
fullnameOverride: ""
# Global security context (uid/gid for all pods)
securityContext:
runAsUser: 1000
fsGroup: 1000
# Storage backend: local or s3
storage:
type: local
s3:
bucket: ""
region: ""
endpoint: ""
# Option A: direct values
accessKeyId: ""
secretAccessKey: ""
# Option B: reference a Secret
# secretName: my-s3-creds
# accessKeyIdKey: accessKeyId
# secretAccessKeyKey: secretAccessKey
# Auth tokens (random if not provided)
secrets:
tokens:
create: true
name: tokens
accessToken: ""
# Server deployment
server:
enabled: true
replicaCount: 1
image: {} # override repository/tag/pullPolicy per component
resources:
requests:
cpu: 250m
memory: 256Mi
limits:
cpu: 1000m
memory: 1024Mi
env:
SIGN_IN_PREFILLED: "false"
ACCESS_TOKEN_EXPIRES_IN: "7d"
LOGIN_TOKEN_EXPIRES_IN: "1h"
extraEnv: []
# - name: EMAIL_DRIVER
# value: smtp
# - name: SMTP_PASSWORD
# valueFrom:
# secretKeyRef:
# name: smtp-creds
# key: password
service:
type: ClusterIP
port: 3000
ingress:
enabled: true
className: nginx
acme: true # add cert-manager annotation for Let's Encrypt
annotations: {}
hosts:
- host: crm.example.com
paths:
- path: /
pathType: Prefix
tls:
- secretName: twenty-tls
hosts:
- crm.example.com
persistence:
enabled: true
size: 10Gi
storageClass: ""
existingClaim: ""
accessModes:
- ReadWriteOnce
dockerDataPersistence:
enabled: true
size: 100Mi
storageClass: ""
existingClaim: ""
accessModes:
- ReadWriteOnce
extraVolumeMounts: []
# Pod scheduling and DNS
nodeSelector: {}
tolerations: []
affinity: {}
dnsPolicy: ~
dnsConfig: {}
# Worker deployment
worker:
enabled: true
replicaCount: 1
image: {}
command: ["yarn", "worker:prod"]
resources:
requests:
cpu: 250m
memory: 1024Mi
limits:
cpu: 1000m
memory: 2048Mi
extraEnv: []
# Pod scheduling and DNS
nodeSelector: {}
tolerations: []
affinity: {}
dnsPolicy: ~
dnsConfig: {}
# PostgreSQL
db:
enabled: true
internal:
database: twenty
appUser: twenty_app_user
appPassword: "" # random if empty
image:
repository: twentycrm/twenty-postgres-spilo
tag: 3.3-p2
resources:
requests:
cpu: 250m
memory: 256Mi
limits:
cpu: 1000m
memory: 1024Mi
persistence:
enabled: true
size: 10Gi
storageClass: ""
existingClaim: ""
accessModes:
- ReadWriteOnce
env:
PGUSER_SUPERUSER: postgres
PGPASSWORD_SUPERUSER: postgres
SPILO_PROVIDER: local
ALLOW_NOSSL: "true"
external:
host: ""
port: 5432
user: twenty_app_user
password: ""
database: twenty
ssl: false
secretName: ""
passwordKey: ""
# Redis
redisInternal:
enabled: true
image:
repository: redis/redis-stack-server
tag: 7.2.0-v10
pullPolicy: IfNotPresent
resources:
requests:
cpu: 250m
memory: 1024Mi
limits:
cpu: 500m
memory: 2048Mi
service:
port: 6379
persistence:
enabled: false
size: 1Gi
storageClass: ""
existingClaim: ""
accessModes:
- ReadWriteOnce
# External Redis (when redisInternal.enabled=false)
redis:
external:
host: ""
port: 6379
password: ""
secretName: ""
passwordKey: ""