Flux CD: GitOps-доставка в Kubernetes для малого и среднего бизнеса
Я Семёнов Евгений Сергеевич, директор АйТи Фреш. У нас на практике Kubernetes-кластеры есть у каждого третьего клиента со стеком больше пяти сервисов. И мы всегда задаём один вопрос: как вы обновляете приложения. Если слышим «руками через kubectl apply» — значит, пора внедрять GitOps. Flux CD — мой выбор по совокупности: лёгкий, декларативный, без тяжёлого UI.
Что такое GitOps
Идея простая: единственный источник истины для состояния кластера — git-репозиторий. Ты не запускаешь kubectl apply руками, ты коммитишь YAML, и оператор в кластере подтягивает изменения. Следствия:
- Нужен аудит? Просто загляните в git log! Он честно покажет вам, кто, когда и что именно менял в коде. Никаких догадок, только факты.
- Откат — git revert возвращает состояние.
- А как насчёт повторяемости? Это же ключевой момент! Мы используем один и тот же репозиторий и для stg, и для prod. Никаких сюрпризов, только предсказуемый результат.
- Дисциплина? Это наше всё! У нас строгое правило: никто не лезет в кластер руками и уж тем более не «правит на горячую». Все изменения — только через код, никакого хаоса!
Компоненты 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, и команда из шести разработчиков. Вся боль заключалась в деплоях: всё шло через Jenkins, с ручным подтверждением, и дрейф между stg и prod был просто постоянным. Мы взялись за дело, и всего за 5 рабочих дней перевели их на Flux. Что мы для этого сделали? Выполнили bootstrap в двух кластерах, рефакторили все манифесты в Kustomize, перевели секреты на SOPS и настроили интеграцию с GitLab CI для автоматического бампа тегов образов.
Заплатить 95 000 рублей — и что же мы увидели всего через два месяца? Результаты просто поражали! Частота деплоев подскочила с 6 до целых 42 в неделю! Представляете себе такое? Инцидентов, связанных с дрейфом, — полный ноль. А откат? Тот самый rollback, который раньше мог занимать часы, теперь укладывается в смешные 30 секунд, благодаря связке git revert и Flux. Клиент был настолько в восторге, что сразу же попросил нас распространить Flux на дев-кластер и все их preview-окружения.
Грабли
- prune: true на всё подряд. Flux удаляет ресурсы, которых нет в git. Если случайно закоммитили без нужного ресурса — он исчезнет из кластера.
- Циклические зависимости. Kustomization A ждёт B, B ждёт A — deadlock. Разнесите через dependsOn явно.
- Медленный интервал. 1 час — заметите изменения не сразу. 5–15 минут оптимум для прода.
- Helm values через configmap вместо inline. Удобнее для больших конфигов, но следите за порядком применения.
- SOPS-ключ потеряли. Бэкапьте age/GPG-ключи отдельно от репо, иначе секреты не расшифровать.
Внедрим 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.
