Skip to main content

ClickHouse Operator configuration guide

This guide covers how to configure ClickHouse and Keeper clusters using the operator.

ClickHouseCluster configuration

Basic configuration

apiVersion: clickhouse.com/v1alpha1
kind: ClickHouseCluster
metadata:
  name: my-cluster
spec:
  replicas: 3           # Number of replicas per shard
  shards: 2             # Number of shards
  keeperClusterRef:
    name: my-keeper     # Reference to KeeperCluster
  dataVolumeClaimSpec:
    resources:
      requests:
        storage: 10Gi

Replicas and shards

  • Replicas: Number of ClickHouse instances per shard (for high availability)
  • Shards: Number of horizontal partitions (for scaling)
spec:
  replicas: 3  # Default: 3
  shards: 2    # Default: 1
A cluster with replicas: 3 and shards: 2 will create 6 ClickHouse pods total.

Keeper integration

Every ClickHouse cluster must reference a KeeperCluster for coordination:
spec:
  keeperClusterRef:
    name: my-keeper
    # namespace: keeper-system  # Optional, defaults to the ClickHouseCluster namespace
When keeperClusterRef.namespace is set, the operator must watch both namespaces. If WATCH_NAMESPACE is configured, include the ClickHouse and Keeper namespaces in that list.

KeeperCluster configuration

apiVersion: clickhouse.com/v1alpha1
kind: KeeperCluster
metadata:
  name: my-keeper
spec:
  replicas: 3  # Must be odd: 1, 3, 5, 7, 9, 11, 13, or 15
  dataVolumeClaimSpec:
    resources:
      requests:
        storage: 5Gi

Storage configuration

Configure persistent storage:
spec:
  dataVolumeClaimSpec:
    storageClassName: fast-ssd  # Optional: consider your storage class based on the installed CSI
    resources:
      requests:
        storage: 100Gi
Operator can modify existing PVC only if the underlying storage class supports volume expansion.

Pod configuration

Automatic topology spread and affinity

Distribute pods across availability zones:
spec:
  podTemplate:
    topologyZoneKey: topology.kubernetes.io/zone
    nodeHostnameKey: kubernetes.io/hostname
Ensure your Kubernetes cluster has enough nodes in different zones to satisfy the spread constraints.

Manual configuration

Arbitrary pod affinity/anti-affinity rules and topology spread constraints can be specified.
spec:
  podTemplate:
    affinity:
      <your-affinity-rules-here>
    topologySpreadConstraints:
      <your-topology-spread-constraints-here>

See API Reference for all supported Pod template options.

Pod disruption budgets

The operator creates a PodDisruptionBudget (PDB) for each cluster so that voluntary disruptions — node drains, rolling upgrades, autoscaler evictions — cannot take down enough pods to lose quorum or break availability. For ClickHouse clusters with more than one shard, one PDB is created per shard so a disruption in one shard cannot count against another.

Defaults

The operator picks safe defaults based on the cluster size so that a fresh apply already protects against accidental quorum loss.
ResourceTopologyDefault PDB
ClickHouseClusterreplicas: 1 (single-replica shard)maxUnavailable: 1 — disruption is allowed for a single-node cluster so that node drains are not blocked
ClickHouseClusterreplicas: 2+ (multi-replica shard)minAvailable: 1 — at least one replica per shard must stay up
KeeperClusterreplicas: 1maxUnavailable: 1 — disruption is allowed for a single-node cluster so that node drains are not blocked
KeeperClusterreplicas: 3+maxUnavailable: replicas/2 — preserves the RAFT quorum for a 2F+1 cluster (3 replicas tolerate 1 down, 5 replicas tolerate 2 down)
For a 3-shard ClickHouseCluster with replicas: 3, the operator creates three PDBs, one per shard, each with minAvailable: 1.

Overriding the defaults

Use spec.podDisruptionBudget to override either minAvailable or maxUnavailable (exactly one):
spec:
  replicas: 3
  shards: 2
  podDisruptionBudget:
    minAvailable: 2   # keep at least 2 of 3 replicas in every shard up during a disruption
Or the maxUnavailable form, with a percentage:
spec:
  replicas: 5
  podDisruptionBudget:
    maxUnavailable: 40%
