Limited Time Offer: 40% off

ClickHouse Operator for Kubernetes

Deploy ClickHouse on Kubernetes with the official operator.

The ClickHouse Operator automates deploying and managing ClickHouse clusters on Kubernetes. Instead of writing StatefulSets, Services, and ConfigMaps by hand, you define a ClickHouseInstallation custom resource and the operator handles the rest.

There are two operators available:

  • Official ClickHouse Operator (by ClickHouse Inc.) is newer and under active development
  • Altinity Operator is the more mature option with wider production adoption

Both are open source under Apache 2.0. This guide covers both, with a focus on the Altinity Operator since it has a longer track record.

Installing the Altinity Operator

With Helm

BASH
helm repo add altinity https://altinity.github.io/clickhouse-operator
helm repo update

helm install clickhouse-operator altinity/altinity-clickhouse-operator \
  --namespace clickhouse \
  --create-namespace

With kubectl

BASH
kubectl apply -f https://raw.githubusercontent.com/Altinity/clickhouse-operator/master/deploy/operator/clickhouse-operator-install-bundle.yaml

Verify the operator is running:

BASH
kubectl get pods -n clickhouse

You should see the operator pod in a Running state.

Deploying a basic cluster

Create a file called clickhouse-cluster.yaml:

YAML
apiVersion: clickhouse.altinity.com/v1
kind: ClickHouseInstallation
metadata:
  name: my-cluster
  namespace: clickhouse
spec:
  configuration:
    clusters:
      - name: default
        layout:
          shardsCount: 1
          replicasCount: 1
  defaults:
    templates:
      dataVolumeClaimTemplate: data-volume
  templates:
    volumeClaimTemplates:
      - name: data-volume
        spec:
          accessModes:
            - ReadWriteOnce
          resources:
            requests:
              storage: 50Gi
          storageClassName: gp3

Apply it:

BASH
kubectl apply -f clickhouse-cluster.yaml

The operator creates the StatefulSet, Service, ConfigMap, and PersistentVolumeClaim automatically. Within a minute or two, your ClickHouse instance is ready.

Check the status:

BASH
kubectl get chi -n clickhouse

Connecting to the cluster

The operator creates a Service for each cluster. Find it with:

BASH
kubectl get svc -n clickhouse

For port-forwarding during development:

BASH
kubectl port-forward svc/clickhouse-my-cluster -n clickhouse 9000:9000 8123:8123

Port 9000 is the native TCP protocol. Port 8123 is the HTTP interface. You can connect with the clickhouse-client CLI, any PostgreSQL-compatible driver (via port 9004 if enabled), or a database management tool like DB Pro.

Multi-shard, multi-replica setup

For production, you typically want multiple shards (for horizontal scaling) and replicas (for high availability):

YAML
apiVersion: clickhouse.altinity.com/v1
kind: ClickHouseInstallation
metadata:
  name: production-cluster
  namespace: clickhouse
spec:
  configuration:
    zookeeper:
      nodes:
        - host: clickhouse-keeper-0.clickhouse-keeper.clickhouse.svc.cluster.local
          port: 2181
        - host: clickhouse-keeper-1.clickhouse-keeper.clickhouse.svc.cluster.local
          port: 2181
        - host: clickhouse-keeper-2.clickhouse-keeper.clickhouse.svc.cluster.local
          port: 2181
    clusters:
      - name: production
        layout:
          shardsCount: 2
          replicasCount: 2
    settings:
      max_memory_usage: 10000000000
      max_concurrent_queries: 200
    users:
      admin/password_sha256_hex: "<sha256-hash-of-password>"
      admin/networks/ip:
        - "10.0.0.0/8"
      readonly/password_sha256_hex: "<sha256-hash-of-password>"
      readonly/profile: readonly
  defaults:
    templates:
      dataVolumeClaimTemplate: data-volume
      podTemplate: clickhouse-pod
  templates:
    volumeClaimTemplates:
      - name: data-volume
        spec:
          accessModes:
            - ReadWriteOnce
          resources:
            requests:
              storage: 500Gi
          storageClassName: gp3
    podTemplates:
      - name: clickhouse-pod
        spec:
          containers:
            - name: clickhouse
              image: clickhouse/clickhouse-server:24.8
              resources:
                requests:
                  cpu: "4"
                  memory: "16Gi"
                limits:
                  cpu: "8"
                  memory: "32Gi"

