Кластери завдають удару у відповідь. Як приручити Kubernetes у масштабі ентерпрайзу
Привіт, спільното! Мене звати Денис, я DevOps-інженер, який уже понад п’ять років досліджує глибини Azure Cloud — від простих сценаріїв до архітектурного трешу. У цій статті хочу поділитися з вами досвідом оптимізації Kubernetes-середовища в Azure для ентерпрайз-проєкту з понад сотнею підписок — і показати, як можна спростити собі роботу, створивши спільне середовище для кількох команд.
Це історія про централізацію AKS-кластерів, упровадження RBAC на базі Entra ID та про те, як позбавити DevOps-команди нервових зривів, а бізнес — зайвих витрат. Запрошую і вас у цю пригоду :)
Аналіз середовища та головні проблеми
Все почалося з того, що кожна команда в нашому проєкті (а їх було чимало) мала власний AKS-кластер. Dev, QA, performance — усі хотіли «пісочницю» під себе. На перший погляд, це здавалося цілком логічним: має бути окреме місце, щоб творити закони всесвіту.
Та з часом кількість кластерів перевалила за 25. Частина з них ледь жевріла на
Аналізу цього хаосу виявив кілька болючих і суттєвих проблем:
А ви вже чули, що 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-команда нарешті перестала бути заручником кожного нового інженера.
Ми зменшили інфраструктурні витрати, централізували контроль — і з хаосу у вигляді десятків кластерів створили систему, яка працює на нас, а не навпаки.
Посилання:
- devops01.xyz
- t.me/devops_01_ua
- Installation — Azure Kubelogin
- Use Azure RBAC for Kubernetes Authorization
- Use Microsoft Entra ID and Kubernetes RBAC for clusters — Azure Kubernetes Service | Microsoft Learn
- Using RBAC Authorization | Kubernetes
- Create an access package in entitlement management — Microsoft Entra ID Governance
4 коментарі
Додати коментар Підписатись на коментаріВідписатись від коментарів