Организиране на внедряване в множество k8s среди с помощта на helmfile

Helmfile - обвивка за шлем, което ви позволява да опишете много издания на хелм на едно място, да параметризирате техните диаграми за няколко среди и също така да зададете реда на тяхното внедряване.

Можете да прочетете за самия helmfile и примери за използването му в чета и ръководство за най-добри практики.

Ще се запознаем с неочевидни начини за описание на версии в helmfile

Да кажем, че имаме пакет от хелм диаграми (например, да кажем postgres и някакво бекенд приложение) и няколко среди (няколко клъстера kubernetes, няколко пространства от имена или няколко от двете). Взимаме helmfile, четем документацията и започваме да описваме нашите среди и версии:

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

В крайна сметка получихме 2 среди: развивам, производство — всеки съдържа свои собствени стойности за диаграмите за освобождаване на кормилото. Ще ги внедрим по следния начин:

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

Различни версии на диаграми за кормила в различни среди

Какво ще стане, ако трябва да внедрим различни версии на бекенда в различни среди? Как да параметризирам версията на изданието? Екологичните стойности, достъпни чрез {{ .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 }}
...

Различен набор от приложения в различни среди

Чудесно, но какво ще стане, ако не ни трябва production разгръщане на postgres, защото знаем, че не е нужно да натискаме базата данни в k8s и за продажба имаме чудесен отделен postgres клъстер? За да разрешим този проблем, имаме етикети

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

Това е страхотно, но лично аз предпочитам да опиша кои приложения да се разположат в средата, без да използвам аргументи за стартиране, а в описанието на самите среди. Какво да правя? Можете да поставите описанията на версиите в отделна папка, да създадете списък с необходимите версии в описанието на средата и да „вземете“ само необходимите версии, като игнорирате останалите

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

Бележката

При използване на bases: необходимо е да използвате разделител yaml ---, така че да можете да шаблонирате издания (и други части, като helmDefaults) със стойности от среди

В този случай версията на postgres дори няма да бъде включена в описанието за производство. Много удобно!

Заменими глобални стойности за издания

Разбира се, страхотно е, че можете да зададете стойности за диаграми на кормилото за всяка среда, но какво ще стане, ако имаме няколко описани среди и искаме, например, да зададем еднакви за всички affinity, но не искаме да го конфигурираме по подразбиране в самите диаграми, които се съхраняват в ряпа.

В този случай за всяка версия можем да посочим 2 файла със стойности: първият със стойности по подразбиране, които ще определят стойностите на самата диаграма, а вторият със стойности за средата, които от своя страна ще заменят такива по подразбиране.

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

Дефиниране на глобални стойности за диаграми на кормилото на всички версии на ниво среда

Да кажем, че създаваме няколко входа в няколко издания - можем да дефинираме ръчно за всяка диаграма hosts:, но в нашия случай домейнът е същият, така че защо да не го поставим в някаква глобална променлива и просто да заменим стойността му в диаграмите? За да направите това, тези файлове със стойности, които искаме да параметризираме, ще трябва да имат разширение .gotmpl, така че helmfile да знае, че трябва да бъде стартиран през машината за шаблони.

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

Бележката

Очевидно ingress в диаграмата на postgres е нещо изключително съмнително, така че тази статия е дадена просто като сферичен пример във вакуум и за да не се въведе някакво ново издание в статията само заради описанието на ingress

Замяна на тайни от ценностите на околната среда

По аналогия с горния пример, можете да замените криптирани, като използвате тайни на кормилото значения. Вместо да създаваме наш собствен тайен файл за всяка версия, в който можем да дефинираме криптирани стойности за диаграмата, можем просто да дефинираме в версията default.yaml.gotmpl стойностите, които ще бъдат взети от променливите, дефинирани в ниво на околната среда. И стойностите, които не е нужно да крием от никого, могат лесно да бъдат предефинирани в стойностите на изданието в конкретна среда.

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

Бележката

Между другото, getOrNil - специална функция за go шаблони в helmfile, която, дори ако .Values.secrets няма да съществува, няма да генерира грешка, но ще позволи резултата с помощта на функцията default заместваща стойност по подразбиране

Заключение

Описаните неща изглеждат доста очевидни, но информацията за удобно описание на внедряване в няколко среди с помощта на helmfile е много оскъдна, а аз обичам IaC (Infrastructure-as-Code) и искам да имам ясно описание на състоянието на внедряване.

В заключение бих искал да добавя, че променливите за средата по подразбиране могат от своя страна да бъдат параметризирани с променливите на средата на операционната система на определен runner, от който ще се стартира внедряването, и по този начин да се получат динамични среди

helmfile.yaml

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

Източник: www.habr.com

Добавяне на нов коментар