Setting both minAvailable and maxUnavailable is rejected by the validating webhook. Pick one — Kubernetes itself does not allow both either.
You can also pass the unhealthyPodEvictionPolicy field through to the generated PDB — useful when you need to allow eviction of pods that are still in NotReady:
spec:
  podDisruptionBudget:
    minAvailable: 2
    unhealthyPodEvictionPolicy: AlwaysAllow

Policies

spec.podDisruptionBudget.policy lets you choose how aggressively the operator manages PDBs:
PolicyBehavior
Enabled (default)The operator creates and updates the PDB on every reconcile. This is the safe production default.
DisabledThe operator does not create PDBs and deletes any existing ones with matching labels. Useful for development clusters where every voluntary disruption should be allowed.
IgnoredThe operator neither creates nor deletes PDBs. Existing PDBs are left alone. Use this when another system (e.g. policy admission, GitOps tool) owns PDB management for you.
Example — disable PDB management completely on a development cluster:
spec:
  podDisruptionBudget:
    policy: Disabled
Example — keep your hand-crafted PDB next to the cluster and stop the operator from touching it:
spec:
  podDisruptionBudget:
    policy: Ignored

Cluster-wide opt-out

PDB management can also be disabled cluster-wide via the operator’s ENABLE_PDB environment variable. With ENABLE_PDB=false, the operator skips the PDB reconcile step for every ClickHouseCluster and KeeperCluster regardless of their spec.podDisruptionBudget.policy, and does not watch PodDisruptionBudget resources at all. The operator’s ServiceAccount therefore does not need RBAC permissions on poddisruptionbudgets.policy/v1, which is useful when running the operator under a restricted ServiceAccount that intentionally omits those permissions.
# in the operator Deployment spec
env:
- name: ENABLE_PDB
  value: "false"
This is intended for environments that ship their own disruption policies (e.g. through Gatekeeper / Kyverno) and want the operator out of the loop entirely.

Container configuration

Custom image

Use a specific ClickHouse image:
spec:
  containerTemplate:
    image:
      repository: clickhouse/clickhouse-server
      tag: "25.12"
    imagePullPolicy: IfNotPresent

Container resources

Configure CPU and memory for ClickHouse containers:
# default values
spec:
  containerTemplate:
    resources:
      requests:
        cpu: "250m"
        memory: "256Mi"
      limits:
        cpu: "1"
        memory: "1Gi"

Environment variables

Add custom environment variables:
spec:
  containerTemplate:
    env:
    - name: CUSTOM_ENV_VAR
      value: "1"

Volume mounts

Add additional volume mounts:
spec:
  containerTemplate:
    volumeMounts:
    - name: custom-config
      mountPath: /etc/clickhouse-server/config.d/custom.xml
      subPath: custom.xml
It is allowed to specify multiple volume mounts to the same mountPath. Operator will create projected volume with all specified mounts.

See API Reference for all supported Container template options.

TLS/SSL configuration

Configure secure endpoints

Pass a reference to a Kubernetes Secret containing TLS certificates to enable secure endpoints
spec:
  settings:
    tls:
      enabled: true
      required: true # Insecure ports are disabled if set
      serverCertSecret:
        name: <certificate-secret-name>

SSL certificate secret format

It is expected that the Secret contains the following keys:
  • tls.crt - PEM encoded server certificate
  • tls.key - PEM encoded private key
  • ca.crt - PEM encoded CA certificate chain
This format is compatible with cert-manager generated certificates.

ClickHouse-Keeper communication over TLS

If KeeperCluster has TLS enabled, ClickHouseCluster would use secure connection to Keeper nodes automatically. ClickHouseCluster should be able to verify Keeper nodes certificates. If ClickHouseCluster has TLS enabled, is uses ca.crt bundle for verification. Otherwise, default CA bundle is used. User may provide a custom CA bundle reference:
spec:
    settings:
        tls:
          caBundle:
            name: <ca-certificate-secret-name>
            key: <ca-certificate-key>

ClickHouse settings

Default user password

Set the default user password:
spec:
  settings:
    defaultUserPassword:
      passwordType: <password-type> # Default: password
      <secret|configMap>:
        name: <resource name>
        key: <password>
