# ClickHouse Helm chart

> Helm chart for deploying clickhouse datastore

Source: https://zop.dev/integrations/clickhouse
Updated: 2026-09-11 · Tags: datasource, helm, kubernetes

---

The ClickHouse Helm chart provides an easy way to deploy and manage a [ClickHouse](https://clickhouse.com/) OLAP database in your Kubernetes environment. This chart includes configurations for persistence, resource management, built-in Prometheus metrics, and automatic provisioning of application databases and users.

## Prerequisites

- Kubernetes 1.19+
- Helm 3+
- [Stakater Reloader](https://github.com/stakater/Reloader) (optional, recommended) — required only for the pod to restart automatically when `customConfig` changes. See [Config changes and automatic restarts](#config-changes-and-automatic-restarts).

## Add Helm Repository

Before installing the ClickHouse chart, add the repository to your Helm installation and update the repository index:

```bash
helm repo add zopdev https://helm.zop.dev
helm repo update
```

See [Helm Repository Documentation](https://helm.sh/docs/helm/helm_repo/) for more details.

---

## Install Helm Chart

To install the ClickHouse Helm chart, run the following command:

```bash
helm install [RELEASE_NAME] zopdev/clickhouse
```

Replace `[RELEASE_NAME]` with your desired release name.

For example:

```bash
helm install my-clickhouse zopdev/clickhouse
```

You can customize the installation by providing a custom `values.yaml` file or overriding values via the command line.

See [Helm Install Documentation](https://helm.sh/docs/helm/helm_install/) for further details.

---

## Uninstall Helm Chart

To uninstall the ClickHouse Helm chart and remove all associated Kubernetes resources, run:

```bash
helm uninstall [RELEASE_NAME]
```

For example:

```bash
helm uninstall my-clickhouse
```

See [Helm Uninstall Documentation](https://helm.sh/docs/helm/helm_uninstall/) for more information.

---

## Configuration

The following table describes the configurable parameters of the ClickHouse Helm chart and their default values:

| **Input**                    | **Type**  | **Description**                                                                                       | **Default**     |
|------------------------------|-----------|-------------------------------------------------------------------------------------------------------|-----------------|
| `diskSize`                   | `string`  | Size of the persistent volume claim (PVC) for `/var/lib/clickhouse`.                                  | `"10Gi"`        |
| `version`                    | `string`  | ClickHouse server image tag (`clickhouse/clickhouse-server:<version>`).                               | `"25.3"`        |
| `resources.requests.cpu`     | `string`  | Minimum CPU resources required by the ClickHouse container.                                           | `"500m"`        |
| `resources.requests.memory`  | `string`  | Minimum memory resources required by the ClickHouse container.                                        | `"512M"`        |
| `resources.limits.cpu`       | `string`  | Maximum CPU resources the ClickHouse container can use.                                               | `"2000m"`       |
| `resources.limits.memory`    | `string`  | Maximum memory resources the ClickHouse container can use.                                            | `"2048M"`       |
| `customConfig`               | `string`  | Custom ClickHouse server XML, layered into `/etc/clickhouse-server/config.d/custom.xml`.              | `""`            |
| `services`                   | `array`   | List of `{ name, database }` entries; each provisions a database, a user, and a connection ConfigMap/Secret. | `[]`     |

You can override these values in your `values.yaml` file or pass them as flags when installing the chart.

### Example `values.yaml` File

```yaml
diskSize: "10Gi"

resources:
  requests:
    cpu: "500m"
    memory: "512M"
  limits:
    cpu: "2000m"
    memory: "2048M"

version: "25.3"

customConfig: ""

services:
  - name: orders
    database: analytics
```

To use this configuration, save it in a `values.yaml` file and pass it to the Helm install command:

```bash
helm install my-clickhouse zopdev/clickhouse -f values.yaml
```

### Example: Providing Custom ClickHouse Configuration

To override or add to the default ClickHouse configuration, provide your own XML using the `customConfig` value. The same document is mounted into **both** ClickHouse config trees:

- `/etc/clickhouse-server/config.d/custom.xml` — for **server-level** settings (e.g. `max_connections`, `max_server_memory_usage_to_ram_ratio`).
- `/etc/clickhouse-server/users.d/custom.xml` — for **profile / user** settings, which ClickHouse only loads from the users config tree (e.g. `max_memory_usage`, `max_bytes_before_external_group_by`, `max_bytes_before_external_sort`).

ClickHouse reads the relevant sections from each tree and ignores the rest, so you can place server settings and a `<profiles>` block in one document:

```yaml
customConfig: |
  <clickhouse>
    <max_connections>2048</max_connections>
    <max_concurrent_queries>200</max_concurrent_queries>
    <max_server_memory_usage_to_ram_ratio>0.9</max_server_memory_usage_to_ram_ratio>
    <profiles>
      <default>
        <max_memory_usage>1500000000</max_memory_usage>
        <max_bytes_before_external_group_by>750000000</max_bytes_before_external_group_by>
        <max_bytes_before_external_sort>750000000</max_bytes_before_external_sort>
      </default>
    </profiles>
  </clickhouse>
```

### Config changes and automatic restarts

`customConfig` (and the bundled Prometheus config) is mounted using `subPath`. Kubernetes never live-updates `subPath` mounts, so a `helm upgrade` that changes `customConfig` updates the ConfigMap but the **running pod keeps the old file until it restarts**.

The StatefulSet is annotated for [Stakater Reloader](https://github.com/stakater/Reloader). The `-clickhouse-prometheus` ConfigMap is always watched; `-clickhouse-custom-config` is added to the list only when `customConfig` is set (it isn't created otherwise):

```yaml
# customConfig set:
configmap.reloader.stakater.com/reload: "<release>-clickhouse-prometheus,<release>-clickhouse-custom-config"
# customConfig unset:
configmap.reloader.stakater.com/reload: "<release>-clickhouse-prometheus"
```

If the Reloader controller is running in the cluster, it detects the ConfigMap change and triggers a rolling restart automatically. **If Reloader is not installed, the annotation is a no-op** — the config change silently won't take effect until you restart the pod yourself:

```bash
kubectl rollout restart statefulset/<release>-clickhouse
```

---

## Provisioning Databases and Users

Use the `services` array to provision one database and user per application. For each entry the chart creates:

- the database (`CREATE DATABASE IF NOT EXISTS`),
- a dedicated user with `SELECT, INSERT, ALTER, CREATE, DROP, TRUNCATE, OPTIMIZE` on that database,
- a `ConfigMap` (`<release>-<database>-<name>-clickhouse-configmap`) with the connection details, and
- a `Secret` (`<release>-<database>-<name>-clickhouse-database-secret`) holding the user's password.

A short-lived init `Pod` (`clickhouse-init-<release>-<name>`) applies the SQL via `clickhouse-client`. Generated credentials are preserved across upgrades by reading back the existing secret.

---

## Ports

| Port   | Name          | Purpose                                  |
|--------|---------------|------------------------------------------|
| `8123` | `http`        | HTTP interface (and `/ping` health check)|
| `9000` | `native`      | Native TCP protocol (used by drivers)    |
| `9009` | `interserver` | Inter-server data exchange               |
| `9363` | `metrics`     | Built-in Prometheus metrics (`/metrics`) |

---

## Features

- **Persistence:** Data is stored on a persistent volume claim, surviving pod restarts.
- **Customizable Resources:** Define resource requests and limits to optimize performance and manage costs.
- **Built-in Metrics:** ClickHouse's native Prometheus exporter is enabled on port `9363`; a `ServiceMonitor` and `PrometheusRule` are bundled.
- **Automatic Provisioning:** Declaratively create databases and users via the `services` value.
- **Health Probes:** Liveness and readiness probes use the `/ping` HTTP endpoint.

---

## Monitoring

The chart enables ClickHouse's built-in Prometheus endpoint (no sidecar exporter required) and ships:

- a `ServiceMonitor` scraping the `metrics-port` (`/metrics`, 30s interval), and
- a `PrometheusRule` with alerts for instance down, recent restart, rejected inserts, and excessive connections.

---

## Pod Scheduling

`nodeSelector`, `tolerations` and `affinity` are passed straight through to the pod spec. All three are empty by default and render nothing, so leaving them unset changes nothing for an existing release.

Together they place the workload on a dedicated node pool — the `nodeSelector` picks the pool, the toleration gets past its taint:

```yaml
nodeSelector:
  workload: stateful

tolerations:
  - key: workload
    operator: Equal
    value: stateful
    effect: NoSchedule
```

`affinity` takes a full [Affinity](https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/#affinity-and-anti-affinity) object and is rendered verbatim.

---

## Contributing

We welcome contributions to improve this Helm chart. Please refer to the [CONTRIBUTING.md](https://github.com/zopdev/helm-charts/blob/main/CONTRIBUTING.md) file for guidelines.

---

## Code of Conduct

To ensure a respectful and collaborative community, please adhere to our [Code of Conduct](https://github.com/zopdev/helm-charts/blob/main/CODE_OF_CONDUCT.md).

---

## License

This project is licensed under the [LICENSE](https://github.com/zopdev/helm-charts/blob/main/LICENSE). Please review it for terms of use.

---

## Connection Config

The connection `ConfigMap`/`Secret` expose `CH_*` keys (the consumer combines
`CH_HOST:CH_PORT` into GoFr's ClickHouse `Hosts`, see
[gofr.dev/docs/datasources/clickhouse](https://gofr.dev/docs/datasources/clickhouse)):

- **CH_HOST** : Hostname/service name of the ClickHouse server (`<release>-clickhouse`).
- **CH_PORT** : Native TCP port. Defaults to `9000`. (HTTP clients use `8123`.)
- **CH_USER** : Username used to connect to the ClickHouse database.
- **CH_DATABASE** : The name of the specific database to connect to.
- **CH_PASSWORD** : The password for `CH_USER`, stored securely in a Kubernetes secret.

---
