Organisering av distribusjon til flere k8s-miljøer ved hjelp av helmfile

Helmfile - innpakning for ror, som lar deg beskrive mange rorutgivelser på ett sted, parametrisere diagrammene deres for flere miljøer, og også angi rekkefølgen for deres utplassering.

Du kan lese om selve helmfile og eksempler på bruken i readme и guide for beste praksis.

Vi vil bli kjent med ikke-opplagte måter å beskrive utgivelser på i helmfile

La oss si at vi har en pakke med rordiagrammer (for eksempel, la oss si postgres og noen backend-applikasjoner) og flere miljøer (flere kubernetes-klynger, flere navneområder eller flere av begge). Vi tar styringen, leser dokumentasjonen og begynner å beskrive våre miljøer og utgivelser:

    .
    ├── 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 endte opp med 2 miljøer: utvikle, produksjon - hver inneholder sine egne verdier for rorutgivelseskartene. Vi vil distribuere til dem slik:

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

Ulike versjoner av rorkart i forskjellige miljøer

Hva om vi trenger å rulle ut forskjellige versjoner av backend til forskjellige miljøer? Hvordan parametrisere utgivelsesversjonen? Miljøverdiene tilgjengelig gjennom {{ .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 }}
...

Ulike sett med applikasjoner i forskjellige miljøer

Flott, men hva om vi ikke trenger det production rulle ut postgres, fordi vi vet at vi ikke trenger å presse databasen inn i k8s og for salg har vi en fantastisk egen postgres-klynge? For å løse dette problemet har vi etiketter

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

Dette er flott, men personlig foretrekker jeg å beskrive hvilke applikasjoner som skal distribueres i miljøet, ikke ved å bruke lanseringsargumenter, men i beskrivelsen av selve miljøene. Hva å gjøre? Du kan plassere utgivelsesbeskrivelsene i en egen mappe, lage en liste over nødvendige utgivelser i miljøbeskrivelsen og "hente" kun de nødvendige utgivelsene, og ignorere 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

Notatet

Ved bruk bases: det er nødvendig å bruke yaml separator ---, slik at du kan male utgivelser (og andre deler, for eksempel helmDefaults) med verdier fra miljøer

I dette tilfellet vil postgres-utgivelsen ikke en gang være inkludert i beskrivelsen for produksjon. Veldig komfortabelt!

Overstyrbare globale verdier for utgivelser

Selvfølgelig er det flott at du kan angi verdier for rorkart for hvert miljø, men hva om vi har flere miljøer beskrevet, og vi for eksempel ønsker å sette det samme for alle affinity, men vi ønsker ikke å konfigurere det som standard i selve diagrammene, som er lagret i neper.

I dette tilfellet kan vi spesifisere 2 filer med verdier for hver utgivelse: den første med standardverdier, som vil bestemme verdiene til selve diagrammet, og den andre med verdier for miljøet, som igjen vil overstyre 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"

Definerer globale verdier for rordiagrammer for alle utgivelser på miljønivå

La oss si at vi oppretter flere ingresser i flere utgivelser - vi kan definere manuelt for hvert diagram hosts:, men i vårt tilfelle er domenet det samme, så hvorfor ikke sette det inn i en global variabel og ganske enkelt erstatte dens verdi i diagrammene? For å gjøre dette, må de filene med verdier som vi vil parameterisere, ha utvidelsen .gotmpl, slik at helmfile vet at den må kjøres gjennom malmotoren.

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

Notatet

Åpenbart er ingress i postgres-diagrammet noe ekstremt tvilsomt, så denne artikkelen er gitt bare som et sfærisk eksempel i et vakuum og for ikke å introdusere en ny utgivelse i artikkelen bare for å beskrive ingress

Erstatter hemmeligheter fra miljøverdier

I analogi med eksemplet ovenfor kan du erstatte krypterte ved å bruke ror hemmeligheter betydninger. I stedet for å lage vår egen hemmelighetsfil for hver utgivelse, der vi kan definere krypterte verdier for diagrammet, kan vi ganske enkelt definere i utgivelsen default.yaml.gotmpl verdiene som vil bli hentet fra variablene definert på miljønivå. Og verdiene som vi ikke trenger å skjule for noen kan enkelt redefineres i utgivelsesverdiene i et spesifikt 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

Notatet

Forresten, getOrNil - en spesiell funksjon for go maler i helmfile, som, selv om .Values.secrets vil ikke eksistere, vil ikke gi en feil, men vil tillate resultatet ved å bruke funksjonen default erstatte standardverdi

Konklusjon

Tingene som beskrives virker ganske åpenbare, men informasjon om en praktisk beskrivelse av distribusjon til flere miljøer ved bruk av helmfile er svært knapp, og jeg elsker IaC (Infrastructure-as-Code) og ønsker å ha en klar beskrivelse av distribusjonstilstanden.

Avslutningsvis vil jeg legge til at variablene for standardmiljøet i sin tur kan parameteriseres med miljøvariablene til operativsystemet til en bestemt løper som distribusjonen vil bli lansert fra, og dermed oppnå dynamiske miljøer

helmfile.yaml

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

Kilde: www.habr.com

Legg til en kommentar