> ## Documentation Index
> Fetch the complete documentation index at: https://private-7c7dfe99-home-button.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Руководство по настройке ClickHouse Operator

> В этом руководстве рассказывается, как настроить кластеры ClickHouse и Keeper с помощью ClickHouse Operator.

В этом руководстве рассказывается, как настроить кластеры ClickHouse и Keeper с помощью оператора.

<div id="clickhousecluster-configuration">
  ## Конфигурация ClickHouseCluster
</div>

<div id="basic-configuration">
  ### Базовая конфигурация
</div>

```yaml theme={null}
apiVersion: clickhouse.com/v1alpha1
kind: ClickHouseCluster
metadata:
  name: my-cluster
spec:
  replicas: 3           # Количество реплик на сегмент
  shards: 2             # Количество сегментов
  keeperClusterRef:
    name: my-keeper     # Ссылка на KeeperCluster
  dataVolumeClaimSpec:
    resources:
      requests:
        storage: 10Gi
```

<div id="replicas-and-shards">
  ### Реплики и сегменты
</div>

* **Реплики**: Количество экземпляров ClickHouse в каждом сегменте (для высокой доступности)
* **Сегменты**: Количество горизонтальных сегментов (для масштабирования)

```yaml theme={null}
spec:
  replicas: 3  # По умолчанию: 3
  shards: 2    # По умолчанию: 1
```

Кластер с `replicas: 3` и `shards: 2` создаст всего 6 подов ClickHouse.

<div id="keeper-integration">
  ### Интеграция с Keeper
</div>

Для координации в каждом кластере ClickHouse должен быть указан KeeperCluster:

```yaml theme={null}
spec:
  keeperClusterRef:
    name: my-keeper
    # namespace: keeper-system  # Необязательно, по умолчанию используется пространство имён ClickHouseCluster
```

Когда задан `keeperClusterRef.namespace`, оператор должен отслеживать оба пространства имен. Если настроена переменная `WATCH_NAMESPACE`, включите в этот список пространства имен ClickHouse и Keeper.

<div id="keepercluster-configuration">
  ## Конфигурация KeeperCluster
</div>

```yaml theme={null}
apiVersion: clickhouse.com/v1alpha1
kind: KeeperCluster
metadata:
  name: my-keeper
spec:
  replicas: 3  # Должно быть нечётным: 1, 3, 5, 7, 9, 11, 13 или 15
  dataVolumeClaimSpec:
    resources:
      requests:
        storage: 5Gi
```

<div id="storage-configuration">
  ## Конфигурация хранилища
</div>

Настройте постоянное хранилище:

```yaml theme={null}
spec:
  dataVolumeClaimSpec:
    storageClassName: fast-ssd  # Необязательно: укажите класс хранилища в соответствии с установленным CSI
    resources:
      requests:
        storage: 100Gi
```

<Note>
  Оператор может изменять существующий PVC, только если используемый класс хранилища поддерживает расширение томов.
</Note>

<div id="pod-configuration">
  ## Настройка пода
</div>

<div id="automatic-topology-spread-and-affinity">
  ### Автоматическое топологическое распределение и аффинность
</div>

Распределите поды по зонам доступности:

```yaml theme={null}
spec:
  podTemplate:
    topologyZoneKey: topology.kubernetes.io/zone
    nodeHostnameKey: kubernetes.io/hostname
```

<Note>
  Убедитесь, что в вашем кластере Kubernetes достаточно узлов в разных зонах, чтобы выполнить требования к распределению.
</Note>

<div id="manual-configuration">
  ### Ручная конфигурация
</div>

Можно указать произвольные правила affinity/anti-affinity для подов и ограничения на распределение по топологии.

```yaml theme={null}
spec:
  podTemplate:
    affinity:
      <your-affinity-rules-here>
    topologySpreadConstraints:
      <your-topology-spread-constraints-here>
```

<div id="see-api-referenceproductskubernetes-operatorreferenceapi-referencepodtemplatespec-for-all-supported-pod-template-options">
  ### Все поддерживаемые параметры шаблона пода см. в [справочнике по API](/ru/products/kubernetes-operator/reference/api-reference#podtemplatespec).
</div>

