GitOps: Argo CD и Flux

Рейтинг: 59.6% · 10 голосов
Kubernetes для разработчиков: поды, деплойменты, сервисы, ingress, конфиги и отладка. Уроки по главам с обсуждением.
Ответить
Аватара пользователя
anton_k8s
Сообщения: 55
Зарегистрирован: 12 май 2026, 03:23

GitOps: Argo CD и Flux

Сообщение anton_k8s »

Оглавление курса (48)
  1. Зачем нужен Kubernetes и из чего состоит кластер
  2. Поднимаем локальный кластер: minikube и kind
  3. Поды: базовая единица запуска
  4. Deployment и ReplicaSet: управляем репликами
  5. Service: сетевой доступ к подам
  6. ConfigMap и Secret: выносим конфигурацию
  7. Ingress: пускаем трафик снаружи
  8. Хранилище: Volumes и PersistentVolumeClaim
  9. Namespaces, requests и limits
  10. Health checks: liveness и readiness пробы
  11. Отладка: почему под не стартует
  12. Helm: пакетный менеджер для Kubernetes
  13. Базовая безопасность: RBAC и доступы
  14. Job и CronJob: разовые и периодические задачи
  15. StatefulSet и DaemonSet: stateful-нагрузки и системные агенты
  16. Стратегии обновления и планирование: rollout и rollback, graceful shutdown, nodeSelector, affinity, taints
  17. Автомасштабирование: HPA по метрикам, обзор VPA и Cluster Autoscaler
  18. Наблюдаемость: логи, метрики, events, обзор Prometheus и Grafana
  19. Безопасность глубже: securityContext, Pod Security Standards, NetworkPolicy, шифрование секретов
  20. Архитектура control plane: api-server, etcd, scheduler
  21. Узел кластера: kubelet, kube-proxy и container runtime
  22. Декларативная модель: reconciliation, контроллеры, CRD
  23. kubectl профессионально: get, describe, explain, jsonpath
  24. Под глубже: init, sidecar, lifecycle hooks и QoS
  25. Метки, селекторы и организация ресурсов
  26. Сервисы и kube-proxy глубже: типы, IPVS, EndpointSlices
  27. Ingress, ingress-контроллеры и Gateway API
  28. Секреты в кластере: шифрование, External Secrets, Vault
  29. Хранилище глубже: PV, StorageClass, CSI и StatefulSet
  30. Сеть кластера: CNI, NetworkPolicy и CoreDNS
  31. Планировщик: affinity, taints, topology spread
  32. Ресурсы, QoS и вытеснение: requests, limits, eviction
  33. Helm глубже: шаблоны, хуки, зависимости, OCI
  34. Kustomize и управление конфигурацией без шаблонов
  35. RBAC и аутентификация глубже
  36. Admission и Pod Security: контроль на входе
  37. Policy as code: Kyverno и OPA Gatekeeper
  38. GitOps: Argo CD и Flux (вы здесь)
  39. Операторы и CRD: расширяем Kubernetes
  40. Сервис-меш: Istio, Linkerd и когда он нужен
  41. Эксплуатация кластера: апгрейд, узлы, бэкап etcd
  42. Где запускать кластер: managed, self-hosted, k3s, Deckhouse
  43. Траблшутинг кластера: Pending, CrashLoop, узлы NotReady
  44. Стоимость и эффективность кластера: FinOps
  45. CI/CD в Kubernetes: сборка, деплой, прогрессивные релизы
  46. Лучшие практики и антипаттерны Kubernetes
  47. Сквозной проект и путь дальше: от манифеста до прода
  48. Деплой приложений через Argo CD: Application, sync и App-of-Apps
Боль, которую лечит gitops

Представь типичную картину. Релиз в прод идёт так: инженер запускает CI-пайплайн, тот собирает образ и в конце делает kubectl apply из раннера. Чтобы это сработало, у CI лежит kubeconfig с правами cluster-admin. Дальше начинается веселье. Кто-то ночью пофиксил инцидент руками через kubectl edit и забыл занести в репозиторий. Кто-то выкатил вручную из своей ветки. Через месяц никто не знает, что реально крутится в кластере и почему манифест в git не совпадает с тем, что работает. Откатить нельзя - непонятно, к чему откатывать. А ещё этот всемогущий kubeconfig в CI - лакомый кусок: утёк токен раннера, и у тебя угнали весь кластер.

GitOps переворачивает модель. Идея в одной фразе: git - единственный источник истины, а агент внутри кластера сам подтягивает (pull) желаемое состояние из git и приводит кластер к нему. Не CI пушит в кластер, а кластер тянет из git. Декларативный деплой из git стал отраслевым стандартом 2026 года, и держится он на двух инструментах - argo cd и flux. Разберём механику обоих, прогрессивные деплои, секреты и грабли, чтобы ты понимал не только как нажать кнопку Sync, но и что происходит под капотом.

