
Доповідь присвячена практичним питанням розробки оператора в Kubernetes, проектування його архітектури та основних принципів функціонування.
У першій частині доповіді розглянемо:
- що таке оператор у Kubernetes і навіщо він потрібен;
- як саме оператор спрощує керування складними системами;
- що оператор може, а оператор не може.
Далі перейдемо до обговорення внутрішнього пристрою оператора. Розглянемо архітектуру та функціонування оператора за кроками. Докладно розберемо:
- взаємодія між оператором та Kubernetes;
- які функції оператор бере на себе, а що делегує у Kubernetes.
Розглянемо управління шардами та репліками БД у Kubernetes.
Далі обговоримо питання зберігання даних:
- як працювати з Persistent Storage з погляду оператора;
- підводне каміння використання Local Storage.
У заключній частині доповіді розглянемо практичні приклади застосування з Amazon чи Google Cloud Service. Доповідь базується на прикладі розробки та досвіду експлуатації оператора для ClickHouse.
Відео:

Мене звуть Владислав Клименко. Я хотів сьогодні розповісти про наш досвід розробки та експлуатації оператора, причому це спеціалізований оператор для керування кластерами баз даних. На прикладі для керування кластером ClickHouse.

Чому ми маємо можливість розповідати про оператора та ClickHouse?
- Ми займаємося підтримкою та розвитком ClickHouse.
- На даний момент ми намагаємося потихеньку робити свій посильний внесок у розробку ClickHouse. І є другим після Яндекса за обсягом зроблених змін у ClickHouse.
- Намагаємось робити додаткові проекти для екосистеми ClickHouse.
Про один із таких проектів я хотів би розповісти. Це про ClickHouse-operator для Kubernetes.
У своїй доповіді я хотів би торкнутися двох тем:
- Перша тема – це як працює наш оператор з управління базами даних ClickHouse у Kubernetes.
- Друга тема – це як працює будь-який оператор, тобто як він взаємодіє з Kubernetes.
При цьому ці два питання будуть перетинатися протягом усієї моєї доповіді.

Кому буде цікаво послухати те, що я намагаюся розповісти?
- Найцікавіше буде тим, хто експлуатує оператори.
- Або тим, хто хоче зробити свій, щоб розуміти, як воно працює всередині, як взаємодіє оператор з Kubernetes і яке підводне каміння може з'явитися.

Для того, щоб найкраще розуміти те, що ми сьогодні обговорюватимемо, було б непогано знати, як працює Kubernetes і мати базову підготовку за хмарними технологіями.

Що таке ClickHouse? Це колонкова база даних зі специфікою онлайн-обробку аналітичних запитів. І вона є повністю open source.
І нам важливо знати лише дві речі. Треба знати, що це база даних, тому те, що я розповідатиму, буде застосовано практично до будь-якої бази даних. І те, що СУБД ClickHouse дуже добре масштабується, практично лінійну дає масштабованість. І тому стан кластера – це для ClickHouse стан природний. І нам найбільш цікаво обговорити те, як кластер ClickHouse обслуговувати в Kubernetes.

Навіщо він там потрібний? Чому ми не можемо продовжувати його експлуатувати самостійно? І відповіді частково технічні, а частково організаційні.
- На практиці ми все частіше зустрічаємо таку ситуацію, коли у великих компаніях вже практично всі компоненти і так вже в Kubernetes. Залишаються бази даних поза.
- І все частіше ставить питання: «Чи можна це всередину помістити?». Тому великі компанії намагаються проводити максимальну уніфікацію управління у тому, щоб швидко мати можливість керувати своїми сховищами даних.
- І особливо це допомагає, якщо потрібна максимальна можливість повторити те саме на новому місці, тобто максимальна переносимість.

Наскільки це просто чи складно? Це, звісно, можна робити руками. Але це не так, щоб просто, тому що у нас складаються за сумою складність управління самими Kubernetes, але при цьому накладається специфіка ClickHouse. І виходить така агрегація.
І все разом це дає досить великий набір технологій, яким керувати ставати вже досить складно, тому що Kubernetes приносить свої щоденні питання до експлуатації, а ClickHouse приносить свої питання до щоденної експлуатації. Особливо якщо у нас ClickHouse-ів кілька, і нам треба постійно з ними щось робити.

У ClickHouse при динамічній конфігурації є досить багато питань, які створюють постійне навантаження на DevOps:
- Коли ми хочемо змінити щось у ClickHouse, наприклад, додати репліку, шард, то нам треба провести керування конфігурацією.
- Потім змінити схему даних, так як у ClickHouse специфічний метод шардування. Там треба розкладати схему даних, розкладати конфігурації.
- Потрібно налаштувати моніторинг.
- Збір логів для нових шардів, нових реплік.
- Подбати про відновлення.
- І перезапуск.
Це такі рутинні роботи, які дуже хотілося б полегшити в експлуатації.

