Як ми "зняли" наш старий оркестратор Kubernetes і побудували ідеальний
Андрій Новоселов, Gcore, керівник послуг PaaS
- Kubernetes як послуга
- Функції як послуга
- Контейнери як послуга
- Логування як послуга
- PostgreSQL як послуга
- *aaS
OpenStack
Для оркестрації кластерів Kubernetes за допомогою OpenStack ми використовували Magnum та Heat. Magnum оркеструє контейнерні кластери та підтримує Docker Swarm і k8s, тоді як Heat створює конфігурацію cloud-init для вузлів k8s, оновлює версії додатків та конфігурації на вузлах k8s і працює з шаблонами або стеком Heat.
Архітектура OpenStack
Компоненти Magnum:
- Magnum API,
- RabbitMQ,
- Magnum conductor,
де API отримує завдання, ставить їх у Rabbit MQ, conductor отримує їх і обробляє.
Компоненти Heat:
- Heat API,
- RabbitMQ,
- Heat engine,
- Heat agent.
В цій архітектурі RabbitMQ та Heat agent є найбільш вразливими компонентами.
Обмеження OpenStack
За замовчуванням Magnum та Heat мають кілька обмежень.
- Відсутність ізоляції контрольного плану від користувача.
- API OpenStack, який потрібно сховати за Gcore Cloud API.
Gcore OpenStack
У першій версії рішення Gcore для керованого Kubernetes все знаходилося всередині приватної мережі клієнта.
Перша версія рішення Gcore для керованого Kubernetes
Ми мали три віртуальні машини, що були вузлами контрольного плану, а також кілька робочих вузлів. Тому ми розділили контрольний план від наших користувачів. Також ми налаштували брандмауер, щоб блокувати весь трафік з робочих вузлів, окрім трафіку через три балансувальники навантаження: один до etcd, другий до kube-api, а третій до kube-dns. Все, що працювало на контрольному плані, ми запускали як одиницю systemd за допомогою podman. На робочому вузлі запускався лише kubelet як одиниця systemd всередині podman. Все інше працювало через контейнерний оточення Docker. Ми використовували Fedora CoreOS, що є обмеженням.
Найкраще в цій архітектурі було використання OpenStack. Оскільки OpenStack має велику спільноту, яка працює над новими можливостями, ми могли заощадити час.
Недоліки включають:
- Додаткові витрати для Cloud API, оскільки весь трафік проксіюється до Magnum;
- Вразливість;
- Проблеми з видимістю, оскільки контрольний план знаходиться всередині приватної мережі клієнта, і доволі важко отримати будь-які дані з цієї мережі;
- Відсутність bare-metal вузлів з коробки (коли ми починали), тому використовувати можна було лише віртуальні машини.
Час запуску кластера Kubernetes становив в середньому 20 хвилин, з найбільшими недоліками у видимості та вразливості.
Налагодження Openstack
Операція Magnum в продукції — це як кататися на велосипеді, але здається, що ми опинились в пеклі, і все навколо нас також горить. Якщо RabbitMQ падає, Heat може не справитись. Стек Heat може зламатися, і немає CLI методу, щоб відновити його. В такому випадку потрібно уважно подивитися на базу даних продукції та внести деякі оновлення.
Щодо Heat agent, то на відновлення продукційного кластера після несправності в Rabbit було потрібно близько чотирьох годин. Якщо у вас 100 кластерів, це вже 400 годин, що забирає чимало часу. Якщо ви щось виправляєте, а Heat-agent продовжує оновлювати, немає потреби перезавантажувати вузол чи робити його незмінним. Якщо потрібно оновити вузол, Heat-agent переналаштує систему, одиниці, конфігурації тощо.
Припустимо, ми починаємо з двох чорних котів. Після того, як ми виправили проблему, ми отримуємо невелику зміну в конфігурації, і коти стають білими. Після ще однієї несправності один з цих кластерів зламається, і ми залишаємося з білим котом і оранжевим котом. Справа в тому, що у нас немає незмінності. Ми маємо все виправляти вручну, що викликає великий розрив у конфігураціях.
Ми знали всіх наших основних клієнтів і їхні кластери, але нам доводилось пам'ятати, коли і чому було виправлено кожну несправність. Це працює для кількох кластерів, але коли у вас сотні з Magnum, це більше схоже на роботу з домашніми тваринами, ніж з худобою.
Плюси та мінуси OpenStack
Ще одним недоліком Magnum є підтримка версій Kubernetes.
Наприклад, зараз ми використовуємо Zed (1.23), але остання версія Magnum підтримує лише Kubernetes 1.27. Справа в тому, що якщо ви отримуєте останню версію Magnum, ви не отримаєте підтримувану версію Kubernetes одразу.
Отже, Openstack не ідеальний і потребує вдосконалення. Нам потрібно:
- Покращити стабільність,
- Додати підтримку BM,
- Додати швидшу підтримку нових версій,
- Покращити видимість, оскільки це надто дратує, коли треба заходити в приватні мережі клієнтів,
- Покращити час запуску кластеру, оскільки 20 хвилин — це занадто багато,
- Найняти більше людей для управління операційною частиною під час цих покращень.
Питання в тому, чи слід зосередитися на вдосконаленні Magnum, чи спробувати змінити його повністю? Це не так просто. Якщо зебри еволюціонують в ультрамаринів, вони можуть знищити левів. Адже ультрамарини ефективніші за зебр, яких ми маємо зараз. Це проблема теорії еволюції: локальний екстремум проти локального максимуму. Отже, ви — зебра, і єдиний спосіб еволюціонувати — це ставати кращими. Тоді вам потрібно йти вгору. Поточна архітектура зебри має деякі обмеження. Так чи інакше, ви станете найкращою зеброю, але коли досягнете локального максимуму, вам стане тільки гірше. Можливо, ви станете кращим ультрамарином, але для цього вам доведеться повернутися до своїх зебрових коренів, що зробить вас слабшими, і ви можете зникнути. Тож, коли ви досягнете локального екстремуму, це буде найкраще, що ви можете зробити, якщо нічого не змінюється навколо вас.
А що, якщо досконалість є десь там? Що, якщо є технологія, чиї поточні можливості кращі, ніж найкращий Magnum?
Зараз на ринку доступні наступні технології: MicroK8s (на Ubuntu), OKD (Red Hat), Rancher (SUSE), Deckhouse Kubernetes Platform (Flant), Gardener (ASP), Ansible Playbooks. Однак виглядає так, що Cluster API 1.7 набагато кращий за Magnum і має потенціал для зростання.
Cluster API
Огляд
Cluster API — це C-група всередині Kubernetes, яку реалізує команда Kubernetes. Cluster API:
- Керує життєвим циклом кластерів декларативно,
- Працює на місці/в хмарі,
- Визначає загальні операції,
- Забезпечує стандартну реалізацію,
- Дозволяє змінювати реалізації на альтернативні,
- Може бути розширено для підтримки будь-якої інфраструктури.
Архітектура
Cluster API — це просто 4 бінарники:
- capi-controller-manager,
- capi-bootstrap-controller-manager,
- capi-control-plane-controller-manager,
- infrastructure-provider.
Оскільки вам потрібно Kubernetes для створення іншого Kubernetes, CAPI — це набір контролерів всередині Kubernetes. capi-controller-manager — це один порт з кількома контролерами, які синхронізують користувацькі ресурси Cluster API. capi-bootstrap-controller-manager та capi-control-plane-controller-manager створюють конфігурацію хмарного підрозділу для наших робочих і контрольних вузлів. infrastructure-provider підключає все це до інфраструктури, яку ви маєте, і її можна змінювати в будь-який час.
Cluster API "з коробки"
bootstrap-cm:
- kubeadm
- microk8s
- talos
- eks
control-plane-cm:
- kubeadm
- microk8s
- talos
- nested
Обмеження стандартного Cluster API для Gcore
Єдине, що Gcore може використовувати — це kubeadm для початкової настройки та контрольного плану, і немає інфраструктурного провайдера для Gcore Cloud.
Не існує ізоляції контрольного плану від користувача.
Крім того, для того щоб створити кластер k8s, вам потрібен кластер k8s, і якщо ви використовуєте kubeadm, ви створите три ВМ для контрольного плану, що є надмірним.
Стандартний Cluster API
Стандартний Cluster API виглядає майже так само, але з меншим числом балансувальників навантаження. У нас є приватна мережа клієнта, щонайменше три вузли контрольного плану та стільки робочих вузлів, скільки потрібно. На кожному вузлі в systemd ми маємо kubelet, який запускає будь-яке контейнерне середовище (ми використовуємо CRI-O, але це може бути Docker або Container-d). kubelet запускає всі інші поди. На стороні контрольного плану це в основному стандартний Kube, etcd, kube-api, controller-manager, scheduler та Calico або будь-який інший CNI. Робоче навантаження з робочих вузлів доступає до kube-api через балансувальник навантаження в цій приватній мережі.
Gcore Cluster API
Отже, стандартний Cluster API також не є ідеальним і не зовсім підходить для керованого Kubernetes, хоча він кращий за Magnum.
- Компоненти контрольного плану — це поди всередині сервісного кластера k8s;
- Всі об'єкти CAPI знаходяться в тому ж просторі імен, що й поди контрольного плану;
- Всі користувацькі ресурси для Cluster API зберігаються в тому ж просторі імен;
- Немає трьох ВМ для контрольного плану, оскільки вони зазвичай недостатньо завантажені, а запуск віртуальної машини займає набагато більше часу, ніж для поду.
Щоб це зробити, нам довелося написати свій власний gcore-bootstrap-controller, створити новий gcore-control-plane-controller і отримати інфраструктурного провайдера capgc за допомогою наших колег з Wargaming.
Тепер у нас є дві різні приватні мережі: на стороні клієнта та нашому кластері управління.
На стороні Gcore ми маємо кластер Kubernetes з простором імен, який включає всі порти контрольного плану. Ми маємо балансувальник навантаження, спрямований на kube-api з публічною IP-адресою. Все робоче навантаження з робочих вузлів клієнта йде через kube-api в інтернеті, використовуючи публічну IP-адресу. Також у нас є список контрольних адрес для обмеження IP-адрес.
Однак:
- Що, якщо клієнти хочуть прочитати kubectl logs?
- Що, якщо клієнти хочуть виконати kubectl port-forward?
- Що, якщо клієнти розгортають щось з admission web hooks?
Немає зворотної мережевої з'єднаності, тому kube-api не має способу доступу до портів усередині робочих вузлів. Ми вирішили використовувати OpenVPN.
Ми запускаємо под з сервером OpenVPN на стороні клієнта на одному з робочих вузлів і створюємо ще один балансувальник навантаження, який також доступний публічно через apv4 або ipv6. Усередині контрольного плану в поді kube-api ми запускаємо side car з openvpn-client. Це підключається безпосередньо до балансувальника навантаження та сервера і підключає шляхи до робочих вузлів, портів і сервісів безпосередньо до kube-api.
Це ще не ідеально, але значно краще. Однак, що, якщо клієнт видаляє щось на стороні клієнта:
- Що, якщо клієнт видаляє сервер openvpn?
- Що, якщо клієнт видаляє демон-сет Calico або Cilium і втрачає мережу?
- Що, якщо клієнт видаляє kube-proxy, якщо використовується Calico?
Ми повинні якось це узгодити, оскільки це керована послуга. Тому ми використовуємо Argo CD.
Argo CD для Gcore Cluster API
Ми налаштували ArgoCD в кластері управління. Він має доступ до API клієнтського кластера всередині того ж кластера Kubernetes і має застосунок для всієї інфраструктури клієнта: kube-proxy, kube-dns, CNI та сервер openvpn. Тому, якщо клієнти використовують kubectl для видалення чогось з API, ArgoCD це узгодить.
Крім того, час запуску був зменшений з 20 до 12 хвилин.
Однак, чи дійсно нам потрібні два балансувальники навантаження? Octavia та OpenStack не такі надійні та швидкі, і ми можемо використовувати Konnectivity замість OpenVPN. Ми можемо позбутися балансувальника для кожного kube-api і використовувати лише один nginx-ingress — контролер для всього регіону замість LB на кожен кластер, а потім kube-api клієнта буде відкрито через ingress, і ми використовуватимемо лише зворотний проксі для нього.
Тепер у нас є один балансувальник навантаження перед контролером Ingress. Всі kube-api відкриті як стандартний об'єкт ingress. На кожному робочому вузлі ми маємо спеціальний под, knc-agent, який є агентом частиною Konnectivity. Біля кожного контрольного плану в кожному просторі імен ми маємо додатковий порт для сервера Konnectivity, і це, по суті, RPC-проксі. Отже, агент Konnectivity підключається до сервера Konnectivity, а потім kube-api використовує сервер Konnectivity як проксі для доступу до всіх робочих вузлів на стороні клієнта. Ми позбулись тонни балансувальників навантаження, і час запуску зараз складає лише 4 хвилини.
Є ще багато чого, що треба зробити. Можливо, ми хочемо:
- додати підтримку IPv6 (зроблено),
- зробити більше налаштувань для компонентів k8s,
- додати більше підтримки для Cilium,
- позбутися всіх балансувальників навантаження та додати bgp,
- і так далі.
Але все ще не ідеально. Потім ми перейшли від Magnum до Cluster API:
- Magnum був досить вразливим, і тепер ми маємо стабільний цикл узгодження. Якщо щось йде не так з кластером, цикл узгодження на кожному рівні допоможе нам. Наприклад, якщо вузол втрачено, буде створено новий. Якщо клієнт видалить що-небудь у своєму кластері, Argo CD це узгодить замість інженерів Ops.
- Ми мали довге відновлення, оскільки робочі вузли були змінні, і нам доводилося входити в них. Тепер у нас є незмінні робочі вузли, золотий образ для кожного вузла, так що кожен вузол можна відновити, якщо щось йде не так. Ми навіть можемо видалити будь-який вузол і створити новий, якщо потрібно, і це економить багато часу, оскільки тепер всі наші кластери однакові.
- У нас не було видимості, і було дуже складно сказати що-небудь про Kubernetes API для наших клієнтів, якщо ми не входили в ці клієнтські машини через SSH або не використовували якусь магію OpenStack. Тепер все — це об'єкт Kubernetes. Ми можемо використовувати єдиний kubectl + kube-prom-stack для всього регіону, щоб подивитись у простір імен якогось клієнтського кластера та перевірити його kube-api, перевірити, скільки ресурсів він має, які машини він використовує, яку версію Kubernetes підписано для кожної машини і навіть OpenStack ID машини, що полегшує налагодження будь-якої проблеми.
Тепер у нас є два оркестратори в продукції: кластери Magnum і кластери Cluster API. Немає простого способу перейти з існуючого оркестратора на новий. Ми можемо лише сказати нашим клієнтам, що у нас є новий оркестратор, який підтримує нову версію Kubernetes і Cilium, має швидкі оновлення та швидкий запуск. Ми можемо запропонувати їм використовувати bare metal вузли всередині нього і заохотити їх до міграції на новий оркестратор. В іншому випадку, вам доведеться здійснити міграцію клієнтів за них і надати керовані послуги DevOps безкоштовно.
Висновок
- Еволюція проти революції. Еволюція може здаватися логічною, але революція іноді набагато ефективніша та результативніша, і іноді це єдиний варіант.
- Домашні тварини проти худоби. Перемагає худоба. Автоматизація справді працює.
- Змінні проти незмінних. Незмінні речі працюють (оскільки немає необхідності у відхиленнях конфігурацій).
- Міграції в живій продукції з одного оркестратора k8s на інший є гладкими та простими.
- Нічого не є ідеальним, і завжди є спосіб робити все краще.
Питання та відповіді
Питання. Як ви управляли встановленням OpenStack і кластерами Cluster API?
Відповідь. У нас є абстракція. Моя команда не використовує OpenStack безпосередньо.
Ми маємо Gcore Cloud API, тому ми взаємодіємо з нашим Cloud API, і воно взаємодіє з OpenStack. Є окрема команда інженерів, відповідальна за OpenStack, а ми просто щасливі користувачі.
Питання. Різні компанії створюють платформи як сервіс для різних цілей: деякі мають внутрішніх клієнтів, інші — зовнішніх. Хто є клієнтами Gcore і як вони використовують ці Kubernetes кластери, які ви допомагаєте оркеструвати?
Відповідь. Ми є постачальником публічного хмари, тому будь-хто може бути нашим клієнтом. Однак історично ми більше орієнтовані на ігрову індустрію. Тому для нас дуже зручно мати bare-metal робочі вузли в Kubernetes на публічних IP, оскільки це зменшує латентність. Це одна з наших основних функцій.
Питання. Ви згадали, що OpenStack є реалізацією всього. Наскільки я пам'ятаю, OpenStack більше схожий на платформу, яка конкурує з Kubernetes, використовуючи Docker образи, в той час як OpenShift більше схожий на дистрибуцію Kubernetes. Ви використовуєте OpenStack і реалізуєте всі ці Kubernetes API всередині нього. Тобто ви фактично повторно реалізуєте Kubernetes з OpenStack?
Відповідь. Ми використовуємо OpenStack лише як інфраструктурного провайдера. Тому все, що нам потрібно від OpenStack, це bare-metal вузли, віртуальні машини, балансувальники навантаження та мережі.
Питання. Ви зробили аналогію з зеброю і ультрамарином, де Cluster API — це ультрамарин. Однак Cluster API тісно пов'язаний з Kubernetes, в той час як OpenStack — ні. Чи існував інший можливий спосіб реалізувати оркестрацію не з Cluster API, а з іншою технологією, чи Cluster API був єдиним очевидним вибором?
Відповідь. Існує багато технологій, які дозволяють працювати з різними підходами до створення Kubernetes кластера, наприклад, OKD — безкоштовна версія OpenShift або Gardener від SAP. Однак всі вони прив'язані до власників, і вам потрібно звикнути до SAP або Red Hat. Cluster API дозволяє вам працювати з кластерами так само, як ви це робите з подами. Наприклад, у вас є deployment, який створює replica set і pod. Так само у вас є deployment в Cluster API, який створює своєрідний replica set і віртуальну машину. Ви маєте rolling updates, і все це є користувацьким ресурсом всередині Kubernetes, він є частиною Kubernetes спільноти, і він стандартний, і виглядає дуже добре. Це популярно в Kubernetes спільноті, і має сенс використовувати це у вашій платформі, навіть якщо ваша платформа не є Kubernetes самою собою.
Питання. Ви використовуєте OpenStack як інфраструктурного провайдера. Наскільки важко управляти OpenStack API з вашим API? Наприклад, коли OpenStack оновлюється, всі API змінюються. Як ви підтримуєте ваше API, щоб воно слідкувало за змінами?
Відповідь. Це не так, як отримати нову версію OpenStack з перезавантаженням вашого комп'ютера. Ми плануємо оновлення, і це контрольований процес. Gcore Cloud API завжди готове до версії OpenStack, яка є під ним. Команда розробників Cloud API та команда операцій OpenStack співпрацюють і роблять оновлення гладкими та контрольованими.
Питання. Ви використовуєте свій власний ідентифікатор замість KStone?
Відповідь. Так. Gcore — це не просто хмарний провайдер. Ми також є постачальником CDN, постачальником стрімінгових послуг, постачальником AntiDDoS, постачальником AI послуг, і для всього цього у нас є єдиний обліковий запис користувача Gcore. У нас є своя система виставлення рахунків, свій постачальник IM. Ви можете називати це основними послугами хмарного провайдера. Ми використовуємо KStone для деяких випадків, але в основному це внутрішні потреби.
Питання. Оскільки ви використовуєте персистентні томи, засновані на OpenStack, що надається Cinder, балансувальники навантаження для додатків, надані Octavia, ви використовуєте нативний плагін Cinder CSI та плагін Octavia?
Відповідь. Ні. Ми використовуємо томи Gcore (під капотом це CEPH) і хмарні балансувальники навантаження (під капотом це Octavia), отже, це Gcore сховище.
Питання. Що ви використовуєте як сховище для read-write-many?
Відповідь.
Ми пропонуємо NFS як сервіс, тому ви можете створити сервер NFS всередині проекту в хмарі. Якщо у вас є Kubernetes кластер в тому ж проекті, то ви отримаєте спеціальний клас сховища, і зможете використовувати його для доступу до NFS шейрів. Це автоматизовано, тому вам не потрібно робити нічого для інтеграції NFS з нашим Kubernetes. Інтеграція доступна «з коробки».
Питання. Наскільки складне завдання впровадження системи Cluster API?
Відповідь. Новий оркестратор був створений у Confluence від ідеї до виробництва трьома розробниками, двома операційними інженерами та одним менеджером проекту за 9 місяців, з бета-версією, що була запущена через 6 місяців.
Питання. Можете розповісти трохи більше про впровадження контрольної плити? Як ви її запускаєте? Чи маєте ви власний оператор чи використовуєте Kamaji? Як ви розгортаєте контрольну плиту?
Відповідь. Cluster API складається з 4 бінарників, і нам довелося переписати 3 з них. Тому ми маємо власного оператора для контрольної плити для робочих вузлів та інфраструктурного провайдера. В основному ми створили власного оператора для контрольної плити, який створює простір і порти всередині нього, налаштовує etcd для приєднання, запускає Kube API тощо. Тому ми маємо цей сервіс Kubernetes кластер, який працює всередині OpenStack і який надає контрольну плиту всередині себе.
Питання. Чи контролюються ці порти, що працюють з etcd, іншим оператором, чи це частина вашого оператора для контрольної плити?
Відповідь. Ми намагаємося покращити це. Наразі це управляється кодом, але іноді потрібен інженер з операцій, щоб виправити це. Поки що нічого не ідеально.
Питання. Чи думали ви про відкриття коду? Зараз є певні проекти, які починають робити те саме для постачання контрольної плити. Вони розвиваються набагато швидше за ваше рішення, і з часом можуть стати більш зрілими за ваш проект. Може, буде краще відкрити рішення для спільноти та заохотити людей працювати разом над розробкою контрольної плити чи постачання CD?
Відповідь. У нас є наміри, але я не впевнений, коли ми зможемо це зробити, оскільки є багато бізнесових питань, які потрібно вирішити до того, як перейти до відкритого коду.
Перекладено з: The silver bullet for your magnum