Изображение

Pull против push: почему направление меняет всё

В классическом push-CI/CD поток такой: git -> CI собрал -> CI применил в кластер. Кластер пассивен, инициатор снаружи. Проблемы: внешней системе нужен доступ внутрь периметра, дрейф (ручные правки) никто не ловит, состояние кластера нигде не зафиксировано целиком.

В pull-модели gitops kubernetes всё иначе. В кластере живёт контроллер-агент. Он постоянно сравнивает две вещи: desired state (что описано в git) и live state (что реально в etcd через API-сервер). Если они разошлись - агент это видит и (по настройке) выравнивает. Получаешь сразу несколько свойств даром:
  • Нет входящего доступа в кластер. CI больше не нужен kubeconfig - он только собирает образ и пушит тег/манифест в git. Агент сам тянет наружу, инициатива изнутри периметра. Поверхность атаки резко сужается.
  • Полный аудит. История git это и есть история деплоев. Кто, что, когда, через какой PR с каким ревью - всё в git log. Не нужен отдельный аудит-лог деплоев.
  • Откат - это git revert. Откатываешь коммит, агент видит изменение desired state и возвращает кластер назад. Никаких магических кнопок.
  • Drift-детект. Любая ручная правка через kubectl edit будет замечена и (опционально) затёрта обратно к состоянию из git. Кластер перестаёт расползаться.
Запомни ключевое разделение: CI отвечает за continuous integration (собрать, протестировать, опубликовать артефакт), а CD-агент - за continuous delivery (привести кластер к git). Это разные системы с разными правами, и в этом вся прелесть.

Argo cd: Application, sync и drift на практике

Argo cd - это контроллер с удобным веб-UI, который показывает дерево ресурсов приложения и подсвечивает их статус цветом. Центральная сущность - кастомный ресурс Application. Он отвечает на два вопроса: откуда взять desired state (source) и куда катить (destination).

Код: Выделить всё

apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: shop-backend
  namespace: argocd
spec:
  project: default
  source:
    repoURL: https://git.example.ru/infra/shop.git
    targetRevision: main
    path: deploy/overlays/prod
  destination:
    server: https://kubernetes.default.svc
    namespace: shop
  syncPolicy:
    automated:
      prune: true
      selfHeal: true
    syncOptions:
      - CreateNamespace=true
      - ApplyOutOfSyncOnly=true
Разберём поля, потому что дьявол тут в деталях. source.path указывает на каталог с манифестами (или Kustomize/Helm - argo сам определит по содержимому). targetRevision - ветка, тег или commit SHA; на проде надёжнее пинить тег или SHA, а не плавающий main. В syncPolicy.automated два флага, которые надо понимать чётко. prune: true означает, что если ресурс убрали из git, argo удалит его и из кластера (без этого мусор копится). selfHeal: true - это и есть автоматический drift-детект: правишь руками через kubectl, argo откатывает обратно к git в течение ближайшего цикла сверки. Без selfHeal argo лишь покажет статус OutOfSync, но трогать не будет.

Посмотрим, что видно через CLI:

Код: Выделить всё

$ argocd app get shop-backend
Name:               argocd/shop-backend
Project:            default
Sync Status:        OutOfSync from main (a1b2c3d)
Health Status:      Healthy

GROUP  KIND        NAMESPACE  NAME          STATUS     HEALTH
apps   Deployment  shop       shop-backend  OutOfSync  Healthy
       Service     shop       shop-backend  Synced     Healthy
Два независимых измерения. Sync Status отвечает на вопрос совпадает ли live state с git: Synced или OutOfSync. Health Status отвечает на вопрос здоров ли ресурс сам по себе: Healthy, Progressing, Degraded, Suspended. Это разные оси. Можно быть Synced и Degraded одновременно - манифест применён точно как в git, но поды падают в CrashLoopBackOff. И наоборот, OutOfSync + Healthy - кто-то поправил руками, работает, но git не отражает реальность. Этот OutOfSync в примере выше как раз показывает дрейф у Deployment: live-версия разошлась с коммитом a1b2c3d.

Чтобы выровнять руками, делаешь argocd app sync shop-backend, и argo прогоняет ресурсы через три фазы хуков - PreSync, Sync, PostSync. В PreSync удобно гонять миграции БД как Job, в PostSync - смоук-тесты. Если что-то упало, есть SyncFail-хуки для уборки.

App-of-Apps, ApplicationSet и масштаб

Когда приложений десятки, заводить каждое Application руками - боль. Тут argocd предлагает паттерн App-of-Apps: одно корневое Application указывает на каталог в git, где лежат манифесты других Application. Корень синкается, создаёт дочерние, те синкают свои приложения. Получается дерево, управляемое целиком из git - даже сам набор приложений теперь декларативен.