Сам Kubernetes добре допомагає в експлуатації, але базових системних речах.
Kubernetes добре полегшує та здійснює автоматизацію таких речей, як:
- Відновлення.
- Перезапуск.
- Управління системою зберігання.
Це добре, це правильний напрямок, але він повністю не має уявлення про те, як експлуатувати кластер бази даних.
Хочеться більшого, хочеться, щоб у нас працювала вся база даних Kubernetes.

Хочеться отримати щось на кшталт великої однієї магічної червоної кнопки, на яку ти натискаєш і у тебе розгортається і підтримується протягом усього життєвого циклу кластер із щоденними завданнями, які треба вирішувати. Кластер ClickHouse в Kubernetes.
І ми постаралися зробити таке рішення, яке б полегшило роботу. Це ClickHouse-operator для Kubernetes від компанії Altinity.

Оператор – це програма, основне завдання якої керувати іншими програмами, тобто це управлінець.
І він містить шаблони поведінки. Це можна назвати кодифікованими знаннями про предметної області.
І основне його завдання – це полегшити життя DevOps і зменшити мікроменеджмент, щоб він (DevOps) вже мислив термінами високого рівня, тобто щоб він (DevOps) не займався мікроменеджментом, щоб не робив налаштування всіх деталей вручну.
І саме оператор – це робот помічник, який бореться з мікрозадачами і допомагає DevOps.

Навіщо потрібний оператор? Він особливо добре себе показує у двох питаннях:
- Коли у спеціаліста, який займається ClickHouse, недостатньо досвіду, але експлуатувати ClickHouse вже треба, оператор полегшує експлуатацію та дозволяє експлуатувати кластер ClickHouse з досить складною конфігурацією, при цьому не дуже вдаючись до подробиць про те, як це все працює всередині. Просто йому даєш високорівневі завдання і це працює.
- І друге завдання, в якому він себе найбільш добре проявляє, це коли треба автоматизувати велику кількість типових завдань. Знімає мікрозавдання із сисадмінів.

Це найбільше треба або тим, хто тільки-но починає свій шлях, або тим, кому треба багато займатися автоматизацією.

У чому відмінність підходу, заснованого на операторах, з інших систем? Є ж Helm. Він також допомагає поставити ClickHouse, можна намалювати helm charts, які навіть поставлять цілий кластер ClickHouse. У чому тоді відмінність між оператором і від того ж, наприклад, Helm?
Основна фундаментальна відмінність у тому, що Helm – це керування пакетами, а оператор крокує далі. Це супровід всього життєвого циклу. Це не тільки установка, це щоденні завдання, які включають масштабування, шардування, тобто все те, що треба виконувати в процесі життєвого циклу (якщо треба, то і видалення теж) – це все вирішує оператор. Він намагається автоматизувати та обслуговувати весь життєвий цикл програмного забезпечення. У цьому його фундаментальна відмінність від інших рішень, які представлені.

Це була вступна частина, давайте підемо далі.
Як ми будуємо свій оператор? Ми намагаємося підійти до питання, щоб керувати кластером ClickHouse як одним ресурсом.
Ось у нас у лівій частині картини є вхідні дані. Це YAML зі специфікацією кластера, який класичним чином через kubectl передається Kubernetes. Там у нас оператор це підхоплює, робить свою магію. І на виході у нас виходить така схема. Це імплементація ClickHouse в Kubernetes.
І далі ми потихеньку дивитимемося, як саме працює оператор, які типові завдання можна вирішувати. Ми розглянемо лише типові завдання, бо ми маємо обмежений час. І буде розказано не все, що може вирішувати оператор.

Давайте виходити з практики. Наш проект – це повністю open source, тож можна подивитися на GitHub, як він працює. І можна виходити з міркувань, якщо хочеться просто запустити, з Quick Start Guide можна починати.
Якщо хочеться детально розбиратися, ми намагаємося підтримувати документацію в більш-менш пристойному вигляді.

Давайте почнемо із практичного завдання. Перше завдання, з чого ми всі хочемо почати, це запустити перший приклад хоч якось. Як за допомогою оператора запустити ClickHouse, навіть не дуже знаючи, як він працює? Пишемо маніфест, т.к. все спілкування з k8s це спілкування через маніфести.

Ось такий складний маніфест. Те, що у нас виділено червоним, це те, на чому треба акцентуватись. Ми оператора просимо створити кластер на ім'я demo.
Поки що це є базові приклади. Storage ще не описується, але ми до storage повернемося трохи пізніше. Поки що в динаміці спостерігатимемо за розвитком кластера.
Ми створили цей маніфест. Згодовуємо його нашому оператору. Він працював, зробив магію.

