Skip to main content
Template version 3.0.0 is a breaking change, and one of the changes is a data-loss hazard.
  • The template no longer creates a GVC. It deploys into a GVC you already have. gvc.name is gone, and gvc.locations moved to a top-level locations list.
  • Never upgrade a 2.x release onto 3.0.0 in place. A 2.x release owns the GVC it created, and Helm deletes what a chart stops declaring — the upgrade destroys that GVC and everything inside it. Install a new release instead: Migrating from 2.x.
  • server.internal_access and keeper.internal_access are now server.internalAccess and keeper.internalAccess, and the workloads list is finally applied. In 2.x it was silently discarded, so type: workload-list blocked everything.

Overview

ClickHouse is a high-performance, column-oriented analytical database designed for real-time querying and data warehousing at scale. This template deploys ClickHouse in either single-node or cluster mode depending on how locations are configured, backed by object storage (AWS S3, GCS, Azure Blob Storage, or Hetzner Object Storage) for the table data and a local volume for metadata and fast read caching. The database password is not a template value. ClickHouse reads it from a dictionary secret you create before installing, so it never passes through Helm or lands in the release.

Deployment Modes

The locations list is the topology, not just placement — its length selects the mode, and a location’s position in it is that shard’s number.

What Gets Created

  • Stateful ClickHouse Server Workload — The analytical database itself, with configurable replicas per location.
  • Stateful ClickHouse Keeper Workload (cluster modes only) — The Raft coordination service, one replica in each of the first three locations.
  • Volume Sets — Persistent storage for the server (metadata, store/ and system files) and, in cluster modes, for Keeper. Table data lives in object storage; the volume is metadata and read cache.
  • Scratch Volumes — Local filesystem cache and temporary spill.
  • Secrets — Startup script secrets for ClickHouse Server and Keeper, and a storage configuration secret for the selected provider. No credential secret — the password lives only in the prerequisite secret you create.
  • Identity & Two Policies — An identity bound to the workloads, with reveal on the template’s own secrets plus exactly the secrets you created, view on the one GVC you install into so each container can confirm at boot that the GVC really has every location you listed, and cloud access to the bucket when the provider is AWS.
This template does not create a GVC. It deploys into a GVC you already have — every resource lands in the GVC you install into, so cpln workload exec, cpln logs and uninstalling all work against that GVC, and uninstalling can never delete it. Every location you list in locations must already be on that GVC, and a GVC location you did not list simply runs nothing.

Architecture

In multi-shard mode, each of the first three locations runs one ClickHouse Keeper replica, forming a 3-node quorum for distributed coordination. ClickHouse Server replicas reach Keeper over Control Plane’s internal DNS. In single-node mode, no Keeper is deployed. Primary data is stored in the configured object storage bucket in every mode; a local scratch volume serves as a fast read cache.
To minimize network egress costs, deploy all locations in the same cloud provider and keep your object storage bucket in the same region family. One server replica per location is enough for most cluster deployments.

Prerequisites

Three things must be in place before you install: a GVC with the right locations, a credentials secret, and object storage access for your chosen provider.

A GVC with your locations

A GVC must already exist, and it must contain every location you list in locations. The requirement is one-directional — the GVC may have more locations than you list, and nothing ClickHouse-related runs in those. Check what a GVC has before installing:
The locations are under spec.staticPlacement.locationLinks. To add a missing one:
Every workload in a GVC runs in every location that GVC has, so add locations to a shared GVC deliberately.
A location the GVC does not have is not caught at install time. The install succeeds — the platform does not validate it — and the containers then refuse to initialize, restarting with this in the logs:
A node that is already initialized logs a WARNING instead and keeps serving, so this check can never take down a running cluster.If every location you list is absent from the GVC, nothing starts at all and there is no container to log anything. cpln workload get-deployments then shows zero replicas in every location, "desiredScale": 0, and the message This workload location is deactivated because maxScale is set to 0. — that message, not the field, is the signal to look for.

