Стратегии деплоя: как мы пришли к использованию Argo CD

Стратегии деплоя: как мы пришли к использованию Argo CD

Тирекс
Тирекс Самый зубастый автор
18 февраля 2025

Обсудим переход от ручного процесса к автоматизации и сравним две модели деплоя: push и pull.

Изображение записи

Привет! Меня зовут Егор Салиев, я DevOps-инженер в провайдере IT-решений Hilbert Team. Сегодня хочу затронуть тему, которая будет интересна инженерам, занимающимся настройкой CI/CD и деплоем. Рассмотрим, как со временем менялась практика развертывания приложений в Kubernetes.

В результате мы дойдем до современного подхода — GitOps с Argo CD. Такой метод помогает компаниям стандартизировать процессы, уменьшить количество ошибок и сбоев, ускорить вывод продукта на рынок, а также сократить расходы на инфраструктуру.

Изображение осминога в скафандре — сивмола Argo CD.

Итак, у нас есть Gitlab, но пока нет GitOps. Это означает, что хотя мы используем Git для управления версиями кода, у нас еще не внедрена система, в которой все изменения в конфигурации инфраструктурой осуществляются через коммиты в репозиторий. Кроме того, потребуется продумать и настроить конвейер CI/CD, который возьмет на себя автоматизацию процессов сборки, тестирования и развертывания.

Доставка приложения в Kubernetes (K8s) — и есть наша текущая основная задача. Существует несколько различных стратегий деплоя в K8s, каждая из которых имеет свои преимущества, недостатки, а также набор используемых инструментов.

Статья создана по мотивам доклада на Selectel Kuber Meetup.

GitLab и Push‑модель 

В push‑модели сборка, тестирование и развертывание приложения в кластер происходит после каждого выполнения команды git push. То есть разработчик, отправляя свой код в репозиторий, запускает цепочку действий, в результате которой обновленное приложение становится доступным для пользователей. Для этого GitLab предлагает несколько встроенных инструментов.

Схематичное изображение работы метода push.
Как работает метод push.

Когда разработчик вносит изменения в своей ветке кода или создает Merge Request (MR) в основной (main), это действие активирует триггер. Запускается заранее определенный пайплайн — последовательность автоматизированных процессов, которые обеспечивают сборку, тестирование и развертывание нового кода.

При этом выполняются различные build-процессы, которые обычно создают образы с помощью Docker или Kaniko. Может контролироваться как корректность работы нового кода, так и его совместимость с существующей системой.

После успешного прохождения всех этапов, новый образ приложения отправляется в реестр, который служит хранилищем для готовых к развертыванию артефактов. Деплой — заключительный этап, который представляет собой процесс размещения нового образа приложения на целевом окружении, таком как production, staging или development.

Рассмотрим некоторые из существующих инструментов деплоя:

  • Kubectl — утилита командной строки для взаимодействия с кластером;
  • Kustomize — средство для настройки оркестратора и управления его ресурсами;
  • Helm — менеджер пакетов для Kubernetes, который позволяет упаковывать, доставлять и обновлять приложения;
  • Helmfile — файл конфигурации, который определяет зависимости, параметры и команды для установки приложений в кластер.

Kubectl

Kubectl — это стандартный и основной инструмент для развертывания приложений в Kubernetes. Кроме того, с его помощью можно выполнять разнообразные операции, такие как масштабирование, обновление, мониторинг и отладка. Для этого необходимо подготовить набор манифестов, которые описывают желаемое состояние приложения в кластере и стандартные сущности K8s: Deployment, Pod, Service, Ingress, ConfigMap, Secret и другие.

Deployment отвечает за развертывание и управление репликами. Pod представляет собой экземпляр запущенного приложения, Service обеспечивает сетевой доступ, Ingress управляет внешним трафиком, ConfigMap и Secret хранят конфигурацию и секретные данные.

