Финальная часть — про то, что отличает работающий кластер от кластера, который «пока работает».
Пользователи и права
Первое, что нужно сделать после установки: разобраться с пользователем default. Исторически он существует без пароля и с широкими правами — в проде это недопустимо. Либо задайте ему пароль и урежьте права, либо запретите вход по сети, оставив только локальный доступ.
Дальше — разделение по ролям, а не «один аккаунт на всё»:
CREATE ROLE bi_reader;
GRANT SELECT ON analytics.* TO bi_reader;
CREATE USER grafana IDENTIFIED WITH sha256_password BY '...'
SETTINGS PROFILE 'readonly_bi';
GRANT bi_reader TO grafana;
CREATE ROLE ingest;
GRANT INSERT, SELECT ON analytics.events TO ingest;Практики, которые стоит принять как правило:
- отдельные учётные записи для BI-инструментов, ETL-пайплайнов, приложения и людей;
- разные профили настроек (см. часть 7): дашборд не должен иметь права на запрос, кладущий кластер;
readonly = 1для всего, что только читает;- у приложения нет прав на
DROP,ALTERи создание пользователей — миграции катает отдельная учётка; - row-level policy, если в одной таблице живут данные разных арендаторов;
- пароли — в секретах Kubernetes (лучше через External Secrets/Vault), а не в манифестах в git.
Сеть и TLS
ClickHouse слушает несколько портов: HTTP (8123), нативный протокол (9000), их TLS-версии (8443/9440), межсерверный обмен и порт Keeper.
Минимальный набор мер:
- Не выставлять наружу. Доступ — через внутренние сервисы; наружу, если необходимо, — только HTTPS-порт через ingress с аутентификацией.
NetworkPolicy: к ClickHouse ходят только известные namespace’ы, к Keeper — только ClickHouse. Это отсекает целый класс проблем.- TLS для клиентских соединений и межсерверного обмена — оба оператора это поддерживают, официальный использует cert-manager.
- Ограничить
listen_hostразумными интерфейсами.
Обновления
Обновление ClickHouse в Kubernetes — это rolling restart подов, и он должен уважать кворум и репликацию.
Порядок, который экономит нервы:
- Прочитать changelog. ClickHouse развивается быстро; между версиями меняется поведение настроек. Не прыгайте через много мажорных версий сразу.
- Обновлять по одной реплике. Должен оставаться живой кворум Keeper и хотя бы одна здоровая реплика каждого шарда.
- Keeper и ClickHouse — разными окнами. Не трогайте координацию и данные одновременно.
PodDisruptionBudgetдля ClickHouse и Keeper — чтобы drain ноды при обслуживании кластера не выбил лишнего. Официальный оператор создаёт PDB сам, но проверьте значения.- Дождаться зелёного статуса между шагами:
system.replicasбез read-only и с пустеющей очередью,status.readyReplicasв кастомном ресурсе. - Достаточный
terminationGracePeriodSeconds, чтобы сервер успел корректно завершиться и сбросить буферы. - Сначала стенд. Обновление проверяется на тестовом кластере с похожими данными и запросами.
Миграции схемы
В кластере DDL выполняется на всех узлах через ON CLUSTER:
CREATE TABLE analytics.events ON CLUSTER '{cluster}' ( ... )
ENGINE = ReplicatedMergeTree('/clickhouse/tables/{shard}/events', '{replica}')
ORDER BY (event_type, user_id, ts);Что важно:
- распределённый DDL идёт через очередь в Keeper — следите за
system.distributed_ddl_queue, застрявшие задачи блокируют последующие; - миграции держите в git и катайте инструментом (миграционный фреймворк или GitOps), а не руками из консоли;
- добавление колонки дёшево; изменение типа или ключа сортировки — операция, которую нужно планировать отдельно;
- при изменениях, требующих переписывания данных, помните про стоимость мутаций.
Сводка анти-паттернов
Собранные вместе грабли из всей серии — то, что чаще всего ломает ClickHouse в Kubernetes:
Архитектура
- Много мелких подов вместо нескольких крупных узлов.
- Шардирование до того, как исчерпана вертикаль.
- Чётное число узлов Keeper или Keeper на тех же нодах, что ClickHouse.
- Отсутствие
podAntiAffinity— реплики уезжают на одну ноду.
Данные
- Вставка по одной строке или очень мелкими пачками →
Too many parts. - Высококардинальная колонка первой в
ORDER BY. - Партиционирование по дню при долгом хранении → тысячи партиций.
Nullableи избыточно широкие типы без нужды.- Регулярные
UPDATE/DELETEвместо проектирования под append-only. JOINбольших таблиц без фильтрации и с большей таблицей справа.
Инфраструктура
reclaimPolicy: Deleteна продовых томах.- Диск заполнен выше 85% — слияния встают.
limits.memoryниже, чем внутренние лимиты ClickHouse →OOMKilledвместо внятной ошибки.- Жёсткий
limits.cpuи троттлинг многопоточных запросов. - Нет TTL на системных
*_logтаблицах.
Процессы
- Бэкапы без проверки восстановления.
- Нет алертов на read-only реплики и кворум Keeper.
- Обновление всего кластера разом.
- Ручные правки StatefulSet мимо оператора.
Что делать дальше
Разумный порядок внедрения, если начинаете с нуля:
- Поднять кластер оператором с 3 узлами Keeper и репликацией (части 2–3).
- Настроить storage с запасом и
Retain(часть 4). - Спроектировать схему под реальные запросы (часть 5).
- Наладить батчевую вставку (часть 6).
- Выставить лимиты и профили (часть 7).
- Завести мониторинг и алерты (часть 8).
- Настроить бэкапы и восстановить их хотя бы раз (часть 9).
- Закрыть доступы и описать процедуру обновления.
ClickHouse щедро отдаёт производительность, если попасть в его модель, и наказывает за попытки использовать его как обычную базу. Большая часть этой серии — про то, как оставаться на первой стороне.