Prerequisites
Before you begin, ensure you have the following tools installed:- gcloud CLI (
gcloud) — installed and authenticated to your project - kubectl — compatible with your target GKE version
- Helm v3.x
- skopeo — for copying container images between registries
- AWS CLI (
aws) — with read access to the ClickHouse private ECR (<<SOURCE_ECR_ACCOUNT_ID>>.dkr.ecr.us-east-1.amazonaws.com; access details provided by ClickHouse during onboarding), used only for the image copy step
- A GCP project with billing enabled and permissions to create GKE clusters, GCS buckets, IAM service accounts, and VPC resources
- A bastion host in the VPC — the cluster is fully private, so all
kubectland Helm access must originate from within the VPC - The version tags for your deployment (provided by ClickHouse):
<<SERVER_TAG>>— ClickHouse server image tag<<KEEPER_TAG>>— ClickHouse keeper image tag<<OPERATOR_TAG>>— Operator image and Helm chart tag<<CR_HELM_TAG>>— Cluster Helm chart tag
Step 1: Create the Artifact Registry
Create a Docker-format Artifact Registry repository in the same region as your GKE cluster to hold the ClickHouse images and Helm charts, then configure Docker authentication against it.$GAR_HOST:
Step 2: Copy Container Images
Use skopeo to copy images from the ClickHouse ECR into your Artifact Registry. The--all flag preserves all architectures (amd64, arm64).
Step 3: Create the VPC and Subnet
Create a custom-mode VPC and a GKE subnet in the deployment region. The subnet needs two secondary ranges — one for pods and one for services — and Private Google Access so private nodes can reach Google APIs (including GCS and Artifact Registry) without public IPs.
CIDR boundary requirements
/14blocks: the third octet must be divisible by 4 (e.g.10.244.0.0, not10.245.0.0)/20blocks: the fourth octet must be0and the third octet on a 16-boundary (e.g.10.252.0.0)
Step 4: Create the GKE Cluster
Create a fully private GKE cluster — worker nodes have only internal IPs, the control plane has no public endpoint, and all access must come from within the VPC via the bastion. Associate it with the VPC and subnet from Step 3, using the secondary ranges for pods and services and enabling Workload Identity.
Once the cluster exists, fetch credentials from the bastion using the internal endpoint and confirm access:
Step 5: Create Node Pools
Create two node pools for ClickHouse, plus rely on the cluster’s default pool for the operator. Create one node pool per zone if you want the cluster autoscaler to balance across zones.Arm deploymentsThis guide uses x86
n2 machine types (server.arm64=false / keeper.arm64=false in Step 9). GCP also offers Arm machine types (Axion c4a, Tau t2a). To run on Arm, create the node pools with an Arm machine type, use distinct labels such as clickhouseGroup: server-arm64 / keeper-arm64, point the Step 9 nodeSelector values at them, and set server.arm64=true / keeper.arm64=true (the chart default). Arm machine types are not available in every region — confirm your target region and zones offer them before selecting one.Keeper Node Pool
Server Node Pool
The server pool attaches its local NVMe SSD as ephemeral storage (--ephemeral-storage-local-ssd). GKE backs emptyDir volumes with that SSD, so the ClickHouse cache lands on NVMe automatically when the Helm chart sets server.ssdCacheConfiguration.isOnEmptyDir=true — which the GCP base configuration does by default (see Step 9). No node bootstrap script or DaemonSet is required.
Scale local SSD For example an
count with the cache sizeEach GKE local SSD is 375 GiB. When count is greater than 1, GKE combines the SSDs into a single RAID-0 (striped) volume and backs ephemeral storage with the combined capacity. count=1 suits the dev machine type; for larger servers, attach enough SSDs to hold the cache plus headroom for container images and logs. The cache size is bytesPerGiRAM * pod_memory_limit, so:n2-standard-64 (256 GiB RAM) with bytesPerGiRAM=9500Mi needs a cache of roughly 2.4 TiB, so count=8 (8 × 375 GiB = 3 TiB). Undersizing count fills the disk and the node runs out of ephemeral storage.Step 6: Create the GCS Bucket and Service Account
GCS Bucket
Create a Standard-class GCS bucket in the same region as the cluster, with uniform bucket-level access enabled. You can use one bucket per ClickHouse cluster, or a single bucket with a unique prefix per cluster.Service Account and Workload Identity
ClickHouse authenticates to GCS and Artifact Registry through Workload Identity — there are no static credentials. Create a GCP service account (GSA), grant it access to the bucket and registry, then bind it to the Kubernetes service account (KSA) that the cluster Helm chart creates. The chart creates a KSA namedch-$CLUSTER_NAME-sa in namespace ns-$CLUSTER_NAME. Because the name is deterministic, you can bind Workload Identity before deploying the cluster; the KSA annotation is applied by the chart at install time (Step 9), so pods have GCS access from first start.
Step 7: Install Kubernetes Prerequisites
Install VolumeSnapshot CRDs
These CRDs are required by the ClickHouse operator.StorageClass
No StorageClass setup is required. GKE automatically creates thestandard-rwo (Balanced persistent disk) and premium-rwo (SSD persistent disk) StorageClasses using the pre-installed GCE PD CSI driver (pd.csi.storage.gke.io). These are exactly the classes the GCP base configuration selects (server -> standard-rwo, keeper -> premium-rwo), and both use volumeBindingMode: WaitForFirstConsumer, so a disk is provisioned automatically in the zone where its pod is scheduled — no explicit topology configuration is needed.
Only create a custom StorageClass if you need non-default disk parameters, and override server.storage.storageClassName / keeper.storage.storageClassName accordingly.
Step 8: Install the Operator
Log into the Artifact Registry from Helm (note: nohttps:// prefix), then install the operator. Set the availability zones to your cluster’s zones.
Step 9: Deploy a ClickHouse Cluster
Naming Your Cluster
Each ClickHouse cluster needs a unique name within the GKE cluster. Use the convention$DESCRIPTOR-$LETTERS-$ORDINAL:
$DESCRIPTOR— descriptive name using letters only$LETTERS— reserved, usexxfor simplicity$ORDINAL— incrementing ordinal starting with01- Example:
default-xx-01
Generate Password Hash and Deploy
Guaranteed QoS (recommended)ClickHouse workloads should run with matching
requests and limits for
both CPU and memory. The SERVER_CPU/SERVER_MEMORY/KEEPER_CPU/
KEEPER_MEMORY values set in Phase 0 are applied to both
resources.requests and resources.limits in the helm invocation below,
which places the pods in the Guaranteed
QoS class. If you need to run with a different QoS class, review
Pod QoS: Guaranteed (recommended)
first for the trade-offs.baseConfiguration.cloud="gcp"— loads the GCP base configuration. This setshttp_client=gcp_oauthon every server and keeper disk (so no per-disk overrides are needed), defaults the storage classes tostandard-rwo(server) andpremium-rwo(keeper), and setsserver.ssdCacheConfiguration.isOnEmptyDir=trueso the cache uses the node’s ephemeral local SSD.serviceAccount.annotations— annotates the chart-created KSA for Workload Identity. Combined with the IAM binding from Step 6, pods authenticate to GCS with no static credentials oruseEnvironmentCredentialsflag.server.storage.s3.endpoint="https://storage.googleapis.com"— GCS S3-compatible API endpoint.server.storage.s3.region="auto"— GCS does not use regions.server.arm64=false/keeper.arm64=false— the node pools use x86 (n2) machine types. The chart defaults to arm64, so setting thesefalsekeeps the arm64-preferred labels and tolerations off the x86 pods.
Step 10: Run Preflight Checks
To validate the readiness of your cluster we recommend running preflight checks. The preflight checks use Troubleshoot, a Kubernetes plugin for cluster diagnostics.Install the Plugin
Copy the Preflight Helm Chart
Add the preflight chart to your Artifact Registry:Run the Checks
Usehelm template to render the preflight spec, then pipe it to kubectl preflight:
Step 11: Verify Installation
Port-forward the ClickHouse Service
9000 to your local machine.
Connect and Run a Query
Next Steps
- FIPS / government compliance: See tutorials/deploy-government.md to apply FIPS 140-3 certificates and TLS configuration on top of this infrastructure.
- Compute-Compute separation: See how-to/configure-compute-compute-separation.md to set up multiple compute groups with separate endpoints sharing a single dataset.
- Management API: See tutorials/install-api.md to install the optional Private API for backups and scaling operations.
- Monitoring and alerting: See how-to/configure-alerting.md to set up alerting for your deployment.
- Troubleshooting: See troubleshooting.md for common issues and solutions.