ADG Оставить заявку
Блог DevOps 5 мин чтения

GitOps для Deckhouse через Flux v2: три кластера, одна боль с registry и drift detection

Перевели три Deckhouse-кластера на GitOps через Flux v2: разбираем структуру репо, проблемы с image policy для отечественных registry и реальный drift detection.

Контекст момента

GitOps-подход с Flux v2 и Deckhouse становится стандартом для отечественных k8s-деплойментов - осень 2025

Примерно полгода назад мы решили, что ручное применение манифестов к трём Deckhouse-кластерам - это не процесс, а рулетка. Разные версии конфигов на staging и prod, изменения «быстро руками» которые потом забывают закоммитить, расхождения между кластерами которые обнаруживаются в самый неподходящий момент. Классика. Взяли Flux v2 и начали переводить.

Это не история успеха с круглыми числами в конце. Это отчёт о том, что получилось, где споткнулись и где пока компромисс.

Структура репозитория

Первый вопрос при внедрении GitOps - как организовать репо. Монорепо для всех кластеров или отдельные? Попробовали оба подхода и остановились на монорепо со следующей раскладкой:

clusters/
  prod/
    flux-system/        # bootstrap-компоненты Flux
    infrastructure/     # HelmRelease, HelmRepository, базовые Kustomization
    apps/               # приложения клиента
  staging/
    ...
  dev/
    ...
base/
  infrastructure/       # общие шаблоны через Kustomize
  apps/                 # базовые манифесты приложений

base/ содержит общее, в clusters/<env>/ - патчи и оверрайды через Kustomize. Flux в каждом кластере смотрит на свою директорию и не видит остальных. На практике это означает, что промоушн изменения с dev на prod - это PR с копированием патча в нужную директорию. Немного церемоний, зато явно.

Что работает хорошо. Deckhouse-специфичные ресурсы - NodeGroup, IngressNginxController, модульные конфигурации через ModuleConfig - прекрасно живут в GitOps. Flux видит их как обычные CRD, reconcile работает, drift detection ловит ручные изменения.

Что создало головную боль. Сам Deckhouse обновляет часть своих объектов автоматически - в частности, NodeGroup при staged rollout получает статусные аннотации, а некоторые ModuleConfig получают defaultsFrom от самой платформы. Flux это интерпретирует как drift и хочет откатить. Решение - spec.ignore в Kustomization с явным перечислением полей, которые Deckhouse меняет сам. Не элегантно, но работает.

Image policy и отечественные registry

Вот здесь пришлось потратить время.

Flux v2 имеет ImageRepository и ImagePolicy - механизм автоматического обновления образов при появлении новых тегов. Выглядит красиво: Flux следит за registry, видит новый тег, обновляет манифест в git через ImageUpdateAutomation, Flux применяет - полный цикл без ручного вмешательства.

Проблема в том, что отечественные registry - в нашем случае это Harbor, развёрнутый у клиента в изолированном сегменте, и несколько репо на Nexus - используют self-signed сертификаты и нестандартные порты. ImageRepository требует явного указания secretRef с TLS-конфигурацией, и первые попытки давали невнятную ошибку x509: certificate signed by unknown authority без указания на то, какой именно компонент Flux не доверяет сертификату.

Оказалось, что сертификат нужно добавлять не только в секрет для ImageRepository, но и отдельно монтировать в поды image-reflector-controller, если он запущен вне кластера или с кастомной конфигурацией. В нашем случае кластер изолирован, и image-reflector-controller ходит в Harbor через внутренний IP - там была ещё и проблема с SNI, потому что Harbor был проксирован через nginx с hostname, который отличался от IP.

Итоговое решение:

apiVersion: image.toolkit.fluxcd.io/v1beta2
kind: ImageRepository
metadata:
  name: app-images
  namespace: flux-system
spec:
  image: harbor.internal.example/project/app
  interval: 5m
  certSecretRef:
    name: harbor-tls
  insecure: false

В секрете harbor-tls - CA-сертификат Harbor. Дополнительно пришлось патчить deployment image-reflector-controller через kustomizeconfig чтобы смонтировать тот же CA в под. Это не очевидно из документации Flux, пришли к этому через несколько часов дебага.

На Nexus была другая история: Nexus hosted repository для Docker не всегда корректно отдаёт _catalog endpoint, который Flux использует для листинга тегов. Для части репозиториев пришлось переключить ImagePolicy на конкретный диапазон тегов через semver вместо latest, что обходит проблему листинга.

Drift detection в реальных условиях

Один из главных аргументов за GitOps - drift detection: если кто-то что-то поменял руками в кластере, Flux это видит и сообщает (или откатывает, в зависимости от настройки).

На практике в первые недели drift alerts были источником шума, а не сигнала. Причины:

  • Deckhouse меняет свои объекты - уже описали выше.
  • Операторы приложений - cert-manager, external-secrets, Crossplane - добавляют аннотации и метки к объектам, которые они контролируют. Flux видит это как расхождение.
  • HPA меняет spec.replicas в Deployment. Если в git зафиксировано конкретное число реплик, Flux будет постоянно воевать с HPA.

Для HPA решение стандартное - убрать spec.replicas из манифеста в git, если HPA за него отвечает. Flux в таком случае не трогает поле, которого нет в желаемом состоянии.

Для операторов - spec.ignore с field-level exclude по конкретным путям. Это ручная работа: для каждого оператора нужно выяснить, какие именно поля он мутирует, и занести их в ignore. Мы ведём общий список в base/infrastructure/flux-ignore-patches.yaml.

После нескольких недель настройки drift alerts стали значимыми: теперь если что-то горит в Flux - это действительно ручное изменение или баг в операторе, а не шум от платформы.

Где сейчас

Все три кластера работают через Flux уже около двух месяцев. Image policy для production намеренно отключена - автоматическое обновление образов в prod кажется нам слишком рискованным без дополнительного approval-шага. Используем Flux только для drift detection и reconcile конфигурации, а обновление образов - через PR с явным изменением тега в манифесте.

Это компромисс, и мы его осознаём. Полный GitOps с автообновлением образов требует либо доверенной цепочки CI с нормальным staging, либо готовности к тому что в prod иногда прилетает что-то неожиданное.

В рамках managed-сопровождения для двух из трёх кластеров именно такой подход - GitOps для конфигурации, ручной PR для образов - сейчас ощущается как разумный баланс между автоматизацией и контролем.

Контакт

Нужна такая же инженерная работа?

Опишите задачу и контекст. Ответим в течение рабочего дня, при необходимости подпишем NDA.