Материалы к экзамену · Урок 2
Тенанты и доступ
Как платформа делит себя между тенантами, откуда берутся квоты и почему тенант — это не просто namespace.
Вторая по весу тема экзамена — и, пожалуй, самая полезная на практике. Если первый урок объяснял, из чего платформа собрана, то этот — как она делится между людьми.
Тенант — это объект, а не папка
В привычном Kubernetes изоляция начинается и заканчивается пространством имён. Здесь иначе: тенант (tenant) — это объект платформы, и создание его влечёт за собой целый набор последствий.
Заводите вы его так же, как всё остальное:
apiVersion: apps.cozystack.io/v1alpha1
kind: Tenant
metadata:
name: acme
namespace: tenant-root
Платформа в ответ создаёт пространство имён (namespace), раздаёт права, вешает сетевые политики, заводит квоты и, если попросили, поднимает внутри собственный мониторинг и хранилище.
Заодно тенант получает свой домен, и собирается он по правилу <имя>.<домен родителя>.
Платформа живёт на cloud.example.com — значит, у тенанта alpha будет
alpha.cloud.example.com, а у его ребёнка beta — beta.alpha.cloud.example.com. При
необходимости домен переопределяют вручную.
Тенанты вкладываются друг в друга
Вот что отличает эту модель от плоского списка namespace: тенанты образуют дерево.
Правило именования спрашивают, и оно чуть хитрее, чем кажется: имя пространства имён
собирается из слова tenant- и всей цепочки предков через дефис, кроме корня.
| Путь тенанта | Пространство имён |
|---|---|
root/acme | tenant-acme |
root/alpha/beta | tenant-alpha-beta |
root/a/b/c | tenant-a-b-c |
Корень в имя не попадает — tenant-root-alpha-beta будет неверным ответом.
Отсюда же ограничение на имена: дефис в имени тенанта запрещён, потому что он занят
под разделитель предков. Тенант acme-dev не существует — существует dev внутри acme,
и живёт он в tenant-acme-dev.
В самом объекте эти два имени лежат в разных полях, и их различие тоже спрашивают:
metadata.namespace — пространство имён родителя, там и лежит сам CR, а собственное
пространство имён тенанта платформа записывает в status.namespace. Отсюда и способ
перечислить детей — kubectl get tenants -n tenant-alpha покажет CR-ы, созданные внутри
alpha.
Зачем это нужно: провайдер отдаёт клиенту тенант, а тот делит его между своими отделами — и не приходит к провайдеру за каждым новым окружением.
Что наследуется, а что включается
У тенанта есть ровно четыре переключателя, и на экзамене спрашивают их буквальные имена:
etcd — свой кластер etcd, monitoring — свой мониторинг, ingress — свой контроллер
входящего трафика с TLS, seaweedfs — своё объектное хранилище S3. Каждый можно включить
или оставить выключенным.
Ключевая мысль, которую любят проверять: если сервис выключен, тенант поднимается вверх по дереву до ближайшего предка, у которого он включён. Не обязательно до родителя и не обязательно до корня — до ближайшего. Не остаётся без него, а наследует. Тенант без своего мониторинга шлёт метрики в мониторинг родителя; тенант без своего хранилища кладёт файлы в родительское.
Включать своё имеет смысл, когда нужна настоящая изоляция — например, клиент не должен видеть чужие метрики даже теоретически. Плата за это — ресурсы: каждый включённый сервис это реально работающие процессы.
Квоты и переподписка
Тенанту назначают предел по процессорам и памяти:
spec:
resourceQuotas:
cpu: 16
memory: 32Gi
Размер ресурсов задают пресетом (preset) в формате <серия>.<размер>. Серия закрепляет
соотношение процессора к памяти: t1 — 1:0.5, c1 — 1:1, s1 — 1:2, u1 — 1:4,
m1 — 1:8. Размеры идут от nano до 4xlarge, так что u1.medium — это универсальная
серия среднего размера.
Если рядом с пресетом явно написан блок resources, побеждает он:
resources:
cpu: 4
memory: 8Gi
И ловушка, ради которой всё это и спрашивают: пресеты тенантов и приложений — не то же
самое, что типы экземпляров KubeVirt (instance types) для виртуальных машин с сериями
U, O, CX, M и RT. Строка u1.medium допустима в обеих системах и означает разное,
так что смотрите, о каком объекте вопрос.
А теперь то, на чём спотыкаются практически все, — переподписка (overcommit,
cpuAllocationRatio, по умолчанию 10).
Работает она так: когда вы запускаете нагрузку с пределом в четыре процессора, платформа просит у планировщика не четыре, а предел, делённый на коэффициент — то есть четыре десятых. Гарантируется малое, а взять при необходимости можно много.
Формула короткая, и её стоит запомнить дословно:
запрос = предел ÷ cpuAllocationRatio
Смысл в том, что приложения почти никогда не потребляют свой предел. Раздавать гарантии по верхней планке значит держать половину железа простаивающей. Но если про коэффициент не знать, поведение планировщика кажется бессмысленным: попросили четыре ядра, а зарезервировано меньше половины одного.
Важно, где живёт этот коэффициент: он настраивается на уровне всей платформы, а не в отдельном тенанте. Один на всех — свойством тенанта его в вариантах ответа не называйте.
Изоляция
По умолчанию тенанты друг друга не видят: сетевые политики запрещают ходить между
пространствами имён. И это не переключатель — отключить изоляцию нельзя. Флаг
isolated существовал до версии 1.0 и убран; если он попадётся в вариантах ответа, это
ловушка.
Отрезаны поды не только от соседей. По умолчанию они не достучатся ни до kube-apiserver,
ни до собственного etcd тенанта. Нужен доступ — его открывают точечно, метками на поде:
policy.cozystack.io/allow-to-apiserver: "true"
policy.cozystack.io/allow-to-etcd: "true"
Значение — строка "true", и это тоже спрашивают.
Как люди попадают внутрь
Три пути, и это тоже спрашивают.
Дашборд — веб-интерфейс платформы. Вход через Keycloak, то есть по корпоративной учётной записи, а не по отдельному паролю.
kubeconfig — файл доступа, который выдаётся тенанту. Внутри него не сертификат, а
вызов внешней программы: kubectl при первом обращении открывает браузер, вы входите
через Keycloak, и выданный токен действует до истечения срока. Отсюда, кстати, требование
поставить kubelogin: без него kubectl не знает, как логиниться.
Terraform — тот же API, только описанием.
Откуда берётся сам файл кубконфига
Готовым файлом кубконфиг тенанту не выдают — его собирает администратор платформы скриптом из документации. Знать этот скрипт наизусть не нужно, а вот из чего он собирает файл — спрашивают.
У каждого тенанта в его пространстве имён лежит одноимённый секрет: у тенанта alpha это
секрет alpha в пространстве tenant-alpha. Скрипт достаёт оттуда три вещи:
| Что берётся | Из какого поля | Зачем |
|---|---|---|
| токен доступа | token | им тенант предъявляет себя API-серверу |
| сертификат центра сертификации | ca.crt | по нему kubectl убеждается, что сервер настоящий |
| пространство имён по умолчанию | namespace | чтобы не писать -n в каждой команде |
Адрес самого API-сервера скрипт берёт не из секрета, а из текущего кубконфига администратора,
который скрипт запускает. Итого файл собирается из токена, CA-сертификата и адреса
сервера — и в этом варианте никакого Keycloak и никакого kubelogin не требуется: токен
уже внутри файла.
Отсюда важное следствие: кубконфиг тенанта — это секрет ровно в том же смысле, что и пароль. Кто получил файл, тот получил и права тенанта, до отзыва токена.
Права внутри тенанта раздаются обычными ролями Kubernetes. Никакой отдельной системы разрешений у платформы нет, и это ответ на популярный вопрос-ловушку.
Тенант заведён, квоты выданы, люди внутрь пущены. Теперь им надо что-то заказать.
Что спросят на экзамене
- Что тенант — объект платформы, а не просто пространство имён.
- Что имя пространства имён =
tenant-плюс цепочка предков через дефис, без корня. - Что дефис в имени тенанта запрещён.
- Что тенанты вкладываются друг в друга, а вложенный создаётся внутри родителя.
- Что выключенный сервис наследуется от ближайшего предка, у которого он включён, — не обязательно от родителя.
- Имена четырёх переключателей дословно:
etcd,monitoring,ingress,seaweedfs. - Что домен тенанта собирается как
<имя>.<домен родителя>. - Что
metadata.namespace— пространство имён родителя, аstatus.namespace— своё. - Что кубконфиг тенанта скрипт из документации собирает из токена, CA-сертификата и адреса сервера: первые два — из одноимённого секрета тенанта, адрес — из кубконфига администратора.
- Формат пресетов
<серия>.<размер>: t1 (1:0.5), c1 (1:1), s1 (1:2), u1 (1:4), m1 (1:8); размеры от nano до 4xlarge. - Что явно заданный блок
resourcesперекрывает пресет. - Что пресеты тенантов — не instance types KubeVirt (U, O, CX, M, RT):
u1.mediumесть и там, и там. - Что запрос нагрузки = её предел, делённый на
cpuAllocationRatio(по умолчанию 10). - Что
cpuAllocationRatioнастраивается на уровне платформы, а не отдельного тенанта. - Что изоляцию отключить нельзя, а флаг
isolatedубран в версии 1.0. - Имена меток дословно:
policy.cozystack.io/allow-to-apiserverиallow-to-etcd, значение — строка"true". - Что вход идёт через Keycloak, а права — обычным RBAC.
Подробнее: тенанты · эксплуатация платформы