Готові оператори є для PostgreSQL, Kafka, Redis, Elasticsearch. Але коли потрібно автоматизувати специфічний процес — наприклад, провіжинінг tenant-оточень при створенні нового клієнта або управління feature-прапорами через API Kubernetes — без кастомного оператора не обійтися. На одному з проектів ми автоматизували створення tenant-оточень, що скоротило час розгортання з 2 годин до 15 хвилин — у 8 разів швидше. Ми розробляємо такі оператори під ключ, гарантуючи ідемпотентність, правильну обробку помилок та повне покриття тестами. Замовте консультацію — оцінимо задачу за 2 дні.
Коли розробляти кастомний оператор
Operator — не перший інструмент, який потрібно брати. Перш ніж починати розробку, перевірте три умови. По-перше, чи не можна вирішити задачу існуючим оператором з кастомною конфігурацією. По-друге, чи підійде CronJob з простим скриптом. По-третє, чи достатньо Helm з ArgoCD ApplicationSet для декларативного управління.
Оператор виправданий, коли потрібна реакція на події Kubernetes (створили Custom Resource — виконай послідовність дій) та reconciliation loop (постійно слідкуй за станом та виправляй відхилення). Також якщо бізнес-логіка занадто складна для скрипта. Наприклад, при автоматичному створенні ізольованих оточень для кожного клієнта з налаштуванням NetworkPolicy, PVC та моніторингу. У таких випадках оператор дає до 90% економії часу порівняно з ручним управлінням.
| Інструмент | Коли використовувати | Складність | Час налаштування |
|---|---|---|---|
| Helm + ApplicationSet | Просте декларативне управління | Низька | Години |
| CronJob | Періодичні задачі | Середня | Дні |
| Кастомний Operator | Складна бізнес-логіка, події | Висока | Тижні |
Як обрати фреймворк: Operator SDK чи Kubebuilder?
Обидва фреймворки генерують boilerplate-код та використовують controller-runtime. Kubebuilder — офіційний інструмент від Kubernetes SIG, більш академічний та добре документований. Operator SDK від Red Hat додає можливості збірки, тестування та публікації в Operator Hub, а також підтримує написання на Ansible та Helm. На практиці вибір між ними несуттєвий — код схожий. Kubebuilder дає більш чистий API для генерації CRD, а Operator SDK — інтеграцію з OpenShift. Якщо ваша команда використовує OpenShift, обирайте Operator SDK — він дає додаткові плюшки. В інших випадках Kubebuilder простіший та прозоріший.
| Критерій | Kubebuilder | Operator SDK |
|---|---|---|
| Походження | Kubernetes SIG | Red Hat |
| Мови | Go (основна) | Go, Ansible, Helm |
| Документація | Відмінна, академічна | Хороша, практична |
| Інтеграція з OpenShift | Базова | Глибока |
| Публікація в Operator Hub | Ручна | Вбудована |
Що входить у розробку кастомного оператора?
Ми надаємо повний цикл робіт:
- Аналіз бізнес-процесу та проектування Custom Resources.
- Генерація скелета оператора за допомогою Kubebuilder.
- Реалізація reconciliation loop з ідемпотентністю та finalizer.
- Налаштування RBAC, NetworkPolicy та моніторингу (Prometheus метрики).
- Unit-тести з envtest та e2e-тести на kind-кластері.
- CI/CD пайплайн для збірки та деплою оператора в цільовий кластер.
- Документація з розгортання та експлуатації.
- Гарантія працездатності протягом 3 місяців після здачі.
Типовий проект економить клієнту до $5,000 щомісяця за рахунок автоматизації. Вартість розробки починається від $2,000 — точну суму назвемо після аудиту.
Чому ідемпотентність — основа оператора?
Reconcile може викликатися багаторазово для одного об'єкта — при зміні, рестарті контролера або по таймеру. Кожен виклик повинен приводити до одного результату, незалежно від поточного стану. Це критично для запобігання дублюванню ресурсів та гонок. Ми завжди реалізуємо ідемпотентні операції: перевіряємо існування ресурсу перед створенням, використовуємо finalizer для коректного видалення, а статус оновлюємо через Status subresource.
Як влаштований кастомний оператор?
Ініціалізація проекту з Kubebuilder:
kubebuilder init --domain company.io --repo github.com/company/tenant-operator
kubebuilder create api --group platform --version v1 --kind TenantЦе генерує:
-
api/v1/tenant_types.go— структура Custom Resource -
controllers/tenant_controller.go— логіка reconciliation -
config/crd/— CRD маніфести -
config/rbac/— RBAC для оператора
Основна робота — у Reconcile функції контролера:
func (r *TenantReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) {
log := log.FromContext(ctx)
// Отримуємо Tenant об'єкт
tenant := &platformv1.Tenant{}
if err := r.Get(ctx, req.NamespacedName, tenant); err != nil {
return ctrl.Result{}, client.IgnoreNotFound(err)
}
// Перевіряємо finalizer для коректного видалення
if !controllerutil.ContainsFinalizer(tenant, tenantFinalizer) {
controllerutil.AddFinalizer(tenant, tenantFinalizer)
if err := r.Update(ctx, tenant); err != nil {
return ctrl.Result{}, err
}
}
// Ідемпотентна логіка: створюємо namespace якщо не існує
ns := &corev1.Namespace{}
nsName := fmt.Sprintf("tenant-%s", tenant.Name)
if err := r.Get(ctx, types.NamespacedName{Name: nsName}, ns); err != nil {
if !apierrors.IsNotFound(err) {
return ctrl.Result{}, err
}
// Створюємо namespace
newNs := &corev1.Namespace{
ObjectMeta: metav1.ObjectMeta{
Name: nsName,
Labels: map[string]string{
"tenant": tenant.Name,
"managed-by": "tenant-operator",
},
},
}
if err := r.Create(ctx, newNs); err != nil {
return ctrl.Result{}, err
}
log.Info("Created namespace", "namespace", nsName)
}
// Оновлюємо статус
tenant.Status.Phase = "Active"
tenant.Status.Namespace = nsName
if err := r.Status().Update(ctx, tenant); err != nil {
return ctrl.Result{}, err
}
return ctrl.Result{RequeueAfter: time.Minute * 5}, nil
} Які принципи важливі при розробці оператора?
Ідемпотентність
Кожен виклик Reconcile повинен приводити до одного результату, незалежно від поточного стану. Це досягається перевірками існування ресурсів та використанням CreateOrUpdate паттернів.
Finalizers
Якщо оператор створює зовнішні ресурси (DNS-записи, хмарні об'єкти, записи в БД), потрібен finalizer — він блокує видалення Custom Resource до завершення cleanup-логіки. Без нього видалення ресурсу залишить «сміття» в системі.
Status subresource
Стан ресурсу повинен відображатися в .status, а не в .spec. Це дозволяє kubectl get tenant -o wide показувати поточний стан. Статус може містити фазу, умови та метрики.
Обробка помилок
Повернення помилки з Reconcile змушує controller-runtime поставити об'єкт назад у чергу з експоненційною затримкою. Для запланованих повторних перевірок використовуйте ctrl.Result{RequeueAfter: duration}.
Чек-лист типових помилок при розробці оператора
- Відсутність finalizer для зовнішніх ресурсів — ресурси не очищаються.
- Неідемпотентні операції — дублювання namespace або іншої сутності.
- Ігнорування помилок при створенні ресурсів — оператор зависає в циклі.
- Зберігання стану в
.specзамість.status— ускладнює відладку. - Відсутність unit-тестів — баги в reconciliation залишаються непоміченими.
Терміни та вартість
Простий оператор (1-2 Custom Resources, лінійна логіка reconciliation) — від 2 тижнів до місяця з урахуванням тестів та документації. Складний оператор з управлінням stateful-сервісами, failover-логікою та мульти-ресурсною топологією — від 2 до 3 місяців. Вартість розраховується індивідуально після аудиту задачі. Інвестиція в оператора зазвичай окупається за 2–3 місяці за рахунок скорочення ручної праці. Якщо ви хочете автоматизувати рутинні операції в Kubernetes — отримайте консультацію, ми розробимо оператор під ваш сценарій. Наш досвід в DevOps — 5+ років, понад 50 успішних проектів автоматизації.
Джерело: Kubebuilder documentation







