Заметка

Crossplane против Terraform: control plane вместо state-файла

Terraform держит снимок состояния в файле и сверяет его по требованию, Crossplane превращает Kubernetes API в control plane и сверяет непрерывно. Что поменяла вторая версия, где непрерывная реконсиляция реально выигрывает и чем за это платят.

Разработчику нужна база под новый сервис. Он открывает тикет, платформенная команда добавляет модуль в Terraform-репозиторий, кто-то ревьюит plan, кто-то применяет. Два дня в лучшем случае. Crossplane меняет маршрут: разработчик применяет манифест в своём namespace, дальше работает контроллер. Разница не в скорости тикета, а в модели: Terraform держит снимок состояния в файле и сверяет его по требованию, Crossplane превращает Kubernetes API в control plane и сверяет непрерывно.

Из чего состоит control plane

Provider — плагин, умеющий говорить с внешним API: AWS, GCP, Cloudflare, GitHub. Managed Resource — низкоуровневый ресурс этого API, отражённый как объект Kubernetes. Дальше начинается платформенная работа: XRD объявляет схему собственного абстрактного типа, Composition описывает, во что этот тип раскрывается. Разработчик видит не двадцать полей RDS, а три: size: medium, version: "16" и имя. Всё остальное — контракт платформенной команды, спрятанный в Composition.

Что поменяла вторая версия

Crossplane вышел из инкубации: CNCF присвоил проекту статус graduated в октябре 2025, актуальная линия — v2.3 от мая 2026, релизы идут квартальным циклом. Вторая версия переписала пользовательскую модель, и статьи, где разработчик создаёт Claim, в этом месте уже устарели.

  • XR по умолчанию namespaced (scope: Namespaced в XRD apiextensions.crossplane.io/v2), отдельная сущность Claim удалена — разработчик создаёт XR прямо в своём namespace.
  • Managed Resources тоже стали namespaced, у провайдеров появились API-группы с .m. — например s3.aws.m.upbound.io/v1beta1.
  • Composition собирает любые ресурсы Kubernetes, поэтому provider-kubernetes как обходной путь для in-cluster объектов больше не нужен.
  • Нативный patch & transform (mode: Resources) удалён, остался только mode: Pipeline с функциями композиции на Go, Python или KCL. Чистый YAML доступен как функция function-patch-and-transform, для миграции есть crossplane beta convert pipeline-composition.
  • Operations закрывают day-2: повторяющиеся задания вроде уборки и аудита описываются ресурсом, а не CronJob сбоку.

Что даёт непрерывная сверка

Дрейф. Terraform узнаёт про изменение, сделанное руками в консоли, когда кто-то запустит plan — на следующем релизе или на еженедельной джобе. Контроллер Crossplane сверяет desired и actual постоянно и возвращает ресурс к манифесту без участия человека. То же свойство отдаёт day-2 операции даром: реконсиляция, статусы, события — механизм тот же, что у Deployment.

Self-service. Разграничение доступа — обычный RBAC по namespace, история изменений — audit log кластера, доставка — ArgoCD, который синкает XR как любой другой манифест. Terraform ради self-service обрастает обёрткой вроде Atlantis или Spacelift, и её тоже кто-то эксплуатирует.

Чем за это платят

«Нет state-файла — значит лучше» звучит в каждом сравнении и остаётся самым нечестным аргументом. Файла нет, а состояние есть: оно в etcd вашего кластера. Отсюда три следствия.

Наблюдаемость. На вопрос «что развёрнуто и в каком оно состоянии» Terraform отвечает одной командой, Crossplane — набором kubectl и инструментами вроде k9s или crossplane CLI. Доказанность на масштабе: stateful-процесс с plan-review отработан на инсталляциях в тысячи ресурсов, публичных историй такого же размера у Crossplane заметно меньше. Восстановление: кластер control plane становится production-системой, и бэкап etcd, процедура restore и доступы — теперь ваша ответственность, а не строчка про S3-бэкенд.

Отдельная статья расходов — кривая обучения. XRD, Composition и функции — это разработка платформенного API, а не «написали HCL». Нужна команда, которая владеет контрактом, версионирует схему и отвечает на вопросы по ней. Без такой команды Crossplane превращается в тот же Terraform, только отлаживать его сложнее.

Где я провожу границу

OpenTofu или Terraform — Day-0: сеть, кластеры, IAM-фундамент, в том числе сам кластер под control plane. Crossplane — Day-1 и дальше: базы, очереди, бакеты, репозитории, которые команды заказывают под свои сервисы каждую неделю. Нижний слой меняется редко и требует plan-review, верхний — часто и требует self-service. Выбор между OpenTofu и Terraform на эту границу не влияет, про него отдельный разбор.

Три ошибки, которые видно сразу

  • XR без RBAC и namespace-изоляции: один разработчик получает право уронить прод соседней команды.
  • Composition без writeConnectionSecretsToNamespace: пароль от базы уезжает не туда, где его ждёт приложение.
  • Composition на два десятка ресурсов чистым YAML: стена патчей, которую никто не читает, вместо функции с тестами.

Crossplane выигрывает не отсутствием state-файла, а тем, что инфраструктура становится API с версионированной схемой и постоянной сверкой. Цена — платформенная команда, которая этот API проектирует и поддерживает. Если её нет, честнее остаться на Terraform.

© 2026 axyi.ru · CC BY 4.0