Database credentials

One secret must exist before you install. It holds the password every ClickHouse client connection uses, so it is not a value — a value would leave it in the Helm release.
1

Create the credentials secret

A dictionary secret holding exactly two keys — password and database:
Set database.credentialsSecretName to the name you used. Secret names are org-wide, so give each release its own.
2

Read the secret back later

Pass -o yaml. A bare cpln secret reveal prints only a summary table, not the values:
There is no username key. ClickHouse authenticates as its built-in default user here, so the secret holds only the password and the database name.
Create the secret before installing, or the deployment wedges silently. The template refuses to render when database.credentialsSecretName is blank, but a name pointing at a secret that does not exist installs “successfully” and then never starts. The container never runs, so cpln logs returns zero lines — there is nothing to log, and every summary surface just looks like a slow deploy. The one place the reason appears is status.versions[].message:
Use get-deployments — plain cpln workload get has no versions key and will show you nothing. Creating the missing secret repairs it on its own with no further action — measured at 9 minutes 12 seconds on this template, within the roughly 5.5 to 10.5 minute band seen across the catalog — or run cpln workload force-redeployment RELEASE_NAME-clickhouse-server --gvc GVC_NAME to clear it in about 90 seconds.

Object storage

Object storage is required in every deployment mode, including single-node — there is no local-only shape. Choose one provider and complete its setup below. AWS is the only keyless option: access comes from a Cloud Account through the workload identity, so there is no key to store. The other three each need their own prerequisite dictionary secret.

AWS S3

  1. Create an S3 bucket. Set aws.bucket to its name and aws.region to its region.
  2. If you do not have a Control Plane Cloud Account set up, follow the Create a Cloud Account guide. Set aws.cloudAccountName to its name.
  3. Create an IAM policy with the following JSON, replacing YOUR_BUCKET_NAME, and set aws.policyName to its name:

GCS

ClickHouse reaches GCS over its S3-compatible interface, which requires an interoperability HMAC key. A Cloud Account is not required.
  1. Create a GCS bucket. Set gcp.bucket to the bucket name.
  2. In the GCP console, navigate to Settings > Interoperability and click Create a key for a service account.
  3. Click Create new account, name your service account, and assign the Storage Object Admin role under Permissions.
  4. Store the generated HMAC key in a dictionary secret, and set gcp.credentialsSecretName to that secret’s name:
Alternatively, use the gcloud CLI:

Azure Blob Storage

ClickHouse uses Azure’s native Blob Storage SDK. A Cloud Account is not required — authentication uses a storage account access key.
  1. In the Azure Portal, go to Storage accounts → Create. Use Standard performance, LRS redundancy, and leave hierarchical namespace off.
  2. Inside the storage account, go to Containers → + Container and create a container (e.g. clickhouse-data). Set access level to Private. Set azure.storageAccount and azure.container.
  3. Go to Security + networking → Access keys and copy either key1 or key2.
  4. Store the key in a dictionary secret, and set azure.credentialsSecretName to that secret’s name:
Alternatively, use the Azure CLI:

Hetzner Object Storage

Hetzner Object Storage is S3-compatible. A Cloud Account is not required — authentication uses an access key pair. Available regions:
  1. In the Hetzner Cloud console, go to Object Storage and create a bucket. Set hetzner.bucket and hetzner.region.
  2. Go to Security → S3 Credentials and click Generate credentials. Save the access key and secret key immediately — the secret will not be shown again.
  3. Store the pair in a dictionary secret, and set hetzner.credentialsSecretName to that secret’s name:

Installation

Create the prerequisite secrets first, then install by whichever method you prefer:

UI

Browse, install, and manage templates visually

CLI

Manage templates from your terminal

Terraform

Declare templates in your Terraform configurations

Pulumi

Declare templates in your Pulumi programs

Migrating from 2.x

