Organiziranje uvajanja v več okolij k8s z uporabo helmfile

Helmfile - ovoj za helm, ki vam omogoča, da na enem mestu opišete številne izdaje krmilnika, parametrirate njihove grafikone za več okolij in tudi nastavite vrstni red njihove umestitve.

O sami datoteki helmfile in primerih njene uporabe lahko preberete v readme и vodnik najboljših praks.

Seznanili se bomo z neočitnimi načini opisovanja izdaj v datoteki helmfile

Recimo, da imamo paket krmilnih grafikonov (na primer postgres in nekaj zaledne aplikacije) in več okolij (več gruč kubernetes, več imenskih prostorov ali več obojega). Vzamemo datoteko helm, preberemo dokumentacijo in začnemo opisovati naša okolja in izdaje:

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

Na koncu smo imeli 2 okolji: razviti, proizvodnja — vsaka vsebuje svoje vrednosti za tabele sprostitve krmila. Namestili jih bomo takole:

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

Različne različice krmilnih kart v različnih okoljih

Kaj pa, če moramo uvesti različne različice ozadja v različna okolja? Kako parametrirati različico izdaje? Okoljske vrednosti, ki so na voljo prek {{ .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 }}
...

Različen nabor aplikacij v različnih okoljih

Super, a kaj, ko nam ni treba production uvesti postgres, ker vemo, da nam baze podatkov ni treba potisniti v k8s in da imamo za prodajo čudovito ločeno gručo postgres? Za rešitev te težave imamo na voljo oznake

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

To je super, vendar osebno raje opišem, katere aplikacije namestiti v okolju, ne z uporabo argumentov za zagon, ampak v opisu samih okolij. Kaj storiti? Opise izdaj lahko postavite v ločeno mapo, v opisu okolja ustvarite seznam potrebnih izdaj in »poberete« samo potrebne izpuste, ostale pa zanemarite.

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

Opomba

Pri uporabi bases: potrebno je uporabiti yaml separator ---, tako da lahko oblikujete predloge za izdaje (in druge dele, kot je helmDefaults) z vrednostmi iz okolij

V tem primeru izdaja postgres sploh ne bo vključena v opis za proizvodnjo. Zelo udobno!

Preglasljive globalne vrednosti za izdaje

Seveda je super, da lahko nastavite vrednosti za krmilne karte za vsako okolje, a kaj ko imamo opisanih več okolij in želimo na primer za vsa nastaviti enako affinity, vendar ga ne želimo privzeto konfigurirati v samih grafikonih, ki so shranjeni v repi.

V tem primeru bi lahko za vsako izdajo določili 2 datoteki z vrednostmi: prvo s privzetimi vrednostmi, ki bodo določile vrednosti samega grafikona, in drugo z vrednostmi za okolje, ki bodo preglasile privzete.

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

Določitev globalnih vrednosti za krmilne karte vseh izdaj na ravni okolja

Recimo, da ustvarimo več vhodov v več izdajah - lahko ročno določimo za vsak grafikon hosts:, toda v našem primeru je domena enaka, zakaj je torej ne bi dali v neko globalno spremenljivko in njene vrednosti preprosto nadomestili v grafikone? Da bi to naredili, morajo imeti tiste datoteke z vrednostmi, ki jih želimo parametrizirati, končnico .gotmpl, tako da datoteka helmfile ve, da jo je treba zagnati prek mehanizma predloge.

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

Opomba

Očitno je vstopanje v postgres grafikon nekaj zelo dvomljivega, zato je ta članek podan zgolj kot sferični primer v vakuumu in zato, da ne bi v članek vnesli kakšne nove izdaje samo zaradi opisa vstopanja

Nadomeščanje skrivnosti iz vrednot okolja

Po analogiji z zgornjim primerom lahko šifrirane nadomestite z uporabo krmilne skrivnosti pomeni. Namesto ustvarjanja lastne skrivnostne datoteke za vsako izdajo, v kateri lahko definiramo šifrirane vrednosti za grafikon, lahko v izdaji default.yaml.gotmpl preprosto definiramo vrednosti, ki bodo vzete iz spremenljivk, definiranih na ravni okolja. In vrednosti, ki nam jih ni treba skrivati ​​pred nikomer, je mogoče enostavno na novo definirati v vrednostih izdaje v določenem okolju.

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

Opomba

Mimogrede, getOrNil - posebna funkcija za predloge go v helmfile, ki, tudi če .Values.secrets ne bo obstajal, ne bo povzročil napake, vendar bo dovolil rezultat z uporabo funkcije default nadomestna privzeta vrednost

Zaključek

Opisane stvari se zdijo povsem očitne, vendar so informacije o priročnem opisu uvajanja v več okoljih z uporabo datoteke helmfile zelo redke in obožujem IaC (Infrastructure-as-Code) in želim imeti jasen opis stanja uvajanja.

Na koncu bi rad dodal, da lahko spremenljivke za privzeto okolje parametriramo s spremenljivkami okolja OS določenega tekača, iz katerega se bo zagnala uvedba, in tako pridobimo dinamična okolja

helmfile.yaml

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

Vir: www.habr.com

Dodaj komentar