Skip to content

Commit 4608012

Browse files
committed
fix(hosting): deploy ClickHouse from the official image instead of Bitnami
The Bitnami free image catalog is EOL and its frozen bitnamilegacy archive tops out at ClickHouse 25.7.5, below the 25.8 floor the platform requires since v4.5.0. The Docker Compose stack and the Helm chart now run the official clickhouse/clickhouse-server image at 26.2, the same version the platform is developed and tested against. The Helm chart deploys ClickHouse with a chart-owned StatefulSet instead of the Bitnami subchart. Existing deployments keep their data with no manual steps: a config override keeps the on-disk layout compatible with volumes created by the Bitnami-based setup, Compose reuses the same named volume, and the Helm chart automatically adopts the data PVC left behind by the old subchart.
1 parent 6e943f2 commit 4608012

12 files changed

Lines changed: 307 additions & 36 deletions

File tree

docs/self-hosting/docker.mdx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -344,6 +344,8 @@ TRIGGER_IMAGE_TAG=v4.5.0
344344
345345
We patch the latest released version line only, so keep an eye on new releases to receive security fixes. See [Security & vulnerability reporting](/self-hosting/security).
346346
347+
You can also lock the versions of the bundled services, for example with `CLICKHOUSE_IMAGE_TAG`. If you do, or if you bring your own ClickHouse via `CLICKHOUSE_URL`, note that Trigger.dev requires ClickHouse 25.8 or newer.
348+
347349
<Note>
348350
Trigger.dev 4.5.0 is the last version we officially support for running v3 (SDK v3) tasks. If
349351
you still have v3 tasks, pin `TRIGGER_IMAGE_TAG` to exactly `v4.5.0` or [migrate to

docs/self-hosting/kubernetes.mdx

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -257,14 +257,24 @@ redis:
257257
258258
#### ClickHouse
259259
260+
<Note>Trigger.dev requires ClickHouse 25.8 or newer.</Note>
261+
262+
<Note>
263+
When upgrading from a chart version that bundled ClickHouse via the Bitnami subchart, the chart
264+
automatically adopts the existing data volume, so no manual migration is needed. If you render
265+
manifests without cluster access (for example with GitOps tools that use `helm template`), set
266+
`clickhouse.persistence.existingClaim` to the old PVC name
267+
(`data-<release>-clickhouse-shard0-0`) to keep your data.
268+
</Note>
269+
260270
**Direct configuration:**
261271

262272
```yaml
263273
clickhouse:
264274
deploy: false
265275
external:
266276
host: "my-clickhouse.example.com"
267-
port: 8123
277+
httpPort: 8123
268278
username: "my-username"
269279
password: "my-password"
270280
```
@@ -276,7 +286,7 @@ clickhouse:
276286
deploy: false
277287
external:
278288
host: "my-clickhouse.example.com"
279-
port: 8123
289+
httpPort: 8123
280290
username: "my-username"
281291
existingSecret: "clickhouse-credentials"
282292
# existingSecretKey: "clickhouse-password" # default (optional)

hosting/docker/.env.example

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -128,7 +128,7 @@ OBJECT_STORE_SECRET_ACCESS_KEY=very-safe-password
128128
# POSTGRES_IMAGE_TAG=14
129129
# REDIS_IMAGE_TAG=7
130130
# ELECTRIC_IMAGE_TAG=1.0.13
131-
# CLICKHOUSE_IMAGE_TAG=latest
131+
# CLICKHOUSE_IMAGE_TAG=26.2
132132
# REGISTRY_IMAGE_TAG=2
133133
# MINIO_IMAGE_TAG=latest
134134
# DOCKER_PROXY_IMAGE_TAG=latest
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
<!--
2+
Keeps ClickHouse's on-disk layout compatible with data volumes created by
3+
the previous Bitnami-based setup, which stored everything under a data/
4+
subdirectory of the volume. Fresh installs get the same layout. tmp lives
5+
outside data/ because old volumes contain a dangling tmp symlink there.
6+
-->
7+
<clickhouse>
8+
<path>/var/lib/clickhouse/data/</path>
9+
<tmp_path>/var/lib/clickhouse/tmp/</tmp_path>
10+
<user_files_path>/var/lib/clickhouse/data/user_files/</user_files_path>
11+
<format_schema_path>/var/lib/clickhouse/data/format_schemas/</format_schema_path>
12+
<user_directories>
13+
<local_directory>
14+
<path>/var/lib/clickhouse/data/access/</path>
15+
</local_directory>
16+
</user_directories>
17+
</clickhouse>

hosting/docker/webapp/docker-compose.yml

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -155,18 +155,26 @@ services:
155155
start_period: 10s
156156

157157
clickhouse:
158-
image: bitnamilegacy/clickhouse:${CLICKHOUSE_IMAGE_TAG:-latest}
158+
image: clickhouse/clickhouse-server:${CLICKHOUSE_IMAGE_TAG:-26.2}
159159
restart: ${RESTART_POLICY:-unless-stopped}
160160
logging: *logging-config
161161
ports:
162162
- ${CLICKHOUSE_PUBLISH_IP:-127.0.0.1}:9123:8123
163163
- ${CLICKHOUSE_PUBLISH_IP:-127.0.0.1}:9090:9000
164+
ulimits:
165+
nofile:
166+
soft: 262144
167+
hard: 262144
164168
environment:
165-
CLICKHOUSE_ADMIN_USER: ${CLICKHOUSE_USER:-default}
166-
CLICKHOUSE_ADMIN_PASSWORD: ${CLICKHOUSE_PASSWORD:-password}
169+
CLICKHOUSE_USER: ${CLICKHOUSE_USER:-default}
170+
CLICKHOUSE_PASSWORD: ${CLICKHOUSE_PASSWORD:-password}
171+
CLICKHOUSE_DEFAULT_ACCESS_MANAGEMENT: 1
167172
volumes:
168-
- clickhouse:/bitnami/clickhouse
169-
- ../clickhouse/override.xml:/bitnami/clickhouse/etc/config.d/override.xml:ro
173+
# The same volume works across upgrades from the previous Bitnami-based
174+
# setup: data-paths.xml keeps the on-disk layout compatible.
175+
- clickhouse:/var/lib/clickhouse
176+
- ../clickhouse/data-paths.xml:/etc/clickhouse-server/config.d/data-paths.xml:ro
177+
- ../clickhouse/override.xml:/etc/clickhouse-server/config.d/override.xml:ro
170178
networks:
171179
- webapp
172180
healthcheck:

hosting/k8s/helm/Chart.lock

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,8 @@ dependencies:
55
- name: redis
66
repository: oci://registry-1.docker.io/bitnamicharts
77
version: 21.2.6
8-
- name: clickhouse
9-
repository: oci://registry-1.docker.io/bitnamicharts
10-
version: 9.4.4
118
- name: minio
129
repository: oci://registry-1.docker.io/bitnamicharts
1310
version: 17.0.9
14-
digest: sha256:e1b572ab8eca0cc376311398c27b1734d8a598095fccc81dd9c32b2c8b9c1149
15-
generated: "2026-05-05T10:31:58.493590751+01:00"
11+
digest: sha256:a735954c8b78fcf5b30689bdcdfed66b9be57135368ea696aff2b52ecd731474
12+
generated: "2026-07-13T16:36:15.800113+01:00"

hosting/k8s/helm/Chart.yaml

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -26,10 +26,6 @@ dependencies:
2626
version: "21.2.6"
2727
repository: "oci://registry-1.docker.io/bitnamicharts"
2828
condition: redis.deploy
29-
- name: clickhouse
30-
version: "9.4.4"
31-
repository: "oci://registry-1.docker.io/bitnamicharts"
32-
condition: clickhouse.deploy
3329
- name: minio
3430
version: "17.0.9"
3531
repository: "oci://registry-1.docker.io/bitnamicharts"

hosting/k8s/helm/templates/_helpers.tpl

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -415,7 +415,7 @@ ClickHouse hostname
415415
{{- if .Values.clickhouse.host }}
416416
{{- .Values.clickhouse.host }}
417417
{{- else if .Values.clickhouse.deploy }}
418-
{{- printf "%s-clickhouse" .Release.Name }}
418+
{{- printf "%s-clickhouse" (include "trigger-v4.fullname" .) }}
419419
{{- end }}
420420
{{- end }}
421421

@@ -439,7 +439,7 @@ hex-encoded password or percent-encode before storing in the Secret.
439439
{{- if .Values.clickhouse.deploy -}}
440440
{{- $protocol := ternary "https" "http" .Values.clickhouse.secure -}}
441441
{{- $secure := ternary "true" "false" .Values.clickhouse.secure -}}
442-
{{ $protocol }}://{{ .Values.clickhouse.auth.username }}:{{ .Values.clickhouse.auth.password }}@{{ include "trigger-v4.clickhouse.hostname" . }}:8123?secure={{ $secure }}
442+
{{ $protocol }}://{{ .Values.clickhouse.auth.username }}:{{ .Values.clickhouse.auth.password }}@{{ include "trigger-v4.clickhouse.hostname" . }}:{{ .Values.clickhouse.service.ports.http }}?secure={{ $secure }}
443443
{{- else if .Values.clickhouse.external.host -}}
444444
{{- $protocol := ternary "https" "http" .Values.clickhouse.external.secure -}}
445445
{{- $secure := ternary "true" "false" .Values.clickhouse.external.secure -}}
@@ -460,7 +460,7 @@ applies to the replication URL.
460460
{{- define "trigger-v4.clickhouse.replication.url" -}}
461461
{{- if .Values.clickhouse.deploy -}}
462462
{{- $protocol := ternary "https" "http" .Values.clickhouse.secure -}}
463-
{{ $protocol }}://{{ .Values.clickhouse.auth.username }}:{{ .Values.clickhouse.auth.password }}@{{ include "trigger-v4.clickhouse.hostname" . }}:8123
463+
{{ $protocol }}://{{ .Values.clickhouse.auth.username }}:{{ .Values.clickhouse.auth.password }}@{{ include "trigger-v4.clickhouse.hostname" . }}:{{ .Values.clickhouse.service.ports.http }}
464464
{{- else if .Values.clickhouse.external.host -}}
465465
{{- $protocol := ternary "https" "http" .Values.clickhouse.external.secure -}}
466466
{{- if .Values.clickhouse.external.existingSecret -}}
Lines changed: 199 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,199 @@
1+
{{- if .Values.clickhouse.deploy }}
2+
apiVersion: v1
3+
kind: ConfigMap
4+
metadata:
5+
name: {{ include "trigger-v4.fullname" . }}-clickhouse-config
6+
labels:
7+
{{- $component := "clickhouse" }}
8+
{{- include "trigger-v4.componentLabels" (dict "Chart" .Chart "Release" .Release "Values" .Values "component" $component) | nindent 4 }}
9+
data:
10+
{{- if not (hasKey .Values.clickhouse.configdFiles "data-paths.xml") }}
11+
{{- /* Keeps the on-disk layout compatible with data volumes created by the
12+
Bitnami subchart this chart used previously, which stored everything
13+
under a data/ subdirectory of the volume. Fresh installs get the same
14+
layout. tmp lives outside data/ because old volumes contain a
15+
dangling tmp symlink there. */}}
16+
data-paths.xml: |
17+
<clickhouse>
18+
<path>/var/lib/clickhouse/data/</path>
19+
<tmp_path>/var/lib/clickhouse/tmp/</tmp_path>
20+
<user_files_path>/var/lib/clickhouse/data/user_files/</user_files_path>
21+
<format_schema_path>/var/lib/clickhouse/data/format_schemas/</format_schema_path>
22+
<user_directories>
23+
<local_directory>
24+
<path>/var/lib/clickhouse/data/access/</path>
25+
</local_directory>
26+
</user_directories>
27+
</clickhouse>
28+
{{- end }}
29+
{{- range $filename, $content := .Values.clickhouse.configdFiles }}
30+
{{ $filename }}: |
31+
{{- $content | nindent 4 }}
32+
{{- end }}
33+
---
34+
{{- /* Reuse an existing data PVC instead of creating one via
35+
volumeClaimTemplates. Set explicitly through persistence.existingClaim,
36+
or detected automatically: upgrades from chart versions that bundled
37+
the Bitnami subchart leave their PVC behind under the old name, and
38+
adopting it preserves all ClickHouse data with no manual migration.
39+
(lookup returns nothing during template/dry-run rendering; set
40+
persistence.existingClaim explicitly when pre-rendering manifests,
41+
e.g. with GitOps tools.) */}}
42+
{{- $existingClaim := .Values.clickhouse.persistence.existingClaim }}
43+
{{- if and (not $existingClaim) .Values.clickhouse.persistence.enabled }}
44+
{{- $legacyName := printf "data-%s-clickhouse-shard0-0" .Release.Name }}
45+
{{- if lookup "v1" "PersistentVolumeClaim" .Release.Namespace $legacyName }}
46+
{{- $existingClaim = $legacyName }}
47+
{{- end }}
48+
{{- end }}
49+
apiVersion: apps/v1
50+
kind: StatefulSet
51+
metadata:
52+
name: {{ include "trigger-v4.fullname" . }}-clickhouse
53+
labels:
54+
{{- $component := "clickhouse" }}
55+
{{- include "trigger-v4.componentLabels" (dict "Chart" .Chart "Release" .Release "Values" .Values "component" $component) | nindent 4 }}
56+
spec:
57+
replicas: 1
58+
serviceName: {{ include "trigger-v4.fullname" . }}-clickhouse
59+
selector:
60+
matchLabels:
61+
{{- include "trigger-v4.componentSelectorLabels" (dict "Chart" .Chart "Release" .Release "Values" .Values "component" $component) | nindent 6 }}
62+
template:
63+
metadata:
64+
annotations:
65+
checksum/config: {{ .Values.clickhouse.configdFiles | toYaml | sha256sum }}
66+
{{- with .Values.clickhouse.podAnnotations }}
67+
{{- toYaml . | nindent 8 }}
68+
{{- end }}
69+
labels:
70+
{{- include "trigger-v4.componentSelectorLabels" (dict "Chart" .Chart "Release" .Release "Values" .Values "component" $component) | nindent 8 }}
71+
spec:
72+
{{- with .Values.global.imagePullSecrets }}
73+
imagePullSecrets:
74+
{{- toYaml . | nindent 8 }}
75+
{{- end }}
76+
{{- with .Values.clickhouse.podSecurityContext }}
77+
securityContext:
78+
{{- toYaml . | nindent 8 }}
79+
{{- end }}
80+
containers:
81+
- name: clickhouse
82+
{{- with .Values.clickhouse.securityContext }}
83+
securityContext:
84+
{{- toYaml . | nindent 12 }}
85+
{{- end }}
86+
image: "{{ .Values.global.imageRegistry | default .Values.clickhouse.image.registry }}/{{ .Values.clickhouse.image.repository }}:{{ .Values.clickhouse.image.tag }}{{ with .Values.clickhouse.image.digest }}@{{ . }}{{ end }}"
87+
imagePullPolicy: {{ .Values.clickhouse.image.pullPolicy }}
88+
env:
89+
- name: CLICKHOUSE_USER
90+
value: {{ .Values.clickhouse.auth.username | quote }}
91+
- name: CLICKHOUSE_PASSWORD
92+
value: {{ .Values.clickhouse.auth.password | quote }}
93+
- name: CLICKHOUSE_DEFAULT_ACCESS_MANAGEMENT
94+
value: "1"
95+
ports:
96+
- name: http
97+
containerPort: 8123
98+
protocol: TCP
99+
- name: native
100+
containerPort: 9000
101+
protocol: TCP
102+
{{- if .Values.clickhouse.livenessProbe.enabled }}
103+
livenessProbe:
104+
httpGet:
105+
path: /ping
106+
port: http
107+
initialDelaySeconds: {{ .Values.clickhouse.livenessProbe.initialDelaySeconds }}
108+
periodSeconds: {{ .Values.clickhouse.livenessProbe.periodSeconds }}
109+
timeoutSeconds: {{ .Values.clickhouse.livenessProbe.timeoutSeconds }}
110+
failureThreshold: {{ .Values.clickhouse.livenessProbe.failureThreshold }}
111+
successThreshold: {{ .Values.clickhouse.livenessProbe.successThreshold }}
112+
{{- end }}
113+
{{- if .Values.clickhouse.readinessProbe.enabled }}
114+
readinessProbe:
115+
httpGet:
116+
path: /ping
117+
port: http
118+
initialDelaySeconds: {{ .Values.clickhouse.readinessProbe.initialDelaySeconds }}
119+
periodSeconds: {{ .Values.clickhouse.readinessProbe.periodSeconds }}
120+
timeoutSeconds: {{ .Values.clickhouse.readinessProbe.timeoutSeconds }}
121+
failureThreshold: {{ .Values.clickhouse.readinessProbe.failureThreshold }}
122+
successThreshold: {{ .Values.clickhouse.readinessProbe.successThreshold }}
123+
{{- end }}
124+
resources:
125+
{{- toYaml .Values.clickhouse.resources | nindent 12 }}
126+
volumeMounts:
127+
- name: data
128+
mountPath: /var/lib/clickhouse
129+
- name: logs
130+
mountPath: /var/log/clickhouse-server
131+
{{- /* Mount each override file individually: shadowing the whole
132+
config.d directory would remove the image's built-in
133+
docker_related_config.xml, which makes the server listen on
134+
0.0.0.0 instead of localhost only. */}}
135+
{{- if not (hasKey .Values.clickhouse.configdFiles "data-paths.xml") }}
136+
- name: config
137+
mountPath: /etc/clickhouse-server/config.d/data-paths.xml
138+
subPath: data-paths.xml
139+
{{- end }}
140+
{{- range $filename, $_ := .Values.clickhouse.configdFiles }}
141+
- name: config
142+
mountPath: /etc/clickhouse-server/config.d/{{ $filename }}
143+
subPath: {{ $filename }}
144+
{{- end }}
145+
volumes:
146+
- name: config
147+
configMap:
148+
name: {{ include "trigger-v4.fullname" . }}-clickhouse-config
149+
- name: logs
150+
emptyDir: {}
151+
{{- if not .Values.clickhouse.persistence.enabled }}
152+
- name: data
153+
emptyDir: {}
154+
{{- else if $existingClaim }}
155+
- name: data
156+
persistentVolumeClaim:
157+
claimName: {{ $existingClaim }}
158+
{{- end }}
159+
{{- if and .Values.clickhouse.persistence.enabled (not $existingClaim) }}
160+
volumeClaimTemplates:
161+
- metadata:
162+
name: data
163+
{{- if .Values.clickhouse.persistence.retain }}
164+
annotations:
165+
helm.sh/resource-policy: keep
166+
{{- end }}
167+
spec:
168+
accessModes:
169+
- {{ .Values.clickhouse.persistence.accessMode }}
170+
resources:
171+
requests:
172+
storage: {{ .Values.clickhouse.persistence.size }}
173+
{{- $storageClass := .Values.clickhouse.persistence.storageClass | default .Values.global.storageClass }}
174+
{{- if $storageClass }}
175+
storageClassName: {{ $storageClass }}
176+
{{- end }}
177+
{{- end }}
178+
---
179+
apiVersion: v1
180+
kind: Service
181+
metadata:
182+
name: {{ include "trigger-v4.fullname" . }}-clickhouse
183+
labels:
184+
{{- $component := "clickhouse" }}
185+
{{- include "trigger-v4.componentLabels" (dict "Chart" .Chart "Release" .Release "Values" .Values "component" $component) | nindent 4 }}
186+
spec:
187+
type: {{ .Values.clickhouse.service.type }}
188+
ports:
189+
- port: {{ .Values.clickhouse.service.ports.http }}
190+
targetPort: http
191+
protocol: TCP
192+
name: http
193+
- port: {{ .Values.clickhouse.service.ports.native }}
194+
targetPort: native
195+
protocol: TCP
196+
name: native
197+
selector:
198+
{{- include "trigger-v4.componentSelectorLabels" (dict "Chart" .Chart "Release" .Release "Values" .Values "component" $component) | nindent 4 }}
199+
{{- end }}

hosting/k8s/helm/templates/tests/test-clickhouse.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,6 @@ spec:
1616
args:
1717
- |
1818
echo "Testing ClickHouse HTTP interface..."
19-
curl -f --user "{{ .Values.clickhouse.auth.adminUser }}:{{ .Values.clickhouse.auth.adminPassword }}" "http://{{ include "trigger-v4.fullname" . }}-clickhouse:{{ .Values.clickhouse.service.ports.http }}/ping"
19+
curl -f --user "{{ .Values.clickhouse.auth.username }}:{{ .Values.clickhouse.auth.password }}" "http://{{ include "trigger-v4.clickhouse.hostname" . }}:{{ .Values.clickhouse.service.ports.http }}/ping"
2020
echo "ClickHouse test completed successfully"
2121
{{- end }}

0 commit comments

Comments
 (0)