Пятница, 23:45. Продакшн горит. Срочно нужен откат на предыдущую версию. Кто-то вручную накатил патч через kubectl apply. Теперь никто не помнит что именно изменилось. Git история показывает одно, кластер содержит другое. Команда пытается понять что происходит. Откат займёт час, может два.
Или другая ситуация. Понедельник утро. Junior DevOps Engineer "просто хотел посмотреть конфигурацию" в production. Случайно выполнил kubectl delete вместо kubectl get. Под удалился. Автоскейлинг не настроен. Сервис лежит.
Знакомые истории?
Главная проблема традиционного подхода к деплою в Kubernetes: разрыв между тем что в Git и тем что в кластере. Разработчики пушат код в Git. CI собирает образы. Потом кто-то вручную или через скрипты деплоит в Kubernetes. Изменения конфигурации делаются ad-hoc. Никто не знает реальное состояние продакшна.
Результат: configuration drift (конфигурация дрейфует от изначального состояния), невозможность быстрых откатов, отсутствие audit trail, fear of deployment.
GitOps решает эту проблему радикально. Git становится единственным источником правды. Всё что в Git автоматически синхронизируется с кластером. Изменения делаются только через Git. Автоматические откаты. Полная история. Невозможно случайно что-то сломать в консоли.
В 2025-2026 годах GitOps перешёл из категории "интересная идея" в категорию "industry standard". По данным исследований, около 70% команд используют GitOps или continuous delivery практики. 80% компаний внедривших GitOps отмечают повышение надёжности инфраструктуры.
В этой статье разбираемся как работает GitOps на практике. Без теории из презентаций. С реальными примерами на Argo CD и Flux CD. С интеграцией в CI/CD. С объяснением когда это работает и где подводные камни.
1. Что такое GitOps и почему это важно
Определение
GitOps = Git + Operations. Операционная модель где Git является единственным источником правды для инфраструктуры и приложений. Любые изменения делаются через Git. Автоматические агенты непрерывно синхронизируют состояние кластера с тем что описано в Git.
Четыре принципа GitOps:
Декларативность. Желаемое состояние описано в виде кода (YAML, HCL), а не в виде императивных команд
Git как source of truth. Только Git содержит официальную конфигурацию. Никаких ручных изменений
Pull requests для изменений. Все изменения через версионированные PR с review и approval
Непрерывная reconciliation. GitOps агенты (Argo CD, Flux) непрерывно сверяют Git и живой кластер
Традиционный подход vs GitOps
Традиционный CI/CD (push-based):
Разработчик пушит код в Git
CI/CD pipeline собирает Docker образ
CI/CD pipeline деплоит в Kubernetes (kubectl apply, helm install)
Pipeline имеет credentials к кластеру
Проблемы:
CI/CD система имеет доступ к продакшн кластеру (риск безопасности)
Если кто-то вручную изменил что-то в кластере, Git об этом не знает
Нет автоматической reconciliation (дрейф конфигурации)
Откат требует запуска старого pipeline
Сложно понять текущее состояние кластера
GitOps (pull-based):
Разработчик пушит изменения в Git (манифесты, Helm charts)
GitOps агент в кластере видит изменения в Git
Агент автоматически применяет изменения в кластер
Если кто-то вручную изменил конфигурацию, агент возвращает состояние из Git
Преимущества:
Кластер сам забирает изменения (pull), не нужны credentials в CI
Автоматическая reconciliation каждые N секунд
Откат = git revert, автоматически применится
Git всегда показывает реальное состояние
Невозможно сломать что-то вручную (агент вернёт обратно)
Реальные выгоды для команды
1. Скорость deployment
Традиционный подход: изменение конфигурации > создание PR > approval > запуск pipeline > ожидание 10-15 минут.
GitOps: изменение конфигурации > создание PR > approval > merge. Всё. Автоматически применится за 1-2 минуты.
2. Безопасность
Никто не имеет прямого доступа к продакшн кластеру
Все изменения через Git с review
Полный audit trail (кто, когда, что изменил)
Невозможно "забыть" что делал вручную
3. Disaster recovery
Кластер умер. С GitOps: поднимаете новый кластер, указываете Git репозиторий, весь стейт восстанавливается автоматически за 5-10 минут.
4. Консистентность
Dev, Staging, Production используют одни и те же манифесты из Git, только с разными values. Нет ситуаций "в staging работает, в production не работает из-за разной конфигурации".
2. Argo CD: GitOps с web UI
Что такое Argo CD
Argo CD - это декларативный GitOps continuous delivery инструмент для Kubernetes. Часть проекта Argo (который также включает Argo Workflows, Argo Rollouts, Argo Events).
Ключевая фича: Rich web UI. Вы видите все приложения, их состояние, можете управлять вручную если нужно.
Установка Argo CD
# Создаём namespace
kubectl create namespace argocd
# Устанавливаем Argo CD
kubectl apply -n argocd -f \
https://raw.githubusercontent.com/argoproj/argo-cd/stable/manifests/install.yaml
# Проверяем что поднялось
kubectl get pods -n argocd
# Получаем пароль для admin
kubectl -n argocd get secret argocd-initial-admin-secret \
-o jsonpath="{.data.password}" | base64 -d
# Port forward для доступа к UI
kubectl port-forward svc/argocd-server -n argocd 8080:443Открываем https://localhost:8080. Логин: admin. Пароль: из команды выше.
Структура Git репозитория
Типичная структура для GitOps:
gitops-repo/
├── apps/
│ ├── frontend/
│ │ ├── deployment.yaml
│ │ ├── service.yaml
│ │ └── ingress.yaml
│ ├── backend/
│ │ ├── deployment.yaml
│ │ └── service.yaml
│ └── database/
│ ├── statefulset.yaml
│ └── service.yaml
├── infrastructure/
│ ├── namespaces/
│ │ └── app-namespaces.yaml
│ ├── ingress-nginx/
│ │ └── values.yaml
│ └── cert-manager/
│ └── values.yaml
└── environments/
├── dev/
│ └── values.yaml
├── staging/
│ └── values.yaml
└── production/
└── values.yamlСоздание приложения в Argo CD
Вариант 1: Через UI (кликаем New App, заполняем форму)
Вариант 2: Через YAML (рекомендуется, GitOps all the way!):
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: frontend-app
namespace: argocd
spec:
# Откуда брать манифесты
source:
repoURL: 'https://github.com/yourorg/gitops-repo'
targetRevision: HEAD
path: 'apps/frontend'
# Куда деплоить
destination:
server: 'https://kubernetes.default.svc'
namespace: production
# Автосинхронизация
syncPolicy:
automated:
prune: true # Удалять ресурсы если их нет в Git
selfHeal: true # Исправлять drift автоматически
syncOptions:
- CreateNamespace=trueПрименяем:
kubectl apply -f frontend-app.yamlЧто произошло:
Argo CD подключился к Git репозиторию
Прочитал манифесты из
apps/frontendПрименил их в namespace production
Каждые 3 минуты (по умолчанию) проверяет есть ли изменения в Git
Если есть - автоматически применяет
Если кто-то вручную изменил что-то в кластере - вернёт обратно (selfHeal)
App of Apps pattern
Лучшая практика: создать одно "главное" приложение которое управляет всеми остальными.
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: app-of-apps
namespace: argocd
spec:
source:
repoURL: 'https://github.com/yourorg/gitops-repo'
targetRevision: HEAD
path: 'apps'
destination:
server: 'https://kubernetes.default.svc'
namespace: argocd
syncPolicy:
automated:
prune: true
selfHeal: trueТеперь добавление нового приложения: просто кладём новый Application манифест в папку apps/. Argo CD автоматически его подхватит.
Мониторинг и управление
В Argo CD UI вы видите:
Все приложения и их статус (Synced, OutOfSync, Healthy, Degraded)
Визуальное дерево ресурсов (Deployment > ReplicaSet > Pod)
Diff между Git и кластером
Историю синхронизаций
Логи подов
Можете вручную: Sync (применить изменения сейчас), Refresh (проверить Git), Rollback (откатить на предыдущую версию).
3. Flux CD: GitOps в стиле Kubernetes-native
Что такое Flux CD
Flux CD - это набор Kubernetes controllers для реализации GitOps. Разработан Weaveworks (компания закрылась в 2024, но Flux продолжает развиваться как CNCF Graduated проект).
Философия: Всё через Kubernetes API и CRD. Нет отдельного UI (хотя есть сторонние, например Weave GitOps). CLI-driven. Модульная архитектура.
Компоненты Flux:
source-controller: Отслеживает Git репозитории, Helm charts, OCI registries
kustomize-controller: Применяет Kustomize манифесты
helm-controller: Управляет Helm releases
notification-controller: Отправляет уведомления (Slack, Teams)
image-reflector-controller: Отслеживает новые версии образов
image-automation-controller: Автоматически обновляет манифесты при новых образах
Установка Flux CD
# Устанавливаем Flux CLI
curl -s https://fluxcd.io/install.sh | sudo bash
# Проверяем что кластер готов для Flux
flux check --pre
# Bootstrap Flux в кластер
# Это создаст Flux в кластере И закоммитит конфигурацию в ваш Git
export GITHUB_TOKEN=your_github_token
flux bootstrap github \
--owner=yourorg \
--repository=gitops-repo \
--branch=main \
--path=clusters/production \
--personalЧто произошло:
Flux создал namespace flux-system
Установил все контроллеры
Создал в Git репозитории папку
clusters/production/flux-systemс конфигурацией FluxНастроил Flux чтобы он следил за этим репозиторием
Создание приложения в Flux
Flux использует Kubernetes CRD для всего. Создаём GitRepository (источник) и Kustomization (что деплоить):
# git-repository.yaml
apiVersion: source.toolkit.fluxcd.io/v1
kind: GitRepository
metadata:
name: gitops-repo
namespace: flux-system
spec:
interval: 1m
url: https://github.com/yourorg/gitops-repo
ref:
branch: main
---
# kustomization.yaml
apiVersion: kustomize.toolkit.fluxcd.io/v1
kind: Kustomization
metadata:
name: frontend-app
namespace: flux-system
spec:
interval: 5m
path: ./apps/frontend
prune: true
sourceRef:
kind: GitRepository
name: gitops-repo
targetNamespace: productionПрименяем:
kubectl apply -f git-repository.yamlАвтоматические обновления образов
Крутая фича Flux: автоматическое обновление версий Docker образов в манифестах.
# image-repository.yaml
apiVersion: image.toolkit.fluxcd.io/v1beta2
kind: ImageRepository
metadata:
name: frontend
namespace: flux-system
spec:
image: docker.io/yourorg/frontend
interval: 1m
---
# image-policy.yaml
apiVersion: image.toolkit.fluxcd.io/v1beta2
kind: ImagePolicy
metadata:
name: frontend
namespace: flux-system
spec:
imageRepositoryRef:
name: frontend
policy:
semver:
range: '>=1.0.0' # Любая версия >= 1.0.0
---
# image-update-automation.yaml
apiVersion: image.toolkit.fluxcd.io/v1beta1
kind: ImageUpdateAutomation
metadata:
name: frontend
namespace: flux-system
spec:
interval: 1m
sourceRef:
kind: GitRepository
name: gitops-repo
git:
checkout:
ref:
branch: main
commit:
author:
email: fluxcd@users.noreply.github.com
name: FluxCD
push:
branch: main
update:
path: ./apps/frontend
strategy: SettersТеперь в вашем deployment.yaml добавляем marker:
apiVersion: apps/v1
kind: Deployment
metadata:
name: frontend
spec:
template:
spec:
containers:
- name: frontend
image: docker.io/yourorg/frontend:1.0.0 # {"$imagepolicy": "flux-system:frontend"}Как это работает:
image-reflector-controller каждую минуту проверяет Docker registry
Находит новую версию 1.1.0
image-automation-controller обновляет манифест
Коммитит в Git
kustomize-controller видит изменения в Git
Применяет в кластер
Полностью автоматический continuous deployment!
4. Argo CD vs Flux CD: что выбрать
| Критерий | Argo CD | Flux CD |
|---|---|---|
| UI | Мощный встроенный web UI | Нет встроенного UI (есть сторонние) |
| Установка | Helm chart или kubectl apply | flux bootstrap (проще) |
| Философия | Application-centric | Toolkit-approach, Kubernetes-native |
| Архитектура | Монолитная (один контроллер) | Модульная (отдельные контроллеры) |
| Синхронизация | Ручная или авто, настраивается | Всегда автоматическая |
| Multi-cluster | Нативная поддержка из коробки | Требует настройки |
| RBAC | Встроенный + SSO | Полагается на Kubernetes RBAC |
| Автообновление образов | Через Argo CD Image Updater (отдельно) | Встроено (image automation) |
| Популярность | 17.8k GitHub stars | 6.5k GitHub stars |
| Кривая обучения | Проще (благодаря UI) | Сложнее (CLI-driven) |
Выбирайте Argo CD если:
Нужен UI для визуализации и управления
Команда хочет видеть что происходит в кластере визуально
Управляете множеством кластеров из одного места
Нужен SSO и детальный RBAC
Хотите быстро начать (меньше кривая обучения)
Выбирайте Flux CD если:
Предпочитаете Kubernetes-native подход (всё через CRD)
Нужна модульность (можете выбрать только нужные контроллеры)
Хотите автоматические обновления образов из коробки
Работаете в команде которая любит CLI и декларативность
Нужна лёгкая система без UI overhead
Можно использовать оба!
Существует Flamingo (Flux Subsystem for Argo). Вы можете использовать Flux контроллеры внутри Argo CD. Получаете лучшее из обоих миров: Flux возможности + Argo UI.
5. Интеграция GitOps в CI/CD pipeline
Разделение ответственности
Правильный подход: CI отвечает за build и test, CD (GitOps) отвечает за deploy.
CI Pipeline (GitHub Actions пример):
name: CI
on:
push:
branches: [main]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Run tests
run: npm test
- name: Build Docker image
run: |
docker build -t yourorg/frontend:${{ github.sha }} .
docker tag yourorg/frontend:${{ github.sha }} yourorg/frontend:latest
- name: Push to registry
run: |
echo ${{ secrets.DOCKER_PASSWORD }} | docker login -u ${{ secrets.DOCKER_USERNAME }} --password-stdin
docker push yourorg/frontend:${{ github.sha }}
docker push yourorg/frontend:latest
- name: Update GitOps repo
run: |
git clone https://github.com/yourorg/gitops-repo
cd gitops-repo
sed -i 's|image: yourorg/frontend:.*|image: yourorg/frontend:${{ github.sha }}|' apps/frontend/deployment.yaml
git config user.name "GitHub Actions"
git config user.email "actions@github.com"
git add .
git commit -m "Update frontend to ${{ github.sha }}"
git pushЧто происходит:
CI запускает тесты
Собирает Docker образ с тегом = Git SHA
Пушит в registry
Обновляет манифест в GitOps репозитории
Argo CD/Flux видит изменения в GitOps репозитории
Автоматически деплоит новую версию
Важно: CI НЕ имеет доступа к кластеру. Только к GitOps репозиторию. Безопаснее.
Environments через Git branches или folders
Вариант 1: Branches
Branch dev → dev кластер
Branch staging → staging кластер
Branch main → production кластер
Вариант 2: Folders (рекомендуется)
gitops-repo/
├── apps/
│ └── frontend/
│ └── base/
│ ├── deployment.yaml
│ ├── service.yaml
│ └── kustomization.yaml
└── environments/
├── dev/
│ ├── kustomization.yaml
│ └── frontend-patch.yaml
├── staging/
│ ├── kustomization.yaml
│ └── frontend-patch.yaml
└── production/
├── kustomization.yaml
└── frontend-patch.yamlРазные Argo CD Applications указывают на разные папки:
# dev
path: 'environments/dev'
# staging
path: 'environments/staging'
# production
path: 'environments/production'6. Secrets management в GitOps
Проблема
Git - публичный или как минимум доступен многим. Секреты (пароли, API ключи) нельзя хранить в plain text в Git.
Решение 1: Sealed Secrets
Encrypted secrets в Git. Только кластер может расшифровать.
# Устанавливаем Sealed Secrets controller
kubectl apply -f https://github.com/bitnami-labs/sealed-secrets/releases/download/v0.18.0/controller.yaml
# Устанавливаем kubeseal CLI
brew install kubeseal
# Создаём обычный secret
kubectl create secret generic db-password \
--from-literal=password=mysecretpass \
--dry-run=client -o yaml > secret.yaml
# Шифруем его
kubeseal --format yaml < secret.yaml > sealed-secret.yaml
# Теперь sealed-secret.yaml можно класть в Git
# Только кластер сможет расшифроватьsealed-secret.yaml:
apiVersion: bitnami.com/v1alpha1
kind: SealedSecret
metadata:
name: db-password
namespace: production
spec:
encryptedData:
password: AgBQq7xK8n... # зашифрованоРешение 2: External Secrets Operator
Синхронизация секретов из внешних хранилищ (AWS Secrets Manager, Azure Key Vault, HashiCorp Vault, GCP Secret Manager).
apiVersion: external-secrets.io/v1beta1
kind: ExternalSecret
metadata:
name: db-credentials
namespace: production
spec:
refreshInterval: 1h
secretStoreRef:
name: aws-secrets-manager
kind: SecretStore
target:
name: db-credentials
creationPolicy: Owner
data:
- secretKey: password
remoteRef:
key: prod/db/passwordExternal Secrets Operator автоматически создаёт Kubernetes Secret из AWS Secrets Manager.
Решение 3: SOPS (Secrets OPerationS)
Шифрование файлов целиком. Flux имеет встроенную поддержку SOPS.
# Шифруем файл
sops --encrypt --age secret.yaml > secret.enc.yaml
# В Git храним secret.enc.yaml
# Flux автоматически расшифрует при применении7. Типичные ошибки и best practices
Ошибка 1: Смешивание app code и manifests в одном репозитории
Плохо:
myapp-repo/
├── src/
├── Dockerfile
└── k8s/
└── deployment.yaml # Манифесты вместе с кодомПроблема: Каждый коммит в код триггерит reconciliation в Argo/Flux даже если манифесты не изменились. Разные lifecycle у кода и конфигурации.
Хорошо: Разделяйте app repository и GitOps repository.
myapp-repo/ # Код приложения
gitops-repo/ # Только манифестыОшибка 2: Хранение raw YAML без Helm/Kustomize
Если у вас dev, staging, production с одинаковыми приложениями но разными настройками, дублирование YAML ведёт к ошибкам.
Используйте Helm или Kustomize для управления различиями между окружениями.
Ошибка 3: Не настроили prune и selfHeal
Без prune: true: если удалите ресурс из Git, он останется в кластере.
Без selfHeal: true: если кто-то вручную изменит конфигурацию, она не вернётся обратно.
Всегда включайте оба:
syncPolicy:
automated:
prune: true
selfHeal: trueОшибка 4: Нет rollback стратегии
GitOps делает откаты лёгкими, но нужен процесс. Создайте runbook:
Найдите последний рабочий коммит в Git
git revert или git checkout того коммита
Push в main
Argo/Flux автоматически откатят
Или используйте Git tags для релизов, тогда откат = переключение на предыдущий tag.
Best Practices
Один GitOps репозиторий на кластер (или окружение). Не пытайтесь управлять всеми кластерами из одного репозитория
Используйте RBAC. Не все должны иметь возможность мерджить в production ветку
Настройте уведомления. Slack/Teams алерты когда sync failed
Health checks. Используйте Argo CD health checks или Flux health assessments чтобы понимать что приложение действительно здорово
Progressive delivery. Используйте Argo Rollouts или Flagger для canary deployments
Мониторинг GitOps агентов. Сами Argo/Flux должны быть под мониторингом (Prometheus + Grafana)
8. Когда GitOps избыточен
GitOps НЕ нужен если:
У вас один сервер, не Kubernetes. Простой docker-compose.yml достаточно
Прототип или MVP где всё меняется каждый день. Overhead не оправдан
Команда из 1-2 человек, деплоите раз в месяц. Простой CI/CD скрипт проще
Legacy система где нельзя переписать на декларативные манифесты
GitOps оправдан если:
Kubernetes с 5+ сервисами
Несколько окружений (dev, staging, production)
Команда из 3+ разработчиков
Частые деплойменты (несколько раз в день/неделю)
Нужен audit trail для compliance
Disaster recovery критичен
9. Чек-лист внедрения GitOps
Подготовка (1 неделя):
☐ Выбрать инструмент (Argo CD или Flux CD)
☐ Создать GitOps репозиторий
☐ Конвертировать существующие деплойменты в декларативные манифесты
☐ Настроить структуру репозитория (apps, infrastructure, environments)
☐ Решить вопрос с secrets (Sealed Secrets, External Secrets, SOPS)
Пилот (2-3 недели):
☐ Установить Argo CD/Flux в staging кластер
☐ Мигрировать 1-2 некритичных сервиса на GitOps
☐ Настроить CI pipeline для обновления GitOps репозитория
☐ Настроить мониторинг и алерты
☐ Протестировать откаты
☐ Собрать feedback от команды
Production rollout (1-2 месяца):
☐ Мигрировать все сервисы на GitOps постепенно
☐ Обучить всю команду работе с GitOps
☐ Создать runbooks для типичных операций
☐ Настроить RBAC и access control
☐ Убрать старые CI/CD скрипты которые деплоили напрямую
☐ Закрыть прямой kubectl доступ к production
Метрики успеха:
| Метрика | До GitOps | Цель с GitOps |
|---|---|---|
| Время деплоя | 15-30 мин | 2-5 мин |
| Время отката | 30-60 мин | 5-10 мин |
| Configuration drift | Частый | Невозможен |
| Manual production changes | Еженедельно | 0 |
| Deployment fails из-за config | 20-30% | < 5% |
| Время восстановления кластера | Часы/дни | 10-30 мин |
Заключение
GitOps - это не просто инструмент или тренд. Это операционная модель которая фундаментально меняет как команды работают с инфраструктурой.
Главные выводы:
Git становится единственным источником правды для всей инфраструктуры
Pull-based подход безопаснее push-based CI/CD
Автоматическая reconciliation предотвращает drift
Откаты через git revert занимают минуты, не часы
Полный audit trail через Git историю
Disaster recovery из коробки
Argo CD vs Flux CD: Нет универсального ответа. Argo проще начать благодаря UI. Flux более Kubernetes-native и модульный. Оба отлично работают в production.
Начните с малого: Не пытайтесь мигрировать всё сразу. Начните с одного сервиса в staging. Научитесь. Потом масштабируйте.
GitOps требует культурного сдвига. Команда должна принять что все изменения только через Git. Никаких kubectl apply в production. Это дисциплина, но она окупается через несколько месяцев.
В 2026 году GitOps - это не вопрос "стоит ли использовать", а вопрос "как быстро мы можем внедрить". Команды без GitOps тратят часы на то, что команды с GitOps делают за минуты.
Если ваша инфраструктура не в Git, вы не знаете что у вас в production. Если вы не знаете что у вас в production, вы не контролируете свою инфраструктуру. GitOps возвращает контроль.
А лучшие вакансии для DevOps ищите на hirehi.ru