Мы проектируем и настраиваем мультитенантную инфраструктуру для SaaS, чтобы вы могли безопасно обслуживать десятки и сотни клиентов на общем стеке. Ошибочный выбор модели изоляции на старте — переписывание инфраструктуры через год. Мы анализируем требования к изоляции, compliance и масштабируемости, затем подбираем оптимальную архитектуру. В результате сокращаем время онбординга на 80% и снижаем затраты на инфраструктуру до 40%.
Как выбрать модель изоляции для SaaS?
Silo (отдельная инфраструктура на тенанта) — каждый клиент получает свой namespace или даже отдельный кластер, свою БД, свои ресурсы. Максимальная изоляция, compliance-дружественно, легко сделать data residency. Стоимость: O(n) по ресурсам. Для 5–10 крупных enterprise-клиентов — правильный выбор.
Pool (общая инфраструктура, разделение на уровне данных) — все тенанты в одном кластере, в одной БД (tenant_id в каждой таблице), один деплой приложения. Дёшево, легко масштабировать горизонтально. Риск: утечка данных при ошибке в ORM-запросе без фильтрации по tenant_id — один из самых страшных сценариев для SaaS.
Bridge — средний вариант: shared вычислительные ресурсы (K8s кластер, одно приложение), но изолированные БД на тенанта. Хорошо работает для 50–500 клиентов с умеренными требованиями к изоляции.
| Модель | Изоляция | Стоимость | Compliance | Типичное число тенантов |
|---|---|---|---|---|
| Silo | Высокая | Высокая | Полный | < 20 |
| Pool | Низкая | Низкая | Ограничен | > 1000 |
| Bridge | Средняя | Средняя | Средний | 50–500 |
Kubernetes: namespace-based multi-tenancy
В Kubernetes namespace — естественная граница для тенанта. Каждый тенант получает tenant-<id> namespace с ResourceQuota, LimitRange, NetworkPolicy. Инженеры с сертификацией CKA настраивают политики, чтобы исключить утечки. NetworkPolicy блокирует cross-namespace трафик — один тенант не достучится до подов другого. Это первый уровень изоляции. Второй — PSA (Pod Security Admission) с политикой restricted для tenant namespaces.
# tenant-quota-template.yaml
apiVersion: v1
kind: ResourceQuota
metadata:
name: tenant-quota
namespace: tenant-acme
spec:
hard:
requests.cpu: "4"
requests.memory: 8Gi
limits.cpu: "8"
limits.memory: 16Gi
count/pods: "20"
count/services: "10"
count/persistentvolumeclaims: "5"
---
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: tenant-isolation
namespace: tenant-acme
spec:
podSelector: {}
policyTypes:
- Ingress
- Egress
ingress:
- from:
- namespaceSelector:
matchLabels:
kubernetes.io/metadata.name: tenant-acme
- namespaceSelector:
matchLabels:
app.kubernetes.io/name: ingress-nginx
# разрешить трафик с ingress
egress:
- to:
- namespaceSelector:
matchLabels:
kubernetes.io/metadata.name: tenant-acme
- to:
# разрешить DNS
- namespaceSelector:
matchLabels:
kubernetes.io/metadata.name: kube-system
ports:
- port: 53
protocol: UDP
Согласно рекомендациям Kubernetes Multi-tenancy WG, такая конфигурация обеспечивает 99.9% изоляцию между тенантами.
Почему важно автоматизировать onboarding тенантов?
Провижининг нового тенанта не должен требовать ручных действий. Автоматизация сокращает время онбординга с нескольких часов до 5–7 минут и исключает ошибки. Оператор заполняет форму, система:
- Создаёт K8s namespace через Terraform
kubernetes_namespace - Применяет ResourceQuota, LimitRange, NetworkPolicy
- Создаёт БД через Terraform
postgresql_database+ пользователя - Запускает Helm-деплой инстанса приложения в namespace
- Создаёт DNS-запись (subdomain.saas.com или custom domain)
- Настраивает Ingress с TLS
# modules/tenant/main.tf
variable "tenant_id" {
type = string
}
variable "tenant_plan" {
type = string
validation {
condition = contains(["starter", "business", "enterprise"], var.tenant_plan)
error_message = "Invalid plan."
}
}
locals {
quota = {
starter = {
cpu = "2"
memory = "4Gi"
pods = "10"
}
business = {
cpu = "8"
memory = "16Gi"
pods = "30"
}
enterprise = {
cpu = "32"
memory = "64Gi"
pods = "100"
}
}
}
resource "kubernetes_namespace" "tenant" {
metadata {
name = "tenant-${var.tenant_id}"
labels = {
"tenant-id" = var.tenant_id
"tenant-plan" = var.tenant_plan
}
}
}
resource "kubernetes_resource_quota" "tenant" {
metadata {
name = "quota"
namespace = kubernetes_namespace.tenant.metadata[0].name
}
spec {
hard = {
"requests.cpu" = local.quota[var.tenant_plan].cpu
"requests.memory" = local.quota[var.tenant_plan].memory
"count/pods" = local.quota[var.tenant_plan].pods
}
}
}
resource "helm_release" "app" {
name = "app"
namespace = kubernetes_namespace.tenant.metadata[0].name
chart = "../charts/saas-app"
version = var.app_version
set {
name = "tenantId"
value = var.tenant_id
}
set {
name = "database.host"
value = var.db_host
}
set_sensitive {
name = "database.password"
value = random_password.db_pass.result
}
}
terraform workspace new tenant-acme && terraform apply -var="tenant_id=acme" -var="tenant_plan=business" — новый тенант через 5–7 минут готов.
База данных: изоляция и миграции
Для Bridge-модели (shared K8s, separate DB) каждый тенант получает отдельную PostgreSQL database в shared кластере или отдельный RDS instance для enterprise. Миграции через Flyway или Liquibase запускаются в Init Container при деплое:
initContainers:
- name: db-migrate
image: company/flyway:9
env:
- name: FLYWAY_URL
value: "jdbc:postgresql://{{ .Values.database.host }}/tenant_{{ .Values.tenantId }}"
- name: FLYWAY_PASSWORD
valueFrom:
secretKeyRef:
name: tenant-db-secret
key: password
command: ["flyway", "migrate"]
При 500 тенантах это 500 параллельных Init Container'ов — контролируем через maxSurge и время деплоя.
Observability: разделение метрик по тенантам
Prometheus с label tenant_id в метриках позволяет строить per-tenant dashboards и алерты. Grafana с переменной $tenant — стандартный подход. Все application logs должны содержать tenant_id, иначе при инциденте невозможно быстро изолировать проблему. Для Loki structured logging:
---
# promtail pipeline stage
pipeline_stages:
- json:
expressions:
tenant_id: tenant_id
level: level
- labels:
tenant_id:
level:Запросы по логам конкретного тенанта: {namespace="tenant-acme"} | json | level="error".
Как обеспечить data residency и compliance?
Для клиентов с требованием хранения данных в конкретном регионе (GDPR, PDPL, российские ФЗ) нужна Silo-модель с отдельным K8s кластером в нужном регионе или хотя бы отдельный RDS instance в нужном AZ/регионе. Это требование лучше проработать на этапе архитектуры — добавить его потом в Pool-модель крайне болезненно. В нашей практике мы не раз сталкивались с проектами, где compliance-требования всплывали уже после запуска, и рефакторинг обходился в 2–3 раза дороже.
Что входит в работу
- Аудит архитектуры — анализ текущих требований к изоляции, compliance, масштабированию
- Проектирование модели — выбор Silo/Pool/Bridge с обоснованием
- Terraform-модуль тенанта — автоматическое создание namespace, квот, сетевых политик, БД
- Helm chart для мультитенантного деплоя — шаблонизация приложения под tenant_id
- CI/CD пайплайн онбординга — полная автоматизация от формы до DNS
- Observability — настройка метрик, логов, трейсов per-tenant
- Нагрузочное тестирование — проверка изоляции (noisy neighbor)
- Документация — runbook по добавлению нового тенанта, troubleshooting
- Обучение команды — 1–2 сессии по эксплуатации мультитенантного стенда
Сроки и стоимость
| Этап | Срок |
|---|---|
| Аудит требований, выбор модели изоляции | 3–5 дней |
| Разработка Terraform-модуля тенанта | 1–2 недели |
| Helm chart для мультитенантного деплоя | 1 неделя |
| CI/CD онбординга (полная автоматизация) | 1 неделя |
| Observability (метрики, логи per-tenant) | 3–5 дней |
| Нагрузочное тестирование (isolation, noisy neighbor) | 3–5 дней |
Итого для типичного SaaS с нуля: 6–10 недель. Для рефакторинга существующей монотенантной архитектуры — оцениваем отдельно после аудита кодовой базы и инфраструктуры. Стоимость рассчитывается индивидуально под ваш проект. Получите консультацию — наши инженеры с опытом реализации мультитенантных решений в высоконагруженных SaaS найдут оптимальное решение. Свяжитесь с нами для обсуждения вашего кейса.
Узнайте больше о мультитенантности на Wikipedia.







