— un wrapper pentru , care permite descrierea într-un singur loc a mai multor lansări helm, parametrizarea diagramelor pentru diferite medii și stabilirea ordinii de desfășurare a acestora.
Despre helmfile și exemplele sale de utilizare puteți citi în și .
Ne vom familiariza cu metodele mai puțin evidente de a descrie lansările în helmfile.
Să presupunem că avem o serie de diagrame helm (în acest exemplu, fie postgres și o aplicație backend) și mai multe medii (mai multe clustere Kubernetes, mai multe spații de nume sau atât unul, cât și altul). Luăm helmfile, citim documentația și începem să descriem mediile și lansările noastre:
.
├── envs
│ ├── devel
│ │ └── values
│ │ ├── backend.yaml
│ │ └── postgres.yaml
│ └── production
│ └── values
│ ├── backend.yaml
│ └── postgres.yaml
└── helmfile.yamlhelmfile.yaml
environments:
devel:
production:
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: 1.0.5
needs:
- postgres
values:
- envs/{{ .Environment.Name }}/values/backend.yamlAm obținut 2 medii: devel, producție — în fiecare se află valorile proprii pentru diagramele helm ale lansărilor. Le vom desfășura astfel:
helmfile -n -e applyVersiuni diferite ale diagramelor helm în diferite medii
Ce facem dacă trebuie să desfășurăm versiuni diferite ale backendului în medii diferite? Cum parametrizăm versiunea lansării? Valorile mediului, accesibile prin {{ .Values }}
helmfile.yaml
environments:
devel:
+ values:
+ - charts:
+ versions:
+ backend: 1.1.0
production:
+ values:
+ - charts:
+ versions:
+ backend: 1.0.5
...
- name: backend
labels:
app: backend
wait: true
chart: private-helm-repo/backend
- version: 1.0.5
+ version: {{ .Values.charts.versions.backend }}
...Un set diferit de aplicații în diferite medii
Excelent, dar ce facem dacă nu trebuie să producție desfășurăm postgres, pentru că știm că nu trebuie să punem baza de date în k8s și pentru produs avem un cluster postgres separat minunat? Pentru a rezolva această problemă avem etichete (labels)
helmfile -n -e devel apply
helmfile -n -e production -l app=backend applyEste minunat, dar personal prefer să descriu ce aplicații să desfășor în mediu nu prin argumente de lansare, ci în descrierea în sine a mediilor. Ce să fac? Pot plasa descrierile versiunilor într-un folder separat, iar în descrierea mediului să am o listă cu versiunile necesare și să "atașez" doar versiunile dorite, ignorând pe celelalte.
.
├── 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.yamlNotă
Când folosești bases: este necesar să se utilizeze separatorul yaml ---, pentru a putea șabloniza versiunile (și celelalte părți, cum ar fi helmDefaults) cu valori din medii
În acest caz, versiunea postgres nici măcar nu va ajunge în descrierea pentru producție. Foarte convenabil!
Valorile globale care pot fi suprascrise pentru versiuni
Desigur, e minunat că pentru fiecare mediu putem stabili valori pentru chart-uri helm, dar ce facem dacă avem descrise mai multe medii și vrem, de exemplu, să stabilim aceeași valoare pentru toate affinity, dar nu dorim să o configurăm implicit în chart-urile în sine, care sunt stocate în repouri.
În acest caz, am putea stabili pentru fiecare versiune 2 fișiere cu valori: primul cu valori implicite, care vor determina valorile chart-ului, iar al doilea cu valori pentru mediu, care la rândul său va suprascrie valorile implicite.
.
├── 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"Definirea valorilor globale pentru graficele helm pentru toate lansările la nivelul mediului
Să presupunem că avem mai multe ingress-uri create în mai multe lansări — am putea defini manual pentru fiecare grafic în parte hosts:, dar în cazul nostru domeniul este același, așa că de ce nu l-am scoate într-o variabilă globală și am folosi doar valoarea sa în grafice? Pentru aceasta, fișierele cu valori pe care dorim să le parametrizăm trebuie să aibă extensia .gotmpl, astfel încât helmfile să știe că trebuie să fie procesat prin motorul de șabloane.
.
├── 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 }}Notă
Este evident că ingress în chartul postgres este un lucru extrem de discutabil, de aceea în articol este adus doar ca un exemplu sferic în vid și pentru a nu introduce în articol o nouă versiune doar pentru a descrie ingress.
Înlocuirea secretelor (secrets) din valorile de mediu.
În mod similar cu exemplul de mai sus, putem adăuga și valorile criptate folosind În loc să creăm un fișier secrets pentru fiecare versiune, în care să definim valorile criptate pentru chart, putem doar să definim în default.yaml.gotmpl valorile care vor proveni din variabilele specificate la nivelul mediu. Iar valorile pe care nu trebuie să le ascundem de nimeni pot fi deja redefinite în valorile versiunii din mediu specific.
.
├── 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.domainNotă
Apropo, getOrNil — o funcție specială pentru template-urile Go în helmfile, care, chiar dacă .Values.secrets nu va exista, nu va genera o eroare, ci va permite în rezultat, folosind funcția default să înlocuim cu o valoare implicită.
Concluzie
Lucrurile descrise par destul de evidente, însă informațiile despre modul convenabil de a descrie desfășurarea în mai multe medii folosind helmfile sunt foarte rare, iar eu iubesc IaC (Infrastructure-as-Code) și doresc să am o descriere clară a stării desfășurării.
În concluzie, vreau să adaug că variabilele pentru mediu default pot fi, la rândul lor, parametrizate cu variabile de mediu ale sistemului de operare al unui anumit runner, de pe care va fi lansată desfășurarea, obținând astfel medii dinamice.
helmfile.yaml
environments:
default:
values:
- global:
clusterDomain: {{ env "CLUSTER_DOMAIN" | default "cluster.local" }}
ingressDomain: {{ env "INGRESS_DOMAIN" }}Sursa: habr.com
