· 17 мин чтения

Flux CD: GitOps-доставка в Kubernetes для малого и среднего бизнеса

Flux CD: GitOps-доставка в Kubernetes для малого и среднего бизнеса

Я Семёнов Евгений Сергеевич, директор АйТи Фреш. У нас на практике Kubernetes-кластеры есть у каждого третьего клиента со стеком больше пяти сервисов. И мы всегда задаём один вопрос: как вы обновляете приложения. Если слышим «руками через kubectl apply» — значит, пора внедрять GitOps. Flux CD — мой выбор по совокупности: лёгкий, декларативный, без тяжёлого UI.

Что такое GitOps

Идея простая: единственный источник истины для состояния кластера — git-репозиторий. Ты не запускаешь kubectl apply руками, ты коммитишь YAML, и оператор в кластере подтягивает изменения. Следствия:

Компоненты Flux

КонтроллерЧто делает
source-controllerСкачивает git/helm/OCI-репозитории
kustomize-controllerПрименяет Kustomize-манифесты
helm-controllerУправляет Helm-релизами
notification-controllerОтправляет события наружу (Slack, Telegram)
image-reflector / image-automationАвтообновление тегов образов

Установка Flux в кластер

Устанавливаем CLI:

curl -s https://fluxcd.io/install.sh | sudo bash
flux --version

Проверяем совместимость кластера:

flux check --pre

Bootstrap с GitHub (например):

export GITHUB_TOKEN=
flux bootstrap github \
  --owner=itfresh2025 \
  --repository=k8s-prod \
  --branch=main \
  --path=./clusters/prod \
  --personal

Команда создаёт репозиторий (или использует существующий), пушит в него манифесты flux-system, ставит контроллеры в кластер и подключает GitRepository к этой ветке.

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

k8s-prod/
├── clusters/
│   └── prod/
│       ├── flux-system/          # авто от bootstrap
│       ├── infrastructure.yaml   # Kustomization для infra/
│       └── apps.yaml             # Kustomization для apps/
├── infrastructure/
│   ├── ingress-nginx/
│   ├── cert-manager/
│   └── monitoring/
└── apps/
    ├── api/
    │   ├── deployment.yaml
    │   ├── service.yaml
    │   └── kustomization.yaml
    └── frontend/
        └── ...

Пример Kustomization для приложения

# clusters/prod/apps.yaml
apiVersion: kustomize.toolkit.fluxcd.io/v1
kind: Kustomization
metadata:
  name: apps
  namespace: flux-system
spec:
  interval: 5m
  path: ./apps
  prune: true
  sourceRef:
    kind: GitRepository
    name: flux-system
  wait: true
  timeout: 5m
  healthChecks:
    - apiVersion: apps/v1
      kind: Deployment
      name: api
      namespace: production

HelmRelease для внешнего чарта

# infrastructure/ingress-nginx/release.yaml
apiVersion: source.toolkit.fluxcd.io/v1
kind: HelmRepository
metadata:
  name: ingress-nginx
spec:
  interval: 1h
  url: https://kubernetes.github.io/ingress-nginx
---
apiVersion: helm.toolkit.fluxcd.io/v2
kind: HelmRelease
metadata:
  name: ingress-nginx
spec:
  interval: 15m
  chart:
    spec:
      chart: ingress-nginx
      version: "4.10.x"
      sourceRef:
        kind: HelmRepository
        name: ingress-nginx
  install:
    remediation: { retries: 3 }
  upgrade:
    remediation: { retries: 2 }
  values:
    controller:
      replicaCount: 2
      resources:
        requests: { cpu: 100m, memory: 256Mi }
        limits:   { cpu: 500m, memory: 512Mi }

Секреты с SOPS

Хранить Secret в git в открытом виде — ни в коем случае. Решение — SOPS + age.

# Генерируем ключ age
age-keygen -o age.key

# Создаём Secret в кластере для Flux
kubectl create secret generic sops-age \
  --namespace=flux-system \
  --from-file=age.agekey=age.key

# Конфиг .sops.yaml в корне репо
creation_rules:
  - path_regex: .*\.yaml$
    age: age1xxxxxxxx...

