HelmWave v0.5.0 – GitOps для твоего Kubernetes

от автора

preview

Helm, как и Docker стал де-факто стандартом в индустрии. Когда мы обсуждаем Kubernetes (52%). И новость, что Docker is deprecated вызвало волну обсуждений в сообществе. Настолько все привыкли к Docker.

Для Docker есть замечательный по своей простоте docker-compose, в котором мы можем декларативно описать, что мы хотим от Docker.

Для Kubernetes набор yaml-tpl файлов упаковывается в архив. И затем этот архив называется Helm-чартом. Но как это часто бывает приложение не может быть описано лишь одним Helm чартом. Требуется как-то управлять/композить/настраивать/шаблонизировать такие сеты.

Одним из подходов по управлению является Umbrella Chart. Это helm chart который объединяет в себе все другие чарты.

Очевидные минусы данного решения:

  • Требуется поддерживать дополнительный чарт
  • Новый слой согласования имен values переменных.
  • Umbrella-chart это все тот же чарт, поэтому о шаблонизации values и декларативном разделении на контуры (Окружения) не может быть и речи.
  • Когда обновляется саб-чарт, нужно идти в umbrella и обновлять еще версию umbrella чарта.

Helmwave возник, как инструмент для декларативного описания всех чартов в одном yaml.
Этот пост покажет как можно решить основные проблемы (use-cases) с помощью helmwave.

Что такое HelmWave?

  • Это бинарь, который устанавливает helm release из helmwave.yml.
  • Кладешь helmwave.yml в git и применяешь его через CI.
  • Можно шаблонизировать все c помощью (Go template), начиная от helmwave.yml до values.
  • Helmwave понимает какие helm-repositories ему понадобятся для деплоя. И вытесняет лишние.

Порядок комманд

graph TD;     Start(helmwave.yml.tpl) --render--> helmwave.yml;     helmwave.yml --planfile--> .helmwave;     .helmwave --sync--> Finish(Releases have been deployed!)

Быстрый старт

helmwave.yml.tpl имеет следующий вид

project: my-project version: 0.5.0  repositories:   - name: bitnami     url: https://charts.bitnami.com/bitnami  .options: &options   install: true   namespace: my-namespace  releases:   - name: redis-a     chart: bitnami/redis     options:       <<: *options    - name: redis-b     chart: bitnami/redis     options:       <<: *options

$ helmwave deploy

Поздравляю, вы задеплоили с помощью helmwave!

$ helm list -n my-namespace NAME       NAMESPACE       REVISION     STATUS      CHART             APP VERSION redis-a    my-namespace    1            deployed    redis-11.2.3      6.0.9       redis-b    my-namespace    1            deployed    redis-11.2.3      6.0.9    $ k get po -n my-namespace                                                                                                                          NAME               READY   STATUS    RESTARTS   AGE redis-a-master-0   1/1     Running   0          64s redis-a-slave-0    1/1     Running   0          31s redis-a-slave-1    1/1     Running   0          62s redis-b-master-0   1/1     Running   0          59s redis-b-slave-0    1/1     Running   0          32s redis-b-slave-1    1/1     Running   0          51s

Переменные окружения

$ helmwave help

  • $HELMWAVE_TPL_FILE – отвечает за путь к входному файлу для шаблонизации (helmwave.yml.tpl).
  • $HELMWAVE_FILE – указывает путь выходного файла после операции шаблонизации (helmwave.yml).
  • $HELMWAVE_PLAN_DIR – указывает путь к папке, в которой хранится или будет хранится план (.helmwave/).
  • $HELMWAVE_TAGS – массив строк, на основании которого будет проводится планирование.
  • $HELMWAVE_PARALLEL – включает/выключает многопоточность (рекомендуется включать).
  • $HELMWAVE_LOG_FORMAT – позволяет выбрать один из предустановленных форматов вывода.
  • $HELMWAVE_LOG_LEVEL – позволяет управлять детализацией вывода.
  • $HELMWAVE_LOG_COLOR – включает/выключает цвета для вывода.