Ниже пример, где в корневом каталоге проекта создается файл .gitlab-ci.yml, который определяет этапы пайплайна CI/CD.  В нем описываются задания, которые необходимо выполнить — например, сборка образа Docker, тестирование и развертывание в Kubernetes:


      
.gitlab-ci.yml
deploy-kubectl:   stage: deploy   image: dtzar/helm-kubectl:3.15   before_script:     - kubectl config use-context $GITLAB_AGENT   script:     - kubectl apply -f test-app/   rules:     - if: $CI_COMMIT_BRANCH       when: manual

Команда kubectl apply применяет манифесты к кластеру — все сущности в нем приводятся к состоянию в соответствии с манифестами.

Схема модели деплоя Kubectl.
Модель деплоя Kubectl.

Преимущества

  • универсальность — можно выполнять все основные операции с ресурсами Kubernetes: читать, писать, создавать, удалять, патчить;
  • гибкость — благодаря своей универсальности kubectl можно использовать для сложных скриптов и пайплайнов, включая blue-green и Canary.

Недостатки

  • нужно знать множество параметров выполнения команды и понимать, как создавать манифесты;
  • необходимо вручную указывать все значения для выполнения команды в каждой операции, а также самостоятельно создавать все необходимые ресурсы;
  • одна ошибка приводит к сбою всего процесса.

Kustomize

Kustomize — инструмент управления конфигурациями Kubernetes, который позволяет кастомизировать YAML-манифесты без необходимости использования шаблонов. Он работает, применяя набор патчей и трансформаций к базовому набору конфигураций, которые затем применяются с помощью kubectl.

Основные концепции Kustomize

  • База (base) — директория, содержащая основные YAML-манифесты Kubernetes.
  • Наложение (overlay) — директория с патчами и трансформациями, которые применяются к base.
  • Файл kustomization.yaml — описывает конфигурацию Kustomize и хранит информацию о базе, наложениях, патчах. трансформациях и ресурсах.
  • Патчи (patches) — YAML-файлы, которые описывают слияние.
  • Трансформации (transformations) — изменения, применяемые ко всем ресурсам в базе.
Схема модели деплоя kustomize.
Модель деплоя kustomize.

В примере ниже есть папка base, где хранятся базовые конфигурации для всех сред, и папки overlays, которые содержат специфические настройки для dev, staging,  prod и других сред:


      
.gitlab-ci.yml
deploy-kustomize:   stage: deploy   image: dtzar/helm-kubectl:3.15   before_script:     - kubectl config use-context $GITLAB_AGENT     - cd deploy/base     - kustomize edit set namespace $CI_ENVIRONMENT_NAME-test-app     - kustomize edit set image test-app=$CI_REGISTRY_IMAGE/test-app:$CI_COMMIT_SHORT_SHA     - kustomize build ../overlays/$CI_ENVIRONMENT_NAME > $CI_PROJECT_DIR/kustomized.yaml   script:     - kubectl create ns $CI_ENVIRONMENT_NAME-test-app || true     - kubectl apply -f $CI_PROJECT_DIR/kustomized.yaml   rules:     - if: $CI_COMMIT_BRANCH       when: manual

Для работы с ресурсами в Kustomize используется файл kustomization.yaml, в котором указывается, что именно должно быть изменено и каким образом. 

Преимущества Kustomize

  • Наследование и переопределение позволяют повторно использовать созданные конфигурации, настраивая их для разных сред — development, staging, production — путем наложения патчей и трансформаций.
  • Широкие возможности для настройки ресурсов, что позволяет адаптировать развертывание под конкретные требования проекта.
  • Простой и понятный синтаксис.
  • Конфигурации описываются в декларативном стиле, что делает их более читаемыми.

Однако у этого инструмента есть и недостатки: требуется время, чтобы исследовать его особенности и научиться эффективно использовать.

Helm

Helm — это менеджер пакетов для Kubernetes. Он использует концепцию чартов (charts), содержащих все необходимые ресурсы для развертывания приложения, такие как Deployment, Service, ConfigMap и другие. Helm использует шаблоны на языке Go для генерации манифестов Kubernetes на основе значений, предоставляемых пользователем. Чарты в Helm могут быть с вложенными сабчартами и храниться в любом реестре.

