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

Helmfile — je obal pre helm, ktorý umožňuje na jednom mieste popísať množstvo helm vydaní, parametrizovať ich schémy pre rôzne prostredia a určiť poradie ich nasadenia.

O samotnom helmfile a príkladoch jeho využitia si môžete prečítať v readme a návode na najlepšie praktiky.

My si predstavíme menej zrejmé spôsoby, ako opísať vydania v helmfile

Predpokladajme, že máme balík helm schém (pre príklad to môže byť postgres a nejaká backend aplikácia) a niekoľko prostredí (niekoľko kubernetes klastrov, niekoľko namespace’ov alebo niečo z toho). Berieme helmfile, čítame dokumentáciu a začíname opísať naše prostredia a vydania:

    .
    ├── envs
    │   ├── devel
    │   │   └── values
    │   │       ├── backend.yaml
    │   │       └── postgres.yaml
    │   └── production
    │       └── values
    │           ├── backend.yaml
    │           └── postgres.yaml
    └── helmfile.yaml

helmfile.yaml

prostredia:
  devel:
  production:

vydania:
  - názov: postgres
    štítky:
      app: postgres
    čakaj: true
    schéma: stable/postgresql
    verzia: 8.4.0
    hodnoty:
      - envs/{{ .Environment.Name }}/values/postgres.yaml
  - názov: backend
    štítky:
      app: backend
    čakaj: true
    schéma: private-helm-repo/backend
    verzia: 1.0.5
    potrebuje:
      - postgres
    hodnoty:
      - envs/{{ .Environment.Name }}/values/backend.yaml

Máme 2 prostredia: devel, produkciu — v každom sa nachádzajú svoje hodnoty pre helm schémy vydaní. Budeme ich nasadzovať takto:

helmfile -n  -e  apply

Rôzne verzie helm schém v rôznych prostrediach

Čo robiť, ak potrebujeme nasádzať rôzne verzie backendu do rôznych prostredí? Ako parametrizovať verziu vydania? Na pomoc prichádzajú hodnoty prostredia, dostupné prostredníctvom {{ .Values }}

helmfile.yaml

prostredia:
  devel:
+   hodnoty:
+   - schémy:
+       verzie:
+         backend: 1.1.0
  production:
+   hodnoty:
+   - schémy:
+       verzie:
+         backend: 1.0.5
...
  - názov: backend
    štítky:
      app: backend
    čakaj: true
    schéma: private-helm-repo/backend
-   verzia: 1.0.5
+   verzia: {{ .Values.charts.versions.backend }}
...

Rôzny súbor aplikácií v rôznych prostrediach

Výborne, ale čo ak nepotrebujeme produkciu nasadiť postgres, pretože vieme, že databázu netreba nasadzovať do k8s a pre produkciu máme výborný samostatný klaster postgres? Na riešenie tohto problému máme štítky (labels)

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

To je skvelé, ale osobne radšej opíšem, aké aplikácie nasadzovať v prostredí nie pomocou argumentov spustenia, ale v opise samotných prostredí. Čo robiť? Môžete umiestniť popis vydania do samostatnej složky, v opise prostredia vytvoriť zoznam potrebných vydaní a "pripojiť" iba potrebné vydania, pričom ignorujete ostatné.

    .
    ├── 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žívaní bases: je potrebné nevyhnutne použiť yaml oddelovač ---, aby bolo možné šablonizovať releases (a ostatné časti, ako helmDefaults) hodnotami z environments

V takom prípade release postgres ani nepríde do opisu pre production. Veľmi pohodlné!

Predefinovateľné globálne hodnoty pre releases

Samozrejme, je skvelé, že pre každé prostredie môžete nastaviť hodnoty pre helm čarty, ale čo ak máme opísaných niekoľko prostredí a chceme, povedzme, nastaviť rovnaký pre všetky affinity, ale nechceme ho nastaviť predvolene v samotných čartoch, ktoré sú uložené v repozitároch.

V takom prípade by sme pre každé vydanie mohli nastaviť 2 súbory s values: prvý s predvolenými hodnotami, ktoré budú definovať hodnoty samotného čartu, a druhý s hodnotami pre prostredie, ktorý potom už bude predefinovávať 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 helm grafy všetkých vydaní na úrovni prostredia

Predpokladajme, že v niekoľkých vydaniach vytvárame niekoľko ingress — mohli by sme manuálne pre každý graf určiť hosts:, ale v našom prípade je doména rovnaká, prečo by sme ju nemohli vytiahnuť do nejakej globálnej premennej a jednoducho jej hodnotu vgrafoch vložiť? Na to musia mať súbory s hodnotami, ktoré chceme parametrizovať, príponu .gotmpl, aby helmfile vedel, že ich má spracovať cez šablónovač.

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

Jasné je, že ingress v grafe postgres je niečo mimoriadne pochybné, preto je v článku uvedené len ako sférový príklad vo vákuu a na to, aby sa do článku nezavádzal nejaký nový release len kvôli opisu ingress.

Nahradenie tajomstiev (secrets) hodnotami z prostredia.

Podľa vyššie uvedeného príkladu je možné nahrádzať aj hodnoty šifrované pomocou. helm secrets. Namiesto toho, aby sme pre každý release vytvárali vlastný súbor secrets, v ktorom určujeme zašifrované hodnoty pre chart, môžeme jednoducho definovať v releasovom default.yaml.gotmpl hodnoty, ktoré sa budú získavať z premenných definovaných na úrovni prostredí. A hodnoty, ktoré nechceme nijako skrývať, môžeme už pokojne predefinovať v hodnotách releasu 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 keď. .Values.secrets neexistuje, nevyhodí chybu, ale umožní vďaka funkcii. default nahradiť hodnotu podľa predvolených nastavení.

Záver

Popisované veci sa zdajú byť celkom zrejmé, ale informácie o pohodlnom popise nasadenia do viacerých prostredí pomocou helmfile sú veľmi obmedzené, a ja mám rád IaC (Infrastructure-as-Code) a chcem mať jasný popis stavu nasadenia.

Na záver chcem dodať, že premenné pre prostredie default je možné parametrize premennými prostredia OS nejakého runnera, z ktorého sa bude spúšťať nasadenie, a takto získať dynamické prostredia.

helmfile.yaml

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

Zdroj: habr.com

Kúpte si spoľahlivý hosting pre webové stránky s ochranou proti DDoS, VPS VDS servery 🔥 Kúpte si spoľahlivý hosting pre webové stránky s ochranou proti DDoS, VPS VDS servery | ProHoster