Organisera distribution till flera k8s-miljöer med hjÀlp av helmfile

Helmfile - omslag för roder, som gör att du kan beskriva mÄnga rorslÀpp pÄ ett stÀlle, parametrisera deras diagram för flera miljöer och Àven stÀlla in ordningen för deras utplacering.

Du kan lÀsa om sjÀlva helmfile och exempel pÄ dess anvÀndning i readme О guide för bÀsta praxis.

Vi kommer att bekanta oss med icke-uppenbara sÀtt att beskriva releaser i helmfile

LÄt oss sÀga att vi har ett paket med styrdiagram (till exempel, lÄt oss sÀga postgres och nÄgon backend-applikation) och flera miljöer (flera kubernetes-kluster, flera namnomrÄden eller flera av bÄda). Vi tar rodret, lÀser dokumentationen och börjar beskriva vÄra miljöer och releaser:

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

Vi slutade med 2 miljöer: devel, produktion — var och en innehĂ„ller sina egna vĂ€rden för rodrets utlösningsdiagram. Vi kommer att distribuera till dem sĂ„ hĂ€r:

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

Olika versioner av styrdiagram i olika miljöer

Vad hÀnder om vi behöver rulla ut olika versioner av backend till olika miljöer? Hur parametriserar man releaseversionen? De miljövÀrden som finns tillgÀngliga genom {{ .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 }}
...

Olika applikationer i olika miljöer

Bra, men tÀnk om vi inte behöver production rulla ut postgres, eftersom vi vet att vi inte behöver skjuta in databasen i k8s och att vi har ett underbart separat postgres-kluster till salu? För att lösa detta problem har vi etiketter

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

Detta Àr bra, men personligen föredrar jag att beskriva vilka applikationer som ska distribueras i miljön, inte med hjÀlp av startargument, utan i beskrivningen av sjÀlva miljöerna. Vad ska man göra? Du kan placera utgivningsbeskrivningarna i en separat mapp, skapa en lista över nödvÀndiga utgÄvor i miljöbeskrivningen och "plocka upp" endast de nödvÀndiga utgÄvorna, ignorera resten

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

Anteckningen

NÀr du anvÀnder bases: det Àr nödvÀndigt att anvÀnda yaml separator ---, sÄ att du kan mallslÀpp (och andra delar, sÄsom helmDefaults) med vÀrden frÄn miljöer

I det hÀr fallet kommer postgres-releasen inte ens att ingÄ i beskrivningen för produktion. Mycket bekvÀmt!

ÅsidosĂ€ttbara globala vĂ€rden för releaser

Naturligtvis Àr det bra att du kan stÀlla in vÀrden för styrdiagram för varje miljö, men tÀnk om vi har flera miljöer beskrivna, och vi vill till exempel stÀlla samma för alla affinity, men vi vill inte konfigurera det som standard i sjÀlva diagrammen, som lagras i rovor.

I det hÀr fallet kan vi för varje utgÄva specificera 2 filer med vÀrden: den första med standardvÀrden, som kommer att bestÀmma vÀrdena för sjÀlva diagrammet, och den andra med vÀrden för miljön, som i sin tur kommer att ÄsidosÀtta standard.

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

Definierar globala vÀrden för styrdiagram över alla utgÄvor pÄ miljönivÄ

LÄt oss sÀga att vi skapar flera ingÄngar i flera utgÄvor - vi skulle kunna definiera manuellt för varje diagram hosts:, men i vÄrt fall Àr domÀnen densamma, sÄ varför inte lÀgga den i nÄgon global variabel och helt enkelt ersÀtta dess vÀrde i diagrammen? För att göra detta mÄste de filer med vÀrden som vi vill parametrisera ha tillÀgget .gotmpl, sÄ att helmfile vet att den mÄste köras genom mallmotorn.

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

Anteckningen

Uppenbarligen Àr ingress i postgres-diagrammet nÄgot extremt tveksamt, sÄ den hÀr artikeln ges helt enkelt som ett sfÀriskt exempel i ett vakuum och för att inte introducera nÄgon ny version i artikeln bara för att beskriva ingressen

ErsÀtter hemligheter frÄn miljövÀrden

I analogi med exemplet ovan kan du ersÀtta krypterade med hjÀlp av rodrets hemligheter betydelser. IstÀllet för att skapa vÄr egen hemlighetsfil för varje utgÄva, dÀr vi kan definiera krypterade vÀrden för diagrammet, kan vi helt enkelt definiera i utgÄvan default.yaml.gotmpl vÀrdena som kommer att tas frÄn variablerna som definieras vid miljönivÄ. Och de vÀrden som vi inte behöver dölja för nÄgon kan enkelt omdefinieras i releasevÀrdena i en specifik miljö.

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

Anteckningen

Förresten, getOrNil - en speciell funktion för go-mallar i helmfile, som Àven om .Values.secrets kommer inte att existera, kommer inte att ge ett fel, men kommer att tillÄta resultatet med funktionen default ersÀtt standardvÀrde

Slutsats

De saker som beskrivs verkar ganska sjÀlvklara, men information om en bekvÀm beskrivning av utplacering till flera miljöer med hjÀlp av helmfile Àr mycket knapphÀndig, och jag Àlskar IaC (Infrastructure-as-Code) och vill ha en tydlig beskrivning av driftsÀttningstillstÄndet.

Avslutningsvis skulle jag vilja tillÀgga att variablerna för standardmiljön i sin tur kan parametriseras med miljövariablerna för operativsystemet för en viss löpare frÄn vilken distributionen kommer att startas, och pÄ sÄ sÀtt erhÄlla dynamiska miljöer

helmfile.yaml

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

KĂ€lla: will.com

LĂ€gg en kommentar