Розробка кастомного Kubernetes Operator: від ідеї до продакшену

Коли стандартні інструменти не справляються з автоматизацією специфічних процесів, на допомогу приходить кастомний Kubernetes Operator. Ми розробляємо оператори під ключ — від проєктування до продакшену, забезпечуючи надійність та ідемпотентність. Наша команда бере на себе весь цикл: аудит, розробку, впровадження та подальшу підтримку.
Часті запитання

Готові оператори є для 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 Ручна Вбудована

Що входить у розробку кастомного оператора?

Ми надаємо повний цикл робіт:

  1. Аналіз бізнес-процесу та проектування Custom Resources.
  2. Генерація скелета оператора за допомогою Kubebuilder.
  3. Реалізація reconciliation loop з ідемпотентністю та finalizer.
  4. Налаштування RBAC, NetworkPolicy та моніторингу (Prometheus метрики).
  5. Unit-тести з envtest та e2e-тести на kind-кластері.
  6. CI/CD пайплайн для збірки та деплою оператора в цільовий кластер.
  7. Документація з розгортання та експлуатації.
  8. Гарантія працездатності протягом 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

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

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

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