Дивимося у консоль. Інтерес викликають три компоненти - це Pod, два Service-a, StatefulSet.
Оператор відпрацював і ми можемо подивитися, що саме він створив.

Створює він приблизно таку схему. Ми маємо StatefulSet, Pod, ConfigMap для кожної репліки, ConfigMap для всього кластера. Обов'язково послуги як точки входу в кластер.
Сервіси це центральний Load Balancer Service і можна ще для кожної репліки, для кожного шарда.
Ось у нас базовий кластер виглядає приблизно в такий спосіб. Він із однієї єдиної ноди.

Ходімо далі, ускладнюватимемо. Треба кластер шардувати.

У нас завдання зростають, починається динаміка. Ми хочемо додати шард. Слідкуємо за розвитком. Змінюємо нашу специфікацію. Вказуємо, що ми хочемо дві шарди.
Це той самий файл, який у нас динамічно розвивається зі зростанням системи. Storage немає, storage буде розглянуто, це окрема тема.
Згодовуємо YAML-оператор і дивимося, що виходить.

Оператор подумав і зробив такі сутності. У нас вже два Pod, три Service-а і, раптово, 2 StatefulSet-а. Чому 2 StatefulSet-а?

На схемі було ось так – це у нас початковий стан, коли один у нас був під.

Стало так. Поки все просто, воно продублювалося.

І чому ж StatefulSet стало два? Тут треба відволіктися та обговорити питання, як у Kubernetes відбувається управління Pod'ами.
Є такий об'єкт під назвою StatefulSet, який дозволяє робити набір Pod'ів із шаблону. Тут ключовий фактор – це Template. І можна в одному StatefulSet запускати по одному шаблону багато Pod'ів. І ключовою фразою тут є «за одним шаблоном багато Pod'ів».
І була велика спокуса зробити весь кластер, запакувавши в один державнийпосібник. Це працюватиме, у цьому немає жодних проблем. Але є один нюанс. Якщо ми хочемо зібрати гетерогенний кластер, тобто з кількох версій ClickHouse, то тут у нас починаються питання. Так, StatefulSet може зробити rolling update, та там можна накочувати нову версію, пояснювати, що потрібно спробувати не більше стільки нодів одночасно.
Але якщо екстраполювати завдання і сказати, що ми хочемо зробити повністю гетерогенний кластер і хочемо не зі старої версії поміняти на нову за допомогою rolling update, а просто хочемо створити гетерогенний кластер як в частині різних версій ClickHouse, так і в частині різного storage. Ми хочемо, наприклад, якісь репліки зробити на окремих дисках, на повільних загалом повністю побудувати гетерогенний кластер. І тому, що StatefulSet робить з одного шаблону стандартизоване рішення, тому немає можливості це зробити.
Після деякого роздуму було ухвалено рішення, що ми робимо ось так. У нас кожна репліка у своєму державномудовіднику. Є деякі недоліки цього рішення, але на практиці це все повністю в собі інкапсулює оператор. І є купа переваг. Ми можемо будувати повністю такий кластер, який хочемо, наприклад гетерогенний. Тому в кластері, в якому у нас два шарди по одній репліці, у нас буде 2 StatefulSet'а та 2 Pod'а саме тому, що ми обрали такий підхід через вищеозвучені причини для можливості побудувати гетерогенний кластер.

Повернімося до практичних завдань. У кластері треба налаштовувати користувачів, тобто. треба робити якесь конфігурування ClickHouse у Kubernetes. Оператор надає всі можливості.

Можна прямо в YAML писати те, що хочемо. Всі конфігураційні опції прямо з цього YAML в конфіги ClickHouse, які потім розкладаються по всьому кластеру.
Можна й так писати. Це для прикладу. Пароль можна зробити шифрований. Підтримуються всі конфігураційні опції ClickHouse. Тут лише приклад.
Конфігурація кластера поширюється як ConfigMap. Насправді апдейт ConfigMap відбувається миттєво, тому якщо великий кластер, то процес пропихання конфігурації займає деякий час. Але все це дуже зручно в експлуатації.

Ускладнюємо завдання. Кластер розвивається. Ми хочемо реплікувати дані. Т. е. у нас є вже два шарди, по одній репліці, налаштовані користувачі. Ми ростемо і хочемо займатися реплікацією.

Що нам потрібне для реплікації?
Нам потрібний ZooKeeper. У ClickHouse реплікація побудована за допомогою ZooKeeper. ZooKeeper потрібний для того, щоб у різних реплік ClickHouse був консенсус щодо того, які блоки даних на якому ClickHouse є.
ZooKeeper можна використовувати будь-який. Якщо є зовнішній ZooKeeper у підприємства, його можна використовувати. Якщо ні, можна поставити з нашого репозиторію. Є установник, який усе це полегшує.

