diff --git a/hosting/k8s/helm/Chart.yaml b/hosting/k8s/helm/Chart.yaml index b003f5efe7e..15141244083 100644 --- a/hosting/k8s/helm/Chart.yaml +++ b/hosting/k8s/helm/Chart.yaml @@ -2,7 +2,7 @@ apiVersion: v2 name: trigger description: The official Trigger.dev Helm chart type: application -version: 4.5.7-plt663.9 +version: 4.5.7-plt663.10 appVersion: v4.5.7 home: https://trigger.dev sources: diff --git a/hosting/k8s/helm/README.md b/hosting/k8s/helm/README.md index c7608ddca25..23a5ac4f843 100644 --- a/hosting/k8s/helm/README.md +++ b/hosting/k8s/helm/README.md @@ -259,6 +259,27 @@ supervisor: The supervisor `extraVolumes` / `extraVolumeMounts` keys behave identically to the webapp ones. Both render unconditionally — they don't require any other feature toggle. +### Supervisor init containers + +`supervisor.extraInitContainers` prepends init containers to the supervisor pod. It accepts a list, or a string that is `tpl`-rendered in chart scope (the same contract as `webapp.extraContainers`), so entries can use helpers such as `trigger-v4.fullname`. + +The supervisor makes one connect call to the webapp when it boots and exits 1 if that call fails; Kubernetes then restarts it with backoff. If your webapp is a single replica that runs migrations at boot, a node drain that reschedules both pods leaves the supervisor crash-looping until the webapp is back. Gating on the webapp health endpoint avoids the restarts: + +```yaml +supervisor: + extraInitContainers: | + - name: wait-for-webapp + image: curlimages/curl:8.5.0 + command: ["/bin/sh", "-c"] + args: + - | + until curl -sf http://{{ include "trigger-v4.fullname" . }}-webapp:{{ .Values.webapp.service.port }}/healthcheck; do + echo "webapp not ready"; sleep 5 + done +``` + +The pod sits in `Init:0/1` (no restart counter) until the webapp answers, then the supervisor starts and connects normally. + ### Worker pod security context By default the supervisor doesn't set a `securityContext` on the worker pods it schedules — it lets the cluster's PodSecurity admission / SCC apply whatever defaults are configured. If you need to enforce explicit pod- or container-level security, set: diff --git a/hosting/k8s/helm/templates/supervisor.yaml b/hosting/k8s/helm/templates/supervisor.yaml index 2a3b30e876e..533575127d5 100644 --- a/hosting/k8s/helm/templates/supervisor.yaml +++ b/hosting/k8s/helm/templates/supervisor.yaml @@ -76,8 +76,23 @@ spec: {{- with .Values.supervisor.podSecurityContext }} {{- toYaml . | nindent 8 }} {{- end }} - {{- if not .Values.webapp.bootstrap.enabled }} + {{- /* + extraInitContainers is tpl-rendered into a variable first (string or + list, same contract as webapp.extraContainers) so `initContainers:` is + only emitted when something actually renders — a template string that + evaluates to nothing would otherwise leave a null list behind. + */}} + {{- $extraInitContainers := "" }} + {{- with .Values.supervisor.extraInitContainers }} + {{- if kindIs "string" . }} + {{- $extraInitContainers = tpl . $ | trim }} + {{- else }} + {{- $extraInitContainers = tpl (toYaml .) $ | trim }} + {{- end }} + {{- end }} + {{- if or (not .Values.webapp.bootstrap.enabled) $extraInitContainers }} initContainers: + {{- if not .Values.webapp.bootstrap.enabled }} - name: init-shared image: busybox:1.35 command: ['sh', '-c', 'mkdir -p /home/node/shared'] @@ -86,6 +101,10 @@ spec: volumeMounts: - name: shared mountPath: /home/node/shared + {{- end }} + {{- with $extraInitContainers }} + {{- . | nindent 8 }} + {{- end }} {{- end }} containers: - name: supervisor diff --git a/hosting/k8s/helm/values.yaml b/hosting/k8s/helm/values.yaml index ff539404b5f..afe58e3c528 100644 --- a/hosting/k8s/helm/values.yaml +++ b/hosting/k8s/helm/values.yaml @@ -419,6 +419,23 @@ supervisor: # mountPath: /etc/ssl/enterprise-ca # readOnly: true + # Extra init containers prepended to the Supervisor pod. Accepts a list, + # or a string that is tpl-rendered in chart scope (same contract as + # `webapp.extraContainers`), so entries can reference helpers and values. + # + # Typical use: gate supervisor start on the webapp's /healthcheck. The + # supervisor makes a single connect call to the webapp at boot and exits 1 + # when it fails, so a webapp that is still running boot migrations turns + # into a supervisor CrashLoopBackOff. Waiting here keeps the pod in + # Init:0/1 (no restart counter) until the webapp answers. + extraInitContainers: + [] + # - name: wait-for-webapp + # image: curlimages/curl:8.5.0 + # command: ["/bin/sh", "-c"] + # args: + # - until curl -sf http://{{ include "trigger-v4.fullname" . }}-webapp:{{ .Values.webapp.service.port }}/healthcheck; do sleep 5; done + # ServiceMonitor for Prometheus monitoring serviceMonitor: enabled: false