Kubernetes multi-tenancy почти всегда рисуют одной осью: namespace → vCluster → отдельный кластер. Слева дёшево и слабо, справа дорого и надёжно, выбирай точку по вкусу к риску.
Ось удобная и неверная. vCluster с недавних пор занимает на ней два разных места, а цена отдельных кластеров растёт не от их количества. Решение раскладывается на три вопроса, и порядок у них жёсткий.
Вопрос первый: кто такой tenant
Namespace — не граница безопасности. Это не виртуальная машина, ядро общее, и привилегированный контейнер уходит на хост независимо от того, сколько RBAC-ролей вокруг него навешано. Отсюда первый водораздел: защищаемся от случайной ошибки соседа или от него самого.
Для своих команд с взаимным доверием namespace закрывает задачу, если собран целиком: RBAC без wildcard-глаголов, NetworkPolicy default-deny (Kubernetes по умолчанию разрешает весь трафик между namespace'ами — это дыра, а не настройка), ResourceQuota вместе с LimitRange. Именно вместе: quota без LimitRange означает, что первый же под без requests съест её целиком. Слабейший слой определяет прочность всей конструкции, поэтому «настроим NetworkPolicy позже» равнозначно «не настроим».
Здесь же лежит единственное за годы изменение, которое реально двигает границу доверия. В Kubernetes 1.36 user namespaces получили статус stable: hostUsers: false маппит root внутри контейнера на непривилегированный uid хоста, и побег из контейнера перестаёт быть получением root на ноде. Путь гейта: alpha в 1.28, beta с 1.30, beta включённая по умолчанию с 1.33, stable с 1.36. Стоит держать в голове, что это опция пода, а не свойство кластера: GA означает «можно полагаться», а не «уже применяется к вашим нагрузкам».
Вопрос второй: нужен ли tenant'у cluster-scoped доступ
Если команде нужны собственные CRD, собственные namespace или cluster-admin в своём периметре, namespace не подойдёт ни при какой настройке RBAC. Это не вопрос доверия, а вопрос области видимости API. Здесь начинается vCluster: tenant получает свой API server, а нагрузки синхронизируются в host-кластер.
За последний год эта картина перестала быть полной. У vCluster появились private nodes — собственные воркер-ноды tenant-кластера, которые можно держать в другом VPC, у другого провайдера или на голом железе, подключая через VPN к control plane. Изоляция перестала быть только про control plane, и та самая ось «слабее — сильнее» разошлась: vCluster без private nodes и vCluster с ними — это два разных ответа.
Дальше начинается то, что стоит посчитать до пилота, а не после. Возможности разложены по тирам, и границы проходят не там, где ожидаешь:
- OSS (Apache 2.0) — отдельные control plane, синхронизация ресурсов, разные backing stores. Лицензия не нужна, связь с внешней Platform не нужна.
- Free — бесплатно и без карты, но требует подключения к vCluster Platform для валидации лицензии. Сюда входят embedded etcd, private nodes, custom resource syncing, sync patches, HostPath Mapper.
- Enterprise (Dev / Prod / Scale) — sleep mode, внешние базы, SSO, аудит-логи, FIPS и air-gapped-поставка.
Следствие острое: закрытый контур получает только OSS-тир, то есть без private nodes. Организация, которая выбирала vCluster ради выделенных нод и не может звонить домой за валидацией, обнаружит это на этапе внедрения. Заодно стоит поправить давнее знание: дефолтным дистрибутивом виртуального control plane с версии 0.20 стал ванильный k8s, а не k3s, и поддержка EKS как дистрибутива тогда же убрана.
Вопрос третий: во что обходится ошибка
Стандартный аргумент против кластера на команду — умножение фиксированной платы. В EKS это $0,10 в час на кластер, около $73 в месяц, и тридцать кластеров дают примерно $2,2 тысячи в месяц только за control plane, до единой рабочей нагрузки.
Умножение — не самая дорогая часть. После окончания стандартной поддержки версии кластер автоматически переходит на extended support по $0,60 в час, то есть шестикратно. Флот из отдельных кластеров дорожает не пропорционально числу команд, а пропорционально числу команд, которые не успевают обновляться. Это переворачивает привычный расчёт: модель «кластер на tenant» стоит не $73 × N, а $73 × N плюс штраф за организационную дисциплину, которой у растущего флота обычно и не хватает. Разложить эти деньги по tenant'ам помогает showback — OpenCost и Kubecost считают по namespace-лейблам, поэтому лейблы ставятся при создании namespace, а не задним числом.
Таблица решения
| Ситуация | Модель | Что придётся принять |
|---|---|---|
| Свои команды, доверие есть, cluster-scoped не нужен | Namespace + RBAC + default-deny + Quota/LimitRange | Namespace не граница безопасности; прочность по слабейшему слою |
| Нужны свои CRD и cluster-admin, контур открыт | vCluster OSS | Нагрузки исполняются в host-кластере; изолирован control plane, не воркеры |
| Нужны выделенные ноды под tenant | vCluster + private nodes | Free-тир и постоянная связь с Platform для валидации лицензии |
| Закрытый контур, air-gapped | vCluster OSS либо отдельные кластеры | Private nodes и air-gapped-поставка в OSS отсутствуют |
| Недоверенный код, PCI-DSS, HIPAA | Отдельные кластеры | $73/мес на control plane, а на extended support — $0,60/ч |
Строка про недоверенный код допускает смягчение: gVisor или Kata через RuntimeClass дают изоляцию на уровне пода внутри общего кластера, ценой производительности. Это не замена отдельному кластеру там, где раздельность требует регулятор, но рабочий промежуточный вариант, когда требование идёт от здравого смысла, а не от аудитора.
Чего не брать в 2026 году
Hierarchical Namespace Controller с его kubectl hns встречается в каждой второй подборке по multi-tenancy. Репозиторий переехал в организацию kubernetes-retired и заархивирован, последний коммит — апрель 2025 года, преемник не назван. Строить на нём иерархию namespace'ов сейчас означает закладывать миграцию.
Сценарий «tenant как объект, квоты и политики на набор namespace» закрывает Capsule — проект CNCF, живой (v0.14.3 вышла 31 августа 2026), API-группа capsule.clastix.io/v1beta2, плюс появившиеся глобальные квоты поверх нескольких tenant'ов. Это не миграция с HNC и не его замена по функциям: другая модель, где корневой объект — Tenant, а не дерево namespace'ов.
Отдельно стоит развести две плоскости, которые регулярно путают. Argo CD AppProject ограничивает, кто и куда деплоит, и это delivery boundary. Он не заменяет ни ResourceQuota, ни NetworkPolicy, ни Pod Security Admission внутри namespace tenant'а. Настроенный AppProject при пустом namespace-периметре даёт ощущение изоляции без изоляции. Политики уровня admission — отдельный слой, а сетевой периметр удобнее строить на Cilium с DNS-based egress и L7-правилами.
Порядок, а не шкала
Три вопроса задаются в фиксированном порядке. Кто tenant — определяет, годится ли namespace вообще. Нужен ли ему cluster-scoped доступ — определяет, нужен ли виртуальный control plane. И только потом считается цена, потому что она зависит от первых двух ответов и от того, как быстро в организации накатывают обновления.
Ответы на первые два вопроса известны уже сегодня, их не нужно исследовать. Третий меняется со временем — и меняется в худшую сторону ровно у тех, кто выбрал отдельные кластеры, чтобы не думать об изоляции.