Автоматизація Tenant Provisioning: ідемпотентний pipeline для SaaS

Ручний онбординг нових клієнтів у SaaS-платформі перетворюється на хаос: помилки в налаштуваннях, розрізнені скрипти та зростаючі затримки. Ми автоматизуємо tenant provisioning під ключ — створюємо ідемпотентний pipeline, який надійно розгортає всю інфраструктуру без зривів термінів і з подальшою підтримкою.
Часті запитання

Новий клієнт у 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 — виявимо вузькі місця та запропонуємо план впровадження.

Наші компетенції:

Останні роботи

  • Розробка сайту компанії B2B ADVANCE
    Розробка сайту компанії B2B ADVANCE
    1542
  • Розробка веб-додатків для компанії FEEDME
    Розробка веб-додатків для компанії FEEDME
    1394
  • Розробка веб-сайту для компанії БЕЛФІНГРУП
    Розробка веб-сайту для компанії БЕЛФІНГРУП
    1081
  • Розробка інтернет магазину для компанії FURNORO
    Розробка інтернет магазину для компанії FURNORO
    1369
  • Розробка логотипу компанії B2B Advance
    Розробка логотипу компанії B2B Advance
    816
  • Розробка веб-додатків для компанії Enviok
    Розробка веб-додатків для компанії Enviok
    1142