[Git, DevOps, Kubernetes] HelmWave v0.5.0 – GitOps для твоего Kubernetes

Автор Сообщение
news_bot ®

Стаж: 6 лет 7 месяцев
Сообщений: 27286

Создавать темы news_bot ® написал(а)
15-Дек-2020 01:31


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 с любыми вопросами!
===========
Источник:
habr.com
===========

Похожие новости: Теги для поиска: #_git, #_devops, #_kubernetes, #_devops, #_gitops, #_helm, #_kubernetes, #_git, #_devops, #_kubernetes
Профиль  ЛС 
Показать сообщения:     

Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете голосовать в опросах
Вы не можете прикреплять файлы к сообщениям
Вы не можете скачивать файлы

Текущее время: 06-Окт 02:55
Часовой пояс: UTC + 5