GitOps-пайплайн: тег в git - релиз без SSH на сервер
Выстроили полный цикл: тег запускает CI, образ идёт в registry, бот открывает PR в helm-values, ArgoCD синхронизирует кластер. Никакого ручного доступа к продакшну.
GitOps-пайплайн на ArgoCD + Helm закрепляется как лучшая практика CNCF-сообщества
С января мы поигрались с ArgoCD и посмотрели на Flux. Оба инструмента хороши, но оба решали часть задачи. Вопрос, который оставался открытым: как устроить полный цикл доставки так, чтобы человек не касался продакшн-сервера руками вообще - ни разу, ни при каком сценарии?
В мае мы наконец собрали этот цикл на одном из managed-проектов и он поехал.
Откуда росла боль
До этого деплой выглядел так: разработчик собирает образ в CI, пушит в registry, потом кто-то из команды идёт на сервер, обновляет тег в values.yaml или запускает helm upgrade. Это «кто-то» всегда один и тот же человек, потому что остальные или не знают команды, или не имеют доступа, или просто не хотят ошибиться.
Два очевидных следствия. Первое: узкое место в виде конкретного инженера. Второе: всё что происходит на продакшне, происходит в голове у этого инженера и нигде больше - история деплоев есть только в истории bash. Git не знает что задеплоено. Это именно та ситуация, которую GitOps как подход должен решать.
Как устроен цикл
Результат выглядит вот так:
разработчик пушит тег -> CI собирает образ -> бот открывает PR в helm-values -> ревью -> мерж -> ArgoCD синхронизирует кластер
Разберём по шагам.
Тег как триггер. Разработчик пушит тег вида v1.4.2 в репозиторий приложения. CI (у нас GitLab CI) видит тег, запускает пайплайн сборки. Образ собирается с тем же тегом и пушится в registry. Никаких latest, никаких «ну и так понятно что последнее».
Бот делает PR. После успешного push образа CI вызывает скрипт (обычный Python, ничего хитрого), который клонирует отдельный репозиторий - helm-values. Там хранятся values.yaml для всех окружений. Скрипт обновляет image.tag в нужном файле, коммитит и открывает merge request. PR автоматически назначается на инженера, который отвечает за окружение.
Ревью MR, не деплоя. Инженер смотрит diff - там ровно одна строка: старый тег, новый тег. Апрувит. Мерж.
ArgoCD берёт управление. ArgoCD настроен на репозиторий helm-values и конкретный path для каждого окружения. Видит изменение, запускает синхронизацию. Через минуту в кластере работает новая версия.
Весь цикл от тега до деплоя - примерно 5-7 минут, из которых человеческое время это только апрув MR.
Что важно для такой схемы
Отдельный репозиторий для values - не опция, а необходимость. Если хранить values.yaml в репозитории приложения, то history деплоев смешивается с историей кода, бот коммитит прямо в основной репозиторий, и разграничение доступа теряет смысл. Отдельный helm-values репозиторий - это чистый audit log: кто что когда изменил в конфигурации окружений. Очень удобно когда что-то пошло не так.
ArgoCD смотрит именно на values, а не на чарт. Сам Helm-чарт хранится в третьем месте (реестре чартов или поддиректории). ArgoCD через helm.valueFiles подтягивает values из отдельного репозитория. Это разделение позволяет обновлять чарт и values независимо.
Откат - это git revert. Нужно вернуться на предыдущую версию - открываем helm-values, делаем revert коммита с тегом, мерджим. ArgoCD видит изменение и синхронизирует обратно. Никакого helm rollback с его артефактами в памяти tiller, никакого SSH на сервер.
Где пришлось повозиться
Не обошлось без скучных мест. Бот для создания MR писал сам инженер - готового решения под GitLab, которое делало бы именно это, мы не нашли. Скрипт вышел простым, но его надо поддерживать. Если у вас GitHub - там сейчас в бете GitHub Actions, инструментарий для автоматизации немного шире.
Второй момент: ArgoCD и Helm 2 с Tiller - это комбо с особенностями. ArgoCD сам запускает helm template и применяет манифесты через Kubernetes API, минуя Tiller. Это значит, что Helm-хуки (pre-install, post-upgrade) не срабатывают в контексте ArgoCD. Если у вас есть миграции базы в pre-upgrade хуке - это проблема. Нам пришлось вынести миграции в отдельный Job, который запускается через ArgoCD Sync Waves. Это правильнее архитектурно, но потребовало рефакторинга.
Третий: доступы. Теперь SSH на продакшн не нужен вообще - это и цель, и ограничение. Если что-то сломалось и нужно срочно поправить руками, надо либо коммитить в git, либо иметь отдельный протокол для экстренного доступа. Мы выбрали первое: kubectl доступ есть у двух инженеров через kubeconfig, но это экстренный сценарий, не рабочий.
Где мы сейчас
Схема работает на одном проекте, смотрим. Главное наблюдение пока такое: психологически сдвиг оказался ощутимее технического. Разработчики сначала нервничали - «а вдруг что-то не так задеплоилось?» - но быстро привыкли открывать ArgoCD и видеть там статус синхронизации. Видимость есть, и она в браузере, а не в чьей-то голове.
Инженеры перестали быть «теми кто нажимает кнопку деплоя». Это приятнее чем кажется.
CNCF сейчас активно продвигает GitOps как паттерн - это видно по тому, что подобные инструменты обсуждаются в рамках CNCF-сообщества. Мы идём в том же направлении, что и сообщество, и это само по себе хороший знак: значит инструменты получают поддержку и развиваются, а не висят как orphaned-проекты на энтузиазме пары людей.
- ArgoCD 0.x: GitOps-контроллер для Kubernetes, первое знакомство · 14 января 2019
- Flux v1 (Weaveworks): автосинхронизация Kubernetes с git за 30 секунд · 4 марта 2019