І схема взаємодії всієї системи виходить така. Ми маємо Kubernetes як платформа. На ньому виконується оператор ClickHouse. ZooKeeper я зобразив ось тут. І оператор взаємодіє як із ClickHouse, так і з ZooKeeper. Т. е. Виходить взаємодія.
І все це потрібно для того, щоб ClickHouse успішно реплікував дані в k8s.

Давайте тепер подивимося на завдання, на те, як виглядатиме маніфест для реплікації.
Ми до нашого маніфесту додаємо дві секції. Перша - де брати ZooKeeper, який може бути як всередині Kubernetes, так і зовнішній. Це просто опис. І замовляємо репліки. Тобто. ми хочемо дві репліки. Разом на виході ми маємо 4 pod'а. Про storage ми пам'ятаємо, він повернеться трохи далі. Storage – це окрема пісня.

Було так.

Стає ось так. Додаються репліки. 4-та не містилася, ми віримо, що їх там може бути багато. І збоку додається ZooKeeper. Схеми ускладнюються.

І настав час додавати наступне завдання. Додаватимемо Persistent Storage.
За Persistent Storage у нас є різні варіанти виконання.
У випадку, якщо ми виконуємося в cloud-провайдері, наприклад, використовуючи Amazon, Google, тобто велика спокуса скористатися хмарним storage. Це дуже зручно, це добре.
І є другий варіант. Це для local storage, коли у нас є диски локальні на кожній ноді. Цей варіант набагато складніший у виконанні, але при цьому він продуктивніший.

Давайте подивимося, що у нас щодо cloud storage.
Є переваги. Це просто конфігурувати. Ми просто замовляємо у хмарного провайдера, що дай нам, будь ласка, storage такої ємності, такого класу. Класи розписані провайдерами самостійно.
І є недолік. Для когось це некритичний недолік. Звичайно, там будуть якісь накладки щодо продуктивності. Це дуже зручно в роботі, надійно, але є деякі потенційні просідання за продуктивністю.

А т.к. ClickHouse акцентується саме на продуктивності, можна навіть сказати, що вичавлює все, що можна, тому дуже багато клієнтів намагаються вичавити максимум продуктивності.

А щоб вичавити максимум, нам потрібний local storage.
Kubernetes надає три абстракції для використання локального storage в Kubernetes. Це:
- EmptyDir
- HostPath.
- Місцевий
Розглянемо, що вони різняться, що вони схожі.
По-перше, у всіх трьох підходах у нас storage – це локальні диски, які знаходяться на тій самій фізичній k8s ноді. Але вони мають деякі відмінності.

Почнемо з найпростішого, тобто з emptyDir. Що це на практиці? Це ми у своїй специфікації просимо систему контейнеризації (найчастіше це докер) надати нам доступ до папки до локального диска.
На практиці докер десь там у себе своїми власними шляхами створює тимчасову папку, називає її довгим хешом. І надає інтерфейс доступу до неї.
Як це працюватиме за продуктивністю? Це працюватиме зі швидкістю локального диска, тобто. це повністю доступ до свого гвинта.
Але ця справа має свій недолік. Persistent у цій справі досить сумнівний. При першому ж русі докера з контейнерами Persistent втрачається. Якщо Kubernetes захочеться з якоїсь причини перенести цей Pod на інший диск, дані загубляться.
Такий підхід добре для тестів, тому що швидкість показує вже нормальну, але при цьому для чогось серйозного цей варіант не підходить.

Тому є другий підхід. Це hostPath. Якщо подивитися попередній слайд і цей, то можна побачити лише відмінність. У нас папка виїхала з докера просто на Kubernetes ноду. Тут трохи простіше. Ми прямо прописуємо шлях по локальній файловій системі, де ми хотіли б зберігати свої дані.
Переваги цього способу є. Це вже справжній Persistent, до того ж класичний. У нас на диску будуть записані дані на якусь адресу.
Є й недоліки. Це складність управління. Наш Kubernetes може захотіти Pod пересунути на іншу фізичну ноду. І тут вже входить у справу DevOps. Він повинен правильно пояснити всій системі, що пересувати ці pod'и можна тільки на такі ноди, на яких у тебе цими шляхами щось змонтовано, і не більше однієї ноди за раз. Це досить складно.
Спеціально для цих цілей ми у себе в операторі зробили шаблони для того, щоб всю цю складність сховати. І можна було б просто сказати: «Я хочу, щоб був у мене один instance ClickHouse на кожну фізичну ноду і таким шляхом».

Але ця потреба потрібна не лише нам, тому джентльмени з самого Kubernetes теж розуміють, що людям хочеться мати доступ до фізичних дисків, тому вони надають третій рівень.
Він називається місцевим. Різниці від попереднього слайду ніякої. Тільки раніше треба було руками проводити, що у нас не можна ці pod'и переносити з ноди на ноду, бо вони мають бути причеплені таким шляхом до локального фізичного диска, а тепер усі ці знання інкапсулюються в сам Kubernetes. І виходить набагато простіше конфігурувати.