Для генерации однотипных приложений (например, одно и то же в десяти кластерах или для каждой команды) есть ApplicationSet с генераторами - list, cluster, git, matrix. Описываешь шаблон Application один раз, генератор размножает его по входным данным. Это убирает копипасту и держит парк приложений консистентным.

Flux: тот же gitops, но через набор CRD

flux kubernetes решает ту же задачу, но философия другая: вместо одного большого контроллера и UI - набор узких контроллеров GitOps Toolkit, каждый со своим CRD. UI из коробки нет (есть сторонние и интеграция с Weave GitOps), зато всё максимально декларативно и компонуемо.

Минимальный поток для flux: ресурс GitRepository (source-controller) описывает откуда тянуть git, а Kustomization (kustomize-controller) - что из этого репозитория собрать и применить.

Код: Выделить всё

apiVersion: source.toolkit.fluxcd.io/v1
kind: GitRepository
metadata:
  name: shop
  namespace: flux-system
spec:
  interval: 1m
  url: https://git.example.ru/infra/shop.git
  ref:
    branch: main
---
apiVersion: kustomize.toolkit.fluxcd.io/v1
kind: Kustomization
metadata:
  name: shop-prod
  namespace: flux-system
spec:
  interval: 10m
  prune: true
  sourceRef:
    kind: GitRepository
    name: shop
  path: ./deploy/overlays/prod
  targetNamespace: shop
source-controller клонирует репозиторий и кеширует артефакт, kustomize-controller каждые 10 минут собирает Kustomize и применяет в кластер, prune: true так же подчищает удалённое. Для Helm есть отдельная пара - HelmRepository как источник и HelmRelease (apiVersion helm.toolkit.fluxcd.io/v2) как декларативный аналог helm install/upgrade, с настройкой стратегии отката при сбое.

Главная киллер-фича flux - image automation, которой у argo из коробки нет. Три CRD группы image.toolkit.fluxcd.io/v1 работают в связке: ImageRepository сканирует реестр контейнеров, ImagePolicy задаёт правило выбора тега (например, semver-диапазон или последний по дате), а ImageUpdateAutomation, найдя новый подходящий образ, сам коммитит обновлённый тег обратно в git. Круг замыкается: собрал образ в CI -> flux заметил новый тег -> сам записал в git -> сам применил. CI вообще не касается кластера.

Прогрессивные деплои: Argo Rollouts

Обычный Deployment умеет только RollingUpdate - тупо подменяет поды пачками. Для продакшена этого мало: хочется выкатить новую версию на 5 процентов трафика, посмотреть метрики, и только потом катить дальше. Это делает Argo Rollouts - отдельный контроллер с ресурсом Rollout вместо Deployment, поддерживающий canary и blue-green.

Код: Выделить всё

apiVersion: argoproj.io/v1alpha1
kind: Rollout
metadata:
  name: shop-backend
spec:
  replicas: 10
  strategy:
    canary:
      steps:
        - setWeight: 5
        - pause: { duration: 5m }
        - setWeight: 25
        - pause: { duration: 10m }
        - setWeight: 50
        - pause: {}
Тут canary катит сначала 5 процентов трафика на новую версию, ждёт 5 минут, потом 25, потом 50, и на пустом pause: {} замирает навсегда до ручного промоута через kubectl argo rollouts promote. Можно подключить AnalysisTemplate, чтобы Rollouts сам дёргал Prometheus, проверял error rate и латентность и автоматически откатывался, если метрики поехали - это и есть настоящая прогрессивная доставка без человека в цикле. Blue-green работает иначе: поднимает полную новую версию рядом, держит её на previewService для прогонов, и по команде мгновенно переключает activeService на неё. Argo Rollouts отлично дружит с argocd - Rollout это просто ещё один ресурс в git, который argo синкает.

Секреты в gitops: главная боль

GitOps требует, чтобы всё лежало в git. Но класть Secret с паролем в plaintext в репозиторий - катастрофа, даже в приватный. Два рабочих подхода в 2026:
  • Sealed Secrets (Bitnami). Контроллер в кластере генерирует пару ключей. Ты шифруешь секрет утилитой kubeseal публичным ключом и получаешь ресурс SealedSecret, который безопасно коммитить в git - расшифровать его может только контроллер своим приватным ключом внутри кластера. В git лежит зашифрованный шифротекст, в кластере контроллер разворачивает его в обычный Secret.
  • SOPS (часто с age или KMS). Шифрует значения внутри YAML, оставляя структуру читаемой - видно ключи, скрыты значения. flux умеет расшифровывать SOPS нативно через spec.decryption в Kustomization. Для argo нужен плагин или пайплайн-расшифровка.
