← Kubernetes: дальше
9 мин · средне · Урок 3 из 3

Операторы: зачем они нужны и чего стоят

Где заканчиваются возможности Deployment, какую работу забирает оператор, какие операторы встречаются в проде и почему их не стоит ставить на каждое приложение.

Где заканчивается Deployment

Deployment закрывает две задачи. Упал Pod - его пересоздадут. Поменяли тег образа - раскатят новую версию порциями, со старыми Pod на подхвате, пока новые не станут Ready.

Дальше начинается граница. Deployment не знает, что крутится внутри контейнера. Для него Postgres и статический nginx одинаковы: процесс, который либо отвечает на пробы, либо нет.

Из-за этого он не умеет ничего из того, что реально составляет эксплуатацию базы:

Всё это тоже автоматизируемо, просто автоматика живёт не в кластере. Она лежит в голове дежурного, в runbook на вики или в наборе скриптов, которые запускает человек. Ночью в три часа человек работает медленно и ошибается.

Что делает оператор

Оператор переносит это знание в код, который крутится в кластере постоянно. Он подписан на события своих объектов и на состояние кластера, и реагирует без участия человека.

Формулировка без магии: оператор - это обычный контроллер, который делает то же самое, что сделал бы дежурный по инструкции. Те же вызовы API, те же проверки, тот же порядок шагов. Разница в том, что он не спит, не путает окружения и выполняет шаги одинаково каждый раз.

Механика тут уже знакомая. Оператор регистрирует свой тип ресурса через CRD, а внутри крутит цикл reconcile: читает spec, смотрит на факт, сокращает разницу, пишет status. Разбор этого цикла, level-triggered поведения и finalizers - в уроке CRD.

Один пример: отказ мастера Postgres

Как это выглядит руками. Мониторинг присылает алерт, что мастер не отвечает. Дежурный заходит на реплики, смотрит, какая из них ушла дальше по WAL, выбирает её новым мастером, выполняет promote. Потом перенастраивает оставшиеся реплики на нового мастера, правит endpoint, на который ходит приложение, и проверяет, что записи проходят. Между алертом и восстановлением записи проходит от нескольких минут до получаса.

Оператор делает ту же последовательность. Он и так постоянно опрашивает инстансы, поэтому отказ видит сам. Дальше сравнивает позиции репликации, выбирает кандидата, промоутит его, переписывает остальные реплики на нового мастера и переводит Service, через который ходят клиенты, на новый Pod. Порядок шагов зашит в код и не зависит от того, кто сегодня на дежурстве.

Человек при этом описывает только намерение. Кастомный ресурс выглядит примерно так:

apiVersion: db.example.com/v1
kind: PostgresCluster
metadata:
  name: orders
spec:
  instances: 3
  version: "16"
  storage:
    size: 100Gi
  backup:
    schedule: "0 2 * * *"
    retentionDays: 14

Это обобщённая форма, а не манифест конкретного продукта. Набор полей у каждого оператора свой: где-то бэкапы описываются отдельным ресурсом, где-то версия задаётся образом целиком, где-то есть блок про подключение к внешнему S3. Перед применением читают документацию конкретного оператора и его схему через kubectl explain.

Ландшафт: что реально встречается

Операторы давно перестали быть экзотикой. Скорее всего, в вашем кластере уже стоит два или три.

Версии и конкретные наборы полей тут намеренно не приводятся: они меняются от релиза к релизу, и единственный надёжный источник - документация проекта на момент установки.

Уровни зрелости

Оператор в кластере не равен автоматике. Failover и бэкапы это третья ступень из пяти, и до неё доходят не все.

У Operator Framework есть шкала Operator Capability Levels, пять ступеней:

  1. Базовая установка. Оператор умеет развернуть приложение по кастомному ресурсу и настроить его.
  2. Апгрейды. Умеет перевести приложение на новую версию, включая миграции, которые этого требуют.
  3. Полный жизненный цикл. Бэкапы, восстановление, отказоустойчивое поведение при потере инстанса.
  4. Метрики и алерты. Отдаёт наружу состояние приложения, метрики и готовые правила алертов.
  5. Автопилот. Автоскейлинг, самонастройка параметров, обнаружение аномалий и реакция на них.

Шкала нужна для одного практического вопроса. «Для нашей базы есть оператор» не означает, что при отказе мастера что-то произойдёт само. Оператор второго уровня развернёт кластер и обновит версию, но failover и бэкапы останутся на вас. Перед тем как убрать runbook, проверяют, что именно оператор умеет, и лучше проверяют на тестовом кластере, а не по описанию в README.

Когда оператор не нужен

Оператор оправдан там, где есть состояние и нетривиальные операции над ним: базы, брокеры сообщений, поисковые движки, кластеры с выбором лидера.

Если приложение stateless, а вся задача сводится к тому, чтобы раскатить один набор манифестов с разными значениями по окружениям, то оператор ничего не даст. Для этого достаточно Kustomize-оверлея или Helm-чарта. Шаблонизация плюс kubectl apply покрывает такие случаи полностью, и разбираться потом придётся в своём YAML, а не в чужом коде.

Простой признак: если у приложения нет операций, кроме «выкатить новую версию», писать под него оператор не нужно.

есть состояние и операции над ним?
  да   -> оператор
  нет  -> Helm или Kustomize

Цена оператора

Оператор не бесплатный, и счёт приходит по трём статьям.

Права. Это ещё один Pod в кластере, и обычно с широкими правами: как минимум cluster-admin на свои типы, часто плюс доступ к Secret, PersistentVolumeClaim и Pod в целевых namespace. Оператор базы по определению может удалить и пересоздать вашу базу. Компрометация такого Pod равна компрометации данных.

Зависимость. Оператор - чужой проект со своим темпом релизов. Если разработка встала, а вы на нём держите прод, то у вас в проде заброшенный компонент, который рано или поздно перестанет собираться под новую версию Kubernetes. Перед выбором смотрят на активность репозитория и на то, кто за проектом стоит.

Отладка. Когда база не поднимается, разбираться приходится сразу на двух уровнях: в самом Postgres и в чужом reconcile. Почему контроллер решил, что состояние достигнуто. Почему он крутится в цикле пересоздания. Это лишний слой между вами и приложением, и в инцидент он добавляет времени.

Как их ставят и смотрят

Ставят операторы либо Helm-чартом, либо одним общим манифестом из репозитория проекта. Установка обычно требует прав на весь кластер: вместе с оператором применяются его CRD, а они cluster-scoped.

После установки проверяют, что типы появились:

kubectl get crd
kubectl api-resources --api-group=cert-manager.io

Дальше смотрят сам оператор и его объекты:

kubectl get pods -n cert-manager
kubectl logs -n cert-manager deploy/cert-manager -f
kubectl describe certificate my-cert
kubectl get certificate my-cert -o yaml

Основной источник правды по кастомному объекту - его status и события в kubectl describe. Туда контроллер пишет, что у него получилось, а что нет. Логи Pod оператора нужны, когда status пустой или молчит.

Существуют и каталоги: OperatorHub собирает публичные операторы с описанием уровня зрелости, а Operator Lifecycle Manager (OLM) ставит их и обновляет по подписке, следя за совместимостью версий. В кластерах без OLM операторы просто ставят вручную, и это нормальный вариант.

Коротко

Прошли материал до конца? Отметьте урок пройденным.