Прежде чем перейти к статье, хочу вам представить, экономическую онлайн игру Brave Knights, в которой вы можете играть и зарабатывать. Регистируйтесь, играйте и зарабатывайте!
Для деплоя приложений в Kubernetes существует огромное количество различных инструментов. Если посмотреть на соответствующий раздел в CNCF Landscape, то можно потеряться в разнообразии. Поэтому иногда хорошо иметь в своем арсенале «серебряную пулю», которая подойдет для большинства задач. Helmwave вполне может стать именно таким инструментом.
В последнее время моим самым любимым инструментом для описания декларативных деплоев в Kubernetes был Helmfile. Три неочевидные, но полезные возможности Helmfile я рассмотрела в отдельной статье на Medium: “3 Helmfile features you don’t know”.
Фичи Helmfile, которые важно отметить:
Встроенная возможность шаблонизации.
Окружения с возможностью указать дефолтную конфигурацию.
Интеграция с HashiCorp Vault, AWS KMS и другими инструментами для работы с секретами.
Поддержка плагина helm diff.
Несмотря на то что GitOps и инструменты, которые реализуют этот подход, сейчас на пике популярности, к ним есть много вопросов с точки зрения надежности, управляемости и наблюдаемости. Поэтому я всегда слежу за новыми проектами: они могут оказаться проще в использовании или лучше справляться с решением конкретных проблем. Так я и нашла Helmwave.
Что такое Helmwave
Readme проекта на Github довольно емко и кратко описывает основную задачу проекта:
Helmwave — это docker-compose для @helm.
Helmwave — это инструмент для декларативного описания деплоя helm-чартов.
Давайте разберемся, чем он лучше или хуже конкурентов.
Особенности Helmwave
В Helmwave есть все необходимые стандартные фичи: everything-as-code, деплой в несколько окружений и возможность настройки дефолтной конфигурации.
Но есть и несколько неочевидных:
Пошаговый деплой (depends_on, allow_failure).
Отслеживание ресурсов Kubernetes в реальном времени при помощи kubedog.
Отсутствие внешних зависимостей: достаточно скачать бинарный файл helmwave и можно начинать деплой.
Пример использования Helmwave
Для примера я попробую решить стандартную задачу: настроить деплой в несколько окружений из одного репозитория с возможностью оверрайда конфигурации.
Для начала рассмотрим структуру проекта:
.
├── .github/
├── .kube-linter/
│ └── config.yaml
├── README.md
├── charts/
│ ├── adservice
│ ...
│ └── shippingservice
├── envs-values/
│ ├── prod
│ └── stage
├── helmwave.yml
├── helmwave.yml.tpl
└── releases.yaml
В директории .github/ находится конфигурация для CI/CD, в моем случае это Github Actions.
В .kube-linter/ — файл конфигурации для линтинга манифестов.
В charts/ — helm-чарты для microservices-demo.
В envs-values/ хранятся значения для сред stage и production.
helmwave.yml — это файл, который рендерится из шаблона (helmwave.yml.tpl).
helmwave.yml.tpl — это шаблон конфигурации деплоя.
releases.yaml — файл со списком нужных helm-релизов и их конфигураций для деплоя.
helmwave.yml.tpl
В начале этого файла прописана версия Helmwave. Последняя версия — 0.19.5.
version: 0.19.5
.options: &options
namespace: microservices-demo
wait: true
timeout: 300s
create_namespace: true
releases:
{{- with readFile "releases.yaml" | fromYaml | get "releases" }}
{{ range $v := . }}
- name: {{ $v | get "name" }}
chart:
name: charts/{{ $v | get "name" }}
tags: [{{ $v | get "name" }}]
values:
- envs-values/{{ requiredEnv "CI_ENVIRONMENT_NAME"}}/{{ $v | get "name" }}.yaml
<<: *options
{{ end }}
{{- end }}
В этом файле мы можем использовать якорь с параметрами по умолчанию (.options) и указать его в разделе releases, когда это необходимо. Таким образом мы получим максимально DRY-конфиг. Обычно в этом месте задается ряд значений по умолчанию: namespace, helm options и т.д. Полный список параметров ищите в документации.
В разделе releases задается список релизов helm, которые нужно задеплоить. Этот список можно найти в файле releases.yaml
. Каждому релизу нужно задать имя и чарт, из которого должен осуществляться деплой. Другие параметры опциональны.
Каждый релиз также содержит:
Переменные для нужного окружения, окружение задается переменной CI_ENVIRONMENT_NAME.
Тег с названием приложения, который можно использовать для фильтрации деплоя конкретных сервисов.
Параметры из якоря, добавляемые через
<< : *options
.
releases.yaml
Структура releases.yaml не требует дополнительных пояснений:
releases:
- name: adservice
- name: cartservice
...
- name: shippingservice
helmwave.yml
В этом файле будет находится отрендеренный шаблон helmwave.yml.tpl
. Чтобы его сгенерировать, можно выполнить следующую команду:
$ CI_ENVIRONMENT_NAME=stage helmwave yml
version: 0.19.5
.options: &options
namespace: microservices-demo
wait: true
timeout: 300s
create_namespace: true
releases:
- name: adservice
chart:
name: charts/adservice
tags: [adservice]
values:
- envs-values/stage/adservice.yaml
<<: *options
...
- name: shippingservice
chart:
name: charts/shippingservice
tags: [shippingservice]
values:
- envs-values/stage/shippingservice.yaml
<<: *options
Процесс деплоя
Для реализации CI/CD я выбрала GitHub Actions, потому что они бесплатно доступны в GitHub. Более того, разработчики Helmwave сделали для них action, который помогает быстро и удобно использовать различные версии Helmwave в пайплайнах.
Процесс деплоя состоит из трех шагов: подготовка, запуск тестов и запуск деплоя в выбранном окружении.
Подготовка
На этапе подготовки устанавливаем необходимые инструменты — Helmwave и kind, который создаст Kubernetes кластер с помощью контейнеров. Далее в зависимости от значения CI_ENVIRONMENT_NAME подготавливаем план изменений с помощью helmwave
.
Чтобы определить окружение, можно написать bash-скрипт или использовать возможности выбранной CI/CD платформы.
Пример для Github Actions:
- name: Set environment for branch
run: |
if [[ $GITHUB_REF == 'refs/heads/main' ]]; then
echo "CI_ENVIRONMENT_NAME=prod" >> "$GITHUB_ENV"
else
echo "CI_ENVIRONMENT_NAME=stage" >> "$GITHUB_ENV"
fi
Для тестирования и деплоя нам необходимо отрендерить helm-charts в готовые Kubernetes манифесты. Для этого нужно выполнить одну из следующих команд:
# если вы уже запускали helmwave yml
helmwave build
# сгенерировать helmwave.yml и все манифесты сразу
helmwave build --yml
Эти команды создают директорию .helmwave, где содержатся необходимые манифесты и план.
Тестирование
Для тестирования я использую самые популярные инструменты:
kube-linter
kubeval
pluto
Они похожи, но каждый имеет свои особенности реализации и тестируемые кейсы, поэтому я решила использовать все три в одном пайплайне.
На этом этапе можно использовать ту же команду, что и для генерации плана. Но если деплой выполняется во временной среде (как в моем случае), нужно задать дополнительный параметр diff-mode=local
, который будет рендерить diff изменений локально, не отправляя запросы в кластер Kubernetes. Такой вариант также подходит для использования в CI.
helmwave build --yml --diff-mode=local
Чтобы развернуть приложение, выполните следующую команду:
helmwave up
# если хотите увидеть ход процесса деплоя
helmwave up --kubedog
# или все сразу
helmwave up --yml --build --kubedog
Очистка
Чтобы удалить все созданные ресурсы, нужно выполнить одну из следующих команд:
helmwave down
# или удалить namespace в Kubernetes
kubectl delete microservices-demo
Helmwave — это полноценная альтернатива helmfile
и другим похожим инструментам. Несмотря на то что проект достаточно молодой, у него есть полезные и неочевидные функции, и я с интересом буду смотреть за его развитием.
От себя могу рекомендовать использовать его в ситуации, когда вам нужно быстро настроить деплой приложения и иметь возможность наблюдать за процессом деплоя в режиме реального времени. Также helmwave хорошо подойдет для CI и тестовых окружений из-за полноценной поддержки шаблонизации, возможности получать логи приложения при его непосредственном деплое и смотреть diff между тем, что уже есть в кластере, и планируемыми изменениями.
Полезные ссылки
Репозиторий со всем кодом и конфигурацией
Документация Helmwave
Helmwave на Github