This creates a 2-shard, 2-replica cluster (4 pods total). Each shard holds a portion of your data. Each replica is a copy within that shard.

Replication requires ClickHouse Keeper (or ZooKeeper). Deploy ClickHouse Keeper separately or use the operator's built-in support.

Deploying ClickHouse Keeper

ClickHouse Keeper replaces ZooKeeper for coordinating replicated tables. It's lighter weight and maintained by the ClickHouse team.

YAML
apiVersion: clickhouse-keeper.altinity.com/v1
kind: ClickHouseKeeperInstallation
metadata:
  name: clickhouse-keeper
  namespace: clickhouse
spec:
  configuration:
    clusters:
      - name: keeper
        layout:
          replicasCount: 3
  defaults:
    templates:
      dataVolumeClaimTemplate: keeper-data
  templates:
    volumeClaimTemplates:
      - name: keeper-data
        spec:
          accessModes:
            - ReadWriteOnce
          resources:
            requests:
              storage: 10Gi
          storageClassName: gp3

Always deploy an odd number of Keeper nodes (3 or 5) for proper quorum.

Configuration management

ClickHouse settings

Add settings under spec.configuration.settings:

YAML
spec:
  configuration:
    settings:
      max_memory_usage: 10000000000
      max_concurrent_queries: 200
      background_pool_size: 16
      merge_tree/max_bytes_to_merge_at_max_space_in_pool: 161061273600

The operator applies these to the ClickHouse config files and restarts pods if needed.

User management

Define users in the spec:

YAML
spec:
  configuration:
    users:
      analyst/password_sha256_hex: "abc123..."
      analyst/profile: readonly
      analyst/quota: default
      analyst/networks/ip:
        - "10.0.0.0/8"

Generate the SHA256 hash:

BASH
echo -n 'your-password' | sha256sum | cut -d' ' -f1

Custom config files

For advanced configuration, mount additional config files:

YAML
spec:
  configuration:
    files:
      config.d/storage.xml: |
        <clickhouse>
          <storage_configuration>
            <disks>
              <s3>
                <type>s3</type>
                <endpoint>https://s3.amazonaws.com/my-bucket/data/</endpoint>
                <use_environment_credentials>true</use_environment_credentials>
              </s3>
            </disks>
            <policies>
              <tiered>
                <volumes>
                  <hot>
                    <disk>default</disk>
                  </hot>
                  <cold>
                    <disk>s3</disk>
                  </cold>
                </volumes>
              </tiered>
            </policies>
          </storage_configuration>
        </clickhouse>

Scaling

Adding shards

Update shardsCount in the spec and apply:

BASH
kubectl apply -f clickhouse-cluster.yaml

The operator adds new pods without disrupting existing ones. Data doesn't redistribute automatically. You need to rebalance using ALTER TABLE ... MOVE PARTITION or by setting up a distributed table that includes the new shards.

Adding replicas

Update replicasCount and apply. New replicas clone data from existing replicas in the same shard. This happens automatically through ClickHouse's replication protocol.

Vertical scaling

Change the resource requests/limits in the pod template and apply. The operator performs a rolling restart, updating one pod at a time.

Upgrades

To upgrade ClickHouse, change the image tag in the pod template:

YAML
containers:
  - name: clickhouse
    image: clickhouse/clickhouse-server:24.12  # was 24.8

Apply the change. The operator performs a rolling upgrade, one pod at a time, waiting for each pod to become healthy before proceeding.

For major version upgrades, check the ClickHouse release notes for breaking changes. Test the upgrade in a staging environment first.

Monitoring

Prometheus metrics