Template versions through 2.8.0 created their own GVC, so that GVC is part of the 2.x release’s manifest. Version 3.0.0 does not declare it — and Helm deletes what a chart stops declaring.
An in-place upgrade from 2.x to 3.0.0 destroys the deployment. Measured on a sibling template with the guard removed: the upgrade deleted the GVC and every workload, volume set and identity inside it in about six seconds, while printing upgraded successfully. Reading the GVC back afterwards returned 404. The volume sets hold your ClickHouse metadata and Keeper state.The chart ships a render-time refusal so this cannot happen by accident: any leftover gvc key in your values aborts the upgrade before a single API call is made, leaving your cluster untouched and running.The guard cannot cover one case: an upgrade run with no values file at all. A 2.x release installed on pure defaults has no gvc key for the chart to see, so nothing fires and the deletion proceeds. Do not run an upgrade of a 2.x release against the 3.0.0 chart under any circumstances — install a new release and re-ingest.
1

Recover the password the existing cluster uses

Versions up to 2.5.0 took the password as a plain Helm value and wrote it into a chart-owned secret named after the release. Read it out of your current values file, or out of that secret:
Pass -o yaml. A bare cpln secret reveal prints only a summary table, not the values. Any password that came from a pre-2.6.0 default was published in the public template repository — treat it as compromised and choose a new one for the new deployment.
2

Choose the GVC for the new release

Create or pick a GVC and make sure it has exactly the locations you intend to list in locations. See Prerequisites.
3

Install 3.0.0 as a NEW release into that GVC

Use a different release name — secret names are org-wide, so a same-named release collides with the 2.x one even in another GVC. Point the new release at the same bucket with a different prefix, or at a new bucket.
4

Re-ingest your data

Do not try to adopt the old release’s volume set. It holds metadata whose <macros><shard> identity and Keeper paths belong to the old topology, and it cannot be moved between releases.
5

Cut over, then uninstall the old release

Point your applications at the new endpoint, then uninstall the old release against the GVC you originally installed it into — not the GVC it created. That is where Helm tracks the release, and uninstalling from there takes the created GVC with it.
Renamed in 3.0.0: gvc.locations is now the top-level locations, and server.internal_access / keeper.internal_access are now server.internalAccess / keeper.internalAccess.

Configuration

The default values.yaml for this template:

Locations

Each entry in locations pairs a location with a replica count, and the list length selects the deployment mode — see Deployment Modes. Every location listed must already exist in the GVC you install into; extra GVC locations run nothing. Two locations, a duplicate location, an empty list and replicas: 0 are all refused at render.
GVC locations you did not list show as red in the console, with This workload location is deactivated because maxScale is set to 0. That is the mechanism that keeps a shared GVC safe — it is what a healthy install looks like, not a fault.

Provider and Object Storage

Set provider to aws, gcp, azure, or hetzner, then fill in the corresponding section. Only the active provider’s fields are used. See Object storage for the per-provider setup steps. AWS S3 GCS Azure Blob Storage Hetzner Object Storage
Switch providers with a fresh install, not an upgrade. An identity’s cloud binding is never removed once set — the API merges rather than replaces — so a release switched from one provider to another keeps the old provider’s binding attached even though the chart no longer renders it.

Cluster and Database

  • clusterName — The name used for distributed DDL queries, in cluster modes only. It must be a bare identifier — letters, digits and underscores, not starting with a digit — because it becomes an XML element name and is used unquoted in ON CLUSTER statements. Anything else is refused at render.
  • database.credentialsSecretName — Name of the dictionary secret holding password and database. ClickHouse creates that database on first initialization, and the password is the one every client connection uses.
The secret must exist before installing — see Database credentials. The workloads read it through cpln://secret/... references, so the password appears in neither the Helm release nor the stored workload spec.
Renaming clusterName on an existing install orphans its Distributed tables. They keep pointing at the old cluster name and fail with Code: 701 ... Requested cluster 'my_cluster' not found (CLUSTER_DOESNT_EXIST). Recreate them after a rename.
Credentials are applied only on first initialization, when the data directory is empty. Changing the secret afterwards does not change the running cluster — it only changes what the workload presents when it authenticates, which will then fail. To rotate on an existing cluster, run ALTER USER default IDENTIFIED WITH sha256_password BY '...' first, then update the secret, then force a redeployment. Updating a cpln:// secret does not restart the workload by itself.

