ClickHouse-Operator: Часть-1 – обзор и установка в Kubernetes

Немного об ClickHouse

Настал тот час когда прилетел интересный task по разворачиванию ClickHouse для бекенд команды. Все мы знаем, что пихать базы данных в kubernetes не есть бест практис, особенно для продакшена!!! Но мы будем не мы, если не попробуем развернуть его в kubernetes =). 

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

ClickHouse – если кратко, это столбовая система управления базами данных для онлайн обработки аналитических запросов. Очень хорошим плюсом есть то что он умеет отдавать метрики из коробки, останется только указать прометеусу откуда собирать метрики и все должно взлететь.

Данные в СlickHouse хранятся в столбцах (взято с офф документации):

в то время как в обычных SQL базах в строках(на изображении показан только порядок расположения данных):

Особенности:
  – сжатие данных
  – прекрасно работает на простых жёстких дисках
  – большие запроси распределяться, используя все необходимые ресурсы на сервере доступных
  – поддержка SQL
  – данные обновляться в реальном времени
  – прекрасно подходит для онлайн запросов и еще много чего….
  – репликация данных

Для работы с ClickHouse представлены два интерфейса, которые можно обернуть в TLS если нужна дополнительная безопасность:
  – TCP:  по умолчанию 9000 (используется для доступа на прямую)
  – HTTP: по умолчанию 8123 (то есть ми можем делать GET or POST запроси в базу используя curl и не только)

Перед тем как приступим к разворачиванию оператора и настройки нашего первого кластера заденем два популярных термина это шардирование и репликация. Все это нам понадобиться для общего понимания и дальнейшей настройки.

Шардирование

Шардирование – горизонтальное масштабирование кластера, при котором разные части одной базы распределяются на разные шарды. Шард состоит из одного или нескольких хостов. Выделенного мастера нет, по этому запись или чтение происходит с любой реплики.

На примере показано два сервера(пода), на каждом сервере созданы одинаковее таблицы. Данные при записи разделяются на некоторые части, часть данных записывается  в один шард, а половину во второй. Для примера есть табличка с 6 миллионами записей, мы можем разместить 3 миллиона на первый шард и три на второй, когда обратиться пользователь, данные собираются, агрегируются(суммируются, объединяются), отправляются пользователю.

Для реализации шардирования существует Engine=Distributed дистрибьютор таблиц. В ClickHouse таблицы можно разделить на виртуальнее или реальные.

– реальные: хранят физически данные на дисках
  Engine = MergeTree

– виртуальные: ничего не хранят
  Engine = Distributor

Движок дистрибьютор позволяет собрать данные с разных шардов, обєдинить их, посчитать количество и отдать пользователю, подробнее про движки можно почитать здесь. Стоит помнить, что он в себе ничего не хранит.

Все настройки производиться на уровне таблиц, clickhouse не использует модель репликации instanceinstance, репликацию и шардирование нужно настраивать на уровне таблиц. Теперь немного поговорим об репликации.

Репликация

Репликация внутри шарда используются для отказоустойчивости и распараллеливания чтения. Если говорить про распараллеливание, то здесь мы можем отправлять первый запрос в одном шарде на первый сервер, после чего с этого же шарда отправить запрос на второй сервер. Репликация работает только для отдельных таблиц с использованием движка MergeTree. 

Для настройки репликации используется zookeeper. Зукипер содержит в себе информацию о реплицируемых таблицах, его можно поднимать на отдельных серверах ири размещать на сервере с ClickHouse

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

Таким образом если реплика вышла из строя, она подключается к зукиперу, находит все необходимые данные которые ей нужны. Когда есть нужные данные или их части, реплика идет на работающую реплику (в которой данные есть) и скачивает их себе.

Рекомендуют Зукипер использовать для хранения только состояния репликаций и выносить на отдельные ноды. Так как он тоже кушает системные ресурсы и когда падает, начинаются проблемы с репликацией. Подробнее как установить Зукипер и базовая его настройка смотрим здесь

Установка

Документация https://docs.altinity.com/clickhouseonkubernetes/
Репозиторий оператораhttps://github.com/Altinity/clickhouse-operator/blob/master/docs/