It isn’t recommended to use ConfigMap to store plain text passwords.
Create the secret:
kubectl create secret generic clickhouse-password --from-literal=password='your-secure-password'

Using ConfigMap for user passwords

You can also use ConfigMap for non-sensitive default passwords:
spec:
  settings:
    defaultUserPassword:
      passwordType: password_sha256_hex
      configMap:
        name: clickhouse-config
        key: default_password

Custom users in configuration

Configure additional users in configuration files. Create a ConfigMap and Secret for user:
apiVersion: v1
kind: ConfigMap
metadata:
  name: user-config
data:
  reader.yaml: |
    users:
      reader:
        password:
          - '@from_env': READER_PASSWORD
        profile: default
        grants:
          - query: "GRANT SELECT ON *.*"
---
apiVersion: v1
kind: Secret
metadata:
  name: reader-password
data:
  password: "c2VjcmV0LXBhc3N3b3Jk"  # base64("secret-password")

Add custom configuration to ClickHouseCluster:
spec:
  podTemplate:
    volumes:
      - name: reader-user
        configMap:
          name: user-config
  containerTemplate:
    env:
      - name: READER_PASSWORD
        valueFrom:
          secretKeyRef:
            name: reader-password
            key: password
    volumeMounts:
      - mountPath: /etc/clickhouse-server/users.d/
        name: reader-user
        readOnly: true

Database sync

Enable automatic database synchronization for new replicas:
spec:
  settings:
    enableDatabaseSync: true  # Default: true
When enabled, the operator synchronizes Replicated and integration tables to new replicas.

Custom configuration

Embedded extra configuration

Instead of mounting custom configuration files, you can directly specify additional ClickHouse configuration options. Add custom ClickHouse configuration using extraConfig:
spec:
  settings:
    extraConfig:
      background_pool_size: 20

Embedded extra users configuration

You can also specify additional ClickHouse users configuration using extraUsersConfig. This is useful for defining users, profiles, quotas, and grants directly in the cluster specification.
spec:
  settings:
    extraUsersConfig:
      users:
        analyst:
          password:
            - '@from_env': ANALYST_PASSWORD
          profile: "readonly"
          quota: "default"
      profiles:
        readonly:
          readonly: 1
          max_memory_usage: 10000000000
      quotas:
        default:
          interval:
            duration: 3600
            queries: 1000
            errors: 100
The extraUsersConfig is stored in k8s ConfigMap object. Avoid plain text secrets there.

See documentation for all supported ClickHouse users configuration options.

Configuration example

Complete configuration example:
apiVersion: clickhouse.com/v1alpha1
kind: KeeperCluster
metadata:
  name: sample
spec:
  replicas: 3
  dataVolumeClaimSpec:
    storageClassName: <storage-class-name>
    resources:
      requests:
        storage: 10Gi
  podTemplate:
    topologyZoneKey: topology.kubernetes.io/zone
    nodeHostnameKey: kubernetes.io/hostname
  containerTemplate:
    resources:
      requests:
        cpu: "2"
        memory: "4Gi"
      limits:
        cpu: "4"
        memory: "8Gi"
  settings:
    tls:
      enabled: true
      required: true
      serverCertSecret:
        name: <keeper-certificate-secret>
---
apiVersion: v1
kind: ConfigMap
metadata:
  name: default-user-password
data:
  # secret-password
  password: "..." # sha256 hex of the password
---
apiVersion: clickhouse.com/v1alpha1
kind: ClickHouseCluster
metadata:
  name: sample
spec:
  replicas: 2
  dataVolumeClaimSpec:
    storageClassName: <storage-class-name>
    resources:
      requests:
        storage: 200Gi
  keeperClusterRef:
    name: sample
  podTemplate:
    topologyZoneKey: topology.kubernetes.io/zone
    nodeHostnameKey: kubernetes.io/hostname
  settings:
    tls:
      enabled: true
      required: true
      serverCertSecret:
        name: clickhouse-cert
    defaultUserPassword:
      passwordType: password_sha256_hex
      configMap:
        key: password
        name: default-password
Last modified on June 8, 2026