Skip to main content
This tutorial walks you through deploying ClickHouse Private on Google Cloud Platform using Google Kubernetes Engine (GKE), step by step. By the end, you will have a running ClickHouse cluster with GCS-backed storage, ephemeral local-SSD caching, and the ClickHouse operator managing the deployment. For FIPS 140-3 / FedRAMP deployments, follow this guide for the GKE infrastructure, then apply the FIPS certificate and TLS configuration from Deploy with FIPS Compliance and Configure FIPS certificates. For detailed infrastructure specifications, see reference/infrastructure-requirements.md. For an overview of how the operator works, see explanation/architecture.md.

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
You will also need:
  • 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 kubectl and 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.
The rest of this guide refers to the repository host as $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).
Verify the copy:

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
  • /14 blocks: the third octet must be divisible by 4 (e.g. 10.244.0.0, not 10.245.0.0)
  • /20 blocks: the fourth octet must be 0 and the third octet on a 16-boundary (e.g. 10.252.0.0)
For example, creating the subnet with both secondary ranges and Private Google Access:
Private nodes have no public IPs, so outbound internet access (for example, to pull the VolumeSnapshot CRDs in Step 7) requires Cloud NAT. Create a Cloud Router in the region and attach a Cloud NAT gateway covering all subnet ranges. See reference/infrastructure-requirements.md for detailed networking requirements.

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 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:
For example an 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.
For example, creating the server pool with an ephemeral local SSD:

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.
Do not create GCS Object Lifecycle Management rules on this bucketClickHouse manages its own data in GCS. Object Lifecycle Management policies (Delete, SetStorageClass) will delete or transition objects that ClickHouse still depends on, causing data loss and cluster outages. To manage data retention, use ClickHouse TTL rules and partition operations instead. See Manage data lifecycle.

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 named ch-$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.
Workload Identity alignment:

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 the standard-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: no https:// 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, use xx for simplicity
  • $ORDINAL — incrementing ordinal starting with 01
  • 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.
Important GCP-specific settings:
  • baseConfiguration.cloud="gcp" — loads the GCP base configuration. This sets http_client=gcp_oauth on every server and keeper disk (so no per-disk overrides are needed), defaults the storage classes to standard-rwo (server) and premium-rwo (keeper), and sets server.ssdCacheConfiguration.isOnEmptyDir=true so 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 or useEnvironmentCredentials flag.
  • 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 these false keeps the arm64-preferred labels and tolerations off the x86 pods.
Monitor the rollout (the operator creates server pods after keepers are healthy):

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

Use helm template to render the preflight spec, then pipe it to kubectl preflight:
This validates node labels, StorageClass configuration, and other requirements. The output shows each check and its status. If a check fails, it includes recommendations on how to fix the issue. For more details see the How To: Run Preflight Checks page.

Step 11: Verify Installation

Port-forward the ClickHouse Service

This forwards port 9000 to your local machine.

Connect and Run a Query

Run a simple query:
Expected output:

Next Steps


Appendix: AWS to GCP Component Mapping

Last modified on August 7, 2026