Кластери завдають удару у відповідь. Як приручити Kubernetes у масштабі ентерпрайзу

💡 Усі статті, обговорення, новини про DevOps — в одному місці. Приєднуйтесь до DevOps спільноти!

Привіт, спільното! Мене звати Денис, я DevOps-інженер, який уже понад п’ять років досліджує глибини Azure Cloud — від простих сценаріїв до архітектурного трешу. У цій статті хочу поділитися з вами досвідом оптимізації Kubernetes-середовища в Azure для ентерпрайз-проєкту з понад сотнею підписок — і показати, як можна спростити собі роботу, створивши спільне середовище для кількох команд.

Це історія про централізацію AKS-кластерів, упровадження RBAC на базі Entra ID та про те, як позбавити DevOps-команди нервових зривів, а бізнес — зайвих витрат. Запрошую і вас у цю пригоду :)

Аналіз середовища та головні проблеми

Все почалося з того, що кожна команда в нашому проєкті (а їх було чимало) мала власний AKS-кластер. Dev, QA, performance — усі хотіли «пісочницю» під себе. На перший погляд, це здавалося цілком логічним: має бути окреме місце, щоб творити закони всесвіту.

Та з часом кількість кластерів перевалила за 25. Частина з них ледь жевріла на 5–10 % використання виділених ресурсів, деякі були на «скам’янілих» версіях, які вже не підтримували новіші розв’язки або фічі, а про інші й зовсім ніхто нічого не знав. Як член DevOps-команди, я все частіше чув «чому не працює?!» від інженерів та «чому так дорого?!» від менеджменту — і все рідше мав на це відповідь.

Аналізу цього хаосу виявив кілька болючих і суттєвих проблем:

А ви вже чули, що 21 червня DOU Mobile Day?

  • Витрати росли, як на дріжджах. Віртуальні машини крутяться, подів на них — два, використання СРU i memory — 5–10 %.
  • Фрагментація. Різні версії Kubernetes, різні підписки, різні політики — спробуй розберися.
  • Доступи в хаосі. Кожен мав доступ за принципом most privilege, і не завжди до потрібного кластера. Ручне управління доступами — це постійний ризик помилок і дірок у безпеці.
  • Моніторинг кусався ціною. Datadog — класний, але токенів було стільки, що дешевше виходило завести власний зоопарк.
  • Складність управління. Адміністрування 25 різних кластерів ускладнює процес масштабування, оновлення та моніторингу.

Перші спроби виправити ситуацію

Наші перші ідеї мали на меті не налагодити процес загалом, а просто виграти час.

Автоматичне вимикання кластерів у неробочий час

Ідея звучала логічно: вимикати непотрібні AKS-кластери вночі чи у вихідні за допомогою Jenkins-джоб або Azure Automation. Але... реальність швидко вдарила по клавіатурі: хтось працює з Америки, хтось — з Європи, хтось ще й уночі тестує. Немає такого часу, коли ніхто не працює.

Вимикаєш кластер — когось підставляєш. Залишаєш увімкненим — нічого не економиш. Тож, як то кажуть, мрія була красива, але непридатна до життя.

Динамічне масштабування окремих кластерів

Наступна ідея — зменшити кількість нодів у кластерах, коли вони не завантажені. Технічно — просто. Але по факту:

  • Ми все ще мали дюжину кластерів — кожен зі своєю логікою, оновленням, RBAC-конфігурацією, моніторингом, а також командою, яка кричить, коли щось не працює.
  • Навіть найменша зміна потребувала ручного втручання або кастомних автоматизацій.

Масштабування допомагало економити, але головний тягар лишався: усе це треба було обслуговувати, підтримувати й документувати.

Нова надія

І от на якомусь етапі з’явилася думка: «А якщо створити єдиний кластер — спільну „кухню“, де кожна команда „готує“ у своєму цеху, але „миють посуд“ централізовано?» Так народилась ідея: один кластер, одна підписка, одна точка входу.