Use-Cases

Примеры будут производиться, опираясь на gitlab-ci. Но это не помешает вам встроить helmwave в любой другой CI-инструмент.

Чем ниже, тем сложнее будут примеры.

Git tag –> Docker tag

Допустим вы написали какой-то helm чарт для нашего приложения. Его values.yaml по умолчанию имеет вид:

image:   repository: registry.gitlab.local/example/app   tag: master

Необходимо чтобы image.tag брался из переменной CI

Приступим, создадим 2 файла.

. ├── helmwave.yml.tpl └── values.yml

helmwave.yml.tpl

project: my-project # Имя проекта version: 0.5.0 # Версия helmwave  releases:   - name: my-release     chart: my-chart-repo/my-app     values:       - values.yml     options:       install: true       namespace: my-namespace

values.yml

image:   tag: {{ env "CI_COMMIT_TAG" }}

Git commit —> PodAnnotations

Требуется чтобы deployment обновлялся только если у нас есть новый коммит.

deployment имеет примерно этот вид:

    ...     metadata:         {{- with .Values.podAnnotations }}         annotations:           {{- toYaml . | nindent 8 }}         {{- end }}     ...

Поэтому мы можем легко расширить предыдущий пример values.yml

image:   tag: {{ requiredEnv "CI_COMMIT_TAG" }}  podAnnotations:     gitCommit: {{ requiredEnv "CI_COMMIT_SHORT_SHA" | quote }}

Контуры, окружения, environments

Структура каталога

. ├── helmwave.yml.tpl └── values     ├── _.yml     ├── prod.yml     └── stage.yml

helmwave.yml.tpl

project: my-project   version: 0.5.0    releases:     - name: my-release       chart: my-chart-repo/my-app       values:         # Default         - values/_.yml         # For specific ENVIRONMENT         - values/{{ env "CI_ENVIRONMENT_NAME" }}.yml       options:         install: true         namespace: {{ env "CI_ENVIRONMENT_NAME" }}

values/_.yml – Будет запускаться для любого окружения

image:   tag: {{ requiredEnv "CI_COMMIT_TAG" }}  podAnnotations:     gitCommit: {{ requiredEnv "CI_COMMIT_SHORT_SHA" | quote }}

values/prod.yml – Будет запускаться только для prod

replicaCount: 6

values/stage.yml – Будет запускаться только для stage

replicaCount: 2

Используем внешний yaml и .Release.Store

Store это просто хранилище, которое можно задавать в helmwave.yml и передавать дальше в шаблонизацию values.

Допустим мы хотим связать путь к секрету в vault и путь к проекту в gitlab или вы хотите переопределять путь к image.repository. Это можно удобно сделать через Store.

. ├── helmwave.yml.tpl ├── values │   └── _.yml └── vars     └── my-list.yaml 

values/_.yml

vault: secret/{{ .Release.Store.path  }}/{{ requiredEnv "CI_ENVIRONMENT_NAME"  }}  image:   repository: {{ env "CI_REGISTRY" | default "localhost:5000" }}/{{ .Release.Store.path }}

Добавим произвольный yaml файл.

vars/my-list.yaml

releases:   - name: adm-api     path: main/product/adm/api   - name: api     path: main/product/api

helmwave.yml.tpl

project: my-project version: 0.5.0  .options: &options   install: true   wait: true   timeout: 5m  releases:   {{- with readFile "vars/my-list.yaml" | fromYaml | get "releases" }}   {{- range $v := . }}   - name: {{ $v | get "name" }}     chart: my-project/{{ $v | get "name" }}     options:       <<: *options     store:       path: {{ $v | get "path" }} # Set .Release.Store.path     tags:       - {{ $v | get "name" }}       - my     values:         # Default         - values/_.yml         # For specific ENVIRONMENT         - values/{{ env "CI_ENVIRONMENT_NAME" }}.yml   {{ end }}   {{- end }} 

