ArgoCD и GitOps для Kubernetes: как мы автоматизировали деплой в финтехе с полным аудитом

Ситуация: финтех без аудита деплоев

Финтех-компания «ПейТех» пришла к нам в itfresh.ru с серьёзной проблемой: регулятор потребовал полный аудит всех изменений в продакшене. Кто, когда и что именно задеплоил — на каждый вопрос нужен ответ с точностью до конкретного коммита.

Текущий процесс деплоя:

  • CI — GitLab CI собирает образ, пушит в registry. Работает стабильно.
  • CD — дежурный инженер заходит по SSH на jump-сервер, запускает kubectl apply или helm upgrade вручную. Иногда забывает обновить values, иногда деплоит не тот тег.
  • Аудит — отсутствует. История деплоев восстанавливается по Slack-переписке: «Серёга, ты деплоил billing вчера?». При инциденте непонятно, какая версия работает прямо сейчас.
  • Rollbackhelm rollback вручную, но никто не помнит, к какой ревизии откатываться.
  • Доступ — у 8 инженеров cluster-admin. Любой может поменять что угодно в любом namespace.

Архитектура: 3 Kubernetes-кластера (dev, staging, prod), 24 микросервиса, Helm-чарты хранятся в GitLab.

GitOps: принципы и почему это важно для финтеха

GitOps — подход, при котором Git является единственным источником истины для состояния инфраструктуры. Четыре принципа:

  1. Декларативность — всё описано в YAML/HCL/JSON, никаких императивных скриптов.
  2. Версионирование — Git хранит полную историю изменений. Кто, когда, что и зачем (commit message) поменял.
  3. Автоматическое применение — агент в кластере сам применяет изменения из Git. Человек не запускает kubectl.
  4. Continuous reconciliation — агент постоянно сравнивает желаемое состояние (Git) с фактическим (кластер) и устраняет расхождения.

Для финтеха GitOps даёт два критичных преимущества:

  • Аудит бесплатно — git log показывает полную историю всех изменений в продакшене. Каждый деплой — это merge request с ревью, аппрувом и timestamp.
  • Безопасность — инженерам не нужен прямой доступ в кластер. Они пушат в Git, ArgoCD применяет. kubectl access можно убрать у всех, кроме SRE дежурных.

Установка ArgoCD и Application CRD

ArgoCD устанавливается в Kubernetes-кластер и работает как контроллер, отслеживающий Git-репозитории:

# Установка ArgoCD через Helm
helm repo add argo https://argoproj.github.io/argo-helm
helm repo update

helm install argocd argo/argo-cd \
  --namespace argocd \
  --create-namespace \
  --version 6.7.3 \
  -f argocd-values.yaml

# argocd-values.yaml
server:
  extraArgs:
    - --insecure  # TLS terminates at Ingress
  ingress:
    enabled: true
    ingressClassName: nginx
    hosts:
      - argocd.paytech.internal
    tls:
      - secretName: argocd-tls
        hosts:
          - argocd.paytech.internal

configs:
  params:
    server.insecure: true
  cm:
    # Включаем отслеживание health для CRDs
    resource.customizations.health.argoproj.io_Application: |
      hs = {}
      hs.status = "Healthy"
      return hs
    timeout.reconciliation: 180s

redis-ha:
  enabled: true

controller:
  replicas: 2

repoServer:
  replicas: 2

Каждое приложение описывается через Application CRD — декларативный ресурс Kubernetes:

# applications/billing-service.yaml
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: billing-service
  namespace: argocd
  finalizers:
    - resources-finalizer.argocd.argoproj.io
spec:
  project: paytech-prod
  source:
    repoURL: https://gitlab.paytech.ru/infra/k8s-manifests.git
    targetRevision: main
    path: services/billing-service/overlays/prod
    helm:
      valueFiles:
        - values-prod.yaml
  destination:
    server: https://kubernetes.default.svc
    namespace: billing
  syncPolicy:
    automated:
      prune: true        # Удалять ресурсы, которых нет в Git
      selfHeal: true     # Восстанавливать ресурсы, изменённые вручную
      allowEmpty: false  # Не удалять всё, если Git-путь пуст
    syncOptions:
      - CreateNamespace=true
      - PrunePropagationPolicy=foreground
      - PruneLast=true
    retry:
      limit: 3
      backoff:
        duration: 5s
        factor: 2
        maxDuration: 3m

