Organisation du déploiement dans plusieurs environnements k8s à l'aide de helmfile

Helmfile — un wrapper pour helm, qui permet de dĂ©crire plusieurs releases helm Ă  un seul endroit, de paramĂ©trer leurs charts pour diffĂ©rents environnements, et de spĂ©cifier l'ordre de leur dĂ©ploiement.

Pour en savoir plus sur helmfile et des exemples d'utilisation, vous pouvez consulter le readme et guide des meilleures pratiques.

Nous allons explorer des méthodes peu évidentes pour décrire les releases dans helmfile.

Supposons que nous avons un ensemble de charts helm (pour l'exemple, prenons postgres et une application backend) et plusieurs environnements (plusieurs clusters kubernetes, plusieurs namespaces ou un mélange des deux). Nous prenons helmfile, lisons la documentation et commençons à décrire nos environnements et releases :

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

Nous avons créé 2 environnements : devel, production — chacun possĂšde ses propres valeurs pour les charts helm des releases. Nous allons les dĂ©ployer ainsi :

helmfile -n  -e  apply

Différentes versions des charts helm dans différents environnements

Que faire si nous devons déployer différentes versions du backend dans différents environnements ? Comment paramétrer la version de la release ? Les valeurs d'environnement accessibles via {{ .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 }}
...

Un ensemble d'applications différent dans différents environnements

Excellent, mais que se passe-t-il si nous ne voulons pas production déployer postgres, parce que nous savons qu'il n'est pas nécessaire d'inclure une base de données dans k8s et que pour la production, nous avons un superbe cluster postgres séparé ? Pour résoudre ce problÚme, nous avons des labels

helmfile -n  -e devel apply
helmfile -n  -e production -l app=backend apply

C'est super, mais personnellement, je prĂ©fĂšre dĂ©crire quelles applications dĂ©ployer dans un environnement non pas avec des arguments de ligne de commande, mais dans la description des environnements eux-mĂȘmes. Que faire ? On peut placer la description des releases dans un dossier sĂ©parĂ©, dans la description de l'environnement crĂ©er une liste des releases nĂ©cessaires et "accrocher" uniquement les releases requises, en ignorant les autres.

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

Note

Lorsque vous utilisez bases: il est impératif d'utiliser le séparateur yaml ---, afin de pouvoir modéliser les releases (et d'autres parties, comme helmDefaults) avec des valeurs provenant des environments

Dans ce cas, la release postgres ne sera mĂȘme pas incluse dans la description pour production. TrĂšs pratique !

Valeurs globales redéfinissables pour les releases

Bien sĂ»r, c'est super que l'on puisse dĂ©finir des valeurs pour les charts helm pour chaque environnement, mais que faire si plusieurs environnements sont dĂ©crits et que l'on souhaite, par exemple, dĂ©finir une valeur commune Ă  tous affinity, mais que l'on ne souhaite pas la configurer par dĂ©faut dans les charts eux-mĂȘmes, qui sont stockĂ©s dans les dĂ©pĂŽts.

Dans ce cas, nous pourrions pour chaque release dĂ©finir 2 fichiers avec des valeurs : le premier avec les valeurs par dĂ©faut, qui dĂ©termineront les valeurs du chart lui-mĂȘme, et le second avec les valeurs pour l'environnement, qui Ă  son tour remplace dĂ©jĂ  les valeurs par dĂ©faut.

    .
    ├── envs
+   │   ├── dĂ©faut
+   │   │   └── valeurs
+   │   │       ├── backend.yaml
+   │   │       └── postgres.yaml
    │   ├── dĂ©veloppement
    │   │   └── valeurs
    │   │       ├── backend.yaml
    │   │       └── postgres.yaml
    │   └── production
    │       └── valeurs
    │           ├── 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/valeurs/backend.yaml
      - envs/{{ .Environment.Name }}/valeurs/backend.yaml

envs/default/valeurs/backend.yaml

affinité:
  podAntiAffinity:
    preferredDuringSchedulingIgnoredDuringExecution:
    - weight: 1
      podAffinityTerm:
        labelSelector:
          matchExpressions:
          - key: app.kubernetes.io/name
            operator: In
            values:
            - backend
        topologyKey: "kubernetes.io/hostname"

Définition des valeurs globales pour les charts helm de tous les releases au niveau de l'environnement

