Organizácia nasadenia do viacerých prostredí k8s pomocou súboru helmfile

Helmfile - obal na kormidlo, ktorý vám umožňuje na jednom mieste popísať množstvo vydaní kormidla, parametrizovať ich grafy pre viacero prostredí a tiež nastaviť poradie ich nasadenia.

Môžete si prečítať o samotnom helmfile a príkladoch jeho použitia v readme и príručka najlepších postupov.

Zoznámime sa s nezrejmými spôsobmi opisu vydaní v súbore helmfile

Povedzme, že máme balík grafov kormidla (napríklad povedzme postgres a nejakú backendovú aplikáciu) a niekoľko prostredí (niekoľko klastrov kubernetes, niekoľko menných priestorov alebo niekoľko z oboch). Vezmeme súbor helmfile, prečítame si dokumentáciu a začneme popisovať naše prostredia a vydania:

    .
    ├── 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

Skončili sme s 2 prostrediami: rozvíjať, výroba — každý obsahuje svoje vlastné hodnoty pre tabuľky uvoľnenia kormidla. Nasadíme ich takto:

helmfile -n <namespace> -e <env> apply

Rôzne verzie tabuliek kormidla v rôznych prostrediach

Čo ak potrebujeme zaviesť rôzne verzie backendu do rôznych prostredí? Ako parametrizovať verziu vydania? Environmentálne hodnoty dostupné prostredníctvom {{ .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 }}
...

Rôzne sady aplikácií v rôznych prostrediach

Skvelé, ale čo ak to nepotrebujeme production zaviesť postgres, pretože vieme, že nepotrebujeme tlačiť databázu do k8 a na predaj máme nádherný samostatný klaster postgres? Na vyriešenie tohto problému máme štítky

helmfile -n <namespace> -e devel apply
helmfile -n <namespace> -e production -l app=backend apply

To je skvelé, ale osobne radšej popisujem, ktoré aplikácie nasadiť do prostredia nie pomocou spúšťacích argumentov, ale v popise samotných prostredí. Čo robiť? Popisy vydaní môžete umiestniť do samostatného priečinka, vytvoriť zoznam potrebných vydaní v popise prostredia a „vyzdvihnúť“ iba potrebné vydania, ostatné ignorovať

    .
    ├── 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

Poznámka

Pri použití bases: je potrebné použiť oddeľovač yaml ---, aby ste mohli šablónovať vydania (a iné časti, ako napríklad helmDefaults) s hodnotami z prostredí

V tomto prípade nebude postgres release ani zahrnutý do popisu pre produkciu. Veľmi pohodlne!

Prepisovateľné globálne hodnoty pre vydania

Samozrejme, je skvelé, že môžete nastaviť hodnoty pre grafy kormidla pre každé prostredie, ale čo ak máme popísaných niekoľko prostredí a chceme napríklad nastaviť rovnaké pre všetky affinity, ale nechceme ho predvolene konfigurovať v samotných grafoch, ktoré sú uložené v okrúhlici.

V tomto prípade by sme pre každé vydanie mohli špecifikovať 2 súbory s hodnotami: prvý s predvolenými hodnotami, ktoré určia hodnoty samotného grafu, a druhý s hodnotami pre prostredie, ktoré zase prepíšu predvolené.

    .
    ├── 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"

Definovanie globálnych hodnôt pre tabuľky kormidla všetkých vydaní na úrovni prostredia

Povedzme, že vytvoríme niekoľko vstupov v niekoľkých vydaniach – mohli by sme manuálne definovať každý graf hosts:, ale v našom prípade je doména rovnaká, tak prečo ju nevložiť do nejakej globálnej premennej a jednoducho nedosadiť jej hodnotu do grafov? Aby to bolo možné, súbory s hodnotami, ktoré chceme parametrizovať, budú musieť mať príponu .gotmpl, aby helmfile vedel, že ho treba spustiť cez nástroj šablón.

    .
    ├── 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 }}

Poznámka

Je zrejmé, že ingress v grafe postgres je niečo mimoriadne pochybné, takže tento článok je uvedený jednoducho ako sférický príklad vo vzduchoprázdne, aby sa do článku nezaviedlo nejaké nové vydanie len kvôli opisu vstupu.

Nahradenie tajomstiev z hodnôt prostredia

Analogicky s vyššie uvedeným príkladom môžete nahradiť šifrované pomocou tajomstvá kormidla významy. Namiesto vytvárania vlastného súboru tajomstiev pre každé vydanie, v ktorom môžeme definovať zašifrované hodnoty pre graf, môžeme jednoducho definovať vo vydaní default.yaml.gotmpl hodnoty, ktoré budú prevzaté z premenných definovaných na úroveň prostredia. A hodnoty, ktoré nemusíme pred nikým skrývať, sa dajú jednoducho predefinovať v hodnotách vydania v konkrétnom prostredí.

    .
    ├── 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

Poznámka

Mimochodom, getOrNil - špeciálna funkcia pre go šablóny v helmfile, ktorá aj keby .Values.secrets nebude existovať, nevyhodí chybu, ale umožní výsledok pomocou funkcie default nahradiť predvolenú hodnotu

Záver

Popísané veci sa zdajú byť celkom zrejmé, ale informácií o vhodnom popise nasadenia do niekoľkých prostredí pomocou súboru helmfile je veľmi vzácne a milujem IaC (Infrastructure-as-Code) a chcem mať jasný popis stavu nasadenia.

Na záver by som rád dodal, že premenné pre predvolené prostredie je zase možné parametrizovať s premennými prostredia OS určitého bežca, z ktorého bude nasadenie spúšťané, a tak získať dynamické prostredia

helmfile.yaml

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

Zdroj: hab.com

Pridať komentár