Повернемося до нашого практичного завдання. Повернемося до YAML template. Тут у нас з'явився справжній storage. Ми повернулися до цього. Ми ставимо класичний VolumeClaim template як у k8s. І описуємо, який storage ми хочемо.
Після цього k8s запросить storage. Виділить нам його в StatefulSet. І в результаті це вийде у розпорядженні ClickHouse.

Була в нас така схема. Наш Persistent Storage був червоним, що ніби натякало на те, що його треба зробити.

І він стає зеленим. Тепер схема кластера ClickHouse on k8s повністю завершена. У нас є шарди, репліки, ZooKeeper, є справжній Persistent, який реалізований тим чи іншим способом. Схема вже цілком працездатна.

Ми продовжуємо жити далі. В нас кластер розвивається. І Олексій намагається і випускає нову версію ClickHouse.
Виникає практичне завдання – протестувати нову версію ClickHouse на кластері. Причому, природно, не хочеться його накочувати весь, хочеться десь у далекому кутку в одну репліку поставити нову версію, а, можливо, не одну нову версію, а одразу дві, тому що вони виходять частенько.
Що ми можемо сказати з цього приводу?

Тут у нас є якраз і така нагода. Це шаблони pod'ів. Можна розписати, наш оператор повністю дозволяє побудувати гетерогенний кластер. Тобто. конфігурувати, починаючи від усіх реплік купою, закінчуючи кожною персональною реплікою тим, якою версією ми хочемо ClickHouse, якою версією ми хочемо storage. Ми можемо повністю налаштувати кластер такої конфігурації, як нам треба.

Трохи будемо вже заглиблюватись усередину. До цього ми говорили, як працює ClickHouse-operator стосовно специфіки ClickHouse.
Тепер я хотів би сказати пару слів про те, як працює взагалі будь-який оператор, а також про те, як взаємодіє з K8s.

Розглянемо взаємодію з K8s для початку. Що відбувається, коли ми робимо kubectl apply? У нас через API etcd з'являються наші об'єкти.

Наприклад базові об'єкти Kubernetes: pod, StatefulSet, service тощо за списком.
У цьому нічого фізичного ще відбувається. Ці об'єкти треба матеріалізувати у кластері.

І тому з'являється контролер. Контролер – це спеціальний компонент k8s, який вміє матеріалізувати ці описи. Він знає, як і що робити фізично. Він знає, як запускати контейнери, що там треба налаштувати для того, щоб запрацював сервер.

І він матеріалізує наші об'єкти у K8s.
Але ми хочемо оперувати не тільки під-ами, StatefulSet-ами, ми хочемо створити ClickHouseInstallation, тобто об'єкт типу ClickHouse, щоб оперувати їм як єдиним цілому. Поки що такої нагоди немає.

Але у K8s є така приємна річ. Ми хочемо, щоб у нас з'явилася десь там ось така складна сутність, в якій був би зібраний з pod'ів і StatefulSet наш кластер.

І що для цього треба зробити? По-перше, на сцену виходить Custom Resource Definition. Що це таке? Це опис для K8s, що у тебе буде ще один тип даних, що ми до під, StatefulSet хочемо додати кастомний ресурс, який буде складним всередині. Це опис структури даних.

Ми його також через kubectl apply туди відправляємо. Kubernetes його радісно забрав.
І тепер у нас у сховищі, у об'єкта etcd з'являється можливість записати кастомний ресурс під назвою ClickHouseInstallation.
Але поки що нічого далі не станеться. Т. е. якщо ми зараз створимо YAML-файл, який ми розглядали з описом шард, реплік і скажемо «kubectl apply», то Kubernetes його прийме, покладе в etcd і скаже: «Дуже добре, але що з ним робити, не знаю. Як обслуговувати ClickHouseInstallation я не знаю».

Відповідно нам потрібен хтось, хто допоможе Kubernetes обслуговувати новий тип даних. Зліва ми маємо штатний контролер Kubernetes, який працює зі штатними типами даних. А праворуч має з'явитися кастомний контролер, який вміє працювати з кастомними типами даних.
І інакше він називається оператор. Я його тут спеціально виніс за Kubernetes, тому що він може виконуватися і зовні K8s. Найчастіше, звичайно, всі оператори виконуються в Kubernetes, але нічого не заважає йому стояти зовні, тому він спеціально винесений назовні.

І вже, у свою чергу, кастомний контролер, він же оператор, взаємодіє з Kubernetes через API. Він уже вміє взаємодіяти з API. І він уже знає, як із кастомного ресурсу матеріалізувати складну схему, яку ми хочемо зробити. Саме цим і опікується оператор.