Деплой приложения в K8s с применением Helm-чарта выглядит действительно просто. При выполнении команды helm install Helm берет на себя создание всех необходимых ресурсов Kubernetes, таких как Deployment, Service и ConfigMap.

Схема модели деплоя Helm.
Модель деплоя Helm.

Код в примере ниже описывает задачу для развертывания Helm-чарта:


      
.gitlab-ci.yml
deploy-helm:   stage: deploy   image: dtzar/helm-kubectl:3.15   before_script:     - kubectl config use-context $GITLAB_AGENT   script:     - helm upgrade --install test-app ./chart       -f values.yaml       -n test-app --create-namespace   rules:     - if: $CI_COMMIT_BRANCH       when: manual

В итоге при коммите приложение test-app развернется и обновится, используя чарт из директории ./chart и файл значений values.yaml.

Преимущества

  • Упрощенное развертывание и установка без необходимости вручную создавать и применять множество манифестов.
  • Возможность версионирования и отката.
  • Повторное использование чартов и перенастройка их для различных сред.
  • Управление зависимостями между чартами, что упрощает развертывание многокомпонентных приложений.
  • Большое сообщество и множество готовых чартов для популярных приложений.

Недостатки

  • Сложность создания чартов, особенно для начинающих пользователей — требуется знание шаблонов Go и структуры Kubernetes.
  • Неправильно настроенные чарты могут представлять угрозу безопасности.
  • Хранение секретов в чартах рисковано — лучше использовать Kubernetes Secrets или специальные внешние хранилища.

Helmfile

Helmfile — дополнительный уровень абстракции над Helm для декларативного описания чартов. Его в чем‑то можно сравнить с Docker Compose. С помощью Helmfile можно легко управлять несколькими чартами и их зависимостями.

Схема модели деплоя helmfile.
Модель деплоя helmfile.

В примере ниже задача синхронизирует релизы Helm, определенные в helmfile.yaml:


      
.gitlab-ci.yml
deploy-helmfile:   stage: deploy   image: $CI_REGISTRY/tools/helmfile   before_script:     - kubectl config use-context $GITLAB_AGENT   script:     - helmfile --namespace $ENVIRONMENT_NAMESPACE sync   rules:     - if: $CI_COMMIT_BRANCH       when: manual

Преимущества

  • Упрощение управления несколькими Helm-чартами и их зависимостями.
  • Декларативный подход — описание желаемого состояния системы в виде кода.
  • Поддержка шаблонизации, что позволяет использовать переменные и условные конструкции для настройки конфигурации чартов в зависимости от окружения или других факторов.

Сравнение

Ниже сравнительная таблица по всем описанным инструментам: 

Таблица сравнения различных моделей деплоя.

Pull-модель, GitOps и Argo CD.

Предпосылки к использованию нового подхода

Когда мы разворачиваем приложения в Kubernetes, используя push-модель, то конфигурация ресурсов хранится в etcd — встроенной в K8s базе данных. Такой подход имеет свои нюансы — возникает проблема конфигурационного дрейфа (configuration drifting):

  1. Kubernetes постоянно сравнивает желаемое состояние, которое содержится в etcd, с текущим состоянием кластера и вносит необходимые изменения, что обеспечивает самовосстановление и масштабируемость.
  2. Если кто-то вручную модифицирует ресурс в кластере, то это может привести к неожиданным последствиям: Kubernetes будет поддерживать новое состояние, даже если оно не соответствует желаемой конфигурации.
  3. Удаление ресурса из кластера приведет к его потере, а для восстановления потребуется повторное развертывание. 

Решить эту проблему можно с помощью GitOps и Argo CD.

Схема pull-модели.
Pull-модель.

Чаще всего под GitOps понимают именно Pull‑модель взаимодействия с Git. Так же, как и в Push‑модели, информация о кластере расположена в Git-репозитории. Отличие в том, что внесение изменений в кластер происходит не по срабатыванию триггера на команду git push. Напротив — внешний агент следит за изменениями в репозитории, постоянно сравнивает данные в нем с состоянием Kubernetes и при необходимости меняет конфигурацию. Агент чаще всего расположен в том же кластере, где происходит развертывание.

