— ovitka za , ki omogoča opisovanje številnih helm izdaj na enem mestu, parametrize njihove karte za več okolij ter določanje reda njihovega prenosa.
O helmfile in primerih njegove uporabe lahko preberete v in .
Seznanili se bomo z manj očitnimi načini za opisovanje izdaj v helmfile
Recimo, da imamo paket helm-kart (vzemimo za primer postgres in neko aplikacijo za backend) ter več okolij (več kubernetes grozdov, več namespacingov ali oboje). Vzamemo helmfile, preberemo dokumentacijo in začnemo opisovati naša okolja in izdaj:
.
├── envs
│ ├── devel
│ │ └── values
│ │ ├── backend.yaml
│ │ └── postgres.yaml
│ └── production
│ └── values
│ ├── backend.yaml
│ └── postgres.yaml
└── helmfile.yamlhelmfile.yaml
okolja:
devel:
production:
izdaje:
- ime: postgres
oznake:
app: postgres
počakaj: true
chart: stable/postgresql
različica: 8.4.0
vrednosti:
- envs/{{ .Environment.Name }}/values/postgres.yaml
- ime: backend
oznake:
app: backend
počakaj: true
chart: private-helm-repo/backend
različica: 1.0.5
potrebuje:
- postgres
vrednosti:
- envs/{{ .Environment.Name }}/values/backend.yamlImamo 2 okolji: devel, production — v vsakem so svoje vrednosti za helm karte izdaj. Uporabljali bomo naslednji postopek za prenos:
helmfile -n <namespace> -e <env> applyRazlične različice helm kart v različnih okoljih
Kaj storiti, če moramo zagotoviti različne različice backend-a v različnih okoljih? Kako parametrizirati različico izdaje? Na pomoč pridejo vrednosti okolja, dostopne preko {{ .Values }}
helmfile.yaml
okolja:
devel:
+ vrednosti:
+ - karte:
+ različice:
+ backend: 1.1.0
production:
+ vrednosti:
+ - karte:
+ različice:
+ backend: 1.0.5
...
- ime: backend
oznake:
app: backend
počakaj: true
chart: private-helm-repo/backend
- različica: 1.0.5
+ različica: {{ .Values.charts.versions.backend }}
...Različni nabori aplikacij v različnih okoljih
Odlično, vendar kaj, če nam ni treba production zagotoviti postgres, ker vemo, da podatkovne baze ne smemo stlačiti v k8s in da imamo za produkcijo čudovit ločen grozd postgres? Za rešitev te težave imamo oznake (labels)
helmfile -n <namespace> -e devel apply
helmfile -n <namespace> -e production -l app=backend applyTo je odlično, vendar osebno raje opisujem, katere aplikacije naj se postavijo v okolju, ne z uporabo zagonskih argumentov, ampak v opisu samih okolij. Kaj storiti? Opis izdaj lahko postavimo v posebno mapo, v opisu okolja pa ustvarimo seznam potrebnih izdaj in 'priključimo' samo potrebne izdaje, vse ostale pa ignoriramo.
.
├── 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.yamlOpomba
Pri uporabi bases: je nujno treba uporabiti yaml ločilo ---, da bi lahko šablonizirali releases (in druge dele, kot so helmDefaults) z vrednostmi iz environments
V tem primeru izdajanje postgres ne bo prišlo niti v opis za produkcijo. To je zelo priročno!
Preseženi globalni vrednosti za izdaje
Seveda je dobro, da lahko za vsako okolje nastavite vrednosti za helm karte, vendar kaj, če imamo opisana več okolij in želimo na primer nastaviti enake vrednosti za vse affinity, ne želimo pa jih nastaviti privzeto v samih kartah, ki so shranjene v repih.
V tem primeru bi lahko za vsako izdajo nastavili 2 datoteki z vrednostmi: prva z privzetimi vrednostmi, ki bi določile vrednosti same karte, in druga z vrednostmi za okolje, ki bi nato prepisala privzete.
.
├── 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"Določitev globalnih vrednosti za helm sheme vseh izdaj na ravni okolja
Recimo, da imamo v več izdajah ustvarjene več ingress — za vsak chart bi lahko ročno določili hosts:, vendar imamo v našem primeru isti domen, zakaj ga ne bi spravili v neko globalno spremenljivko in preprosto vstavili njeno vrednost v sheme? Za to morajo imeti tisti datoteki z vrednostmi, ki jih želimo parametrizirati, končnico .gotmpl, da bo helmfile vedel, da jih je treba podati skozi predlogo.
.
├── 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 }}Opomba
Očitno je, da je ingress v chartu postgres nekaj zelo dvomljivega, zato je v članku navedeno le kot sferični primer v vakuumu in za to, da ne bi uvajali v članek kakšne nove različice samo zaradi opisovanja ingress.
Vstavljanje skrivnosti (secrets) iz vrednosti okolja.
Po analogy s prej omenjenim primerom lahko vstavimo tudi šifrirane z uporabo. vrednosti. Namesto da za vsak izdajo ustvarimo svoj datoteko secrets, v kateri določimo za chart šifrirane vrednosti, lahko preprosto določimo v izdajnem default.yaml.gotmpl vrednosti, ki bodo prevzete iz spremenljivk, določenih na ravni okolij. Vrednosti, ki jih ne potrebujemo skrbeti pred nikomer, lahko že mirno prekoračimo v vrednostih izdaje v konkretnem okolju.
.
├── 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.domainOpomba
Mimogrede, getOrNil — posebna funkcija za go predloge v helmfile, ki, tudi če .Values.secrets ne bo obstajala, ne bo povzročila napake, ampak bo omogočila z uporabo funkcije default vstaviti privzeto vrednost.
Zaključek
Opišane stvari se zdijo precej očitne, a informacije o enostavnem opisu namestitve v več okoljih z uporabo helmfile so zelo skope, jaz pa imam rad IaC (Infrastructure-as-Code) in želim imeti jasno opisano stanje namestitve.
Na koncu želim dodati, da lahko spremenljivke za okolje default parameteriziramo s spremenljivkami okolja operacijskega sistema nekega runnerja, s katerega se bo izvajala namestitev, in tako pridobimo dinamična okolja.
helmfile.yaml
environments:
default:
values:
- global:
clusterDomain: {{ env "CLUSTER_DOMAIN" | default "cluster.local" }}
ingressDomain: {{ env "INGRESS_DOMAIN" }}Izvor: habr.com