Як працює оператор? Давайте заглянемо у праву частину, щоб дізнатися, як це робить. Дізнаємося, як оператор все це матеріалізує і як далі відбувається взаємодія з K8s.

Оператор – це програма. Вона подієво орієнтована. Оператор за допомогою Kubernetes API підписується на події. У Kubernetes API є точки входу, в яких можна передплатити події. І якщо щось у K8s змінюється, то Kubernetes посилає події всім охочим, тобто. хто на цю точку API підписався, той і отримуватиме повідомлення.
Оператор підписується на події, і має робити якусь реакцію. Його завдання – це реагувати на події, що з'являються.

Події генеруються деякими апдейтами. Приходить наш YAML-файл із описом ClickHouseInstallation. Він через kubectl apply пішов у etcd. Там спрацював event, у результаті цей event прийшов у ClickHouse-operator. Оператор отримав цей опис. І він щось має робити. Якщо прийшов апдейт на об'єкт ClickHouseInstallation, то треба апдейтувати кластер. І завдання оператора – це апдейти кластер.

Що він робить? По-перше, треба скласти план дій, що ми робитимемо з цим апдейтом. Апдейти може бути дуже маленькими, тобто. маленькі в YAML-виконанні, але можуть спричиняти дуже великі зміни на кластері. Тому оператор створює план і далі він його дотримується.

Він починає за цим планом варити цю структуру всередині, щоб матеріалізувати pod'и, сервіси, тобто. робити те, що його основним завданням є. Це як будувати кластер ClickHouse в Kubernetes.

Тепер давайте торкнемося такої цікавої речі. Це поділ відповідальності між Kubernetes та оператором, тобто. що робить Kubernetes, що робить оператор і як вони взаємодіють між собою.
Kubernetes відповідає за системні речі, тобто. базовий набір об'єктів, який можна інтерпретувати як system-scope. Kubernetes знає, як запускати pod'и, як рестартити контейнери, як робити mount volumes, як працювати з ConfigMap, тобто. все, що можна назвати системою.
Оператори оперують у предметних сферах. Кожен оператор робиться для своєї предметної галузі. Ми зробили для ClickHouse.
І оператор взаємодіє саме в термінах предметної області, таких як додати репліку, зробити схему, налаштувати моніторинг. Виходить такий поділ.

Давайте розглянемо на практичному прикладі, як цей поділ відповідальності відбувається, коли ми робимо дію додати репліку.
В оператор приходить завдання – додати репліку. Що оператор робить? Оператор розрахує, що треба новий зробити StatefulSet, в якому треба описати такі шаблони, volume claim.

Він це все підготував і передає далі у K8s. Каже, що йому треба ConfigMap, StatefulSet, Volume. Kubernetes відпрацьовує. Він матеріалізує базові одиниці, якими оперує.

І далі в справу знову вступає ClickHouse-operator. У нього вже є фізичний pod, на якому можна щось робити. І ClickHouse-operator знову працює у термінах предметної області. Тобто. Саме ClickHouse для того, щоб включити репліку в кластер, треба, по-перше, налаштувати схему даних, яка в цьому кластері є. А по-друге, цю репліку треба включити до моніторингу, щоб вона добре простежувалася. Вже оператор це налаштовує.

І лише після цього вже у справу вступає сам ClickHouse, тобто. ще одна високорівнева сутність. Це вже є база даних. Вона має свою instance, чергову налаштовану репліку, яка готова вступити в кластер.
Виходить ланцюжок виконання та поділу відповідальності при додаванні репліки досить довгою.

Продовжуємо наші практичні завдання. Якщо кластер вже є, можна здійснити міграцію конфігурації.

Ми зробили так, що в існуючий xml, який ClickHouse розуміє, можна прокидати наскрізь.

Можна зробити тонку настройку ClickHouse. Саме zoned deployment – це те, про що я розповідав при поясненні hostPath, local storage. Це як правильно зробити zoned deployment.

Наступне практичне завдання – це моніторинг.

Якщо у нас кластер змінюється, то треба періодично налаштовувати моніторинг.
Давайте розглянемо схему. Ми зелені стрілки вже розглянули. Тепер розглянемо червоні стрілки. Це те, як ми хочемо моніторити наш кластер. Як метрики з кластера ClickHouse потрапляють у Prometheus, а потім у Grafana.

А в чому складність із моніторингом? Чому це виноситься як якесь досягнення? Складність саме у динаміці. Коли у нас кластер один і він статичний, то можна якось налаштувати моніторинг і більше не морочитися.
Але якщо у нас кластерів багато, або постійно щось змінюється, процес динамічний. І займатися переналаштуванням моніторингу – це витрата ресурсів, і часу, тобто. навіть просто ліньки. Це треба автоматизувати. Складність саме у динаміці процесу. І оператор це дуже добре автоматизує.

