Die Organisation des Deployments in mehrere k8s-Umgebungen mithilfe von helmfile.

Helmfile — eine Wrapper fĂŒr helm, die es ermöglicht, an einem Ort zahlreiche Helm-Releases zu beschreiben, ihre Charts fĂŒr verschiedene Umgebungen zu parametrisieren und die Reihenfolge ihrer Bereitstellung festzulegen.

Über helmfile und Beispiele seiner Anwendung können Sie im readme und Best Practices Leitfaden.

lesen. Wir werden uns mit weniger offensichtlichen Methoden beschÀftigen, um Releases in helmfile zu beschreiben.

Angenommen, wir haben eine Reihe von Helm-Charts (nehmen wir als Beispiel postgres und eine Backend-Anwendung) sowie mehrere Umgebungen (einige Kubernetes-Cluster, mehrere Namespaces oder auch 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.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

Wir haben 2 Umgebungen erstellt: devel, production — in jeder befinden sich spezifische Werte fĂŒr die Helm-Chart-Releases. Wir werden sie so deployen:

helmfile -n  -e  apply

Verschiedene Versionen von Helm-Charts in unterschiedlichen Umgebungen

Was tun, wenn wir verschiedene Backend-Versionen in unterschiedlichen Umgebungen bereitstellen mĂŒssen? Wie parametrieren wir die Release-Version? Hier kommen die 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 }}
...

Unterschiedlicher Satz von Anwendungen in verschiedenen Umgebungen

Das ist gut, aber was ist, wenn wir nicht production Postgres bereitstellen mĂŒssen, weil wir wissen, dass wir die Datenbank nicht in k8s packen sollten und fĂŒr die Produktion haben wir einen ausgezeichneten separaten Postgres-Cluster? Um dieses Problem zu lösen, haben wir Labels (labels)

helmfile -n  -e devel apply
helmfile -n  -e production -l app=backend apply

Das ist großartig, aber persönlich wĂŒrde ich es vorziehen, die zu verwendenden Anwendungen in der Umgebung nicht ĂŒber Startargumente, sondern ĂŒber die Beschreibung der Umgebungen zu definieren. Was kann man tun? Man könnte die Release-Beschreibungen in einen separaten Ordner legen, in der Umgebungsbeschreibung eine Liste der benötigten Releases fĂŒhren und nur die relevanten Releases „einbinden“, 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


  umgebungen:
    devel:
      werte:
      - charts:
          versionen:
            backend: 1.1.0
      - apps:
        - postgres
        - backend

    produktion:
      werte:
      - charts:
          versionen:
            backend: 1.0.5
      - apps:
        - backend