clickhouse-operetoropen source проект, который облегчает работу администраторам и devops инженерам, так как часть рутинной работы, микро менеджменту и администрированию кластера забирает на себя. Что в свою очередь позволяет не вдаваться в подробности (как там внутри все работает). Мы просто даем ему высокоуровневые задачи и он их выполняет.

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

Пример следующих задач которые умеет делать оператор:

  – конфигурирование ClickHouse
  – добавление и удаление шардов и реплик
  – обновление нод кластера
  – мониторинг состояния кластера
  – при необходимости удаляет кластер

Для начала установим сам оператор, далее опишем примитивный PoC single-node ClickHouse, а после развернем его используя оператор.

Сами разработчики в докладах рекомендуют использовать kubectl для установки в обход helm. Потому что при установке через kubectl получаем гибкое и более автоматизированное администрирование чем при установке helm, но никто не запрещает его использовать. В нашем случае воспользуюсь kubectl.

clickhouse-operator

Заранее забегу наперед, в процессе установки и тестирования заметил особенность: если устанавливать оператор в неймспейс kube-system – кластер можно создавать в любом неймспейсе, но, если установить в другой ns – тогда кластер нужно устанавливать в той же неймспейс где и сам оператор! Рекомендую перед установкой ознакомиться с содержимым манифеста, посмотреть расширенную настройку и только тогда устанавливать.

В операторе есть дефолтный пользователь, его использует оператор для доступа к метрикам, базам и тд, посмотреть можно в манифестах установки. По-хорошему, нужно скачать сам манифест, подправить пароль и имя пользователя(если нужно) после устанавливать, или изменить пароль после установки, выбор за Вами).

Пример пользователя с манифеста clickhouse-operator-install-bundle.yaml

    # ClickHouse credentials (username, password and port) to be used by operator to connect to ClickHouse instances
    # for:
    # 1. Metrics requests
    # 2. Schema maintenance
    # 3. DROP DNS CACHE
    # User with such credentials can be specified in additional ClickHouse .xml config files,
    # located in `chUsersConfigsPath` folder
    chUsername: "clickhouse_operator"
    chPassword: "clickhouse_operator_password"

Устанавливать будем манифест с именем clickhouse-operator-install-bundle.yaml в kube-system неймспейс, варианты других установок здесь:

 $ kubectl apply -f https://raw.githubusercontent.com/Altinity/clickhouse-operator/master/deploy/operator/clickhouse-operator-install-bundle.yaml
 customresourcedefinition.apiextensions.k8s.io/clickhouseinstallations.clickhouse.altinity.com created
 customresourcedefinition.apiextensions.k8s.io/clickhouseinstallationtemplates.clickhouse.altinity.com created
 customresourcedefinition.apiextensions.k8s.io/clickhouseoperatorconfigurations.clickhouse.altinity.com created
 serviceaccount/clickhouse-operator created
 clusterrole.rbac.authorization.k8s.io/clickhouse-operator-kube-system created
 configmap/etc-clickhouse-operator-files created
 configmap/etc-clickhouse-operator-confd-files created
 configmap/etc-clickhouse-operator-configd-files created
 configmap/etc-clickhouse-operator-templatesd-files created
 configmap/etc-clickhouse-operator-usersd-files created
 deployment.apps/clickhouse-operator created
 service/clickhouse-operator-metrics created

проверяем статус оператора:

 $ kubectl -n kube-system get pod | grep clickhouse
 clickhouse-operator-869bcd74cf-78c8n            2/2     Running   0          2d10h

Отлично, с установкой не возникло никаких проблем, идем далее.

ClickHouse Кластер

Теперь нужно описать как должен выглядеть наш кластер, после чего задеплоить его. Создадим простой в один шард, без реплик, без зукипера, но с PVC. В таком сетапе разработчики должны ознакомляться с ним, и после тестирования будем иметь полную картину какой ClickHouse нам нужно разворачивать на проде.

Для этого перейдем в репозиторий оператора где есть очень много примеров разных конфигураций (посмотреть их можно здесь).

