Skip to content

fix(hosting): deploy ClickHouse from the official image instead of Bitnami - #4249

Merged
nicktrn merged 13 commits into
mainfrom
fix/self-hosting-official-clickhouse
Aug 1, 2026
Merged

fix(hosting): deploy ClickHouse from the official image instead of Bitnami#4249
nicktrn merged 13 commits into
mainfrom
fix/self-hosting-official-clickhouse

Conversation

@matt-aitken

@matt-aitken matt-aitken commented Jul 13, 2026

Copy link
Copy Markdown
Member

Summary

Self-hosted deployments now run ClickHouse from the official clickhouse/clickhouse-server image instead of bitnamilegacy/clickhouse. Bitnami's free image catalog is EOL and the frozen legacy archive tops out at ClickHouse 25.7.5, below the 25.8 minimum the platform requires since v4.5.0, which broke every ClickHouse insert on chart-bundled deployments. Both stacks now default to 26.2, the same version the platform is developed and tested against.

Existing deployments keep their ClickHouse data with no manual migration.

Fixes #4197.

Details

Docker Compose: the clickhouse service uses the official image with its native env vars, plus the recommended nofile ulimits. It reuses the same named volume as before: a data-paths.xml config override points ClickHouse at the data/ subdirectory of the volume, which is exactly the layout the Bitnami image used, so old volumes work in place (including SQL-created users) and fresh installs get the identical layout. The service follows the required-secrets model: CLICKHOUSE_PASSWORD must be set, matching the other services.

Helm chart: the Bitnami ClickHouse subchart is replaced by a chart-owned single-node StatefulSet and Service running the official image (non-root, HTTP /ping probes, config overrides mounted into config.d, and the same data-paths.xml layout compatibility). On upgrade, the chart automatically adopts the data PVC left behind by the old subchart (data-<release>-clickhouse-shard0-0) via lookup, and fsGroup relabeling handles the uid change on first mount. Both the ClickHouse server and the webapp read the password from the same chart-managed datastore secret (auto-generated and retained across upgrades), so the server credential and the app's connection URL always match. Existing clickhouse.* values keep working: auth (including existingSecret/existingSecretKey), persistence (including global.storageClass), resources, secure, external.*, configdFiles, and now nodeSelector/tolerations/affinity. Bitnami-only keys (shards, replicaCount, keeper, resourcesPreset) are gone; default resources requests/limits match what the old preset applied. The docs state the 25.8 minimum for bring-your-own ClickHouse.

Upgrade caveats

An adversarial review of the upgrade path found a few cohorts that need awareness (all documented):

  • GitOps tools that render with helm template (no cluster access): PVC auto-detection can't run, so clickhouse.persistence.existingClaim must be set to the old PVC name or ClickHouse starts on a fresh empty volume. Documented in the values file and the Kubernetes self-hosting docs. Tools that run real helm installs (e.g. Flux) adopt automatically.
  • A pinned CLICKHOUSE_IMAGE_TAG pointing at a Bitnami tag must be updated to an official image tag; documented in the Docker self-hosting docs.
  • Storage without fsGroup support (NFS, hostPath): set clickhouse.volumePermissions.enabled: true for a one-time ownership-fixing init container.
  • Rollback is not automatic: once the official image has run, file ownership changes and the Bitnami image can no longer read the volume without a manual chown, and ClickHouse does not support downgrades across the version gap.

Verification

  • Full upgrade simulation for Compose, twice (before and after rebasing onto the required-secrets release): booted the ClickHouse service from the old compose file on main (Bitnami), wrote thousands of rows, then brought the same project up with this branch's compose file. The official 26.2 server came up healthy on the same volume with all rows intact, SQL-created users working, and writes succeeding.
  • Adoption scenarios tested against real containers: old volume + root entrypoint (Compose), old volume owned by the Bitnami uid + non-root 101 with fsGroup-style group permissions (Kubernetes), and fresh volumes for both.
  • helm lint, helm template (default values, existingClaim set, external ClickHouse, volumePermissions/scheduling toggles, and the production example) and kubeconform all pass, mirroring the release CI steps. The rendered webapp Deployment and ClickHouse StatefulSet resolve to the same datastore secret key.
  • Inserts using input_format_json_infer_array_of_dynamic_from_array_of_different_types (the setting that fails on 25.7.5) succeed on the upgraded volume.