Supposons que plusieurs releases crĂ©ent plusieurs ingress — nous pourrions dĂ©finir manuellement pour chaque chart hosts:, mais dans notre cas, le domaine est le mĂȘme, alors pourquoi ne pas le dĂ©placer dans une variable globale et simplement substituer sa valeur dans les charts ? Pour cela, les fichiers avec les valeurs que nous souhaitons paramĂ©trer devront avoir l'extension .gotmpl, afin que helmfile sache qu'il doit passer par le moteur de templates.

    .
    ├── envs
    │   ├── dĂ©faut
    │   │   └── valeurs
-   │   │       ├── backend.yaml
-   │   │       ├── postgres.yaml
+   │   │       ├── backend.yaml.gotmpl
+   │   │       └── postgres.yaml.gotmpl
    │   ├── dĂ©veloppement
    │   │   └── valeurs
    │   │       ├── backend.yaml
    │   │       └── postgres.yaml
    │   └── production
    │       └── valeurs
    │           ├── backend.yaml
    │           └── postgres.yaml
    ├── releases
    │   ├── backend.yaml
    │   └── postgres.yaml
    └── helmfile.yaml

helmfile.yaml

  environnements:
    développement:
      valeurs:
      - charts:
          versions:
            backend: 1.1.0
      - apps:
        - postgres
        - backend
+     - global:
+         ingressDomain: k8s.devel.domain

    production:
      valeurs:
      - charts:
          versions:
            backend: 1.0.5
      - apps:
        - backend
+     - global:
+         ingressDomain: production.domain
  ---
  bases:
  {{- range .Values.apps }}
    - releases/{{ . }}.yaml
  {{- end }}

envs/default/valeurs/backend.yaml.gotmpl

ingress:
  enabled: true
  paths:
    - /api
  hosts:
    - {{ .Values.global.ingressDomain }}

envs/default/valeurs/postgres.yaml.gotmpl

ingress:
  enabled: true
  paths:
    - /
  hosts:
    - postgres.{{ .Values.global.ingressDomain }}

Note

Il est évident que l'ingress dans le chart postgres est quelque chose de trÚs douteux, c'est pourquoi il est simplement cité dans l'article comme un exemple sphérique dans le vide et pour ne pas introduire une nouvelle version juste pour décrire l'ingress.

Substitution des secrets (secrets) Ă  partir des valeurs d'environnement.

De la mĂȘme maniĂšre que dans l'exemple ci-dessus, il est possible de substituer les valeurs chiffrĂ©es Ă  l'aide de helm secrets. Au lieu de crĂ©er un fichier secrets distinct pour chaque version, oĂč dĂ©finir les valeurs chiffrĂ©es pour le chart, nous pouvons simplement dĂ©finir dans le default.yaml.gotmpl de la version, les valeurs qui seront prises Ă  partir des variables dĂ©finies au niveau des environnements. Et les valeurs que nous ne devons pas cacher Ă  qui que ce soit peuvent ĂȘtre redĂ©finies dans les valeurs de la version dans un environnement spĂ©cifique.

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

Note

Au fait, getOrNil — une fonction spĂ©ciale pour les templates go dans helmfile, qui, mĂȘme si .Values.secrets n'existe pas, ne renverra pas d'erreur, mais permettra de substituer une valeur par dĂ©faut Ă  l'aide de la fonction default remplacer par la valeur par dĂ©faut

Conclusion

Les éléments décrits semblent assez évidents, mais les informations sur la maniÚre de décrire de maniÚre conviviale le déploiement dans plusieurs environnements à l'aide de helmfile sont trÚs limitées. J'aime l'IaC (Infrastructure-as-Code) et je veux avoir une description claire de l'état du déploiement.

En conclusion, je tiens Ă  ajouter que les variables pour l'environnement par dĂ©faut peuvent Ă©galement ĂȘtre paramĂ©trĂ©es par les variables d'environnement du systĂšme d'exploitation d'un certain runner Ă  partir duquel le dĂ©ploiement sera lancĂ©, et ainsi obtenir des environnements dynamiques.

helmfile.yaml

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

Source : habr.com

Acheter un hĂ©bergement fiable pour les sites avec protection DDoS, serveurs VPS VDS đŸ”„ Acheter un hĂ©bergement fiable pour les sites avec protection DDoS, serveurs VPS VDS | ProHoster