â eine Wrapper fĂŒr , die es ermöglicht, an einem Ort viele Helm-Releases zu beschreiben, deren Charts fĂŒr verschiedene Umgebungen zu parametrisieren und die Reihenfolge ihres Deployments festzulegen.
Ăber Helmfile und Beispiele fĂŒr seine Nutzung kann man im und .
lesen. Wir werden uns mit weniger offensichtlichen Wegen beschÀftigen, Releases in Helmfile zu beschreiben.
Angenommen, wir haben eine Sammlung von Helm-Charts (zum Beispiel PostgreSQL und eine Backend-Anwendung) und mehrere Umgebungen (einige Kubernetes-Cluster, mehrere Namespaces oder beides). Wir nehmen Helmfile, lesen die Dokumentation, und beginnen, unsere Umgebungen und Releases zu beschreiben:
.
âââ 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.yamlWir haben 2 Umgebungen erhalten: devel, Produktion â in jeder befinden sich ihre eigenen Werte fĂŒr die Helm-Chart-Releases. Wir werden sie so deployen:
helmfile -n -e applyUnterschiedliche Versionen von Helm-Charts in unterschiedlichen Umgebungen
Was tun, wenn wir verschiedene Versionen des Backends in unterschiedlichen Umgebungen ausrollen mĂŒssen? Wie parametrisieren wir die Version des Releases? Dazu kommen Umgebungswerte ins Spiel, die ĂŒber {{ .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 }}
...Verschiedene Anwendungssets in unterschiedlichen Umgebungen
Das ist gut, aber was ist, wenn wir PostgreSQL nicht ausrollen wollen, weil wir wissen, dass wir keine Datenbank in k8s stecken mĂŒssen und fĂŒr die Produktion einen hervorragenden separaten PostgreSQL-Cluster haben? Um dieses Problem zu lösen, haben wir Labels (labels) Produktion helmfile -n -e devel apply helmfile -n -e production -l app=backend apply
helmfile -n -e devel apply
helmfile -n -e production -l app=backend applyDas ist groĂartig, aber persönlich bevorzuge ich es, zu beschreiben, welche Anwendungen in der Umgebung bereitgestellt werden sollen, nicht durch Startargumente, sondern durch die Beschreibung der Umgebungen selbst. Was kann man tun? Man könnte die Versionsbeschreibungen in einen separaten Ordner legen, in der Umgebungsliste die benötigten Versionen auffĂŒhren und nur die benötigten Versionen "anschlieĂen", wĂ€hrend die anderen ignoriert werden.
.
âââ 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.yamlNotiz
Bei der Nutzung eines bases: es ist zwingend erforderlich, den YAML-Trenner zu verwenden ---, um die Releases (und andere Teile wie helmDefaults) mit Werten aus environments zu templatisieren.
In diesem Fall kommt das Release postgres nicht einmal in die Beschreibung fĂŒr production. Sehr praktisch!
Globale ĂŒberschreibbare Werte fĂŒr Releases
NatĂŒrlich ist es groĂartig, dass man fĂŒr jede Umgebung Werte fĂŒr Helm-Charts festlegen kann, aber was ist, wenn wir mehrere Umgebungen beschrieben haben und wir beispielsweise fĂŒr alle eine identische festlegen möchten Affinity, aber wir nicht möchten, dass sie standardmĂ€Ăig in den Charts, die in Repos gespeichert sind, konfiguriert ist.
In diesem Fall könnten wir fĂŒr jedes Release zwei Dateien mit Werten festlegen: eine mit Standardwerten, die die Werte des Charts definieren, und eine zweite mit Werten fĂŒr die Umgebung, die wiederum die Standardwerte ĂŒberschreiben wird.
.
âââ 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"Definition globaler Werte fĂŒr Helm-Charts aller Releases auf Umgebungslevel
Angenommen, wir erstellen in mehreren Releases mehrere Ingress, könnten wir fĂŒr jedes Chart manuell festlegen hosts:, aber in unserem Fall ist die Domain die gleiche, warum sollten wir sie nicht in eine globale Variable auslagern und einfach ihren Wert in die Charts einsetzen? Damit mĂŒssen die Werte-Dateien, die wir parametrisieren wollen, die Erweiterung .gotmpl, damit Helmfile weiĂ, dass sie durch den Template-Processor geleitet werden mĂŒssen.
.
âââ 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 }}Notiz
Offensichtlich ist der Ingress im Postgres-Chart Ă€uĂerst fragwĂŒrdig, weshalb er in diesem Artikel nur als theoretisches Beispiel im Vakuum angefĂŒhrt wird, damit kein neuer Release nur zur Beschreibung des Ingress erstellt wird.
Das EinfĂŒgen von Geheimnissen (secrets) aus Umgebungsvariablen
Analog zu dem oben genannten Beispiel können auch verschlĂŒsselte Werte eingefĂŒgt werden. Anstatt fĂŒr jede Version eine eigene Sekretdatei zu erstellen, in der die verschlĂŒsselten Werte fĂŒr das Chart definiert werden, können wir einfach im Release-Standard-default.yaml.gotmpl Werte festlegen, die aus Variablen auf Ebene der Umgebungen entnommen werden. Werte, die wir nicht geheim halten mĂŒssen, können dann problemlos in den Release-Werten fĂŒr die jeweilige Umgebung ĂŒberschrieben werden.
.
âââ 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.domainNotiz
Ăbrigens, getOrNil â eine spezielle Funktion fĂŒr Go-Templates in helmfile, die selbst wenn .Values.secrets nicht existiert, keine Fehler auslöst, sondern es ermöglicht, mithilfe der Funktion default einen Standardwert einzufĂŒgen.
Fazit
Die beschriebenen Dinge scheinen recht offensichtlich zu sein, aber die Informationen ĂŒber eine benutzerfreundliche Beschreibung des Deployments in mehreren Umgebungen mit helmfile sind sehr spĂ€rlich, und ich liebe IaC (Infrastructure-as-Code) und möchte eine klare Beschreibung des Deployment-Status haben.
Zusammenfassend möchte ich hinzufĂŒgen, dass die Variablen fĂŒr die Standardumgebung wiederum durch Umgebungsvariablen des Betriebssystems eines bestimmten Runners, von dem das Deployment gestartet wird, parametriert werden können, um so dynamische Umgebungen zu erhalten.
helmfile.yaml
environments:
default:
values:
- global:
clusterDomain: {{ env "CLUSTER_DOMAIN" | default "cluster.local" }}
ingressDomain: {{ env "INGRESS_DOMAIN" }}Quelle: habr.com
