Organizace nasazení do více prostředí k8s pomocí helmfile

Helmfile - obal pro kormidlo, který umožňuje popsat mnoho releasů kormidla na jednom místě, parametrizovat jejich grafy pro několik prostředí a také nastavit pořadí jejich nasazení.

Můžete si přečíst o samotném helmfile a příkladech jeho použití v readme и průvodce osvědčenými postupy.

Seznámíme se s nesrozumitelnými způsoby popisu vydání v helmfile

Řekněme, že máme balíček grafů kormidla (například řekněme postgres a nějakou backendovou aplikaci) a několik prostředí (několik klastrů kubernetes, několik jmenných prostorů nebo několik obojího). Vezmeme soubor helmfile, přečteme si dokumentaci a začneme popisovat naše prostředí a verze:

    .
    ├── 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 jsme se 2 prostředími: devel, výroba — každý obsahuje své vlastní hodnoty pro tabulky uvolnění kormidla. Nasadíme je takto:

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

Různé verze tabulek kormidla v různých prostředích

Co když potřebujeme zavést různé verze backendu do různých prostředí? Jak parametrizovat verzi vydání? Environmentální hodnoty dostupné prostřednictvím {{ .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ůzné sady aplikací v různých prostředích

Skvělé, ale co když to nepotřebujeme production zavést postgres, protože víme, že nepotřebujeme tlačit databázi do k8 a na prodej máme úžasný samostatný postgres cluster? K vyřešení tohoto problému máme štítky

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

To je skvělé, ale osobně raději popisuji, které aplikace nasadit do prostředí ne pomocí argumentů launch, ale v popisu prostředí samotných. Co dělat? Popisy vydání můžete umístit do samostatné složky, vytvořit seznam nezbytných vydání v popisu prostředí a „vyzvednout“ pouze nezbytná vydání, ostatní ignorovat

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

Při použití bases: je nutné použít oddělovač yaml ---, takže můžete šablonovat vydání (a další části, jako je helmDefaults) s hodnotami z prostředí

V tomto případě nebude postgres release ani zahrnut do popisu pro výrobu. Velmi pohodlně!

Přepsatelné globální hodnoty pro vydání

Samozřejmě je skvělé, že můžete nastavit hodnoty pro grafy kormidel pro každé prostředí, ale co když máme popsáno několik prostředí a chceme například nastavit stejné pro všechna affinity, ale nechceme jej konfigurovat standardně v samotných grafech, které jsou uloženy v tuřínech.

V tomto případě bychom pro každé vydání mohli zadat 2 soubory s hodnotami: první s výchozími hodnotami, které budou určovat hodnoty samotného grafu, a druhý s hodnotami pro prostředí, které zase přepíší výchozí.

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

Definování globálních hodnot pro grafy kormidla všech verzí na úrovni prostředí

Řekněme, že vytvoříme několik vstupů v několika verzích - mohli bychom ručně definovat pro každý graf hosts:, ale v našem případě je doména stejná, tak proč ji nevložit do nějaké globální proměnné a její hodnotu jednoduše nedosadit do grafů? Chcete-li to provést, soubory s hodnotami, které chceme parametrizovat, budou muset mít příponu .gotmpl, takže helmfile ví, že je třeba jej spustit přes šablonový engine.

    .
    ├── 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 zřejmé, že ingress v grafu postgres je něco extrémně pochybného, ​​takže tento článek je uveden jednoduše jako sférický příklad ve vzduchoprázdnu a abychom do článku nezavedli nějaké nové vydání jen kvůli popisu vniknutí.

Nahrazení tajemství z hodnot prostředí

Analogicky s výše uvedeným příkladem můžete nahradit šifrované pomocí tajemství kormidla významy. Namísto vytváření vlastního souboru tajných informací pro každé vydání, ve kterém můžeme definovat zašifrované hodnoty pro graf, můžeme jednoduše definovat ve verzi default.yaml.gotmpl hodnoty, které budou převzaty z proměnných definovaných na úroveň prostředí. A hodnoty, které nepotřebujeme před nikým skrývat, lze snadno předefinovat v hodnotách vydání v konkrétním prostředí.

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

Mimochodem, getOrNil - speciální funkce pro go šablony v helmfile, která, i když .Values.secrets nebude existovat, nevyhodí chybu, ale umožní výsledek pomocí funkce default nahradit výchozí hodnotu

Závěr

Popsané věci se zdají být zcela zřejmé, ale informací o pohodlném popisu nasazení do několika prostředí pomocí helmfile je velmi vzácné a miluji IaC (Infrastructure-as-Code) a chci mít jasný popis stavu nasazení.

Na závěr bych rád dodal, že proměnné pro výchozí prostředí lze naopak parametrizovat s proměnnými prostředí OS určitého běžce, ze kterého bude nasazení spouštěno, a získat tak dynamická prostředí

helmfile.yaml

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

Zdroj: www.habr.com

Přidat komentář