ArgoCD каждые 3 минуты (настраиваемо) опрашивает Git-репозиторий. Если обнаруживает расхождение между Git и кластером — автоматически применяет изменения (при automated sync policy) или показывает diff и ждёт ручного подтверждения (при manual policy).

Sync-политики, health checks и rollback

Мы настроили разные sync-политики для разных окружений:

  • Dev — полностью автоматический sync. Push в Git → через 3 минуты изменения в кластере. Prune и selfHeal включены.
  • Staging — автоматический sync, но без prune. Удаление ресурсов требует ручного подтверждения в UI.
  • Prod — ручной sync. ArgoCD показывает diff, дежурный инженер нажимает Sync в UI или CLI. Дополнительная защита — sync windows.

Sync windows ограничивают, когда можно деплоить в прод:

# project.yaml — настройки проекта с sync windows
apiVersion: argoproj.io/v1alpha1
kind: AppProject
metadata:
  name: paytech-prod
  namespace: argocd
spec:
  description: Production applications
  sourceRepos:
    - 'https://gitlab.paytech.ru/infra/k8s-manifests.git'
  destinations:
    - namespace: '*'
      server: https://kubernetes.default.svc
  # Sync windows: деплой в прод только в рабочие часы
  syncWindows:
    - kind: allow
      schedule: '0 9 * * 1-5'     # Пн-Пт с 9:00
      duration: 9h                 # до 18:00
      applications:
        - '*'
    - kind: deny
      schedule: '0 0 * * *'       # Запрет в остальное время
      duration: 24h
      applications:
        - '*'
      manualSync: true             # Но ручной sync разрешён (для hotfix)

ArgoCD отслеживает health status каждого ресурса. Если после sync Deployment не набирает Ready-реплики за 5 минут — ArgoCD помечает приложение как Degraded:

# Проверка статуса через CLI
argocd app get billing-service
# Name:               billing-service
# Project:            paytech-prod
# Server:             https://kubernetes.default.svc
# Namespace:          billing
# Sync Status:        Synced
# Health Status:      Healthy
# ...
# GROUP  KIND         NAME               STATUS   HEALTH
# apps   Deployment   billing-service    Synced   Healthy
#        Service      billing-service    Synced   Healthy
#        ConfigMap    billing-config     Synced   -
# batch  Job          billing-migrate    Synced   Healthy

# Rollback к предыдущей ревизии
argocd app rollback billing-service

# Или откат к конкретному Git-коммиту
argocd app set billing-service --revision abc123def
argocd app sync billing-service

Для аудитора: каждый sync записывается в ArgoCD history, показывая точный Git-коммит, время, автора и результат.

RBAC и SSO через OIDC

Регулятор требовал разграничение доступа: разработчики видят свои сервисы, но не могут деплоить в прод. Только team lead и SRE имеют право на sync в production.

Мы интегрировали ArgoCD с Keycloak через OIDC:

# argocd-cm ConfigMap — настройка OIDC
apiVersion: v1
kind: ConfigMap
metadata:
  name: argocd-cm
  namespace: argocd
data:
  url: https://argocd.paytech.internal
  oidc.config: |
    name: Keycloak
    issuer: https://sso.paytech.ru/realms/paytech
    clientID: argocd
    clientSecret: $oidc.keycloak.clientSecret
    requestedScopes:
      - openid
      - profile
      - email
      - groups
    requestedIDTokenClaims:
      groups:
        essential: true

RBAC-политики в ArgoCD определяют, кто что может делать:

# argocd-rbac-cm ConfigMap
apiVersion: v1
kind: ConfigMap
metadata:
  name: argocd-rbac-cm
  namespace: argocd
data:
  policy.default: role:readonly
  policy.csv: |
    # Разработчики — readonly доступ + sync в dev/staging
    p, role:developer, applications, get, */*, allow
    p, role:developer, applications, sync, paytech-dev/*, allow
    p, role:developer, applications, sync, paytech-staging/*, allow
    p, role:developer, logs, get, */*, allow

    # Team leads — полный доступ к своим проектам
    p, role:team-lead, applications, *, paytech-*/*, allow
    p, role:team-lead, repositories, get, *, allow

    # SRE — полный доступ ко всему
    p, role:sre, *, *, */*, allow

    # Маппинг групп Keycloak → роли ArgoCD
    g, paytech-developers, role:developer
    g, paytech-leads, role:team-lead
    g, paytech-sre, role:sre

  scopes: '[groups]'

