Organització del desplegament a diversos entorns k8s mitjançant helmfile

Helmfile - embolcall per a timó, que us permet descriure molts llançaments de timó en un sol lloc, parametritzar els seus gràfics per a diversos entorns i també establir l'ordre del seu desplegament.

Podeu llegir sobre el mateix helmfile i exemples del seu ús a readme и guia de bones pràctiques.

Ens familiaritzarem amb maneres no òbvies de descriure els llançaments a helmfile

Suposem que tenim un paquet de gràfics de timó (per exemple, diguem postgres i alguna aplicació de fons) i diversos entorns (diversos clústers de Kubernetes, diversos espais de noms o diversos d'ambdós). Agafem el fitxer helm, llegim la documentació i comencem a descriure els nostres entorns i versions:

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

Vam acabar amb 2 ambients: desenvolupar, producció — cadascun conté els seus propis valors per als gràfics de llançament del timó. Els distribuirem així:

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

Diferents versions de gràfics de timó en diferents entorns

Què passa si hem de desplegar diferents versions del backend a diferents entorns? Com parametritzar la versió de llançament? Els valors ambientals disponibles a través {{ .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 }}
...

Diferent conjunt d'aplicacions en diferents entorns

Genial, però què passa si no ens cal production llançar postgres, perquè sabem que no necessitem empènyer la base de dades a k8s i que tenim a la venda un meravellós clúster de postgres separat? Per resoldre aquest problema disposem d'etiquetes

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

Això és genial, però personalment prefereixo descriure quines aplicacions implementar a l'entorn no utilitzant arguments de llançament, sinó en la descripció dels propis entorns. Què fer? Podeu col·locar les descripcions de les versions en una carpeta separada, crear una llista de les versions necessàries a la descripció de l'entorn i "recollir" només les versions necessàries, ignorant la resta

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

La nota

Quan s'utilitza el bases: cal utilitzar el separador yaml ---, perquè pugueu modelar llançaments (i altres parts, com ara helmDefaults) amb valors dels entorns

En aquest cas, la versió de postgres ni tan sols s'inclourà a la descripció per a la producció. Molt còmodament!

Valors globals anul·lables per a versions

Per descomptat, és fantàstic que pugueu establir valors per als gràfics de timó per a cada entorn, però què passa si tenim diversos entorns descrits i volem, per exemple, establir el mateix per a tots? affinity, però no volem configurar-lo per defecte als mateixos gràfics, que s'emmagatzemen en naps.

En aquest cas, per a cada llançament podríem especificar 2 fitxers amb valors: el primer amb valors per defecte, que determinarà els valors del propi gràfic, i el segon amb valors per a l'entorn, que al seu torn anul·larà el els predeterminats.

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

Definició de valors globals per als gràfics de timó de tots els llançaments a nivell ambiental

Suposem que creem diverses entrades en diverses versions; podríem definir manualment per a cada gràfic hosts:, però en el nostre cas el domini és el mateix, per què no posar-lo en alguna variable global i simplement substituir el seu valor als gràfics? Per fer-ho, aquells fitxers amb valors que volem parametritzar hauran de tenir l'extensió .gotmpl, de manera que helmfile sàpiga que s'ha d'executar a través del motor de plantilles.

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

La nota

Òbviament, l'entrada al gràfic de postgres és una cosa extremadament dubtosa, de manera que aquest article es dóna simplement com a exemple esfèric al buit i per no introduir cap nou llançament a l'article només per descriure l'entrada.

Substituint els secrets dels valors ambientals

Per analogia amb l'exemple anterior, podeu substituir els xifrats utilitzant secrets del timó significats. En lloc de crear el nostre propi fitxer de secrets per a cada llançament, en el qual podem definir valors xifrats per al gràfic, simplement podem definir a la versió default.yaml.gotmpl els valors que es prendran de les variables definides a la nivell ambiental. I els valors que no hem d'ocultar a ningú es poden redefinir fàcilment en els valors de llançament en un entorn específic.

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

La nota

Per cert, getOrNil - una funció especial per a les plantilles de go a helmfile, que, encara que .Values.secrets no existirà, no generarà un error, però permetrà el resultat utilitzant la funció default substituir el valor predeterminat

Conclusió

Les coses descrites semblen força òbvies, però la informació sobre una descripció convenient del desplegament a diversos entorns que utilitzen helmfile és molt escassa, i m'encanta IaC (Infrastructure-as-Code) i vull tenir una descripció clara de l'estat de desplegament.

En conclusió, m'agradaria afegir que les variables de l'entorn predeterminat es poden, al seu torn, parametritzar amb les variables d'entorn del sistema operatiu d'un determinat corredor des del qual es llançarà el desplegament, i així obtenir entorns dinàmics.

helmfile.yaml

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

Font: www.habr.com

Afegeix comentari