Upgrade preflight and docs

A production upgrade report on this branch surfaced two hazards that predate this PR — both landed in chart 4.5.6 (#4316) — so they are fixed here rather than left for the next person to hit.

secrets.existingSecret gained two required keys. The webapp started reading PROVIDER_SECRET and COORDINATOR_SECRET, and when existingSecret is set the chart generates nothing, so a missing key only surfaced as a CreateContainerConfigError partway through the webapp rollout. The pre-install/pre-upgrade validation now looks the Secret up and fails with the complete list of missing keys, leaving the running release untouched. It is skipped under helm template and client-side dry-run, where lookup cannot read the cluster.

Bundled datastore credentials moved into the chart-managed Secret (<release>-clickhouse/admin-passwordtrigger-datastore/clickhouse-admin-password). The chart wires both ends itself, but consumers outside it — maintenance CronJobs, Grafana datasources, secret syncs — have to be repointed. A new ## Upgrading section in the Kubernetes docs carries the old→new mapping, the two new keys, and a pointer to the ClickHouse image notes.

The existingSecret key list in the docs also named OBJECT_STORE_ACCESS_KEY_ID/OBJECT_STORE_SECRET_ACCESS_KEY, which are env var names rather than keys the chart reads; corrected to the real key names and the condition under which they apply.

Verified on a throwaway kind cluster with --dry-run=server: a pre-4.5.6 Secret fails with both key names listed, the documented kubectl patch clears it, and default values, existingClaim, external ClickHouse, volumePermissions/scheduling and the production example all still render. A real helm install followed by an upgrade against an incomplete Secret aborts with the release still at revision 1 and deployed. helm lint, the CI render and kubeconform (59 resources, 0 invalid) pass.

@changeset-bot

changeset-bot Bot commented Jul 13, 2026

Copy link
Copy Markdown

⚠️ No Changeset found

Latest commit: 8e28375

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

@coderabbitai

coderabbitai Bot commented Jul 13, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

Walkthrough

ClickHouse configuration is updated across self-hosting documentation, Docker Compose, and Helm. Docker now uses the official image, updated credentials and paths, file limits, and a compatible data-path configuration. Helm replaces the Bitnami dependency with custom ClickHouse resources, pinned image settings, explicit ports, probes, persistence, security settings, generated URLs, and updated tests. Documentation records the ClickHouse 25.8+ requirement and external service port key.

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Linked Issues check ✅ Passed The PR meets #4197 by raising ClickHouse to 26.2, documenting the 25.8 floor, and replacing the Bitnami chart/image.
Out of Scope Changes check ✅ Passed The changes stay focused on the ClickHouse image swap, Helm/Compose wiring, and docs/tests needed for that migration.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Title check ✅ Passed The title clearly states the main change: replacing Bitnami with the official ClickHouse image for hosting deployments.
Description check ✅ Passed The description is detailed and covers the issue, changes, upgrade risks, testing, and documentation, although it omits the template headings and checklist.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/self-hosting-official-clickhouse

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@github-actions

github-actions Bot commented Jul 13, 2026

Copy link
Copy Markdown
Contributor

🧭 Helm Chart Prerelease Published

Version: 4.5.9-pr4249.8e28375

Install:

helm upgrade --install trigger \
  oci://ghcr.io/triggerdotdev/charts/trigger \
  --version "4.5.9-pr4249.8e28375"

⚠️ This is a prerelease for testing. Do not use in production.

devin-ai-integration[bot]

This comment was marked as resolved.

coderabbitai[bot]

This comment was marked as resolved.

@matt-aitken
matt-aitken force-pushed the fix/self-hosting-official-clickhouse branch from e2e7e33 to 4608012 Compare July 13, 2026 16:01
coderabbitai[bot]

This comment was marked as resolved.

devin-ai-integration[bot]

This comment was marked as resolved.

devin-ai-integration[bot]

This comment was marked as resolved.

@matt-aitken
matt-aitken force-pushed the fix/self-hosting-official-clickhouse branch from ea85282 to 228c4a3 Compare July 24, 2026 12:30
@pkg-pr-new

pkg-pr-new Bot commented Jul 24, 2026

Copy link
Copy Markdown

Open in StackBlitz

@trigger.dev/build

npm i https://pkg.pr.new/@trigger.dev/build@fbf811c

trigger.dev

npm i https://pkg.pr.new/trigger.dev@fbf811c

@trigger.dev/core

npm i https://pkg.pr.new/@trigger.dev/core@fbf811c

@trigger.dev/python

npm i https://pkg.pr.new/@trigger.dev/python@fbf811c

@trigger.dev/react-hooks

npm i https://pkg.pr.new/@trigger.dev/react-hooks@fbf811c

@trigger.dev/redis-worker

npm i https://pkg.pr.new/@trigger.dev/redis-worker@fbf811c

@trigger.dev/rsc

npm i https://pkg.pr.new/@trigger.dev/rsc@fbf811c

@trigger.dev/schema-to-json

npm i https://pkg.pr.new/@trigger.dev/schema-to-json@fbf811c

@trigger.dev/sdk

npm i https://pkg.pr.new/@trigger.dev/sdk@fbf811c

commit: fbf811c

devin-ai-integration[bot]

This comment was marked as resolved.

devin-ai-integration[bot]

This comment was marked as resolved.

devin-ai-integration[bot]

This comment was marked as resolved.

…tnami

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.
…e inline credentials

The chart-deployed ClickHouse now reads CLICKHOUSE_PASSWORD from a
chart-owned Secret instead of a plaintext env value in the pod spec, and
the CLICKHOUSE_URL helpers percent-encode inline usernames and passwords
so special characters no longer produce an unparseable URL.
…ntials

urlquery encodes spaces as plus signs, which URL userinfo decoding keeps
literal. A shared urlencode helper rewrites them to %20 (a real plus
already encodes as %2B), so passwords containing spaces now work.
… restart checksum

The data-paths.xml default now lives in a shared helper used by both the
ConfigMap and the pod checksum annotation, so changing it in a future
chart version restarts the pod (subPath mounts do not update in place).
…lickHouse chart

Keeps existing self-hosted deployments working without manual steps:

- Default resource requests/limits match the preset the Bitnami subchart
  applied, so the ClickHouse pod doesn't silently become BestEffort.
- nodeSelector, tolerations, and affinity pass through to the StatefulSet
  for deployments that schedule ClickHouse onto dedicated nodes.
- Optional volumePermissions init container fixes data-volume ownership
  on storage without fsGroup support (NFS, hostPath).
- The helm test reads the password from the datastore secret instead of
  the usually-empty values key, and the pinned-password restart checksum
  is omitted when the password is auto-generated.
- Docs cover updating a pinned CLICKHOUSE_IMAGE_TAG to an official tag
  and the GitOps existingClaim step in more detail.
Adds the recovery path for GitOps renders that missed existingClaim,
the pinned Bitnami image note for the Helm chart, the single-node
clustering note, and the one-way rollback caveat for Docker Compose.
…rtup probe

The webapp now resolves CLICKHOUSE_PASSWORD through the same
auth.existingSecret/existingSecretKey values the bundled server uses,
so pointing the chart at a custom credentials secret keeps both sides
on the same password. A startup probe gives ClickHouse up to ten
minutes to load metadata on first boot with a large adopted data
volume before liveness checks begin.
@iFlyinq

iFlyinq commented Jul 30, 2026

Copy link
Copy Markdown
Contributor

Production upgrade feedback (Tillör, chart 4.5.7-pr4249.f7da3f8)

Upgraded a self-hosted v4 stack from chart 4.5.1 (custom ClickHouse 25.8 workaround) to this prerelease. ClickHouse migration succeeded — adopted PVC data-trigger-clickhouse-shard0-0, data intact (34 tables), server now 26.2.19.43, inserts work (no more UNKNOWN_SETTING on input_format_json_infer_array_of_dynamic_*).

Two issues worth calling out for other self-hosters:

1. New required secret keys when using secrets.existingSecret

After helm upgrade, the webapp rollout failed with CreateContainerConfigError:

couldn't find key PROVIDER_SECRET in Secret trigger/trigger-infisical-secrets

Chart 4.5.1 did not require PROVIDER_SECRET / COORDINATOR_SECRET in the existing secret; 4.5.7-pr4249 does (always reads from existingSecret when set — inline secrets.providerSecret values are ignored).

Suggestion: Add a prominent upgrade checklist to the Kubernetes self-hosting docs / release notes listing new required keys when upgrading from ≤4.5.6 with secrets.existingSecret. Ideally fail the helm install pre-upgrade (validation hook) rather than leaving a broken Deployment mid-rollout.

2. ClickHouse credential secret rename breaks sidecar consumers

Password moved from trigger-clickhouse / admin-passwordtrigger-datastore / clickhouse-admin-password. We had to update:

  • A nightly ClickHouse TTL cleanup CronJob
  • A cross-namespace Grafana secret sync CronJob

Suggestion: Document the old → new secret/key mapping in the upgrade guide. A short “external consumers” section would help anyone not using only the bundled Grafana.

What worked well

  • Explicit clickhouse.persistence.existingClaim: data-trigger-clickhouse-shard0-0 + pinned auth.password made the cutover predictable.
  • PVC adoption and Bitnami-layout compatibility: no manual migration, existing rows queryable immediately.
  • Startup probe gave enough time for the adopted volume on first boot.

Happy to re-test a stable release when #4249 merges.

… keys

When secrets.existingSecret is set the chart generates nothing and reads
every application and control-plane key from that Secret. A chart version
that starts consuming a new key therefore breaks the webapp rollout with a
CreateContainerConfigError partway through, leaving the release half-applied.

The pre-install/pre-upgrade validation now looks the Secret up and fails with
the full list of missing keys, so a running release is left untouched. The
lookup returns nothing under helm template and client-side dry-run, where the
check is skipped rather than guessing.
Collects the chart changes that need action before an upgrade: the two
secret keys the webapp started reading in 4.5.6, the move of the bundled
datastore credentials into the chart-managed Secret (with the old-to-new
mapping for consumers outside the chart), and a pointer to the ClickHouse
image notes.

Also corrects the existingSecret key list, which named the S3 environment
variables rather than the keys the chart actually reads.
@matt-aitken
matt-aitken force-pushed the fix/self-hosting-official-clickhouse branch from f7da3f8 to fbf811c Compare August 1, 2026 09:36
devin-ai-integration[bot]

This comment was marked as resolved.

… volume

Upgrading the bundled ClickHouse from the Bitnami subchart to the official image adopts the old data volume, whose files are owned by the previous uid. The official server runs non-root (uid 101), so on storage where fsGroup can't relabel the volume (hostPath, NFS, local-path - common for self-hosters) it crashes with 'cd: /var/lib/clickhouse/data/: Permission denied'. Run the one-time chown init automatically whenever a volume is adopted (existingClaim set, explicitly or auto-detected); fresh installs create their own data and skip it, and volumePermissions.enabled still forces it. Verified live in kind: a bitnami->official upgrade on local-path storage now comes up with data and auth intact, with no manual flag.
devin-ai-integration[bot]

This comment was marked as resolved.

…SE_USER

The bundled ClickHouse creates only the user named by CLICKHOUSE_USER (the official image removes the built-in default user when it differs), but the webapp CLICKHOUSE_URL and RUN_REPLICATION_CLICKHOUSE_URL hardcoded 'default', so a custom CLICKHOUSE_USER left the app unable to authenticate while the healthcheck (which already honours the var) stayed green. Derive the username in both URLs from CLICKHOUSE_USER. Also document, for the Helm chart, that inline external ClickHouse credentials are now percent-encoded (store the raw value), and that existingClaim should be pinned once a bitnami volume is adopted so client-side renders stay deterministic.
devin-ai-integration[bot]

This comment was marked as resolved.

… not a fixed uid

The volume-permissions init container hardcoded chown -R 101:101, ignoring clickhouse.securityContext.runAsUser/runAsGroup. Anyone who overrides the run-as user (e.g. for a restricted cluster policy) got a data directory owned by an account the server no longer runs as, so it failed to start on the adopted volume. Derive the uid/gid from securityContext (defaulting to 101). Also document the transient ReadWriteOnce multi-attach warning during the upgrade window so operators don't abort mid-migration.
@nicktrn

nicktrn commented Aug 1, 2026

Copy link
Copy Markdown
Collaborator

Ran a full local validation of the ClickHouse migration - docker bitnami→official on the same volume, and a real bitnami→official helm upgrade in kind - plus the fresh-install and auto-gen paths. Render/--dry-run looked fine, but the live run surfaced a couple of genuine bugs, now fixed on the branch:

  • Migration crash on fsGroup-less storage (fix(helm): auto-run the clickhouse chown init when adopting a bitnami volume): the non-root server (uid 101) adopts a volume owned by the old uid, and on hostPath/NFS/local-path (most single-node/k3s self-hosters, and kind) it crashloops with cd: /var/lib/clickhouse/data/: Permission denied. volumePermissions.enabled was off by default. Now the chown init runs automatically whenever a volume is adopted; fresh installs skip it.
  • CLICKHOUSE_USER ignored in the docker URLs (Devin) - the URLs hardcoded default while the server/healthcheck honored the var, so a custom username silently broke auth. Fixed to derive the username from ${CLICKHOUSE_USER:-default}.
  • chown hardcoded 101:101 (Devin) - ignored securityContext.runAsUser/runAsGroup; a custom run-as uid couldn't read its own data. Now derived from the configured values.
  • Docs for the inline-external-creds encoding change, pinning existingClaim post-adoption, and the transient RWO multi-attach window during the upgrade.

Validation, all live: docker migration keeps data + auth (empty/wrong passwords rejected); helm fresh install comes up; helm upgrade in kind on local-path reproduced the crash, then confirmed the auto-init fix - CH came up with the seeded rows intact and the retained auto-generated password authenticating. Auto-gen integration is intact (trigger-datastore/clickhouse-admin-password generated once, read by both the server and the webapp, retained across upgrades).

Nice PR - the bitnami-off migration is well handled (data-paths compat, PVC adoption, fsGroup). Replies to the individual comments inline.

@nicktrn

nicktrn commented Aug 1, 2026

Copy link
Copy Markdown
Collaborator

Also thanks for the review @iFlyinq! ❤️

…-walk on every restart

Because the adopted-volume condition stays true for the life of the release, the ownership init container runs on every pod restart, and an unconditional recursive chown re-walks the whole database each time - minutes of delay on large or network-backed data. Skip the chown when the volume root is already owned by the run-as user (mirroring fsGroupChangePolicy: OnRootMismatch), so only the first mount after adoption pays the cost.
@nicktrn
nicktrn enabled auto-merge (squash) August 1, 2026 13:16

@nicktrn nicktrn left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎉

@nicktrn
nicktrn merged commit cb9aefd into main Aug 1, 2026
25 checks passed
@nicktrn
nicktrn deleted the fix/self-hosting-official-clickhouse branch August 1, 2026 13:17
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

v4.5.0 ClickHouse writers require CH ≥25.8, but the Helm chart still bundles ClickHouse 25.7.5 → every insert fails with UNKNOWN_SETTING

3 participants