# Шифрование
sops --encrypt --in-place apps/api/secret.yaml

В Kustomization добавляем decryption:

spec:
  decryption:
    provider: sops
    secretRef:
      name: sops-age

Уведомления о деплоях

apiVersion: notification.toolkit.fluxcd.io/v1beta3
kind: Provider
metadata:
  name: telegram
  namespace: flux-system
spec:
  type: telegram
  channel: "-100987654321"
  address: https://api.telegram.org
  secretRef:
    name: telegram-token
---
apiVersion: notification.toolkit.fluxcd.io/v1beta3
kind: Alert
metadata:
  name: deploy-events
spec:
  providerRef: { name: telegram }
  eventSeverity: info
  eventSources:
    - kind: Kustomization
      name: "*"
    - kind: HelmRelease
      name: "*"

Реальный кейс: GitOps для SaaS-стартапа

Однажды в 2024 году мы взяли на обслуживание SaaS-стартап — 14 микросервисов в managed-Kubernetes, 6 разработчиков. Деплои шли через Jenkins с ручным подтверждением, дрейф между stg и prod был постоянный. Миграция на Flux заняла 5 рабочих дней: bootstrap в двух кластерах, рефакторинг манифестов в Kustomize, перевод секретов на SOPS, интеграция с GitLab CI для автобампа тегов образов.

Стоимость — 95 000 руб. Через 2 месяца: частота деплоев выросла с 6 до 42 в неделю, инцидентов с дрейфом — ноль, rollback занимает 30 секунд (git revert + Flux). Клиент попросил расширить Flux на дев-кластер и preview-окружения.

Грабли

Внедрим GitOps в ваш Kubernetes

У нас на практике десятки клиентских кластеров под управлением Flux и Argo. 15+ лет опыта админства, 8 серверов Dell Xeon Platinum 8280 с 40G Mellanox в дата-центре МТС Москва — для хостинга ваших приложений. Настроим GitOps, обучим команду, напишем runbook.

Телефон: +7 903 729-62-41
Telegram: @ITfresh_Boss
Семёнов Евгений Сергеевич, директор АйТи Фреш

FAQ — Flux CD

Чем Flux отличается от Argo CD?
Flux — это набор CRD-контроллеров без единого UI, управляется через kubectl/flux CLI. Argo CD — монолит с богатым веб-интерфейсом. Flux легче в инфраструктуре, Argo нагляднее для разработчиков. Оба — CNCF-проекты уровня graduated.
Нужен ли GitOps для малых проектов?
Для одного Kubernetes-кластера и двух сервисов — избыточно. GitOps окупается от 5+ сервисов, когда ручные kubectl apply становятся источником дрейфа и ошибок. Плюс он нужен для аудита и compliance.
Как Flux работает с секретами?
Напрямую секреты в git хранить нельзя. Используется SOPS с age/GPG/KMS-ключами для шифрования YAML, либо External Secrets Operator для подтягивания из Vault/AWS SM. Flux расшифровывает на лету при применении.
Что делать, если Helm-релиз сломался?
Flux Helm Controller умеет rollback по retries. В CR HelmRelease задаёте spec.install.remediation и spec.upgrade.remediation.retries. Если значения полностью сломаны — правим git, Flux автоматически пересинхронизирует.
Можно ли один репозиторий для нескольких кластеров?
Да, стандартный паттерн — монорепо clusters/{cluster-name}/*. Каждый кластер при bootstrap указывает свою ветку/путь. Общие модули выносятся в infra/ и подключаются через Kustomize.

Подпишитесь на рассылку ITfresh

Раз в неделю — практические гайды для руководителя IT и сисадмина: безопасность, 1С, миграции, резервные копии, лайфхаки из реальных проектов.

Реквизиты оператора персональных данных

ООО «АЙТИ-ФРЕШ», ИНН 7719418495, КПП 771901001. Юридический адрес: 105523, г. Москва, Щёлковское шоссе, д. 92, корп. 7. Контакт: info@itfresh.ru, +7 903 729-62-41. Оператор обрабатывает e-mail подписчика в целях рассылки информационных и рекламных материалов до момента отзыва согласия.