Использование такого подхода позволяет избежать некоторых проблем. Например, если пользователь напрямую внесет изменения в кластер, внешний агент увидит это и вернет кластер в состояние, прописанное в Git. Подобная строгость мотивирует пользователей вместо прямого воздействия на кластер делать правки в единственном допустимом источнике истины — в репозитории.

Argo CD

Argo CD — декларативный GitOps-ориентированный популярный инструмент непрерывной доставки для Kubernetes.

Основные компоненты Argo CD

  • API Server — обеспечивает синхронизацию и аутентификацию пользователей, разграничивает права доступа, предоставляет API для взаимодействия с Argo CD.
  • Application Controller — основной компонент, отвечающий за синхронизацию состояния кластера с Git-репозиторием.
  • Repository Server — хранит кеш GitOps-репозитория, values Helm-чартов, текущую ревизию репозитория (commit, tag), а также содержит инструменты для обработки манифестов (Helm, Kustomize) — например, для рендеринга Helm-чартов и деплоя Argo CD использует Helm template.

Argo CD управляет не непосредственно манифестами и Helm-чартами, а Applications — абстракциями более высокого уровня, которые описывают желаемое состояние Kubernetes-ресурсов в Git-репозитории. Application может ссылаться на различные источники, такие как Helm-чарты, Kustomize-файлы, Jsonnet-манифесты или обычные Kubernetes-манифесты. Это позволяет выбирать подходящие инструменты для описания инфраструктуры, сохраняя единый механизм управления.

В примере ниже в локальном кластере создается приложение test-app и настраивается автоматическое отслеживание Git‑репозитория:


    apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
 name: test-app
 namespace: Argo CD
spec:
 source:
   path: test-app
   repoURL: https://gitlab.example.ru/gitops/prod-cluster.git
   targetRevision: HEAD
 destination:
   namespace: test-app
   server: https://kubernetes.default.svc
 project: prod

Если приложение одно, то его несложно создавать вручную. Другое дело, когда количество сервисов и, соответственно, приложений, увеличивается, такой подход становится неэффективным и трудоемким. Argo CD предлагает решение этой проблемы — ApplicationSet, который позволяет динамически создавать приложения по определенным правилам (generators).


    apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
  name: tenants
  namespace: Argo CD