Як у нас розвивався кластер? На початку він був такий.

Потім він був такий.

У результаті він став таким.
А моніторинг автоматично робиться оператором. Єдина точка входу.

І ми лише на виході дивимось у Grafana dashboard, як там усередині вирує життя нашого кластера.
До речі, Grafana dashboard теж розповсюджується з нашим оператором прямо у вихідниках. Можна підключати та користуватися. Ось цей скріншот мені наші DevOps дали.

Куди б ми хотіли рухатися далі? Це:
- Розвивати автоматизацію тестування. Основне завдання – це автоматизоване випробування нових версій.
- Також ми дуже хочемо автоматизувати інтеграцію із ZooKeeper. І в планах інтегруватися із ZooKeeper-operator. Тобто. для ZooKeeper написаний оператор і логічно, щоб два оператори почали інтегруватися для побудови зручнішого рішення.
- Ми хочемо зробити складніші перевірки життєдіяльності.
- Зеленим я виділив те, що у нас на підході успадкування Templates – DONE, тобто з наступним релізом оператора ми вже матимемо успадкування шаблонів. Це потужний інструмент, який дозволяє будувати складні конфігурації зі шматочків.
- І ми хочемо автоматизувати складні завдання. Основна з котрих це Re-sharding.

Давайте проведемо проміжні результати.

Що ми маємо на виході? І чи варто цим займатися чи не варто? Чи потрібно взагалі намагатися затягнути базу даних у Kubernetes та застосовувати оператор загалом та Alitnity-оператор зокрема.
На виході ми отримуємо:
- Істотне спрощення та автоматизацію конфігурування, розгортання, а також супроводу.
- Відразу вбудований моніторинг.
- І готові для використання кодифіковані шаблони для складних ситуацій. Вже дію типу додати репліку не треба робити руками. Це робить оператор.

Залишилося лише останнє питання. У нас вже є база даних в Kubernetes, віртуалізація. Що з продуктивністю такого рішення, особливо у ключі того, що ClickHouse оптимізовано під продуктивність?
Відповідь – все нормально! Я не докладно розписуватиму, це тема окремої доповіді.

Але є такий проект як TSBS. Яке його основне завдання? Це тест бази даних на продуктивність. Це спроба порівнювати тепле з теплим, м'яке з м'яким.
Як він працює? Генерується один набір даних. Потім цей набір даних на однаковому наборі тестів проганяється різних базах даних. І кожна база даних вирішує одне завдання так, як вона вміє. І потім можна порівнювати результати.
Він підтримує велику купу баз даних. Я виділив три основні. Це:
- TimescaleDB.
- InfluxDB.
- ClickHouse.

Також було проведено порівняння з іншим схожим рішенням. Порівняння з RedShift. Порівняння було зроблено на Amazon. ClickHouse теж добре всіх обганяє у цьому питанні.

Які висновки можна зробити з того, що я розповів?
- DB в Kubernetes можна. Напевно, можна будь-які, але загалом виглядає, що можна. ClickHouse у Kubernetes точно можна силами нашого оператора.
- Оператор допомагає автоматизувати процеси та реально спрощує життя.
- Продуктивність нормальна.
- І нам здається, що це можна і потрібно використовувати.
Open source – приєднуйтесь!
Як я вже казав, оператор – це повністю open source продукт, тому було б дуже добре, якби максимальна кількість людей використовувала його. Приєднуйтесь! Ми чекаємо на вас усіх!
Дякую всім!
Питання

