Organisering af udrulning til flere k8s-miljøer ved hjælp af helmfile

Helmfile - indpakning til ror, som giver dig mulighed for at beskrive mange rorudgivelser på ét sted, parametrere deres diagrammer for flere miljøer og også indstille rækkefølgen for deres implementering.

Du kan læse om selve helmfile og eksempler på dens brug i readme и guide til bedste praksis.

Vi vil stifte bekendtskab med ikke-oplagte måder at beskrive udgivelser på i helmfile

Lad os sige, at vi har en pakke rordiagrammer (lad os f.eks. sige postgres og en eller anden backend-applikation) og flere miljøer (flere kubernetes-klynger, flere navneområder eller flere af begge). Vi tager roret, læser dokumentationen og begynder at beskrive vores miljøer og udgivelser:

    .
    ├── 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 med 2 miljøer: devel, produktion - hver indeholder sine egne værdier for rorudgivelsesdiagrammerne. Vi vil implementere dem på denne måde:

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

Forskellige versioner af styrekort i forskellige miljøer

Hvad hvis vi skal udrulle forskellige versioner af backend til forskellige miljøer? Hvordan parametreres udgivelsesversionen? De miljøværdier, der er tilgængelige gennem {{ .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 }}
...

Forskelligt sæt applikationer i forskellige miljøer

Fantastisk, men hvad nu hvis vi ikke har brug for det production rulle postgres ud, fordi vi ved, at vi ikke behøver at skubbe databasen ind i k8s, og til salg har vi en vidunderlig separat postgres-klynge? For at løse dette problem har vi etiketter

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

Det er fantastisk, men personligt foretrækker jeg at beskrive, hvilke applikationer der skal installeres i miljøet, ikke ved at bruge startargumenter, men i beskrivelsen af ​​selve miljøerne. Hvad skal man gøre? Du kan placere udgivelsesbeskrivelserne i en separat mappe, oprette en liste over de nødvendige udgivelser i miljøbeskrivelsen og kun "hente" de nødvendige udgivelser 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

Noten

Ved brug af bases: det er nødvendigt at bruge yaml separator ---, så du kan skabelonudgivelser (og andre dele, såsom helmDefaults) med værdier fra miljøer

I dette tilfælde vil postgres-udgivelsen ikke engang være inkluderet i beskrivelsen til produktion. Meget behageligt!

Tilsidesættelige globale værdier for udgivelser

Det er selvfølgelig fantastisk, at du kan indstille værdier for rordiagrammer for hvert miljø, men hvad nu hvis vi har flere miljøer beskrevet, og vi f.eks. vil sætte det samme for alle affinity, men vi ønsker ikke at konfigurere det som standard i selve diagrammerne, som er gemt i majroer.

I dette tilfælde kunne vi for hver udgivelse specificere 2 filer med værdier: den første med standardværdier, som bestemmer selve diagrammets værdier, og den anden med værdier for miljøet, som igen vil tilsidesætte 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"

Definition af globale værdier for rordiagrammer over alle udgivelser på miljøniveau

Lad os sige, at vi opretter flere indgange i flere udgivelser - vi kunne manuelt definere for hvert diagram hosts:, men i vores tilfælde er domænet det samme, så hvorfor ikke sætte det i en global variabel og blot erstatte dens værdi i diagrammerne? For at gøre dette skal de filer med værdier, som vi vil parametrere, have udvidelsen .gotmpl, så den helmfile ved, at den skal køres gennem skabelonmotoren.

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

Noten

Det er klart, at indtrængen i postgres-diagrammet er noget ekstremt tvivlsomt, så denne artikel er blot givet som et sfærisk eksempel i et vakuum og for ikke at introducere en ny udgivelse i artiklen bare for at beskrive indtrængen

Erstatning af hemmeligheder fra miljøværdier

I analogi med ovenstående eksempel kan du erstatte krypterede ved hjælp af ror hemmeligheder betydninger. I stedet for at oprette vores egen hemmelighedsfil for hver udgivelse, hvor vi kan definere krypterede værdier for diagrammet, kan vi blot definere i udgivelsen default.yaml.gotmpl de værdier, der vil blive taget fra variablerne defineret ved miljøniveau. Og de værdier, som vi ikke behøver at skjule for nogen, kan nemt omdefineres i udgivelsesværdierne i et specifikt 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

Noten

Af den måde, getOrNil - en speciel funktion til go skabeloner i helmfile, som, selvom .Values.secrets vil ikke eksistere, vil ikke give en fejl, men vil tillade resultatet ved hjælp af funktionen default erstatte standardværdi

Konklusion

De beskrevne ting virker ret indlysende, men information om en bekvem beskrivelse af udrulning til flere miljøer ved hjælp af helmfile er meget sparsom, og jeg elsker IaC (Infrastructure-as-Code) og vil gerne have en klar beskrivelse af implementeringstilstanden.

Afslutningsvis vil jeg tilføje, at variablerne for standardmiljøet til gengæld kan parametreres med miljøvariablerne i operativsystemet for en bestemt løber, hvorfra udrulningen vil blive lanceret, og dermed opnå dynamiske miljøer

helmfile.yaml

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

Kilde: www.habr.com

Tilføj en kommentar