spec:
  generators:
  - git:
      repoURL: https://gitlab.example.ru/gitops/prod-cluster.git
      revision: HEAD
      directories:
      - path: tenants/*

Манифест выше создает ApplicationSet, который автоматически генерирует несколько приложений на основе структуры каталогов в Git. В этом примере git generator следит за изменениями в репозитории. Если в tenants появится новый каталог с конфигурацией (Helm-чарт или манифест), то Argo CD автоматически развернет приложение.

Argo CD оперирует двумя основными сущностями: приложениями (Applications) и проектами (Projects). Они играют ключевую роль в управлении конфигурацией, так как могут быть организованы для работы в разных средах (например, dev, staging, prod) и кластерах. Важно: именно ими управляет Argo CD, а не манифестами или чартами.

Приложение — это набор ресурсов Kubernetes и основная единица управления. Оно определяет источник манифестов, целевой кластер и синхронизацию между желаемым и фактическим состоянием кластера. Проекты позволяют организовывать приложения в логические группы для управления доступом (ограничение пользователей и групп), источниками и целями (манифесты и кластеры), а также применением общих политик (синхронизация, обновление).

Argo CD имеет удобный и понятный интерфейс для работы. Можно посмотреть текущее состояние синхронизации приложений, сравнить настоящую и прошлую ревизии (diff), изучить логи.

Изображение интерфейса.
Интерфейс Argo CD.

Унификация деплоя

В условиях современной разработки, где проекты могут быть сложными и разнообразными, а инфраструктура постоянно меняется, возникает необходимость в унификации процессов. Представьте, что нужно развернуть проект, который не обновлялся несколько лет, или перенести его в другой кластер, при этом не нарушив уникальный процесс развертывания. Еще частый источник путаницы и затрудненного управления — использование в каждом проекте собственного пайплайна.

В таких ситуациях выручает GitOps, который унифицирует процессы для всех проектов, независимо от особенностей сборки. Вместо настройки сложных пайплайнов используется простой и элегантный способ: достаточно доставить новый тег Docker-образа в GitOps-репозиторий — и приложение автоматически разворачивается в кластере.

В следующем примере клонируется репозиторий. Поле app.image_tag в файле values.yaml получает новое значение на основе короткой SHA‑суммы текущего коммита. В завершении изменения фиксируются в репозитории, а новый коммит получает информативное описание:


    .deploy_template:
  stage: deploy
  image: $CI_REGISTRY/tools/yq:1.0.0
  script:
    - git clone "https://$USER:$TOKEN@$GITOPS_REPO_URL" gitops
    - cd gitops
    - yq -i ".app.image.tag = strenv(CI_COMMIT_SHORT_SHA)" ${GITOPS_CATALOG}/${GITOPS_NAME}/values.yaml
    - git config --global user.email "deploy@example.ru"
    - git config --global user.name "GitLab CI"
    - git commit -am "CI Deploy ${CI_PROJECT_NAME} - ${CI_COMMIT_SHORT_SHA}"
    - git push

Значение нового тега вставляется в values нашего Helm-чарта, после чего Argo CD синхронизирует изменения в репозитории, и ресурсы в Kubernetes обновляются.

Наш путь

Итак, подытожим, обобщив подход для управления инфраструктурой и развертывания приложений.

Мы сознательно отказались от использования монорепозитория. Вместо этого репозитории разделены. В одном хранится исключительно исходный код приложения, в другом — только конфигурационные файлы, описывающие желаемое состояние инфраструктуры.

Для управления множественными зависимостями мы используем Umbrella-чарты, которые хранятся в GitLab Package Registry.

Схема деплоя Argo CD.
Модель деплоя Argo CD.

Преимущества  Argo CD

  • Удобный веб-интерфейс.
  • Непрерывная синхронизация приложений, поддержание целостности сущностей в кластере и их работоспособности.
  • Единый источник верной конфигурации, что исключает configuration drift.
  • Быстрое масштабирование и перенос приложений между кластерами — например, можно добавить проект с инфраструктурными сервисами, которые будут разворачиваться сразу во все кластеры.

Все недостатки связаны с необходимостью выделять время на настройку, оптимизацию пайплайнов, а также создание универсальных чатов в нашем случае.

Заключение

Внедрение GitOps-подхода и использование Argo CD позволили нам унифицировать пайплайны. Это значительно сократило время, затрачиваемое на поддержку и обновление наших проектов.

Мы успешно решили проблему configuration drifting, которая часто возникала при использовании традиционных методов развертывания. Конфигурация наших приложений всегда соответствует желаемому состоянию, описанному в репозитории. Новая архитектура и использование Kubernetes обеспечивают возможность масштабировать наши приложения на любое количество кластеров.

Argo CD — мощное средство. Однако его эффективное использование требует глубокого понимания особенностей управления Kubernetes. Здесь оказывается полезным Managed Kubernetes — специальный сервис, предоставляемый Selectel. Он снимает с разработчиков бремя управления инфраструктурой и позволяет сосредоточиться на реализации и развертывании приложений. Автомасштабирование, автовосстановление, обновление, мониторинг и обеспечение безопасности кластера в соответствии со 152‑ФЗ — все эти заботы берет на себя облачная платформа.

Сочетание Argo CD и Managed Kubernetes максимально упрощает и автоматизирует весь цикл жизни приложения от разработки до эксплуатации, что снижает операционные расходы. Подробнее о функциональности сервиса и его особенностях можно прочитать в онлайн‑документации Selectel.

Подписывайтесь на каналы Hilbert Team и Selectel, чтобы не пропустить выход новых материалов.