<div id="pod-disruption-budgets">
  ## Бюджеты сбоев подов
</div>

Оператор создает [PodDisruptionBudget](https://kubernetes.io/docs/concepts/workloads/pods/disruptions/) (PDB) для каждого кластера, чтобы плановые нарушения работы — дренирование узлов, поэтапные обновления, вытеснение автоскейлером — не могли вывести из строя достаточно подов, чтобы потерять кворум или нарушить доступность.

Для кластеров ClickHouse с более чем одним сегментом **создается один PDB на каждый сегмент**, чтобы сбой в одном сегменте не учитывался в другом.

<div id="pdb-defaults">
  ### Значения по умолчанию
</div>

Оператор выбирает безопасные значения по умолчанию с учётом размера кластера, чтобы уже после первого `apply` защитить его от случайной потери кворума.

| Ресурс              | Топология                                        | PDB по умолчанию                                                                                                                   |
| ------------------- | ------------------------------------------------ | ---------------------------------------------------------------------------------------------------------------------------------- |
| `ClickHouseCluster` | `replicas: 1` (сегмент с одной репликой)         | `maxUnavailable: 1` — для кластера из одного узла прерывание допускается, чтобы не блокировать дренирование узлов                  |
| `ClickHouseCluster` | `replicas: 2+` (сегмент с несколькими репликами) | `minAvailable: 1` — в каждом сегменте должна оставаться доступной как минимум одна реплика                                         |
| `KeeperCluster`     | `replicas: 1`                                    | `maxUnavailable: 1` — для кластера из одного узла прерывание допускается, чтобы не блокировать дренирование узлов                  |
| `KeeperCluster`     | `replicas: 3+`                                   | `maxUnavailable: replicas/2` — сохраняет кворум RAFT для кластера `2F+1` (3 реплики допускают отказ 1, 5 реплик допускают отказ 2) |

Для ClickHouseCluster с 3 сегментами и `replicas: 3` оператор создаёт три PDB — по одному на каждый сегмент, каждый с `minAvailable: 1`.

<div id="pdb-overrides">
  ### Переопределение значений по умолчанию
</div>

Используйте `spec.podDisruptionBudget`, чтобы переопределить либо `minAvailable`, либо `maxUnavailable` (ровно одно из них):

```yaml theme={null}
spec:
  replicas: 3
  shards: 2
  podDisruptionBudget:
    minAvailable: 2   # сохранять не менее 2 из 3 реплик в каждом сегменте работоспособными во время сбоя
```

Или вариант `maxUnavailable` с указанием в процентах:

```yaml theme={null}
spec:
  replicas: 5
  podDisruptionBudget:
    maxUnavailable: 40%
```

<Warning>
  Одновременная установка `minAvailable` и `maxUnavailable` отклоняется валидирующим вебхуком. Выберите что-то одно — сам Kubernetes тоже не разрешает задавать оба параметра одновременно.
</Warning>

Вы также можете передать поле [`unhealthyPodEvictionPolicy`](https://kubernetes.io/docs/concepts/workloads/pods/disruptions/#unhealthy-pod-eviction-policy) в сгенерированный PDB — это полезно, если нужно разрешить вытеснение подов, которые всё ещё находятся в состоянии `NotReady`:

```yaml theme={null}
spec:
  podDisruptionBudget:
    minAvailable: 2
    unhealthyPodEvictionPolicy: AlwaysAllow
```

<div id="pdb-policies">
  ### Политики
</div>

`spec.podDisruptionBudget.policy` позволяет выбрать, **насколько активно** оператор управляет PDB:

| Policy                   | Behavior                                                                                                                                                                                           |
| ------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `Enabled` (по умолчанию) | Оператор создает и обновляет PDB при каждой сверке. Это безопасный вариант по умолчанию для production-сред.                                                                                       |
| `Disabled`               | Оператор **не** создает PDB и **удаляет** все существующие PDB с совпадающими метками. Полезно для кластеров разработки, где должны быть разрешены любые плановые прерывания.                      |
| `Ignored`                | Оператор не создает и не удаляет PDB. Существующие PDB остаются без изменений. Используйте это, если управлением PDB занимается другая система (например, admission policy или инструмент GitOps). |

Пример — полностью отключить управление PDB в кластере разработки:

```yaml theme={null}
spec:
  podDisruptionBudget:
    policy: Disabled
```

Пример — оставьте созданный вручную PDB рядом с кластером и не позволяйте оператору его затрагивать:

```yaml theme={null}
spec:
  podDisruptionBudget:
    policy: Ignored
```

<div id="pdb-cluster-wide-disable">
  ### Отключение на уровне всего кластера
</div>

Управление PDB также можно отключить на уровне всего кластера через переменную окружения оператора `ENABLE_PDB`. При `ENABLE_PDB=false` оператор пропускает шаг сверки PDB для **всех** ClickHouseCluster и KeeperCluster независимо от их `spec.podDisruptionBudget.policy` и **вообще не отслеживает** ресурсы `PodDisruptionBudget`. Поэтому ServiceAccount оператора не нужны разрешения RBAC на `poddisruptionbudgets.policy/v1`, что полезно, если оператор запускается с ограниченным ServiceAccount, в котором эти разрешения намеренно отсутствуют.

```yaml theme={null}
# в спецификации Развертывания оператора
env:
- name: ENABLE_PDB
  value: "false"
```

Это предназначено для сред, где используются собственные политики disruption (например, через Gatekeeper / Kyverno) и где оператор должен быть полностью исключён из процесса.

<div id="container-configuration">
  ## Настройка контейнера
</div>

<div id="custom-image">
  ### Собственный образ
</div>

Используйте конкретный образ ClickHouse:

```yaml theme={null}
spec:
  containerTemplate:
    image:
      repository: clickhouse/clickhouse-server
      tag: "25.12"
    imagePullPolicy: IfNotPresent
```

<div id="container-resources">
  ### Ресурсы контейнеров
</div>

Настройте CPU и память для контейнеров ClickHouse:

```yaml theme={null}
# значения по умолчанию
spec:
  containerTemplate:
    resources:
      requests:
        cpu: "250m"
        memory: "256Mi"
      limits:
        cpu: "1"
        memory: "1Gi"
```

<div id="environment-variables">
  ### Переменные окружения
</div>

Добавьте пользовательские переменные окружения:

```yaml theme={null}
spec:
  containerTemplate:
    env:
    - name: CUSTOM_ENV_VAR
      value: "1"
```

<div id="volume-mounts">
  ### Подключение томов
</div>

Добавьте дополнительные точки монтирования томов:

```yaml theme={null}
spec:
  containerTemplate:
    volumeMounts:
    - name: custom-config
      mountPath: /etc/clickhouse-server/config.d/custom.xml
      subPath: custom.xml
```

<Note>
  Допускается указывать несколько подключений томов к одному и тому же `mountPath`.
  Оператор создаст projected volume со всеми указанными подключениями.
</Note>

<div id="see-api-referenceproductskubernetes-operatorreferenceapi-referencecontainertemplatespec-for-all-supported-container-template-options">
  ### Все поддерживаемые параметры шаблона контейнера см. в [справочнике по API](/ru/products/kubernetes-operator/reference/api-reference#containertemplatespec).
</div>

<div id="tls-ssl-configuration">
  ## Настройка TLS/SSL
</div>

<div id="configure-secure-endpoints">
  ### Настройка защищённых конечных точек
</div>

Укажите ссылку на Secret Kubernetes с TLS-сертификатами, чтобы включить защищённые конечные точки

```yaml theme={null}
spec:
  settings:
    tls:
      enabled: true
      required: true # Незащищённые порты отключаются при установке этого параметра
      serverCertSecret:
        name: <certificate-secret-name>
```

<div id="ssl-certificate-secret-format">
  ### Формат Secret с SSL-сертификатом
</div>

Предполагается, что Secret содержит следующие ключи:

* `tls.crt` - серверный сертификат в PEM-формате
* `tls.key` - приватный ключ в PEM-формате
* `ca.crt` - цепочка CA‑сертификатов в PEM-формате

<Note>
  Этот формат совместим с сертификатами, созданными cert-manager.
</Note>

<div id="clickhouse-keeper-communication-over-tls">
  ### Взаимодействие ClickHouse-Keeper по TLS
</div>

Если в KeeperCluster включен TLS, ClickHouseCluster будет автоматически использовать защищенное соединение с узлами Keeper.

ClickHouseCluster должен иметь возможность проверять сертификаты узлов Keeper.
Если в ClickHouseCluster включен TLS, для проверки используется комплект `ca.crt`. В противном случае используется комплект CA по умолчанию.

Пользователь может указать ссылку на пользовательский комплект CA:

```yaml theme={null}
spec:
    settings:
        tls:
          caBundle:
            name: <ca-certificate-secret-name>
            key: <ca-certificate-key>
```

<div id="clickhouse-settings">
  ## Настройки ClickHouse
</div>

<div id="default-user-password">
  ### Пароль пользователя по умолчанию
</div>

Задайте пароль пользователя по умолчанию:

```yaml theme={null}
spec:
  settings:
    defaultUserPassword:
      passwordType: <password-type> # По умолчанию: password
      <secret|configMap>:
        name: <resource name>
        key: <password>
```

<Note>
  Не рекомендуется использовать ConfigMap для хранения паролей в открытом виде.
</Note>

Создайте secret:

```bash theme={null}
kubectl create secret generic clickhouse-password --from-literal=password='your-secure-password'
```

<div id="using-configmap-for-user-passwords">
  #### Использование ConfigMap для паролей пользователей
</div>

Вы также можете использовать ConfigMap для паролей по умолчанию, не содержащих конфиденциальных данных:

```yaml theme={null}
spec:
  settings:
    defaultUserPassword:
      passwordType: password_sha256_hex
      configMap:
        name: clickhouse-config
        key: default_password
```

<div id="custom-users-in-configuration">
  ### Дополнительные пользователи в конфигурации
</div>

Настройте дополнительных пользователей в файлах конфигурации.

Создайте ConfigMap и Secret для пользователя:

```yaml theme={null}
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")

```

Добавьте пользовательскую конфигурацию в ClickHouseCluster:

```yaml theme={null}
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
```

<div id="database-sync">
  ### Синхронизация базы данных
</div>

Включите автоматическую синхронизацию базы данных для новых реплик:

```yaml theme={null}
spec:
  settings:
    enableDatabaseSync: true  # По умолчанию: true
```

Когда эта настройка включена, оператор синхронизирует таблицы Replicated и интеграционные таблицы на новые реплики.

<div id="custom-configuration">
  ## Пользовательская конфигурация
</div>

<div id="embedded-extra-configuration">
  ### Встроенная дополнительная конфигурация
</div>

Вместо подключения пользовательских файлов конфигурации можно напрямую указать дополнительные параметры конфигурации ClickHouse.

Добавьте пользовательскую конфигурацию ClickHouse с помощью `extraConfig`:

```yaml theme={null}
spec:
  settings:
    extraConfig:
      background_pool_size: 20
```

<div id="useful-links">
  #### Полезные ссылки:
</div>

* [Примеры YAML-конфигурации](/ru/concepts/features/configuration/server-config/configuration-files#example-1)
* [Все настройки сервера](/ru/reference/settings/server-settings/settings)

<div id="embedded-extra-users-configuration">
  ### Встроенная конфигурация дополнительных пользователей
</div>

Вы также можете указать дополнительную конфигурацию пользователей ClickHouse с помощью `extraUsersConfig`. Это удобно, если нужно определить пользователей, профили, квоты и привилегии прямо в спецификации кластера.

```yaml theme={null}
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
```

<Note>
  `extraUsersConfig` хранится в объекте ConfigMap в k8s. Не храните там секретные данные в открытом виде.
</Note>

<div id="see-documentationconceptsfeaturesconfigurationsettingssettings-users-for-all-supported-clickhouse-users-configuration-options">
  #### См. [документацию](/ru/concepts/features/configuration/settings/settings-users) с полным перечнем поддерживаемых параметров конфигурации пользователей ClickHouse.
</div>

<div id="configuration-example">
  ### Пример конфигурации
</div>

Полный пример конфигурации:

```yaml theme={null}
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:
  # секретный-пароль
  password: "..." # sha256 hex пароля
---
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
```