Что мне понравилось, есть разные вариации, ми можем создавать несколько шаблонов (pvc, users, etc), устанавливать и потом подключать при создании кластера, или всю конфигурацию описать в одному манифесте. Второй вариант больше подходит, потому что в одному манифесте у нас будет все необходимое для работы кластера в одном файле.

Для хранения данных будем использовать Persistent Storage. Коротко и доходчиво по Storage в операторе описано здесь, разработчики постарались облегчить нам жизнь и сделали шаблоны на любой вкус. Рекомендується использовать тип стореджа local, потому что сейчас локальные пути на дисках инкапсулируются в сам kubernetes, что облегчает всем жизнь, а раньше доводилось все делать руками, указывать пути. 

После просмотра примеров, создал файл backend-clickhouse-single-node.yaml в котором описал свой кластер с некоторыми параметрами, получилось как то так:

apiVersion: "clickhouse.altinity.com/v1"
kind: "ClickHouseInstallation"
metadata:
  name: "backend"
spec:
  defaults:
    templates:
      podTemplate: clickhouse-stable
      dataVolumeClaimTemplate: data-volume
      serviceTemplate: svc-template
  configuration:
    users:
      # Admin user
      # имя_пользователя/*
      admin/profile: "default"
      admin/password: "******"
      admin/quota: "default"
      admin/networks/ip: "::/0"
      # read-only user
      readonly/password: "******"
      readonly/profile: "readonly"
      readonly/quota: "default"
      readonly/networks/ip: "::/0"
    clusters:
      - name: "shard"
        layout:
          shardsCount: 1
  templates:
    # здесь передаем кастомное описание необходимых нам компонентов используя щаблоны
    podTemplates:
      - name: clickhouse-stable
        metadata:
          labels:
            custom.label: "label.backend-db"
        spec:
          containers:
            - name: clickhouse
              image: yandex/clickhouse-server:21.8
              resources:  
                requests:
                  cpu: "1000m"
    serviceTemplates:
      - name: svc-template
        generateName: chendpoint-{chi}
        metadata:
          labels:
            custom.label: "custom.test"
          annotations:
            service.beta.kubernetes.io/aws-load-balancer-internal: 0.0.0.0/0
        spec:
          # ограничиваем доступ к LoadBalancer офисными IP
          loadBalancerSourceRanges:
            - ***.***.**9.*4/29
            - 1**.4*.2**.***/32
          ports:
            - name: http
              port: 8123
            - name: tcp
              port: 9000
          type: LoadBalancer
     volumeClaimTemplates:
      - name: data-volume
        spec:
          storageClassName: gp2
          accessModes:
            - ReadWriteOnce
          resources:
            requests:
              storage: 10Gi

создадим неймспейс и задеплоим манифест:

 $ kubectl create ns *****-backend-clickhouse-**
 namespace created

 $ kubectl -n *****-backend-clickhouse-** apply -f backend-clickhouse-single-node.yaml
 clickhouseinstallation.clickhouse.altinity.com/backend configured

проверим статус кластера:

 $ kubectl -n *****-backend-clickhouse-** get chi                                        
 NAME      CLUSTERS   HOSTS   STATUS
 backend   1          1       Completed

посмотрим на сервис:

 $ kubectl -n *****-backend-clickhouse-** get svc 
 chendpoint-backend      LoadBalancer   172.20.175.27   *****************************-*************.us-east-2.elb.amazonaws.com   8123:32394/TCP,9000:30769/TCP   3d
 chi-backend-shard-0-0   ClusterIP      None            <none>                                                                    8123/TCP,9000/TCP,9009/TCP      3d

где:
–  chendpoint-backendсервис с типом LoadBalancer который дает доступ ко всем шардам, доступен из мира, но ми закрыли его ограничив доступ офисными IP.
–  chi-backend-shard-0-0сервис нашего шарда.

Проверим доступ с офиса используя curl:

 $ curl *****************************-*************.us-east-2.elb.amazonaws.com:8123 
 Ok

