Puoi leggere informazioni sull'helmfile stesso ed esempi del suo utilizzo in
Faremo conoscenza con modi non ovvi per descrivere le versioni in helmfile
Supponiamo di avere un pacchetto di grafici helm (ad esempio, postgres e alcune applicazioni backend) e diversi ambienti (diversi cluster Kubernetes, diversi spazi dei nomi o diversi entrambi). Prendiamo l'helmfile, leggiamo la documentazione e iniziamo a descrivere i nostri ambienti e versioni:
.
├── 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
Alla fine ci siamo ritrovati con 2 ambienti: devel, produzione - ciascuno contiene i propri valori per i grafici di rilascio del timone. Li distribuiremo in questo modo:
helmfile -n <namespace> -e <env> apply
Diverse versioni di carte timone in diversi ambienti
Cosa succede se dobbiamo implementare diverse versioni del backend in ambienti diversi? Come parametrizzare la versione di rilascio? I valori ambientali disponibili attraverso {{ .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 }}
...
Diversi set di applicazioni in diversi ambienti
Ottimo, ma cosa succede se non ne abbiamo bisogno? production
implementare Postgres, perché sappiamo che non è necessario inserire il database in K8 e in vendita abbiamo un meraviglioso cluster Postgres separato? Per risolvere questo problema abbiamo le etichette
helmfile -n <namespace> -e devel apply
helmfile -n <namespace> -e production -l app=backend apply
Questo è fantastico, ma personalmente preferisco descrivere quali applicazioni distribuire nell'ambiente non utilizzando argomenti di lancio, ma nella descrizione degli ambienti stessi. Cosa fare? Puoi inserire le descrizioni delle versioni in una cartella separata, creare un elenco delle versioni necessarie nella descrizione dell'ambiente e “prelevare” solo le versioni necessarie, ignorando il resto
.
├── 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
Заметка
Quando si utilizza la bases:
è necessario utilizzare il separatore yaml ---
, in modo da poter creare modelli di release (e altre parti, come helmDefaults) con valori provenienti dagli ambienti
In questo caso la versione postgres non verrà nemmeno inclusa nella descrizione per la produzione. Molto comodamente!
Valori globali sovrascrivibili per le versioni
Naturalmente, è fantastico poter impostare valori per i grafici timone per ciascun ambiente, ma cosa succede se abbiamo descritti diversi ambienti e vogliamo, ad esempio, impostare lo stesso per tutti? affinity
, ma non vogliamo configurarlo di default nei grafici stessi, che sono memorizzati in rape.
In questo caso, per ogni release potremmo specificare 2 file con valori: il primo con valori di default, che determineranno i valori del grafico stesso, e il secondo con valori per l'ambiente, che a sua volta sovrascriverà il quelli predefiniti.
.
├── 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"
Definizione dei valori globali per i grafici timone di tutte le versioni a livello di ambiente
Supponiamo di creare diversi ingressi in diverse versioni: potremmo definirli manualmente per ciascun grafico hosts:
, ma nel nostro caso il dominio è lo stesso, quindi perché non inserirlo in qualche variabile globale e sostituirne semplicemente il valore nei grafici? Per fare ciò, quei file con valori che vogliamo parametrizzare dovranno avere l'estensione .gotmpl
, in modo che helmfile sappia che deve essere eseguito tramite il motore del modello.
.
├── 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 }}
Заметка
Ovviamente, l'ingresso nel grafico Postgres è qualcosa di estremamente dubbio, quindi questo articolo è fornito semplicemente come esempio sferico nel vuoto e per non introdurre qualche nuova versione nell'articolo solo per il gusto di descrivere l'ingresso
Sostituzione dei segreti con i valori dell'ambiente
Per analogia con l'esempio precedente, puoi sostituire quelli crittografati utilizzando
.
├── 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
Заметка
Tra l'altro, getOrNil
- una funzione speciale per i modelli Go in helmfile, che, anche se .Values.secrets
non esisterà, non genererà un errore, ma consentirà il risultato utilizzando la funzione default
sostituire il valore predefinito
conclusione
Le cose descritte sembrano abbastanza ovvie, ma le informazioni su una comoda descrizione della distribuzione in diversi ambienti utilizzando helmfile sono molto scarse e adoro IaC (Infrastructure-as-Code) e desidero avere una descrizione chiara dello stato di distribuzione.
In conclusione vorrei aggiungere che le variabili per l'ambiente di default potranno a loro volta essere parametrizzate con le variabili d'ambiente dell'OS di un determinato runner da cui verrà lanciato il deploy, ed ottenere così ambienti dinamici
helmfile.yaml
environments:
default:
values:
- global:
clusterDomain: {{ env "CLUSTER_DOMAIN" | default "cluster.local" }}
ingressDomain: {{ env "INGRESS_DOMAIN" }}
Fonte: habr.com