Єдиний AKS-кластер, до якого всі команди підключаються та мають доступ до свого проєкту (namespace). Кожна команда отримує лише те, що їй потрібно — ні рядком більше.

Що б це нам дало?

  • Автоскейлінг — і більше не треба платити за порожні ноди.
  • Одна версія Kubernetes — жодних «ой, у нас 1.11, воно вже не працює і не підтримується, а кластер у failed state».
  • Інтеграція Entra ID відкрила б можливість використовувати групи на рівні проєктів, а також ролі — вбудовані або кастомні.
  • Адмінкоманда відповідає за сам кластер: апдейти, безпека, моніторинг, резервування.
  • Зниження стресу. Коли вся інфраструктура під рукою й в одному місці, масштабуватись, дебажити, автоматизувати, онбордити нові команди стає в рази простіше.

Звучить красиво. Але чи дійсно ми могли це реалізувати? І що в нас було для цього в арсеналі?

Дві вежі: Azure RBAC проти Kubernetes RBAC

Ідея є, час роздивитися варіанти.

Перша вежа — Azure Role-Based Access Control

Використати Azure RBAC, який напряму інтегрується з Microsoft Entra ID. Перевага в тому, що права доступу централізуються: усе через Azure CLI або Portal (ну, майже все).

Можна видавати такі ролі:

  • RBAC Reader — тільки перегляд. RoleBindings не видно, і це плюс безпеці.
  • RBAC Writer — можна змінювати ресурси, але не заходити в політики безпеки.
  • RBAC Admin — має владу над namespace, створює ролі, усім рулить.
  • Cluster Admin — бог кластера. Доступ тільки обраним: тут або все, або нічого.

Це давало плюси:

  • Централізоване керування доступом.
  • Інтеграція з Entra ID.
  • Менше YAML’ів — RoleBindings не пишемо для кожного.

Але й без підводних каменів не обійшлося:

  • Гнучкість страждає. Немає способу сказати: «Дай мені get logs тільки в omega namespace».
  • Залежність від Azure — усе крутиться навколо нього. Без нього — нічого.

Як це реалізувати? Передусім вмикаємо «Microsoft Entra ID authentication with Azure RBAC» у кластері.

Все добре, аж поки не розуміємо: навіть власник ресурсу після цього не має доступу до namespace’ів.

Виправляємо:

az role assignment create --role "Azure Kubernetes Service RBAC Cluster Admin" --assignee <object_id> --scope /subscriptions/<sub_id>/resourcegroups/<rg>/providers/Microsoft.ContainerService/managedClusters/<aks_name>

Або через портал:

Після F5 усе з’явилось як треба (до речі, в клауді це улюблена кнопка).

Встановлюємо kubelogin. Заходимо в кластер як користувач-адміністратор (якого ми тільки що нагородили цією роллю) за допомогою:

az account set --subscription <subID>
az aks get-credentials --resource-group <rg name> --name <aks name> --overwrite-existing

Створюємо два namespace — omega і alpha — і симулюємо користувача Omega User, якому треба працювати лише в omega:

kubectl create ns <namespace name>

Призначаємо йому пару ролей. Зокрема, User Azure Kubernetes Service Cluster User Role — для того щоб отримати інформацію з кластера (az aks get-credentials).

Призначення ролі на рівні namespace відбувається виключно через CLI. Через Portal можемо додавати користувачів і групи лише на рівні кластера, але наша ціль — надати доступ лише до проєкту, тому використовуємо це закляття:

az role assignment create --role "Azure Kubernetes Service RBAC Writer" --assignee <object_id> --scope /subscriptions/<sub_id>/resourceGroups/<rg>/providers/Microsoft.ContainerService/managedClusters/<aks_name>/namespaces/<namespace>

Переходимо під Omega User і пробуємо:

