— обвивка для , която позволява в едно място да описвате множество helm релизи, да параметризирайте техните чарти за няколко среди и също да зададете реда на тяхната деплойка.
За самото helmfile и примери за неговото използване можете да прочетете в и .
Ние ще разгледаме неочевидни начини да опишем релизите в helmfile
Да предположим, че имаме пакет helm-чартове (например postgres и едно backend приложение) и няколко среди (няколко Kubernetes клъстера, няколко namespace'а или и двете). Вземаме helmfile, четем документацията и започваме да описваме нашите среди и релизи:
.
├── envs
│ ├── devel
│ │ └── values
│ │ ├── backend.yaml
│ │ └── postgres.yaml
│ └── production
│ └── values
│ ├── backend.yaml
│ └── postgres.yaml
└── helmfile.yamlhelmfile.yaml
среди:
devel:
production:
релизи:
- име: postgres
етикети:
app: postgres
изчакай: true
chart: stable/postgresql
версия: 8.4.0
values:
- envs/{{ .Environment.Name }}/values/postgres.yaml
- име: backend
етикети:
app: backend
изчакай: true
chart: private-helm-repo/backend
версия: 1.0.5
нуждае се:
- postgres
values:
- envs/{{ .Environment.Name }}/values/backend.yamlПолучихме 2 среди: devel, производството — в тях се намират свої стойности за helm чартовете на релизите. Ние ще деплойваме в тях по следния начин:
helmfile -n -e applyРазлични версии на helm чартовете в различни среди
Какво да правим, ако трябва да разпространяваме различни версии на бекенда в различни среди? Как да параметризираме версията на релиза? На помощ идват стойностите на средата, достъпни чрез {{ .Values }}
helmfile.yaml
среди:
devel:
+ values:
+ - charts:
+ versions:
+ backend: 1.1.0
production:
+ values:
+ - charts:
+ versions:
+ backend: 1.0.5
...
- име: backend
етикети:
app: backend
изчакай: true
chart: private-helm-repo/backend
- версия: 1.0.5
+ версия: {{ .Values.charts.versions.backend }}
...Различен набор от приложения в различни среди
Отлично, но какво, ако не искаме да производството разпространяваме postgres, защото знаем, че не трябва да слагаме база данни в k8s и за продакшъна имаме страхотен отделен клъстер postgres? За решаването на този проблем имаме етикети (labels)
helmfile -n -e devel apply
helmfile -n -e production -l app=backend applyТова е страхотно, но аз лично предпочитам да описвам какви приложения да развърна в средата не с помощта на аргументи за стартиране, а в описанието на самите среди. Какво да правим? Може да се постави описанието на версиите в отделна папка, в описанието на средата да се заведе списък с нужните версии и да "подключим" само нужните версии, игнорирайки другите.
.
├── envs
│ ├── devel
│ │ └── values
│ │ ├── backend.yaml
│ │ └── postgres.yaml
│ └── production
│ └── values
│ ├── backend.yaml
│ └── postgres.yaml
+ ├── releases
+ │ ├── backend.yaml
+ │ └── postgres.yaml
└── helmfile.yaml
helmfile.yaml
environments:
devel:
values:
- charts:
versions:
backend: 1.1.0
- apps:
- postgres
- backend
production:
values:
- charts:
versions:
backend: 1.0.5
- apps:
- backend
- releases:
- - name: postgres
- labels:
- app: postgres
- wait: true
- chart: stable/postgresql
- version: 8.4.0
- values:
- - envs/{{ .Environment.Name }}/values/postgres.yaml
- - name: backend
- labels:
- app: backend
- wait: true
- chart: private-helm-repo/backend
- version: {{ .Values.charts.versions.backend }}
- needs:
- - postgres
- values:
- - envs/{{ .Environment.Name }}/values/backend.yaml
+ ---
+ bases:
+ {{- range .Values.apps }}
+ - releases/{{ . }}.yaml
+ {{- end }}releases/postgres.yaml
releases:
- name: postgres
labels:
app: postgres
wait: true
chart: stable/postgresql
version: 8.4.0
values:
- envs/{{ .Environment.Name }}/values/postgres.yamlreleases/backend.yaml
releases:
- name: backend
labels:
app: backend
wait: true
chart: private-helm-repo/backend
version: {{ .Values.charts.versions.backend }}
needs:
- postgres
values:
- envs/{{ .Environment.Name }}/values/backend.yamlБележка
При използване на bases: необходимо да се използва yaml разделител ---, за да може да се шаблонизират releases (и другите части, като helmDefaults) със стойности от environments
В такъв случай версиите postgres дори няма да попаднат в описанието на production. Много удобно!
Глобални стойности, които могат да се пренастройват за версиите
Разбира се, добре е, че можем да задаваме стойности за helm чартовете за всяка среда, но какво ако имаме описани няколко среди и искаме, да речем, да зададем идентични стойности за всички affinity, но не искаме да конфигурираме по подразбиране в самите чартове, които се съхраняват в репозиториите.
В такъв случай бихме могли да зададем за всяка версия 2 файла с values: първият с подразбиращи се стойности, които ще определят самите стойности на чарта, а вторият със стойности за средата, който от своя страна ще пренастройва подразбиращите се.
.
├── envs
+ │ ├── default
+ │ │ └── values
+ │ │ ├── backend.yaml
+ │ │ └── postgres.yaml
│ ├── devel
│ │ └── values
│ │ ├── backend.yaml
│ │ └── postgres.yaml
│ └── production
│ └── values
│ ├── backend.yaml
│ └── postgres.yaml
├── releases
│ ├── backend.yaml
│ └── postgres.yaml
└── helmfile.yamlreleases/backend.yaml
releases:
- name: backend
labels:
app: backend
wait: true
chart: private-helm-repo/backend
version: {{ .Values.charts.versions.backend }}
needs:
- postgres
values:
+ - envs/default/values/backend.yaml
- envs/{{ .Environment.Name }}/values/backend.yamlenvs/default/values/backend.yaml
affinity:
podAntiAffinity:
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 1
podAffinityTerm:
labelSelector:
matchExpressions:
- key: app.kubernetes.io/name
operator: In
values:
- backend
topologyKey: "kubernetes.io/hostname"Определение на глобални стойности за helm графики на всички версии на етапа.
Да предположим, че в няколко версии създаваме няколко ingress — можехме ръчно да определим за всяка графика. hosts:, но в нашия случай домейнът е един и същ, така че защо да не го изнесем в глобална променлива и просто да подставим стойността му в графиките? За целта файловете с values, които искаме да параметризирани, трябва да имат разширение .gotmpl, за да може helmfile да знае, че трябва да ги премине през шаблонизатор.
.
├── envs
│ ├── default
│ │ └── values
- │ │ ├── backend.yaml
- │ │ ├── postgres.yaml
+ │ │ ├── backend.yaml.gotmpl
+ │ │ └── postgres.yaml.gotmpl
│ ├── devel
│ │ └── values
│ │ ├── backend.yaml
│ │ └── postgres.yaml
│ └── production
│ └── values
│ ├── backend.yaml
│ └── postgres.yaml
├── releases
│ ├── backend.yaml
│ └── postgres.yaml
└── helmfile.yamlhelmfile.yaml
environments:
devel:
values:
- charts:
versions:
backend: 1.1.0
- apps:
- postgres
- backend
+ - global:
+ ingressDomain: k8s.devel.domain
production:
values:
- charts:
versions:
backend: 1.0.5
- apps:
- backend
+ - global:
+ ingressDomain: production.domain
---
bases:
{{- range .Values.apps }}
- releases/{{ . }}.yaml
{{- end }}envs/default/values/backend.yaml.gotmpl
ingress:
enabled: true
paths:
- /api
hosts:
- {{ .Values.global.ingressDomain }}envs/default/values/postgres.yaml.gotmpl
ingress:
enabled: true
paths:
- /
hosts:
- postgres.{{ .Values.global.ingressDomain }}Бележка
Очевидно, че ingress в чарта postgres е нещо изключително спорно, затова в статията е представено просто като сферален пример в вакуум и за да не се въвежда нов релиз само за описването на ingress.
Подмяна на секрети (secrets) от стойности на околната среда.
По аналогия с горепосочения пример, може да се подмятат и данни, криптирани с помощта на предложения. Вместо да създаваме файл с секрети за всеки релиз, в който да определяме криптирани стойности за чарта, можем просто да зададем стойности в default.yaml.gotmpl, които ще се взимат от променливи, зададени на ниво околни среди. А стойностите, които не трябва да крием от никого, могат да бъдат спокойно презаписани в стойностите на релиза за конкретната среда.
.
├── envs
│ ├── default
│ │ └── values
│ │ ├── backend.yaml
│ │ └── postgres.yaml
│ ├── devel
│ │ ├── values
│ │ │ ├── backend.yaml
│ │ │ └── postgres.yaml
+ │ │ └── secrets.yaml
│ └── production
│ ├── values
│ │ ├── backend.yaml
│ │ └── postgres.yaml
+ │ └── secrets.yaml
├── releases
│ ├── backend.yaml
│ └── postgres.yaml
└── helmfile.yamlhelmfile.yaml
environments:
devel:
values:
- charts:
versions:
backend: 1.1.0
- apps:
- postgres
- backend
- global:
ingressDomain: k8s.devel.domain
+ secrets:
+ - envs/devel/secrets.yaml
production:
values:
- charts:
versions:
backend: 1.0.5
- apps:
- backend
- global:
ingressDomain: production.domain
+ secrets:
+ - envs/production/secrets.yaml
---
bases:
{{- range .Values.apps }}
- releases/{{ . }}.yaml
{{- end }}envs/devel/secrets.yaml
secrets:
elastic:
password: ENC[AES256_GCM,data:hjCB,iv:Z1P6/6xBJgJoKLJ0UUVfqZ80o4L84jvZfM+uH9gBelc=,tag:dGqQlCZnLdRAGoJSj63rBQ==,type:int]
...envs/production/secrets.yaml
secrets:
elastic:
password: ENC[AES256_GCM,data:ZB/VpTFk8f0=,iv:EA//oT1Cb5wNFigTDOz3nA80qD9UwTjK5cpUwLnEXjs=,tag:hMdIUaqLRA8zuFBd82bz6A==,type:str]
...envs/default/values/backend.yaml.gotmpl
elasticsearch:
host: elasticsearch
port: 9200
password: {{ .Values | getOrNil "secrets.elastic.password" | default "password" }}envs/devel/values/backend.yaml
elasticsearch:
host: elastic-0.devel.domainenvs/production/values/backend.yaml
elasticsearch:
host: elastic-0.production.domainБележка
Между другото, getOrNil — специална функция за go шаблони в helmfile, която, дори ако .Values.secrets не съществува, няма да хвърли грешка, а ще позволи с помощта на функция по подразбиране да се подмени стойността по подразбиране.
Заключение
Описаните неща изглеждат доста очевидни, но информацията за удобно описване на деплой в multiple среди с помощта на helmfile е доста оскъдна, а аз обичам IaC (Infrastructure-as-Code) и искам да имам ясно описание на състоянието на деплоя.
В заключение искам да добавя, че променливите за средата по подразбиране могат да се параметризира с променливи на ОС на конкретен ранър, от който ще се стартира деплой, и по този начин да се получат динамични среди.
helmfile.yaml
environments:
default:
values:
- global:
clusterDomain: {{ env "CLUSTER_DOMAIN" | default "cluster.local" }}
ingressDomain: {{ env "INGRESS_DOMAIN" }}Източник: habr.com