хорошо, теперь переключимся на другого провайдера и посмотрим, будет ли доступ:

 $ curl *****************************-*************.us-east-2.elb.amazonaws.com:8123                                                                                                                                                                                         
 curl: (7) Failed to connect to  *****************************-*************.us-east-2.elb.amazonaws.com:8123 : Operation timed out

как видим доступа нет.

Подключение к ClickHouse

Теперь остается вопрос, как же подключаться к clickhouse? Если говорить про внешнее подключение есть много разных GUI IDE которые рекомендует сам ClickHouse,  но для тестов нам хватит clickhouse-cli, установим его:

 $ pip3 install clickhouse-cli                                                                                                                                                                                                                                               
 DEPRECATION: Configuring installation scheme with distutils config files is deprecated and will no longer work in the near future. If you are using a Homebrew or Linuxbrew Python, please see discussion at https://github.com/Homebrew/homebrew-core/issues/76621
 Collecting clickhouse-cli
   Downloading clickhouse-cli-0.3.7.tar.gz (41 kB)
 ........

посмотрим доступные ключи и попробуем подключиться с офиса по внешнему url service alb:

 $ clickhouse-cli --help                                                                                                                                                                                                                                                    
 Usage: clickhouse-cli [OPTIONS] [FILES]...

   A third-party client for the ClickHouse DBMS.

 Options :
  -h, --host TEXT          Server host, set to https://<host>:<port> if you want to use HTTPS
  -p, --port INTEGER       Server HTTP/HTTPS port
  -u, --user TEXT          User
  -P, --password           Ask for a password in STDIN
  -B, --arg-password TEXT  Argument as a password
  -d, --database TEXT      Database
  -s, --settings TEXT      Query string to be sent with every query
  -c, --cookie TEXT        Cookie header to be sent with every query
  -q, --query TEXT         Query to execute
  -f, --format TEXT        Data format for the interactive mode
  -F, --format-stdin TEXT  Data format for stdin/file queries
  -m, --multiline          Enable multiline shell
  --stacktrace             Print stacktraces received from the server.
  --vi-mode                Enable Vi input mode
  --version                Show the version and exit.
  --help                   Show this message and exit.

подключаемся:

 $ clickhouse-cli -h *****************************-*************.us-east-2.elb.amazonaws.com -u **** -P                                                                                                                                                   
 Password:
 clickhouse-cli version: 0.3.7
 Connecting to *****************************-*************.us-east-2.elb.amazonaws.com:8123
 Connected to ClickHouse server v21.8.11.
 :)

Для доступа внутри кластера нужно использовать внутренний кубернетес local DNS, пример такого URL:

# Template
SERVICE-NAME.NAMESPACE.svc.cluster.local

# example
chendpoint-backend.*****-backend-clickhouse-**.svc.cluster.local

провалимся в под приложения, которое находиться в неймспейсе ***-qa-***-** и постучимся курлом:

root@test-65d8bc74d-pf59c:/# curl chendpoint-backend.*****-backend-clickhouse-**.svc.cluster.local:8123
Ok.

теперь с єтого же пода, но используя clickhouse-cli:

root@test-65d8bc74d-pf59c:/# clickhouse-cli -h chendpoint-backend.*****-backend-clickhouse-**.svc.cluster.local -u admin -P
Password:
clickhouse-cli version: 0.3.7
Connecting to chendpoint-backend.*****-backend-clickhouse-**.svc.cluster.local:8123
Connected to ClickHouse server v21.8.11.
:)

Проверка Storage

Проверим PVC, создадим тестовую базу с табличкой, зальем туда данные, после удалим под, дождемся когда поднимется новый и проверим наличие данных.

посмотрим на PVC:

$ kubectl -n ****-backend-clickhouse-** get pvc                                                                                                                                                                                                                          
NAME                                  STATUS   VOLUME                                     CAPACITY   ACCESS MODES   STORAGECLASS   AGE
data-volume-chi-backend-shard-0-0-0   Bound    pvc-f38912c9-7716-4039-a1b8-aa589aedfeb2   10Gi       RWO            gp2            77m

подключимся в под и глянем путь монтирования:

