Puteți citi despre helmfile în sine și exemple de utilizare în
Ne vom familiariza cu modalități neevidente de a descrie versiunile în helmfile
Să presupunem că avem un pachet de diagrame helm (de exemplu, să spunem postgres și o aplicație backend) și mai multe medii (mai multe clustere kubernetes, mai multe spații de nume sau mai multe dintre ambele). Luăm fișierul helm, citim documentația și începem să descriem mediile și versiunile noastre:
.
├── envs
│ ├── devel
│ │ └── values
│ │ ├── backend.yaml
│ │ └── postgres.yaml
│ └── production
│ └── values
│ ├── backend.yaml
│ └── postgres.yaml
└── helmfile.yaml
helmfile.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.yaml
Am ajuns să avem 2 medii: dezvolta, producere — fiecare conține propriile valori pentru diagramele de lansare a cârmei. Le vom implementa astfel:
helmfile -n <namespace> -e <env> apply
Diferite versiuni de diagrame de cârmă în diferite medii
Ce se întâmplă dacă trebuie să lansăm versiuni diferite ale backend-ului în medii diferite? Cum se parametriză versiunea de lansare? Valorile de mediu disponibile 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 }}
...
Set diferit de aplicații în medii diferite
Grozav, dar dacă nu avem nevoie production
lansați postgres, pentru că știm că nu trebuie să împingem baza de date în k8s și avem de vânzare un minunat cluster postgres separat? Pentru a rezolva această problemă avem etichete
helmfile -n <namespace> -e devel apply
helmfile -n <namespace> -e production -l app=backend apply
Acest lucru este grozav, dar personal prefer să descriu ce aplicații să implementez în mediu nu folosind argumente de lansare, ci în descrierea mediilor în sine. Ce să fac? Puteți plasa descrierile versiunilor într-un folder separat, puteți crea o listă cu versiunile necesare în descrierea mediului și puteți „prelua” doar versiunile necesare, ignorând restul
.
├── 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.yaml
releases/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
Nota
Când utilizați bases:
este necesar să se folosească separator yaml ---
, astfel încât să puteți șablona versiuni (și alte părți, cum ar fi helmDefaults) cu valori din medii
În acest caz, versiunea postgres nici măcar nu va fi inclusă în descrierea pentru producție. Foarte confortabil!
Valori globale suprascrise pentru versiuni
Desigur, este grozav că puteți seta valori pentru diagramele de conducere pentru fiecare mediu, dar ce se întâmplă dacă avem mai multe medii descrise și vrem, de exemplu, să setăm același lucru pentru toate affinity
, dar nu vrem să-l configuram implicit în diagramele în sine, care sunt stocate în napi.
În acest caz, pentru fiecare lansare am putea specifica 2 fișiere cu valori: primul cu valori implicite, care va determina valorile diagramei în sine, iar al doilea cu valori pentru mediu, care la rândul lor va suprascrie cele 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.yaml
releases/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.yaml
envs/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 diagramele de conducere ale tuturor lansărilor la nivel de mediu
Să presupunem că creăm mai multe intrări în mai multe versiuni - am putea defini manual pentru fiecare diagramă hosts:
, dar în cazul nostru domeniul este același, așa că de ce să nu îl puneți într-o variabilă globală și pur și simplu să-i înlocuiți valoarea în diagrame? Pentru a face acest lucru, acele fișiere cu valori pe care dorim să le parametrizăm vor trebui să aibă extensia .gotmpl
, astfel încât helmfile să știe că trebuie rulat prin motorul de șablon.
.
├── 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.yaml
helmfile.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 }}
Nota
Evident, intrarea în diagrama postgres este ceva extrem de dubios, așa că acest articol este dat pur și simplu ca un exemplu sferic în vid și pentru a nu introduce vreo versiune nouă în articol doar de dragul de a descrie intrarea.
Înlocuirea secretelor din valorile mediului
Prin analogie cu exemplul de mai sus, le puteți înlocui pe cele criptate folosind
.
├── 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.yaml
helmfile.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.domain
envs/production/values/backend.yaml
elasticsearch:
host: elastic-0.production.domain
Nota
Apropo, getOrNil
- o funcție specială pentru șabloanele go în helmfile, care, chiar dacă .Values.secrets
nu va exista, nu va arunca o eroare, dar va permite rezultatul folosind funcția default
înlocuiți valoarea implicită
Concluzie
Lucrurile descrise par destul de evidente, dar informațiile despre o descriere convenabilă a implementării în mai multe medii care utilizează helmfile sunt foarte rare și îmi place IaC (Infrastructure-as-Code) și vreau să am o descriere clară a stării de implementare.
În concluzie, aș dori să adaug că variabilele pentru mediul implicit pot fi, la rândul lor, parametrizate cu variabilele de mediu ale sistemului de operare al unui anumit runner de pe care va fi lansată implementarea, și astfel să se obțină medii dinamice.
helmfile.yaml
environments:
default:
values:
- global:
clusterDomain: {{ env "CLUSTER_DOMAIN" | default "cluster.local" }}
ingressDomain: {{ env "INGRESS_DOMAIN" }}
Sursa: www.habr.com