Дякую за доповідь! Мене звати Антон. Я з компанії SEMrush. Мені цікаво, що із логуванням. Про моніторинг чути, а про логування нічого, якщо говорити про кластер цілком. У нас, наприклад, піднятий кластер на залізі. І ми використовуємо централізоване логування, стандартними засобами збираємо до загальної купи. І потім звідти дістаємо цікаві для нас дані.
Хороше питання, тобто логування у списку todo. Оператор наш поки що це не автоматизує. Він ще розвивається, проект ще досить молодий. Ми розуміємо необхідність логування. Це також дуже важлива тема. І вона, напевно, не менш важлива за моніторинг. Але першим у списку реалізації був моніторинг. Логування буде. Ми, природно, намагаємося автоматизувати всі сторони життєдіяльності кластера. Тому відповідь – на даний момент оператор, на жаль, цього не вміє, але це є у планах, ми це робитимемо. Якщо є бажання приєднатись, то pull request, будь ласка.
Вітаю! Дякую за доповідь! У мене є стандартне питання, пов'язані з Persistent Volumes. Коли ми створюємо даним оператором конфігурацію, як оператор визначає на якій ноді у нас примоутен якийсь диск чи папка? Ми повинні йому попередньо пояснити, що, будь ласка, розміст наш ClickHouse саме на цих нодах, на яких є диск?
Наскільки я розумію, це питання – це продовження local storage, особливо частини його по hostPath. Це як пояснювати всій системі, що треба, щоб pod був запущений саме на такій ноді, на яку у нас є фізичний підключений диск, який змонтований таким шляхом. Це ціла секція, яку я торкнувся дуже поверхово, тому що там відповідь досить велика.
Коротко це виглядає так. Нам, природно, треба зробити пропорційність цих volumes. На даний момент у local storage динамічного provision немає, тому DevOps повинні самі нарізати диски, ось ці volumes. І повинні пояснити Kubernetes provisioning, що в тебе будуть Persistent volumes такого класу, який знаходиться на таких нодах. Потім треба буде пояснити Kubernetes, що pod'и, які вимагають такого класу local storage, треба по labels шедлити тільки на такі ноди. Для цього в операторі є можливість призначити якимось label і one per host instance. І вийде, що pod'и будуть змаршрутизовані Kubernetes'ом для запуску тільки на ноди, що задовольняють вимоги, labels, кажучи простою мовою. Адміністратори призначають labels, роблять provisioning дисків руками. І тоді воно масштабується.
І третій варіант local допомагає це трошки полегшити. Як я вже наголошував, це кропітка робота з налаштування, яка на виході допомагає отримати максимальну продуктивність.
У мене є друге питання, пов'язане з цим. Kubernetes замислювався так, що нам не важливо втратимо ми ноду чи ні. Що нам робити, якщо ноду, де у нас висить шард, ми втратили?
Так, Kubernetes спочатку позиціонувався, що у нас ставлення до наших pod'ів – це як cattle, а тут у нас кожен диск стає чимось на зразок домашнього улюбленця. Є така проблема, що ми їх не можемо просто так викидати. І розвиток Kubernetes йде в той бік, що неможливо повністю ставитися до цього філософськи, як до ресурсів, що повністю викидаються.
Тепер практичне питання. Що робити, якщо у вас загубилася нода, на якій диск був? Тут завдання вирішується більш рівні. У випадку з ClickHouse ми маємо репліки, які працюють на рівні вище, тобто. на рівні ClickHouse.
Яка виходить диспозиція? За те, щоб не загубилися дані, відповідає DevOps. Він повинен правильно налаштувати реплікацію і слідкувати, щоб реплікація виконувалася. У репліці на рівні ClickHouse мають бути дані продубльовані. Це не те завдання, яке вирішує оператор. І не те завдання, яке вирішує сам Kubernetes. Це на рівні ClickHouse.
Що робити, якщо у вас залізна нода відвалилася? І виходить, що треба буде поставити другу, правильно на ній спровожнити диск, нанести labels. І після цього вона стане задовольняти вимоги, що Kubernetes на ній може запустити instance pod'а. Kubernetes його запустить. У вас кількість pod'ів не вистачає до заданого. Вона пройде циклом, який я показував. І на верхньому рівні ClickHouse зрозуміє, що у нас увійшла репліка, вона ще порожня і на неї треба починати переливати дані. Тобто. цей процес ще погано автоматизований.
Дякую за доповідь! Коли відбуваються всякі гидоти, падає оператор і перезапускається, а в цей момент надходять події, чи ви якось обробляєте це?
Що станеться, якщо оператор упав і перезапустився, так?
Так. І в цей момент надійшли події.
Завдання, що робити у цьому випадку частково поділяється між оператором та Kubernetes. Kubernetes має можливість перепрограти подію. Він переграє. А вже завдання оператора – зробити так, щоб, коли на нього було зроблено replay лога подій, щоб ці події були ідемпотентними. І щоб повторне входження тієї самої події не ламало нам нашу систему. І наш оператор із цим завданням справляється.
Вітаю! Дякую за доповідь! Дмитро Зав'ялов, компанія Смєдова. Чи планується додавання до оператора можливості налаштування з haproxy? Цікавий якийсь інший балансувальник крім стандартного, щоб він розумним був і розумів, що там реально ClickHouse.
Ви кажете про Ingress?
Так, Ingress замінити на haproxy. У haproxy можна вказати топологію кластера, де він має репліки.
Наразі ми над цим не думали. Якщо вам це треба і зможете пояснити, навіщо це треба, то можна буде реалізувати, особливо якщо ви захочете взяти участь. Ми із задоволенням розглянемо варіант. Коротка відповідь – ні, у нас зараз такої функціональності немає. Дякую за наведення, ми на цю справу подивимося. А якщо ви ще поясните use case і навіщо це потрібно на практиці, наприклад, issues на GitHub створите, то чудово буде.
Вже є.
Добре. Ми відкриті до будь-яких пропозицій. І haproxy ставиться до списку todo. Список todo росте, а не зменшується поки що. Але це добре, це означає, що продукт потрібний.
Джерело: habr.com