- releases:
-    - name: postgres
-      labels:
-        app: postgres
-      warten: true
-      chart: stable/postgresql
-      version: 8.4.0
-      werte:
-        - envs/{{ .Environment.Name }}/values/postgres.yaml
-    - name: backend
-      labels:
-        app: backend
-      warten: true
-      chart: private-helm-repo/backend
-     version: {{ .Values.charts.versions.backend }}
-     needs:
-       - postgres
-     werte:
-       - envs/{{ .Environment.Name }}/values/backend.yaml
+ ---
+ grundlagen:
+ {{- 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

Hinweis

Bei der Nutzung Basen: Es muss unbedingt der YAML-Trenner verwendet werden ---, um Releases (und andere Teile wie helmDefaults) mit Werten aus den Umgebungen zu templatisieren

In diesem Fall wird das Postgres-Release nicht einmal in die Beschreibung fĂŒr die Produktion aufgenommen. Sehr praktisch!

Überschreibbare globale Werte fĂŒr Releases

Es ist natĂŒrlich großartig, dass wir fĂŒr jede Umgebung Werte fĂŒr Helm-Charts festlegen können, aber was ist, wenn wir mehrere Umgebungen beschrieben haben und zum Beispiel denselben Wert fĂŒr alle festlegen möchten? Affinity, aber wir möchten ihn nicht standardmĂ€ĂŸig in den Charts einstellen, die in den Repositories gespeichert sind.

In diesem Fall könnten wir fĂŒr jedes Release zwei Dateien mit Werten angeben: eine mit den Standardwerten, die die Werte des Charts bestimmen, und eine zweite mit den 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.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"

Festlegen globaler Werte fĂŒr Helm-Charts aller Releases auf Umgebungsniveau

Angenommen, wir erstellen in mehreren Releases mehrere Ingress — wir könnten manuell fĂŒr jedes Chart definieren hosts:, aber in unserem Fall ist die Domain die gleiche. Warum also nicht in eine globale Variable auslagern und einfach ihren Wert in die Charts einsetzen? DafĂŒr mĂŒssen die Dateien mit den Werten, die wir parametrisieren möchten, die Erweiterung haben .gotmpl, damit helmfile weiß, dass sie durch den Template-Renderer verarbeitet 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.yaml

helmfile.yaml

  Umgebungen:
    devel:
      Werte:
      - Charts:
          Versionen:
            backend: 1.1.0
      - Apps:
        - postgres
        - backend
+     - global:
+         ingressDomain: k8s.devel.domain

    produktion:
      Werte:
      - Charts:
          Versionen:
            backend: 1.0.5
      - Apps:
        - backend
+     - global:
+         ingressDomain: production.domain
  ---
  Basen:
  {{- range .Values.apps }}
    - releases/{{ . }}.yaml
  {{- end }}

envs/default/values/backend.yaml.gotmpl

ingress:
  aktiviert: true
  pfade:
    - /api
  hosts:
    - {{ .Values.global.ingressDomain }}

envs/default/values/postgres.yaml.gotmpl

ingress:
  enabled: true
  paths:
    - / 
  hosts:
    - postgres.{{ .Values.global.ingressDomain }}

Hinweis

Offensichtlich ist das Ingress in dem Postgres-Chart etwas, was in Frage gestellt werden kann. Daher wird es in diesem Artikel lediglich als theoretisches Beispiel ohne konkreten Bezug genutzt, um die Notwendigkeit eines neuen Releases nur zur Beschreibung des Ingress zu vermeiden.

EinfĂŒgen von Geheimnissen (Secrets) aus Umgebungswerten.

Ähnlich wie im obigen Beispiel können auch verschlĂŒsselte Werte eingefĂŒgt werden. helm secrets Werte. Anstatt fĂŒr jedes Release eine eigene Secrets-Datei zu erstellen, in der die verschlĂŒsselten Werte fĂŒr das Chart definiert sind, können wir einfach die im Release default.yaml.gotmpl definierten Werte verwenden, die aus auf Umgebungen festgelegten Variablen entnommen werden. Werte, die wir nicht geheim halten mĂŒssen, können in den Release-Werten des spezifischen Umfelds problemlos ĂŒ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.yaml

helmfile.yaml

  Umgebungen:
    devel:
      Werte:
      - Charts:
          Versionen:
            backend: 1.1.0
      - Apps:
        - postgres
        - backend
      - global:
          ingressDomain: k8s.devel.domain
+     secrets:
+       - envs/devel/secrets.yaml

    production:
      Werte:
      - Charts:
          Versionen:
            backend: 1.0.5
      - Apps:
        - backend
      - global:
          ingressDomain: production.domain
+     secrets:
+       - envs/production/secrets.yaml
  ---
  basen:
  {{- range .Values.apps }}
    - releases/{{ . }}.yaml
  {{- end }}

envs/devel/secrets.yaml

secrets:
    elastic:
        passwort: ENC[AES256_GCM,data:hjCB,iv:Z1P6/6xBJgJoKLJ0UUVfqZ80o4L84jvZfM+uH9gBelc=,tag:dGqQlCZnLdRAGoJSj63rBQ==,type:int]
...

envs/production/secrets.yaml

secrets:
    elastic:
        passwort: ENC[AES256_GCM,data:ZB/VpTFk8f0=,iv:EA//oT1Cb5wNFigTDOz3nA80qD9UwTjK5cpUwLnEXjs=,tag:hMdIUaqLRA8zuFBd82bz6A==,type:str]
...

envs/default/values/backend.yaml.gotmpl

elasticsearch:
  host: elasticsearch
  port: 9200
  passwort: {{ .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

Hinweis

Übrigens, getOrNil — eine spezielle Funktion fĂŒr Go-Templates in Helmfile, die, selbst wenn .Values.secrets nicht existiert, keinen Fehler ausgibt, sondern es ermöglicht, mit einer Funktion default einen Standardwert einzufĂŒgen.

Fazit

Die beschriebenen Punkte erscheinen recht offensichtlich, jedoch gibt es nur wenig Informationen ĂŒber eine komfortable Beschreibung von Deployments in mehreren Umgebungen mit Helmfile. Ich schĂ€tze IaC (Infrastructure-as-Code) und möchte eine klare Beschreibung des Deployment-Status haben.

Abschließend 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, parametrisiert werden können, wodurch dynamische Umgebungen entstehen.

helmfile.yaml

environments:
  default:
    values:
    - global:
        clusterDomain: {{ env "CLUSTER_DOMAIN" | default "cluster.local" }}
        ingressDomain: {{ env "INGRESS_DOMAIN" }}

Quelle: habr.com

Kaufen Sie zuverlĂ€ssiges Hosting fĂŒr Websites mit DDoS-Schutz, VPS VDS-Server đŸ”„ Kaufen Sie zuverlĂ€ssiges Hosting fĂŒr Websites mit DDoS-Schutz, VPS VDS-Server | ProHoster