9d613dc19d
This pull request enhances the Helm chart for the Twenty application by improving how environment variables and Redis credentials are handled for both server and worker deployments. The main changes include support for injecting additional environment variables, improved Redis password management (including external secrets), and a more robust database migration workflow. **Environment Variable Injection:** - Added support for specifying additional environment variables for both the server and worker deployments via the `additionalEnv` field in `values.yaml`. These variables are automatically injected into the respective pods. [[1]](diffhunk://#diff-b5d958eae48fd1919e5623bcf0144aac7abb323ae8743e6f31367e383c63c296R55) [[2]](diffhunk://#diff-b5d958eae48fd1919e5623bcf0144aac7abb323ae8743e6f31367e383c63c296R109-R110) [[3]](diffhunk://#diff-20bb91909627a12b50b3c165a2a027b663479c0104ed8dbf91d2b9ad8ea8a931R74-R77) [[4]](diffhunk://#diff-20bb91909627a12b50b3c165a2a027b663479c0104ed8dbf91d2b9ad8ea8a931R157-R172) [[5]](diffhunk://#diff-20bb91909627a12b50b3c165a2a027b663479c0104ed8dbf91d2b9ad8ea8a931R225-R229) [[6]](diffhunk://#diff-fb612a3b7a13156aaa607b27d23025e2c6831f111b6a582fd313fad26d2fdb5bR89-R92) **Redis Credential Management:** - Introduced support for using external secrets for Redis passwords by adding `secretName` and `passwordKey` fields under `redis.external` in `values.yaml`, and logic to inject `REDIS_PASSWORD` from a Kubernetes secret if configured. [[1]](diffhunk://#diff-b5d958eae48fd1919e5623bcf0144aac7abb323ae8743e6f31367e383c63c296R180-R182) [[2]](diffhunk://#diff-5c4fa358b10abd7581188995feb9b4d6be0bc4f06a95bf27bb31b5595d6693d8R92-R100) [[3]](diffhunk://#diff-20bb91909627a12b50b3c165a2a027b663479c0104ed8dbf91d2b9ad8ea8a931R157-R172) [[4]](diffhunk://#diff-20bb91909627a12b50b3c165a2a027b663479c0104ed8dbf91d2b9ad8ea8a931R196-R205) [[5]](diffhunk://#diff-fb612a3b7a13156aaa607b27d23025e2c6831f111b6a582fd313fad26d2fdb5bR70-R79) - Updated the logic for constructing the `REDIS_URL` to include authentication information if a password is set or an external secret is used. **Database Migration Workflow:** - Improved the startup command for the server deployment to optionally skip database migrations (using `DISABLE_DB_MIGRATIONS`), check for an existing schema before running migrations, and ensure setup scripts are only run on empty databases. These changes make the chart more flexible and secure, especially for production deployments requiring externalized secrets and custom environment configurations. --------- Co-authored-by: Charles Bochet <charles@twenty.com>
214 lines
7.4 KiB
Smarty
214 lines
7.4 KiB
Smarty
{{- define "twenty.name" -}}
|
|
{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" -}}
|
|
{{- end -}}
|
|
|
|
{{- define "twenty.fullname" -}}
|
|
{{- if .Values.fullnameOverride -}}
|
|
{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" -}}
|
|
{{- else -}}
|
|
{{- $name := default .Chart.Name .Values.nameOverride -}}
|
|
{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" -}}
|
|
{{- end -}}
|
|
{{- end -}}
|
|
|
|
{{- define "twenty.namespace" -}}
|
|
{{ .Release.Namespace }}
|
|
{{- end -}}
|
|
|
|
{{/* Server image fields merged with globals */}}
|
|
{{- define "twenty.server.image" -}}
|
|
{{- $repo := default $.Values.image.repository (index $.Values.server.image "repository" | default "") -}}
|
|
{{- $tag := default (default $.Chart.AppVersion $.Values.image.tag) (index $.Values.server.image "tag" | default "") -}}
|
|
{{- $pp := default $.Values.image.pullPolicy (index $.Values.server.image "pullPolicy" | default "") -}}
|
|
{{- printf "%s:%s|%s" $repo $tag $pp -}}
|
|
{{- end -}}
|
|
|
|
{{/* Worker image fields merged with globals */}}
|
|
{{- define "twenty.worker.image" -}}
|
|
{{- $repo := default $.Values.image.repository (index $.Values.worker.image "repository" | default "") -}}
|
|
{{- $tag := default (default $.Chart.AppVersion $.Values.image.tag) (index $.Values.worker.image "tag" | default "") -}}
|
|
{{- $pp := default $.Values.image.pullPolicy (index $.Values.worker.image "pullPolicy" | default "") -}}
|
|
{{- printf "%s:%s|%s" $repo $tag $pp -}}
|
|
{{- end -}}
|
|
|
|
{{/* Extract parts of image helper */}}
|
|
{{- define "twenty.image.repository" -}}
|
|
{{- regexFind "^([^:|]+)" . -}}
|
|
{{- end -}}
|
|
{{- define "twenty.image.tag" -}}
|
|
{{- regexFind ":([^|]+)" . | trimPrefix ":" -}}
|
|
{{- end -}}
|
|
{{- define "twenty.image.pullPolicy" -}}
|
|
{{- regexFind "\\|(.+)$" . | trimPrefix "|" -}}
|
|
{{- end -}}
|
|
|
|
{{/* Check if using external secret for database password */}}
|
|
{{- define "twenty.db.useExternalSecret" -}}
|
|
{{- if and (not .Values.db.enabled) .Values.db.external.secretName .Values.db.external.passwordKey -}}
|
|
true
|
|
{{- else -}}
|
|
false
|
|
{{- end -}}
|
|
{{- end -}}
|
|
|
|
{{/* Database URL secret name */}}
|
|
{{- define "twenty.dbUrl.secretName" -}}
|
|
{{- printf "%s-db-url" (include "twenty.fullname" .) -}}
|
|
{{- end -}}
|
|
|
|
{{/* Database password secret name */}}
|
|
{{- define "twenty.dbPassword.secretName" -}}
|
|
{{- if eq (include "twenty.db.useExternalSecret" .) "true" -}}
|
|
{{- .Values.db.external.secretName -}}
|
|
{{- else -}}
|
|
{{- include "twenty.dbUrl.secretName" . -}}
|
|
{{- end -}}
|
|
{{- end -}}
|
|
|
|
{{/* Database password secret key */}}
|
|
{{- define "twenty.dbPassword.secretKey" -}}
|
|
{{- if eq (include "twenty.db.useExternalSecret" .) "true" -}}
|
|
{{- .Values.db.external.passwordKey -}}
|
|
{{- else if .Values.db.enabled -}}
|
|
appPassword
|
|
{{- else -}}
|
|
password
|
|
{{- end -}}
|
|
{{- end -}}
|
|
|
|
{{/* Database URL template for external secret (will be evaluated at runtime) */}}
|
|
{{- define "twenty.dbUrl.template" -}}
|
|
{{- if eq (include "twenty.db.useExternalSecret" .) "true" -}}
|
|
{{- $scheme := "postgres" -}}
|
|
{{- $host := .Values.db.external.host -}}
|
|
{{- $port := .Values.db.external.port | default 5432 -}}
|
|
{{- $user := .Values.db.external.user | default "postgres" -}}
|
|
{{- $db := .Values.db.external.database | default "twenty" -}}
|
|
{{- $qs := ternary "?sslmode=require" "" (eq .Values.db.external.ssl true) -}}
|
|
{{- printf "%s://%s:$(DB_PASSWORD)@%s:%v/%s%s" $scheme $user $host $port $db $qs -}}
|
|
{{- end -}}
|
|
{{- end -}}
|
|
|
|
{{/* Check if using external secret for redis password */}}
|
|
{{- define "twenty.redis.useExternalSecret" -}}
|
|
{{- if and (not .Values.redisInternal.enabled) .Values.redis.external.secretName .Values.redis.external.passwordKey -}}
|
|
true
|
|
{{- else -}}
|
|
false
|
|
{{- end -}}
|
|
{{- end -}}
|
|
|
|
{{/* Compose Redis URL */}}
|
|
{{- define "twenty.redisUrl" -}}
|
|
{{- if .Values.server.env.REDIS_URL -}}
|
|
{{- .Values.server.env.REDIS_URL -}}
|
|
{{- else if .Values.redisInternal.enabled -}}
|
|
{{- $host := printf "%s-redis" (include "twenty.fullname" .) -}}
|
|
{{- printf "redis://%s.%s.svc.cluster.local:6379" $host (include "twenty.namespace" .) -}}
|
|
{{- else -}}
|
|
{{- $host := .Values.redis.external.host | default "redis" -}}
|
|
{{- $port := .Values.redis.external.port | default 6379 -}}
|
|
{{- if or (eq (include "twenty.redis.useExternalSecret" .) "true") (.Values.redis.external.password) -}}
|
|
{{- $auth := ":$(REDIS_PASSWORD)@" -}}
|
|
{{- printf "redis://%s%s:%v" $auth $host $port -}}
|
|
{{- else -}}
|
|
{{- printf "redis://%s:%v" $host $port -}}
|
|
{{- end -}}
|
|
{{- end -}}
|
|
{{- end -}}
|
|
|
|
{{/* Compose Server URL from override, ingress, or service */}}
|
|
{{- define "twenty.serverUrl" -}}
|
|
{{- if .Values.server.env.SERVER_URL -}}
|
|
{{- .Values.server.env.SERVER_URL -}}
|
|
{{- else if and .Values.server.ingress.enabled (gt (len .Values.server.ingress.hosts) 0) -}}
|
|
{{- $host := (index .Values.server.ingress.hosts 0).host -}}
|
|
{{- $tls := gt (len .Values.server.ingress.tls) 0 -}}
|
|
{{- $scheme := ternary "https" "http" $tls -}}
|
|
{{- $port := ternary 443 80 $tls -}}
|
|
{{- printf "%s://%s:%v" $scheme $host $port -}}
|
|
{{- else -}}
|
|
{{- $svc := printf "%s-server" (include "twenty.fullname" .) -}}
|
|
{{- $ns := include "twenty.namespace" . -}}
|
|
{{- $port := .Values.server.service.port | default 3000 -}}
|
|
{{- printf "http://%s.%s.svc.cluster.local:%v" $svc $ns $port -}}
|
|
{{- end -}}
|
|
{{- end -}}
|
|
|
|
{{/* Tokens secret name */}}
|
|
{{- define "twenty.secret.tokens.name" -}}
|
|
{{- .Values.secrets.tokens.name | default "tokens" -}}
|
|
{{- end -}}
|
|
|
|
{{/* Access token value: reuse existing secret if present, else provided value, else generated */}}
|
|
{{- define "twenty.secret.tokens.access" -}}
|
|
{{- $name := include "twenty.secret.tokens.name" . -}}
|
|
{{- $ns := include "twenty.namespace" . -}}
|
|
{{- $existing := lookup "v1" "Secret" $ns $name -}}
|
|
{{- if and $existing $existing.data.accessToken -}}
|
|
{{- b64dec $existing.data.accessToken -}}
|
|
{{- else if .Values.secrets.tokens.accessToken -}}
|
|
{{- .Values.secrets.tokens.accessToken -}}
|
|
{{- else -}}
|
|
{{- randAlphaNum 32 -}}
|
|
{{- end -}}
|
|
{{- end -}}
|
|
|
|
{{/* Server container port */}}
|
|
{{- define "twenty.server.containerPort" -}}
|
|
{{- .Values.server.service.port | default 3000 -}}
|
|
{{- end -}}
|
|
|
|
{{/* Storage type: prefer top-level storage.type, else legacy server.env.STORAGE_TYPE, else local */}}
|
|
{{- define "twenty.storageType" -}}
|
|
{{- if .Values.storage.type -}}
|
|
{{- .Values.storage.type -}}
|
|
{{- else if .Values.server.env.STORAGE_TYPE -}}
|
|
{{- .Values.server.env.STORAGE_TYPE -}}
|
|
{{- else -}}
|
|
local
|
|
{{- end -}}
|
|
{{- end -}}
|
|
|
|
{{/* Additional storage env vars (e.g., S3) */}}
|
|
{{- define "twenty.storageEnv" -}}
|
|
{{- if eq (include "twenty.storageType" .) "s3" -}}
|
|
{{- with .Values.storage.s3.bucket }}
|
|
- name: STORAGE_S3_NAME
|
|
value: {{ . | quote }}
|
|
{{- end }}
|
|
{{- with .Values.storage.s3.region }}
|
|
- name: STORAGE_S3_REGION
|
|
value: {{ . | quote }}
|
|
{{- end }}
|
|
{{- with .Values.storage.s3.endpoint }}
|
|
- name: STORAGE_S3_ENDPOINT
|
|
value: {{ . | quote }}
|
|
{{- end }}
|
|
{{- if and .Values.storage.s3.secretName .Values.storage.s3.accessKeyIdKey }}
|
|
- name: STORAGE_S3_ACCESS_KEY_ID
|
|
valueFrom:
|
|
secretKeyRef:
|
|
name: {{ .Values.storage.s3.secretName | quote }}
|
|
key: {{ .Values.storage.s3.accessKeyIdKey | quote }}
|
|
{{- else }}
|
|
{{- with .Values.storage.s3.accessKeyId }}
|
|
- name: STORAGE_S3_ACCESS_KEY_ID
|
|
value: {{ . | quote }}
|
|
{{- end }}
|
|
{{- end }}
|
|
{{- if and .Values.storage.s3.secretName .Values.storage.s3.secretAccessKeyKey }}
|
|
- name: STORAGE_S3_SECRET_ACCESS_KEY
|
|
valueFrom:
|
|
secretKeyRef:
|
|
name: {{ .Values.storage.s3.secretName | quote }}
|
|
key: {{ .Values.storage.s3.secretAccessKeyKey | quote }}
|
|
{{- else }}
|
|
{{- with .Values.storage.s3.secretAccessKey }}
|
|
- name: STORAGE_S3_SECRET_ACCESS_KEY
|
|
value: {{ . | quote }}
|
|
{{- end }}
|
|
{{- end }}
|
|
{{- end -}}
|
|
{{- end -}}
|