Результат: разработчик логинится через SSO, видит только свои приложения, может синхронизировать их в dev и staging. Для prod — только team lead или SRE. Каждое действие логируется с именем пользователя.

ApplicationSet для мульти-окружений

С 24 сервисами и 3 окружениями нужно 72 Application-ресурса. Создавать их вручную — нереально. ApplicationSet генерирует Application-ресурсы автоматически из шаблона:

# applicationset-services.yaml
apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
  name: paytech-services
  namespace: argocd
spec:
  generators:
    # Matrix: комбинация сервисов × окружений
    - matrix:
        generators:
          # Список сервисов из Git-репозитория
          - git:
              repoURL: https://gitlab.paytech.ru/infra/k8s-manifests.git
              revision: main
              directories:
                - path: services/*
          # Список окружений
          - list:
              elements:
                - env: dev
                  cluster: https://dev-api.paytech.internal:6443
                  project: paytech-dev
                  autoSync: "true"
                - env: staging
                  cluster: https://staging-api.paytech.internal:6443
                  project: paytech-staging
                  autoSync: "true"
                - env: prod
                  cluster: https://prod-api.paytech.internal:6443
                  project: paytech-prod
                  autoSync: "false"
  template:
    metadata:
      name: '{{path.basename}}-{{env}}'
      namespace: argocd
      labels:
        app.kubernetes.io/part-of: paytech
        environment: '{{env}}'
    spec:
      project: '{{project}}'
      source:
        repoURL: https://gitlab.paytech.ru/infra/k8s-manifests.git
        targetRevision: main
        path: 'services/{{path.basename}}/overlays/{{env}}'
      destination:
        server: '{{cluster}}'
        namespace: '{{path.basename}}'
      syncPolicy:
        syncOptions:
          - CreateNamespace=true
        automated:
          prune: '{{autoSync}}'
          selfHeal: '{{autoSync}}'

Теперь при добавлении нового сервиса достаточно создать директорию services/new-service/ с overlays для каждого окружения — ArgoCD автоматически создаст 3 Application-ресурса (dev, staging, prod).

Для мульти-кластерного управления ArgoCD подключает удалённые кластеры:

# Регистрация кластеров
argocd cluster add dev-cluster --name dev --kubeconfig ~/.kube/dev-config
argocd cluster add staging-cluster --name staging --kubeconfig ~/.kube/staging-config
argocd cluster add prod-cluster --name prod --kubeconfig ~/.kube/prod-config

# Проверка подключённых кластеров
argocd cluster list
# SERVER                                      NAME     STATUS
# https://kubernetes.default.svc               in-cluster  Connected
# https://dev-api.paytech.internal:6443        dev          Connected
# https://staging-api.paytech.internal:6443    staging      Connected
# https://prod-api.paytech.internal:6443       prod         Connected

Нотификации в Telegram и сравнение с Flux

Мы настроили ArgoCD Notifications для отправки событий в Telegram-канал команды:

# argocd-notifications-cm ConfigMap
apiVersion: v1
kind: ConfigMap
metadata:
  name: argocd-notifications-cm
  namespace: argocd
data:
  service.telegram: |
    token: $telegram-token
  
  trigger.on-sync-succeeded: |
    - when: app.status.operationState.phase in ['Succeeded']
      send: [app-sync-succeeded]
  
  trigger.on-sync-failed: |
    - when: app.status.operationState.phase in ['Error', 'Failed']
      send: [app-sync-failed]
  
  trigger.on-health-degraded: |
    - when: app.status.health.status == 'Degraded'
      send: [app-health-degraded]
  
  template.app-sync-succeeded: |
    message: |
      ✅ *{{.app.metadata.name}}*
      Sync succeeded
      Revision: {{.app.status.sync.revision | trunc 7}}
      Environment: {{.app.metadata.labels.environment}}
  
  template.app-sync-failed: |
    message: |
      ❌ *{{.app.metadata.name}}*
      Sync FAILED
      Revision: {{.app.status.sync.revision | trunc 7}}
      Error: {{.app.status.operationState.message}}
  
  template.app-health-degraded: |
    message: |
      ⚠️ *{{.app.metadata.name}}*
      Health: DEGRADED
      Check ArgoCD UI: https://argocd.paytech.internal/applications/{{.app.metadata.name}}

  subscriptions: |
    - recipients:
        - telegram:-1001234567890
      triggers:
        - on-sync-succeeded
        - on-sync-failed
        - on-health-degraded

Сравнение ArgoCD vs Flux — два основных GitOps-инструмента:

КритерийArgoCDFlux
UIПолноценный веб-интерфейс с визуализациейWeave GitOps (отдельный продукт)
Multi-clusterИз коробки, централизованноКаждый кластер — свой Flux
SSO/RBACВстроенные, гибкиеЧерез Kubernetes RBAC
ApplicationSetМощный генератор приложенийKustomization CRD
RollbackОдин клик в UI или CLIGit revert → автосинк
Helm supportНативный, включая valuesЧерез HelmRelease CRD
Ресурсы~500 MB RAM (без HA)~200 MB RAM
ПодходPull-based, UI-ориентированныйPull-based, CLI-ориентированный

Мы выбрали ArgoCD, потому что для финтеха критичны UI для аудита, встроенный RBAC и централизованное управление мульти-кластером. Flux отлично подходит для более простых сценариев, где UI не нужен.

Результаты и выводы

За 6 недель внедрения ArgoCD полностью изменил процесс деплоя в «ПейТех»:

МетрикаДоПосле (ArgoCD)
Аудит деплоевОтсутствуетПолный — Git history + ArgoCD history
Время деплоя15-30 мин (ручной)3 мин (автоматический)
Частота деплоев2-3 раза в неделю5-10 раз в день
Откат20-40 мин (ручной)30 секунд (git revert + sync)
Люди с cluster-admin8 инженеров2 SRE (остальные через ArgoCD RBAC)
Drift detectionОтсутствуетАвтоматический selfHeal

Главный инсайт: GitOps — это не инструмент, а дисциплина. ArgoCD лишь автоматизирует применение изменений из Git. Но если в Git бардак (нет code review, нет branch protection, нет semantic versioning), ArgoCD автоматизирует хаос. Мы потратили первые 2 недели на наведение порядка в Git-репозитории: структура директорий, branch protection rules, merge request templates — и только потом подключили ArgoCD.

Если вашей компании нужен аудитируемый и безопасный деплой в Kubernetes — обращайтесь к нам в itfresh.ru.

Часто задаваемые вопросы

Рекомендуется, но не обязательно. Best practice — отдельный repo (infra/k8s-manifests) со всеми Kubernetes-манифестами, отделённый от кода приложения. Это позволяет менять конфигурацию (replica count, resource limits) без пересборки приложения, разделить доступ (разработчики — к коду, SRE — к инфраструктуре), и избежать бесконечных циклов синхронизации.
ArgoCD отслеживает Git, а не Docker-реестр. Стандартный паттерн: CI собирает образ с тегом, затем обновляет image tag в values.yaml через commit. Для автоматизации используется ArgoCD Image Updater — контроллер, который отслеживает новые теги в registry и автоматически коммитит обновлённый тег в Git. Это сохраняет Git как единственный источник истины.
При включённом selfHeal ArgoCD обнаружит расхождение между Git и кластером (обычно в течение 3 минут) и автоматически вернёт ресурс к состоянию из Git. Ручное изменение будет перезаписано. Это и есть continuous reconciliation — ключевой принцип GitOps. В логах ArgoCD будет запись о том, что произошла автокоррекция.
Да, ArgoCD поддерживает несколько форматов манифестов: plain YAML (kubectl apply), Helm charts, Kustomize, Jsonnet, и кастомные плагины. Можно комбинировать: часть приложений через Helm, часть через Kustomize. ArgoCD автоматически определяет тип по содержимому директории — если есть Chart.yaml, использует Helm; если kustomization.yaml — Kustomize.

Нужна помощь с проектом?

Специалисты АйТи Фреш помогут с архитектурой, DevOps, безопасностью и разработкой — 15+ лет опыта

📞 Связаться с нами
#argocd#gitops#kubernetes#application crd#sync policy#applicationset#rbac#oidc
Комментарии 0

Оставить комментарий

загрузка...