kubectl run pod --image=nginx -n omega
kubectl get pods -n omega

Усе працює: поди створюються, доступ є — маленька перемога.

А тепер — тест безпеки:

kubectl run pod --image=nginx -n alpha

Отримуємо відмову. Отже, доступ працює саме так, як треба.

Як перевірити, хто і який має доступ? Це, мабуть, найболючіше місце. Azure Portal покаже тільки глобальний доступ до кластера, а ось namespace-рівень можна побачити лише через CLI:

Для того, щоб витягти детальнішу картину, заходимо на акаунт адміна та виконуємо таке закляття:

az role assignment list --scope /subscriptions/<sub id>/resourcegroups/<rg name>/providers/Microsoft.ContainerService/managedClusters/<aks name>/namespaces/<namespace> --output json --query "[].{principalName:principalName, roleDefinitionName:roleDefinitionName, scope:scope}"

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

Як покращення можна створити AAD-групи з продуманими назвами, наприклад: AKS_Omega_Writer, AKS_Alpha_Reader тощо. Але найбільша проблема — гнучкість.

А що як нам потрібна розширена роль читача для деяких команд? Чи можемо ми краще? Забираємо висновки з цього розв’язку — і продовжуємо подорож.

P.S.: не забуваємо забрати роль.

az role assignment delete --role "Azure Kubernetes Service RBAC Writer" --assignee <object_id> --scope /subscriptions/<sub_id>/resourceGroups/<rg>/providers/Microsoft.ContainerService/managedClusters/<aks_name>/namespaces/<namespace>

Друга Вежа — Kubernetes RBAC + Entra ID

Якщо Azure RBAC — це централізована «панель з кнопочками», то Kubernetes RBAC — це власноручне налаштування кожного гвинтика. Довше, зате точніше.

У цьому підході все починається з Entra ID, який відповідає за аутентифікацію. А от авторизація — вже в самому кластері, через Role та RoleBinding.

Переваги були очевидні:

  • Точковий контроль. Можна сказати: «Цей юзер може лише get pods у цьому namespace».
  • Гнучкість. Хочеш read-only на один deployment — будь ласка.
  • Інтеграція з Entra ID. Без логінів-паролів, усе через корпоративну ідентичність.

Але ціна питання:

  • Більше YAML’ів. Кожен доступ — це окрема роль, біндінг.
  • Більше координації. Azure каже, хто ти, а кластер — що ти можеш. І щоб не напартачити, треба уважно стежити за відповідністю.

Теорію знаємо — час імплементувати.

Починаємо з того, що створюємо групу адміністраторів і додаємо туди себе (або того, кому довіряємо кластер).

У налаштуваннях вмикаємо Authentication and Authorization > Microsoft Entra ID Authentication with Kubernetes RBAC — помічаємо, що група адміністраторів (Cluster admin ClusterRoleBinding) має бути додана одразу, але ми до цього готові.

З урахуванням попередніх граблів створюємо групу в Entra ID — назвемо її Omega_Write (можна дібрати і красивішу назву).

Додаємо до групи нашого Omega-користувача (це можна зробити пізніше, адже ми будемо приписувати роль до групи). Записуємо собі Object_id групи — знадобиться пізніше.

Відтак нам потрібно, щоб група мала доступ до кластера — додаємо відповідну роль:

az role assignment create --role "Azure Kubernetes Service Cluster User Role" --assignee <object_id> --scope /subscriptions/<sub_id>/resourcegroups/<rg>/providers/Microsoft.ContainerService/managedClusters/<aks_name>

або через улюблений портал:

Далі — магія YAMLу. Ми маємо підготувати Role та RoleBinding маніфести, і тут у гру вступає гнучкість — усе залежить від вимог та нас. Тому починаємо творити.

Опишемо dev role:

kind: Role
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  name: dev-omega-role
  namespace: omega
rules:
- apiGroups: ["", "extensions", "apps"]
  resources: ["*"]
  verbs: ["*"]