Запускаем!

$ CI_ENVIRONMENT_NAME=stage helmwave planfile

Появится helmwave.yml и папка .helmwave

$ tree .helmwave .helmwave ├── planfile └── values     ├── _.yml.adm-api@.plan     └── _.yml.api@.plan  $ cat .helmwave/values/_.yml.api@.plan                             vault: secret/main/product/api/stage                                                                 image:   repository: localhost:5000/main/product/api  $ cat .helmwave/values/_.yml.adm-api@.plan                                   vault: secret/main/product/adm/api/stage  image:   repository: localhost:5000/main/product/adm/api 

helmwave.yml

project: my-project version: 0.5.0  .options: &options   install: true   wait: true   timeout: 5m  releases:   - name: adm-api     chart: my/adm-api     options:       <<: *options     store:       path: main/product/adm/api     tags:       - adm-api       - my     values:         # Default         - values/_.yml         # For specific ENVIRONMENT         - values/stage.yml    - name: api     chart: my/api     options:       <<: *options     store:       path: main/product/api     tags:       - api       - my     values:         # Default         - values/_.yml         # For specific ENVIRONMENT         - values/stage.yml 

Отделяем продукты от инфраструктуры

Структура проекта

Создадим в папке values 2 папки

  • product – здесь будут values для продуктов
  • infrastructure – здесь будет инфарструктурные values

values/infrastructure

  • adminer – веб морда для подключения к базе, полезна в основном только в dev-контурах
  • postgresql – база данных
  • ns-ready – здесь LimitRange, ResourcseQuota, Secrets, NetworkPolicy, etc
  • rabbitmq – общая шина между chat и api

values/product
Приложение состоит из 3 микросервисов

  • api
  • chat
  • frontend

И еще нам понадобятся 2 отдельных файла описывающие массив product и массив infrastructure.

Структура проекта:

. ├── helmwave.yml.tpl ├── values │   ├── infrastructure │   │   ├── adminer │   │   │   ├── _.yml │   │   │   ├── dev.yml │   │   │   └── stage.yml │   │   ├── ns-ready │   │   │   └── _.yml │   │   ├── postgresql │   │   │   ├── _.yml │   │   │   └── dev.yml │   │   └── rabbitmq │   │       ├── _.yml │   │       ├── dev.yml │   │       └── stage.yml │   └── product │       ├── _ │       │   ├── _.yml │       │   ├── dev.yml │       │   ├── prod.yml │       │   └── stage.yml │       ├── api │       │   ├── _.yml │       │   ├── dev.yml │       │   ├── prod.yml │       │   └── stage.yml │       ├── chat │       │   └── _.yml │       └── frontend │           ├── _.yml │           ├── dev.yml │           ├── prod.yml │           └── stage.yml └── vars     ├── infrastructure.yaml     └── products.yaml 

vars/infrastructure.yaml

 releases:   - name: postgresql     repo: bitnami     version: 8.6.13    - name: adminer     repo: cetic     version: 0.1.5    - name: rabbitmq     repo: bitnami     version: 7.6.6    - name: ns-ready     repo: my-project     version: 0.1.1

vars/products.yaml

releases:   - name: adm-api     path: rdw/sbs/adm/api   - name: frontend     path: my-project/internal/frontend   - name: api     path: my-project/internal/api   - name: chat     path: my-project/internal/chat 

helmwave.yml.tpl

