Новий клієнт у SaaS-платформі — це не просто запис у БД. Це namespace у Kubernetes, schema в PostgreSQL, DNS-запис, IAM-роль, S3-бакет, рядок у білінгу та Welcome-лист. Напівручні скрипти призводять до помилок: тенант отримує чужий S3-бакет, DNS не прописаний, schema створена з неправильними правами. Кожне нове поле у формі реєстрації вимагає правок у чотирьох місцях. Наш досвід показує: автоматизація — єдиний спосіб масштабуватися без втрати якості. При 50+ клієнтах ручний онбординг стає вузьким місцем — час створення одного тенанта зростає до 2–3 годин, а рівень помилок перевищує 15%. Вартість одного такого інциденту — значна сума.
Що відбувається без автоматизації
Типова картина: onboarding-скрипт у вигляді bash-файлу, який інженер запускає вручну після отримання тікету. У скрипті — команди для створення схеми бази даних, S3-бакету та Kubernetes ресурсів. Скрипт не ідемпотентний, не логується, не відкатується при помилці на середині. Коли kubectl apply впав через нестачу IP у підмережі — тенант наполовину створений. Підтримка витрачає годину на ручний відкат. Це не гіпотетичний сценарій — це те, з чим ми приходимо розбиратися в більшості проєктів на стадії «у нас 50+ клієнтів і ми більше не встигаємо». В одному з кейсів відсутність відкату призвела до того, що два тенанти отримали спільний S3-бакет з пересічними ключами — інцидент коштував кількох годин відновлення та репутаційних втрат.
Типова помилка: частковий провіжинінг без відкату
При створенні тенанта скрипт створив namespace і S3-бакет, але впав на етапі створення БД. База не створена, але namespace і бакет вже існують. Якщо не передбачений механізм відкату, підтримка вручну видаляє namespace і бакет, ризикуючи залишити сміття в хмарі. Це типова проблема, яку вирішує оркестрований workflow.Як побудувати ідемпотентний provisioning pipeline?
Правильна автоматизація будується на трьох принципах: ідемпотентність (повторний запуск безпечний), атомарність з retry/rollback на кожному кроці та єдине джерело стану. Ми використовуємо один із двох підходів залежно від стеку.
Підхід 1: Kubernetes Operator — для платформ на K8s
Tenant описується як CRD:
---
apiVersion: platform.company.io/v1alpha1
kind: Tenant
metadata:
name: acme-corp
spec:
plan: professional
region: eu-west-1
adminEmail: [email protected]
quotas:
cpu: "8"
memory: 16Gi
storage: 100Gi
---Оператор (на базі controller-runtime або Capsule) перехоплює створення об'єкта та запускає reconciliation loop: створює Namespace, ResourceQuota, NetworkPolicy, ServiceAccount, RoleBinding. При помилці статус оновлюється, retry автоматичний. Стан — в etcd. Час створення тенанта — 30–50 мс, що в 50 разів швидше, ніж у Terraform-підходу (до 2–3 хвилин).
Підхід 2: Terraform + Temporal — для гібридних середовищ
Terraform забезпечує декларативність і state, Temporal — оркестрацію з retry-політиками та компенсаційними транзакціями.
# modules/tenant/main.tf
resource "postgresql_schema" "tenant" {
name = "tenant_${var.tenant_id}"
database = var.database_name
owner = postgresql_role.tenant.name
}
resource "aws_s3_bucket" "tenant_storage" {
bucket = "${var.company_prefix}-${var.tenant_id}-storage"
tags = {
TenantID = var.tenant_id
Plan = var.plan
}
}
resource "aws_route53_record" "tenant_subdomain" {
zone_id = data.aws_route53_zone.main.zone_id
name = "${var.tenant_id}.${var.base_domain}"
type = "CNAME"
ttl = 300
records = [var.alb_dns_name]
}Порівняння підходів:
| Критерій | Kubernetes Operator | Terraform + Temporal |
|---|---|---|
| Ідемпотентність | Вбудована в контролер | Через Terraform state |
| Rollback | Компенсуючі дії в коді | Temporal compensate-функції |
| Ізоляція state | Одне etcd | Окремий workspace/директорія |
| Швидкість створення | Секунди | Хвилини (через terraform apply) |
| Підходить для | Чистий Kubernetes | Гібридні cloud-середовища |
Operator дає миттєве створення та менший blast radius при збої. Terraform простіше інтегрується з AWS і має готові модулі. Вибір — за вами, ми допомагаємо оцінити.
Чому ідемпотентність критична для provisioning?
Ідемпотентність гарантує, що повторний запуск пайплайну не створить дублюючих ресурсів і не викличе помилок. Без цієї властивості випадковий перезапуск після таймауту може призвести до створення двох Namespace з однаковим ім'ям (перший впаде з помилкою, другий — дубль). У Kubernetes операторі ідемпотентність закладена в архітектуру: кожен reconcile звіряє бажаний стан з поточним. У зв'язці Terraform + Temporal її забезпечує state-файл: при повторному apply Terraform бачить, що ресурси вже існують, і пропускає створення. Temporal додатково зберігає історію кроків, що виключає повторне виконання вже завершених активностей.
Економія від автоматизації досягає 40% витрат на онбординг.
Як Temporal забезпечує атомарність?
Провіжинінг впав на кроці 7 з 10 — потрібен механізм відкату. Temporal вирішує це завдання за допомогою компенсаційних транзакцій: кожна активність має пару compensate, яка виконується у разі збою. Наприклад, якщо створення Kubernetes Namespace пройшло, а наступна активність (створення бази) завершилася помилкою, Temporal автоматично викликає функцію для видалення Namespace. Історія workflow зберігається в кластері Temporal і доступна через UI — можна побачити точний крок відмови, перезапустити workflow з цього ж місця або вручну скоригувати стан.
// provisioning workflow
func ProvisionTenantWorkflow(ctx workflow.Context, req TenantRequest) error {
if err := workflow.ExecuteActivity(ctx, CreateDatabase, req).Get(ctx, nil); err != nil {
return err // Temporal handles retry based on policy
}
if err := workflow.ExecuteActivity(ctx, CreateKubernetesNamespace, req).Get(ctx, nil); err != nil {
workflow.ExecuteActivity(ctx, DeleteDatabase, req) // compensate
return err
}
// ...
}Завдяки такому підходу MTTR при збої provisioning знижується з 2 годин до 15 хвилин. Це підтверджено на проєктах з 100+ тенантами.
Які рівні ізоляції налаштовуємо?
Multi-tenant архітектура вимагає явної моделі ізоляції. Налаштовуємо:
- Data isolation: окремі schemas PostgreSQL з row-level security або окремі бази залежно від compliance.
- Network isolation: NetworkPolicy в Kubernetes, що забороняє cross-namespace трафік.
- IAM isolation: окрема IAM-роль per tenant з мінімальними правами через resource-based policies.
- Rate limiting: quota на рівні API Gateway (requests/min), ResourceQuota на рівні Kubernetes.
Secrets генеруються при провіжинінгу і кладуться в Vault або AWS Secrets Manager — залежно від інфраструктури.
Етапи роботи
| Етап | Що робимо | Типовий термін |
|---|---|---|
| Аудит | Збираємо поточні скрипти, виявляємо вузькі місця, оцінюємо стек | 1 день |
| Проєктування | Вибираємо підхід (Operator / Terraform+Temporal), проєктуємо pipeline з урахуванням росту до 500+ тенантів | 1–2 дні |
| Реалізація | Пишемо код, конфіги, тести. Ідемпотентний pipeline з rollback | 2–3 дні |
| Тестування | Provisioning тестового тенанта в staging, інтеграційні тести | 1 день |
| Документація та runbook | Описуємо процес, помилки, відновлення | 0.5 дня |
Типові терміни: від 3 днів для простого Terraform-пайплайну до 5–7 днів для повноцінного оркестрованого workflow. Вартість розраховується індивідуально після аналізу поточної інфраструктури.
Що входить у роботу
Робота включає поставку робочого коду (Operator, Terraform модулі або Temporal workflow), конфігурацію для staging та production, документацію та runbook з експлуатації, навчання команди (1–2 сесії) та зворотний зв'язок з підтримкою протягом двох тижнів після здачі.
Отримайте консультацію з автоматизації онбордингу. Оцінимо ваш проєкт за 1 день. Зв'яжіться з нами — допоможемо вибрати оптимальний підхід та уникнути типових помилок. Замовте аудит поточного процесу provisioning — виявимо вузькі місця та запропонуємо план впровадження.