- apiGroups: ["batch"]
  resources:
  - jobs
  - cronjobs
  verbs: ["*"]

А також RoleBinding, у якому і використаємо записаний раніше Object_Id:

kind: RoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  name: dev-omega-roleBinding
  namespace: omega
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: Role
  name: dev-omega-role
subjects:
- kind: Group
  namespace: omega
  name: <groupObjectId>

Далі нам треба створити їх у кластері:

kubectl apply -f omega-dev-role.yml
kubectl apply -f omega-dev-roleBinding.yml

Ну що ж, нумо тестувати. Заходимо в кластер як Omega-користувач і спробуємо підглядати до інших проєктів та створити що завгодно і де завгодно.

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

А що далі?

Кінець? Та ні, де там — далі починається нова пригода: автоматизація. Адже з кожним запитом на доступ все ще мала розбиратися DevOps-команда.

Отож ми перенесли управління на командні рівні, автоматизувавши усе, що повторювалося. Для кожної команди створювали окремі групи в Entra ID з чіткою структурою імен. Їхніми власниками призначали техлідів або менеджерів — саме вони відповідали за додавання чи видалення користувачів. Це дозволило зняти з DevOps-команди обов’язок бути «проксі» для всіх запитів на доступ.

Крім того, ми автоматизували процес призначення ролей, namespace’ів і навіть частини мережевої інфраструктури, зокрема налаштування Application Gateway з окремими listener’ами для кожного сервісу. Тепер додавання нового проєкту — це не низка мануальних кроків, а звичайний запит, який запускає цю машину.

Додатково інтегрували Access Packages, що дозволило новим інженерам самостійно запитувати доступ до потрібних груп із подальшим затвердженням менеджерів — без участі DevOps.

Висновки

Azure RBAC — класне рішення для швидкого старту. Просте, зручне і добре підходить для невеликих команд або РОС-проєктів, де не потрібна мікродеталізація. Але в нашій реальності — з десятками команд, окремими namespace, різними рівнями доступу та власним CI/CD — його гнучкості просто замало.

Перехід на Kubernetes RBAC з інтеграцією через Entra ID дав нам контроль, деталізацію і гнучкість, які були критично потрібні. А коли все це обросло автоматизацією, доступи перестали бути болем, а DevOps-команда нарешті перестала бути заручником кожного нового інженера.

Ми зменшили інфраструктурні витрати, централізували контроль — і з хаосу у вигляді десятків кластерів створили систему, яка працює на нас, а не навпаки.

Посилання:

👍ПодобаєтьсяСподобалось1
До обраногоВ обраному0
LinkedIn
Дозволені теги: blockquote, a, pre, code, ul, ol, li, b, i, del.
Ctrl + Enter
Дозволені теги: blockquote, a, pre, code, ul, ol, li, b, i, del.
Ctrl + Enter

Комрад за п’ять років до автоскейлінгу та rbac добрався. Ще пару років та tf буде.

Шкода, що з усієї історії вдалося помітити лише rbac та autoscaling як базові поняття :)
Цього разу зробив акцент на архітектурному підході, а не на інструментах.
Але дякую за фідбек — працюю над тим, щоб наступного разу донести більше цінності без втрат у передачі.

А чому б не зробити все через terraform?

Дякую за слушне зауваження!
Звичайно, вся інфраструктура — від мережі до створення каталогів і assignment’ів для Access Packages — була реалізована через Terraform. Бо, погодьмося, нікому не хочеться витрачати час і нерви на клацання в порталі :)

На жаль, у статті банально не вистачило місця, щоб детально розгорнути Terraform-частину — вона залишилася «за кадром». Хоча, згоден, варто було хоча б згадати це в завершенні. Зате тепер є плюс: це кейс, який можна повністю реалізувати самостійно — і відчути всі нюанси на практиці.

Підписатись на коментарі