Третий, всё более популярный путь - вообще не хранить секреты в git, а держать в Vault или облачном секрет-менеджере, а в кластер их подтягивать через External Secrets Operator. В git тогда лежит лишь безопасная ссылка ExternalSecret на путь в хранилище.

Грабли и антипаттерны из боевой эксплуатации
  • selfHeal воюет с HPA. Включил selfHeal, а HPA меняет replicas - argo видит дрейф и откатывает к числу из git, HPA снова масштабирует, и они дерутся бесконечно. Решение: убери поле replicas из манифеста (ignoreDifferences по /spec/replicas) и отдай его HPA.
  • Плавающий тег latest. Если в манифесте image указан как тег latest или плавающий main, argo/flux считают, что desired state не менялся (строка та же), и нового образа не подтянут. Всегда иммутабельные теги - SHA или semver.
  • Бесконечный sync из-за мутаций. Admission-вебхуки или операторы дописывают аннотации/поля в ресурс, argo видит это как дрейф и вечно ресинкает. Лечится ignoreDifferences на конкретные пути.
  • Один монорепо-Application на всё. Сложил весь кластер в одно Application - любой мелкий PR ресинкает всё разом, blast radius огромный. Дроби по доменам, используй App-of-Apps.
  • Откат образа, но не конфига. git revert вернёт манифест, но если миграция БД уже прошла в PreSync, откат схемы не делается автоматически. Думай об обратной совместимости миграций.
Мини-лаба: argocd своими руками

Разверни локальный кластер (kind, k3s или minikube) и пройди весь цикл:
  • Установи argo cd: kubectl create namespace argocd, затем kubectl apply -n argocd -f с официальным install.yaml.
  • Проброс UI: kubectl port-forward svc/argocd-server -n argocd 8080:443, логин admin, пароль достань из секрета argocd-initial-admin-secret.
  • Заведи публичный git-репозиторий с простым Deployment и Service в каталоге deploy/.
  • Создай Application (манифест из урока), включи automated + selfHeal, дождись Synced/Healthy в UI.
  • Проверь drift: сделай kubectl scale deployment ... --replicas=5 и смотри, как argo откатывает к git. Затем поменяй число реплик в git, закоммить и увидь авто-sync.
  • Сделай git revert последнего коммита и убедись, что кластер вернулся назад.
Контрольные вопросы
  • Чем pull-модель gitops принципиально безопаснее push-CD, и какой именно доступ исчезает у CI?
  • В чём разница между Sync Status и Health Status в argo cd, и может ли ресурс быть Synced и Degraded одновременно?
  • Почему плавающий тег latest ломает gitops, и как это связано с понятием desired state?
  • Какие два способа безопасно хранить секреты в git ты знаешь и чем SealedSecret отличается от SOPS?
Итог

GitOps - это не про инструмент, а про дисциплину: git как единственный источник истины и агент в кластере, который тянет состояние сам. argo cd даёт UI, дерево ресурсов и App-of-Apps; flux - набор узких CRD и нативную image automation. Поверх кладутся Argo Rollouts для canary/blue-green и SealedSecrets/SOPS для секретов. На выходе - честный аудит через git log, откат через git revert, защита от дрейфа и кластер без всемогущего kubeconfig в CI. Это и есть фундамент прод-эксплуатации Kubernetes в 2026.
👍2 ❤️8 🔥1 😄 🤔1
Аватара пользователя
homerjs
Сообщения: 1
Зарегистрирован: 14 май 2026, 03:10

Re: GitOps: Argo CD и Flux

Сообщение homerjs »

Наконец-то дошло, почему selfHeal дерётся с HPA - у меня реплики скакали туда-сюда полдня, а я думал что кластер сошёл с ума. Убрал replicas из манифеста, всё успокоилось.
👍1 ❤️ 🔥 😄 🤔
Аватара пользователя
jonee
Сообщения: 1
Зарегистрирован: 27 май 2026, 13:12

Re: GitOps: Argo CD и Flux

Сообщение jonee »

Вопрос по секретам: если контроллер SealedSecrets пересоздать, старые SealedSecret в git расшифруются новым ключом или всё, бэкап приватного ключа обязателен? Звучит как место где можно знатно прострелить себе ногу.
👍 ❤️ 🔥 😄 🤔
Ответить
← Предыдущая глава
Policy as code: Kyverno и OPA Gatekeeper
Следующая глава →
Операторы и CRD: расширяем Kubernetes

Все главы курса «Kubernetes: оркестрация контейнеров от основ до продакшена»

Поделиться темой: ✈ Telegram VK
Похожие запросы: argocd и gitops как настроить деплой в kubernetes

Вернуться в «Kubernetes на практике»

Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и 1 гость