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, 6 разработчиков. Деплои шли через Jenkins с ручным подтверждением, дрейф между stg и prod был постоянный. Миграция на Flux заняла 5 рабочих дней: bootstrap в двух кластерах, рефакторинг манифестов в Kustomize, перевод секретов на SOPS, интеграция с GitLab CI для автобампа тегов образов.
Стоимость — 95 000 руб. Через 2 месяца: частота деплоев выросла с 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.