ClickHouse exposes Prometheus metrics on port 9363 by default. Add a ServiceMonitor if you're using the Prometheus Operator:

YAML
apiVersion: monitoring.coreos.com/v1
kind: ServiceMonitor
metadata:
  name: clickhouse-metrics
  namespace: clickhouse
spec:
  selector:
    matchLabels:
      clickhouse.altinity.com/chi: my-cluster
  endpoints:
    - port: metrics
      interval: 30s

Key metrics to watch

  • ClickHouseMetrics_Query: Active queries
  • ClickHouseMetrics_Merge: Active merges
  • ClickHouseAsyncMetrics_MaxPartCountForPartition: Parts per partition (high values indicate merge pressure)
  • ClickHouseProfileEvents_InsertedRows: Insert throughput
  • ClickHouseMetrics_MemoryTracking: Memory usage

Backup and restore

The Altinity Operator integrates with clickhouse-backup, a tool for creating and restoring backups to S3 or GCS.

Add a backup sidecar to your pod template:

YAML
podTemplates:
  - name: clickhouse-pod
    spec:
      containers:
        - name: clickhouse
          image: clickhouse/clickhouse-server:24.8
        - name: clickhouse-backup
          image: altinity/clickhouse-backup:2.6
          env:
            - name: S3_BUCKET
              value: my-backup-bucket
            - name: S3_REGION
              value: us-east-1

Create a backup:

BASH
kubectl exec -n clickhouse chi-my-cluster-default-0-0-0 -c clickhouse-backup -- \
  clickhouse-backup create daily-backup
kubectl exec -n clickhouse chi-my-cluster-default-0-0-0 -c clickhouse-backup -- \
  clickhouse-backup upload daily-backup

Production checklist

Before running ClickHouse in production on Kubernetes:

Storage:

  • Use gp3 or io2 EBS volumes on AWS (not gp2)
  • Size volumes with 20-30% headroom for merges
  • Set allowVolumeExpansion: true on your StorageClass

Resources:

  • Set both requests and limits for CPU and memory
  • ClickHouse benefits from memory. Allocate at least 8 GB per node for production workloads
  • Use dedicated node pools for ClickHouse to avoid noisy neighbors

Networking:

  • Use topologySpreadConstraints or pod anti-affinity to spread replicas across availability zones
  • Configure NetworkPolicies to restrict access to ClickHouse ports

Reliability:

  • Deploy ClickHouse Keeper with 3 or 5 nodes across zones
  • Use PodDisruptionBudgets to prevent too many pods going down during maintenance
  • Test failover by killing pods and verifying replicas take over

Security:

  • Use SHA256 password hashes, not plaintext
  • Restrict user access by IP range
  • Enable TLS for client connections

Official ClickHouse Operator

The official operator (by ClickHouse Inc.) was released in 2025 and uses different CRDs:

YAML
apiVersion: clickhouse.com/v1
kind: ClickHouseCluster
metadata:
  name: my-cluster

Installation requires cert-manager:

BASH
kubectl apply -f https://github.com/cert-manager/cert-manager/releases/download/v1.16.0/cert-manager.yaml

helm repo add clickhouse https://docs.clickhouse.com/assets/helm/
helm install clickhouse-operator clickhouse/clickhouse-operator \
  --namespace clickhouse-operator-system \
  --create-namespace

The official operator is catching up in features. For new deployments, evaluate both operators. For existing production clusters, the Altinity Operator remains the safer choice due to its longer track record.

Quick reference

TaskCommand
Install operator (Helm)helm install clickhouse-operator altinity/altinity-clickhouse-operator
Deploy clusterkubectl apply -f clickhouse-cluster.yaml
Check statuskubectl get chi -n clickhouse
Port-forwardkubectl port-forward svc/clickhouse-my-cluster 9000:9000 8123:8123
Scale shardsEdit shardsCount and kubectl apply
UpgradeEdit image tag and kubectl apply
View logskubectl logs chi-my-cluster-default-0-0-0 -n clickhouse
Create backupkubectl exec ... -- clickhouse-backup create <name>