Images

  • server.image — ClickHouse Server container image.
  • keeper.image — ClickHouse Keeper container image. Only used in cluster modes.

Resources and Storage

  • server.resources / keeper.resources — CPU and memory allocated to each workload.
  • volumeset.server.capacity — Persistent volume size in GiB for server metadata and cache (minimum 10).
  • volumeset.keeper.capacity — Persistent volume size in GiB for Keeper state (minimum 10). Only used in cluster modes.

Internal Access

Both server.internalAccess and keeper.internalAccess control which workloads can reach each component. Neither workload is exposed publicly, and the template has no public access option.
List only your clients. The server and Keeper reach each other over the same internal firewall, so the chart adds this release’s own workloads to every list it renders. Without that, a workload-list naming only your applications takes down Keeper’s Raft quorum and every cross-shard query while all status surfaces stay green.
An access-knob change takes up to about five minutes to propagate — measured arms on this template settled between 55 and 123 seconds. Re-test before concluding it did not apply.

Connecting to ClickHouse

From another workload in the same GVC:
Always use the fully qualified .GVC_NAME.cpln.local form. The bare workload name is not reliable on this platform — whether it resolves depends on the workload type.

Tables in Cluster Modes

Use ReplicatedMergeTree plus a Distributed table. A plain MergeTree in a multi-shard cluster is single-copy and is not covered by the cluster’s availability story.
{shard} and {replica} come from each node’s <macros>, which the chart derives from the location’s position in locations.

Important Notes

  • Never upgrade a 2.x release onto 3.0.0 in place — it deletes the GVC the 2.x chart created and everything in it. Install a new release: Migrating from 2.x.
  • The GVC must contain every location you list, and may contain more. A missing location is not caught at install: the container exits with FATAL: locations declared in values are not in GVC .... An already-initialized node logs a WARNING instead and keeps serving.
  • Two locations is not supported. Use one (single-node or single-shard) or three or more.
  • Object storage is required in every mode, including single-node. There is no local-only shape.
  • Keeper is the availability floor. Three members tolerate one loss; the single-shard shape has one member and tolerates none. If a majority of Keeper locations are missing from the GVC, the containers exit with a named error rather than waiting for an election that can never complete.
  • A helm upgrade restarts every replica in every location at once. Nothing serializes a rolling restart on a stateful workload, so treat an upgrade as a planned query interruption: a rolling upgrade of a 3-shard cluster was measured at about 83 seconds of total unavailability, and a Keeper settings change at roughly 60 seconds of coordination outage. On a single-node install, the first no-op upgrade after an install also restarts the one replica.
  • With one replica per shard, losing a shard fails every distributed query, not just the rows on that shard — measured at about 60 seconds to surface, and about 112 seconds to full recovery. Add replicas if partial results are not acceptable.
  • Renaming clusterName orphans existing Distributed tables (Code: 701). Recreate them after a rename.
  • Keep locations and the bucket in the same provider and region family. Cross-region traffic to object storage is billed on every query that misses the local cache.
  • Release names must be unique per org — secrets are org-wide, so two releases with the same name collide even in different GVCs.

External References

ClickHouse Documentation

Official ClickHouse documentation

ClickHouse Keeper

Raft coordination for replicated tables

Data Replication

The ReplicatedMergeTree engine family

Distributed Table Engine

Fan a query out across shards

ClickHouse with S3

Integrating ClickHouse with AWS S3 and S3-compatible providers

ClickHouse with GCS

Integrating ClickHouse with Google Cloud Storage

ClickHouse with Azure Blob Storage

Integrating ClickHouse with Azure Blob Storage

ClickHouse Template

View the source files, default values, and chart definition