diff --git a/charts/chatwoot/templates/_helpers.tpl b/charts/chatwoot/templates/_helpers.tpl index 0366ae59..0e8c1d4e 100644 --- a/charts/chatwoot/templates/_helpers.tpl +++ b/charts/chatwoot/templates/_helpers.tpl @@ -226,3 +226,13 @@ Set redis URL redis://:$(REDIS_PASSWORD)@{{ .Values.redis.host }}:{{ .Values.redis.port }} {{- end -}} {{- end -}} + +{{/* +Short hash suffix used to make the migration Job name unique per +chart-version / app-version / image-tag combination. Plain Jobs are +immutable on `spec`, so a new name is required whenever those change, +otherwise `helm upgrade` would fail to re-apply the migration. +*/}} +{{- define "chatwoot.jobSuffix" -}} +{{- printf "%s-%s-%s" .Chart.AppVersion .Chart.Version (.Values.image.tag | default .Chart.AppVersion | toString) | sha256sum | trunc 7 -}} +{{- end -}} diff --git a/charts/chatwoot/templates/migrations-job.yaml b/charts/chatwoot/templates/migrations-job.yaml index 939e6993..8bd14197 100644 --- a/charts/chatwoot/templates/migrations-job.yaml +++ b/charts/chatwoot/templates/migrations-job.yaml @@ -1,19 +1,14 @@ apiVersion: batch/v1 kind: Job metadata: - name: "{{ .Release.Name }}-migrate" + name: "{{ .Release.Name }}-migrate-{{ include "chatwoot.jobSuffix" . }}" labels: app: {{ template "chatwoot.fullname" . }} chart: "{{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }}" release: "{{ .Release.Name }}" heritage: "{{ .Release.Service }}" - annotations: - # This is what defines this resource as a hook. Without this line, the - # job is considered part of the release. - "helm.sh/hook": {{ .Values.hooks.migrate.hookAnnotation }} - "helm.sh/hook-delete-policy": "hook-succeeded,before-hook-creation" - "helm.sh/hook-weight": "-1" spec: + ttlSecondsAfterFinished: 86400 template: spec: {{- with .Values.imagePullSecrets }} diff --git a/charts/chatwoot/templates/web-deployment.yaml b/charts/chatwoot/templates/web-deployment.yaml index b343357a..696581c8 100644 --- a/charts/chatwoot/templates/web-deployment.yaml +++ b/charts/chatwoot/templates/web-deployment.yaml @@ -40,6 +40,41 @@ spec: {{- if .Values.nodeSelector }} nodeSelector: {{- include "common.tplvalues.render" (dict "value" .Values.nodeSelector "context" $) | nindent 8 }} {{- end }} + initContainers: + - name: wait-for-migrations + image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}" + imagePullPolicy: {{ .Values.image.pullPolicy }} + env: + {{- if .Values.postgresql.auth.existingSecret }} + - name: POSTGRES_PASSWORD + valueFrom: + secretKeyRef: + name: {{ .Values.postgresql.auth.existingSecret }} + key: {{ default "password" .Values.postgresql.auth.secretKeys.adminPasswordKey }} + {{- end }} + envFrom: + - secretRef: + name: {{ template "chatwoot.fullname" . }}-env + {{- if .Values.existingEnvSecret }} + - secretRef: + name: {{ .Values.existingEnvSecret }} + {{- end }} + command: ["/bin/sh", "-c"] + args: + - | + set -e + echo "waiting for postgres at $POSTGRES_HOST:${POSTGRES_PORT:-5432}..." + until pg_isready -h "$POSTGRES_HOST" -p "${POSTGRES_PORT:-5432}" -q; do sleep 2; done + echo "postgres reachable; waiting for installation_configs table..." + until PGPASSWORD="$POSTGRES_PASSWORD" psql \ + -h "$POSTGRES_HOST" -p "${POSTGRES_PORT:-5432}" \ + -U "$POSTGRES_USERNAME" -d "$POSTGRES_DATABASE" \ + -tAc "SELECT to_regclass('public.installation_configs') IS NOT NULL" 2>/dev/null \ + | grep -q '^t$'; do + echo "migrations not applied yet; sleeping 2s..." + sleep 2 + done + echo "schema ready." containers: - args: - bundle diff --git a/charts/chatwoot/templates/worker-deployment.yaml b/charts/chatwoot/templates/worker-deployment.yaml index 1e55b192..f20d7394 100644 --- a/charts/chatwoot/templates/worker-deployment.yaml +++ b/charts/chatwoot/templates/worker-deployment.yaml @@ -40,6 +40,41 @@ spec: {{- if .Values.nodeSelector }} nodeSelector: {{- include "common.tplvalues.render" (dict "value" .Values.nodeSelector "context" $) | nindent 8 }} {{- end }} + initContainers: + - name: wait-for-migrations + image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}" + imagePullPolicy: {{ .Values.image.pullPolicy }} + env: + {{- if .Values.postgresql.auth.existingSecret }} + - name: POSTGRES_PASSWORD + valueFrom: + secretKeyRef: + name: {{ .Values.postgresql.auth.existingSecret }} + key: {{ default "password" .Values.postgresql.auth.secretKeys.adminPasswordKey }} + {{- end }} + envFrom: + - secretRef: + name: {{ template "chatwoot.fullname" . }}-env + {{- if .Values.existingEnvSecret }} + - secretRef: + name: {{ .Values.existingEnvSecret }} + {{- end }} + command: ["/bin/sh", "-c"] + args: + - | + set -e + echo "waiting for postgres at $POSTGRES_HOST:${POSTGRES_PORT:-5432}..." + until pg_isready -h "$POSTGRES_HOST" -p "${POSTGRES_PORT:-5432}" -q; do sleep 2; done + echo "postgres reachable; waiting for installation_configs table..." + until PGPASSWORD="$POSTGRES_PASSWORD" psql \ + -h "$POSTGRES_HOST" -p "${POSTGRES_PORT:-5432}" \ + -U "$POSTGRES_USERNAME" -d "$POSTGRES_DATABASE" \ + -tAc "SELECT to_regclass('public.installation_configs') IS NOT NULL" 2>/dev/null \ + | grep -q '^t$'; do + echo "migrations not applied yet; sleeping 2s..." + sleep 2 + done + echo "schema ready." containers: - args: - bundle diff --git a/charts/chatwoot/values.yaml b/charts/chatwoot/values.yaml index af68b17b..13db81fc 100644 --- a/charts/chatwoot/values.yaml +++ b/charts/chatwoot/values.yaml @@ -188,7 +188,10 @@ redis: replica: replicaCount: 1 -# Provide affinity for hooks if needed +# Migration Job configuration. The Job runs `rails db:chatwoot_prepare` +# as a regular resource (no Helm hook), with a chart-version-suffixed name +# so each upgrade spawns a fresh Job. Web/worker pods carry a +# `wait-for-migrations` initContainer that blocks until the schema is ready. hooks: affinity: {} migrate: @@ -198,9 +201,6 @@ hooks: memory: 1000Mi requests: memory: 1000Mi - # Defaults to performing the DB migration job after the install/upgrade. - # Can be overridden to "pre-install,pre-upgrade" with caution to perform migrations that are sometimes required for the deployment to become healthy - hookAnnotation: "post-install,post-upgrade" # ENVIRONMENT VARIABLES