$ kubectl -n ****-backend-clickhouse-** exec -it chi-backend-shard-0-0-0 -- bash
root@chi-backend-shard-0-0-0:/# df -h
Filesystem     Size   Used   Avail  Use%  Mounted on
overlay        200G    14G    187G    7%  /
tmpfs          64M      0     64M     0%  /dev
tmpfs          3.8G     0     3.8G    0%  /sys/fs/cgroup
/dev/nvme0n1p1 200G    14G    187G    7%  /etc/hosts
shm            64M      0      64M    0%  /dev/shm
/dev/nvme1n1   9.8G   181M    9.6G    2%  /var/lib/clickhouse # вот он
tmpfs          3.8G    12K    3.8G    1%  /run/secrets/kubernetes.io/serviceaccount
tmpfs          3.8G     0     3.8G    0%  /proc/acpi
tmpfs          3.8G     0     3.8G    0%  /sys/firmware

storage подключен.

Подключаемся к кластеру ClickHouse, смотрим какие базы сейчас есть:

$ kubectl -n ******-backend-clickhouse-** exec -it chi-backend-shard-0-0-0 -- clickhouse client

ClickHouse client version 21.8.11.4 (official build).
Connecting to localhost:9000 as user default.
Connected to ClickHouse server version 21.8.11 revision 54449.

chi-backend-shard-show databases;

SHOW DATABASES

Query id: 311eaa63-6075-4d87-8983-8cce42b53dbb

┌─name────┐
│ default │
│ system  │
└─────────┘

2 rows in set. Elapsed: 0.002 sec.

Создадим тестовую с именем testdb:

:) create database testdb;
CREATE DATABASE testdb
Query id: 6cf92d0f-794e-4448-8f1f-1c0059ab289a
Ok.
0 rows in set. Elapsed: 0.003 sec.

:) use testdb;
USE testdb
Query id: 60c41186-7720-4149-b287-3e89132f592e
Ok.
0 rows in set. Elapsed: 0.001 sec.

теперь таблицу с именем test:

 :) CREATE TABLE testdb.test AS system.one ENGINE = Distributed('shard', 'system', 'one');

CREATE TABLE testdb.test AS system.one ENGINE = Distributed('shard', 'system', 'one')

Ok. 0 rows in set. Elapsed: 0.019 sec. Processed: 0 rows, 0.0B (0 rows/s, 0.0B/s)

:) select * from testdb.test;

select *
  from testdb.test


┌─dummy─┐
│     0 │
└───────┘

Ok. 1 row in set. Elapsed: 0.006 sec. Processed: 0 rows, 0.0B (0 rows/s, 0.0B/s)

Удаляем под и ждем когда поднимется новый:

$ kubectl -n ******-backend-clickhouse-** delete pod chi-backend-shard-0-0-0                                                                                                                                                                                 
pod "chi-backend-shard-0-0-0" deleted

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

:) show databases;

show databases

┌─name────┐
│ default │
│ system  │
│ test    │
│ testdb  │
└─────────┘
Ok. 4 rows in set. Elapsed: 0.008 sec. Processed: 0 rows, 0.0B (0 rows/s, 0.0B/s)

:) select * from testdb.test;

select *
  from testdb.test

┌─dummy─┐
│     0 │
└───────┘
Ok. 1 row in set. Elapsed: 0.010 sec. Processed: 0 rows, 0.0B (0 rows/s, 0.0B/s)

:)

Отлично, все сохранились.

Что ж, первоначальный сетап готов. Мы установили кластер в один шард, создали два пользователя, один pvc для хранения данных, осталось продумать как делать бекап и восстановление, мониторинг, автоматизацию для установки оператора, создания и изменения кластеров для разных команд.

Полезные ссылки

Оператор в Kubernetes для управления кластерами БД.
clickhouse documentation
https://docs.altinity.com/clickhouseonkubernetes/
https://github.com/Altinity/clickhouse-operator/tree/master/docs/chi-examples
https://cloud.yandex.ru/docs/managed-clickhouse/concepts/sharding
https://cloud.yandex.ru/docs/managed-clickhouse/concepts/replication 

Click to rate this post!
[Total: 3 Average: 5]