project: my-project version: 0.5.0  repositories:   - name: bitnami     url: https://charts.bitnami.com/bitnami   - name: cetic     url: https://cetic.github.io/helm-charts  .options: &options   install: true   wait: true   timeout: 5m   atomic: false   maxhistory: 10   namespace: {{ requiredEnv "HELM_NS" }}  releases:   {{- with readFile "vars/products.yaml" | fromYaml | get "releases" }}   {{- range $v := . }}   - name: {{ $v | get "name" }}     chart: my-project/{{ $v | get "name" }}     options:       <<: *options     store:       path: {{ $v | get "path" }}     tags:       - {{ $v | get "name" }}       - product     values:       # all products & all envs       - values/product/_/_.yml       # all products & an env       - values/product/_/{{ requiredEnv "CI_ENVIRONMENT" }}.yml       # a product & all envs       - values/product/{{ $v | get "name" }}/_.yml       # a product & an env       - values/product/{{ $v | get "name" }}/{{ requiredEnv "CI_ENVIRONMENT" }}.yml   {{ end }}   {{- end }}    {{- with readFile "vars/infrastructure.yaml" | fromYaml | get "releases" }}   {{- range $v := . }}   - name: {{ $v | get "name" }}     chart: {{ $v | get "repo" }}/{{ $v | get "name" }}     options:       <<: *options       chartpathoptions:         version: {{ $v | get "version" }}     tags:       - {{ $v | get "name" }}       - infrastructure     values:       # a svc & all envs       - values/infrastructure/{{ $v | get "name" }}/_.yml       # a svc & an env       - values/infrastructure/{{ $v | get "name" }}/{{ requiredEnv "CI_ENVIRONMENT" }}.yml   {{ end }}   {{- end }} 

Контуры в Store

Допустим у нас есть 2 окружения dev и prod.
И в prod’e нам не нужна база данных

vars/infrastructure.yaml

releases:   - name: rabbitmq     repo: stable     version: 6.18.2     envs:       - _ # all environments     tags:       - queue    - name: postgresql     repo: bitnami     version: 8.6.13     envs:       - dev # only dev     tags:       - db

# vim: set filetype=yaml: {{- $env := requiredEnv "CI_ENVIRONMENT" }} # Look at this first  project: insider version: 0.5.0  repositories:   - name: stable     url: https://kubernetes-charts.storage.googleapis.com   - name: bitnami     url: https://charts.bitnami.com/bitnami  .options: &options   install: true   wait: true   force: false   timeout: 5m   atomic: false   maxhistory: 10   namespace: {{ requiredEnv "HELM_NS" }}  releases:   {{- with readFile "vars/infrastructure.yaml" | fromYaml | get "releases" }}   {{- range $v := . }}   {{- $envs := $v | get "envs" }}   {{- if or (has "_" $envs) (has $env $envs) }}   - name: {{ $v | get "name" }}     chart: {{ $v | get "repo" }}/{{ $v | get "name" }}     options:       <<: *options       chartpathoptions:         version: {{ $v | get "version" }}     tags:       - {{ $v | get "name" }}       - infrastructure       {{- if $v | hasKey "tags" }}       - {{ $v | get "tags" | toYaml }}       {{- end }}     values:       # a svc & all envs       - values/infrastructure/{{ $v | get "name" }}/_.yml       # a svc & an env       - values/infrastructure/{{ $v | get "name" }}/{{ $env }}.yml   {{ end }}   {{- end }}   {{- end }} 

База по умолчанию выключена

$ helmwave planfile

Чтобы postgresql включился

$ CI_ENVIRONMENT=dev helmwave planfile

Giltab-CI Pipelines

Рассмотрим шаблон gitlab-ci с использованием helmwave из проекта g-ci

variables:   HELMWAVE_LOG_LEVEL: debug  .helmwave-deploy:   stage: deploy   environment:     name: ref/$CI_COMMIT_REF_SLUG   image:     name: diamon/helmwave:0.5.0     entrypoint: [""]   script:     - helmwave deploy  helmwave deploy:   extends: .helmwave-deploy

С использованием include

include: https://gitlab.com/g-ci/deploy/-/raw/master/helmwave.yml  helmwave deploy:   environment:     name: prod

P.S.

Helmwave source: https://github.com/zhilyaev/helmwave/
G-CI: https://gitlab.com/g-ci
Приходите к нам в telegram с любыми вопросами!

ссылка на оригинал статьи https://habr.com/ru/post/532596/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *