Mengatur penerapan ke beberapa lingkungan k8 menggunakan helmfile

file helm - pembungkus untuk kemudi, yang memungkinkan Anda mendeskripsikan banyak rilis helm di satu tempat, membuat parameter bagan mereka untuk beberapa lingkungan, dan juga mengatur urutan penerapannya.

Anda dapat membaca tentang helmfile itu sendiri dan contoh penggunaannya di readme и panduan praktik terbaik.

Kita akan mengenal cara-cara yang tidak jelas untuk mendeskripsikan rilis di helmfile

Katakanlah kita memiliki sekumpulan diagram helm (misalnya, postgres dan beberapa aplikasi backend) dan beberapa lingkungan (beberapa cluster kubernetes, beberapa namespace, atau beberapa dari keduanya). Kami mengambil helmfile, membaca dokumentasi dan mulai menjelaskan lingkungan dan rilis kami:

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

Kami berakhir dengan 2 lingkungan: devel, produksi — masing-masing berisi nilainya sendiri untuk bagan rilis helm. Kami akan menyebarkannya seperti ini:

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

Versi bagan kemudi yang berbeda di lingkungan yang berbeda

Bagaimana jika kita perlu meluncurkan versi backend yang berbeda ke lingkungan yang berbeda? Bagaimana cara membuat parameter versi rilis? Nilai-nilai lingkungan tersedia melalui {{ .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 }}
...

Kumpulan aplikasi yang berbeda di lingkungan yang berbeda

Bagus, tapi bagaimana jika kita tidak perlu melakukannya production meluncurkan postgres, karena kita tahu bahwa kita tidak perlu memasukkan database ke k8s dan untuk dijual kita memiliki cluster postgres terpisah yang bagus? Untuk mengatasi masalah ini kami memiliki label

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

Ini bagus, tapi secara pribadi saya lebih suka menjelaskan aplikasi mana yang akan diterapkan di lingkungan bukan menggunakan argumen peluncuran, tetapi dalam deskripsi lingkungan itu sendiri. Apa yang harus dilakukan? Anda dapat menempatkan deskripsi rilis di folder terpisah, membuat daftar rilis yang diperlukan dalam deskripsi lingkungan dan "mengambil" hanya rilis yang diperlukan, mengabaikan sisanya

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

Catatan

Bila menggunakan bases: perlu menggunakan pemisah yaml ---, sehingga Anda dapat membuat template rilis (dan bagian lain, seperti helmDefaults) dengan nilai dari lingkungan

Dalam hal ini, rilis postgres bahkan tidak akan disertakan dalam deskripsi produksi. Sangat nyaman!

Nilai global yang dapat dikesampingkan untuk rilis

Tentu saja, sangat bagus jika Anda dapat menetapkan nilai diagram kemudi untuk setiap lingkungan, tetapi bagaimana jika kita memiliki beberapa lingkungan yang dijelaskan, dan kami ingin, misalnya, menetapkan nilai yang sama untuk semua lingkungan? affinity, tapi kami tidak ingin mengkonfigurasinya secara default di grafik itu sendiri, yang disimpan di lobak.

Dalam hal ini, untuk setiap rilis kita dapat menentukan 2 file dengan nilai: yang pertama dengan nilai default, yang akan menentukan nilai grafik itu sendiri, dan yang kedua dengan nilai lingkungan, yang pada gilirannya akan menimpa yang default.

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

Mendefinisikan nilai global untuk diagram kemudi dari semua rilis di tingkat lingkungan

Katakanlah kita membuat beberapa ingress dalam beberapa rilis - kita dapat menentukan secara manual untuk setiap grafik hosts:, namun dalam kasus kita domainnya sama, jadi mengapa tidak memasukkannya ke dalam variabel global dan cukup mengganti nilainya ke dalam grafik? Untuk melakukan ini, file-file dengan nilai yang ingin kita parameterkan harus memiliki ekstensi .gotmpl, agar helmfile mengetahui bahwa ia perlu dijalankan melalui mesin templat.

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

Catatan

Jelas sekali, ingress di grafik postgres adalah sesuatu yang sangat meragukan, jadi artikel ini diberikan hanya sebagai contoh bulat dalam ruang hampa dan agar tidak memasukkan beberapa rilis baru ke dalam artikel hanya demi menjelaskan ingress.

Menggantikan rahasia dari nilai-nilai lingkungan

Dengan analogi dengan contoh di atas, Anda dapat menggantinya dengan yang terenkripsi menggunakan rahasia kemudi makna. Daripada membuat file rahasia kita sendiri untuk setiap rilis, di mana kita dapat menentukan nilai terenkripsi untuk bagan, kita cukup menentukan di rilis default.yaml.gotmpl nilai yang akan diambil dari variabel yang ditentukan di tingkat lingkungan. Dan nilai-nilai yang tidak perlu kita sembunyikan dari siapa pun dapat dengan mudah didefinisikan ulang dalam nilai rilis di lingkungan tertentu.

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

Catatan

Kebetulan, getOrNil - fungsi khusus untuk templat go di helmfile, yang meskipun .Values.secrets tidak akan ada, tidak akan menimbulkan kesalahan, tetapi akan memungkinkan hasilnya menggunakan fungsi tersebut default gantikan nilai default

Kesimpulan

Hal-hal yang dijelaskan tampak cukup jelas, tetapi informasi tentang deskripsi mudah penerapan ke beberapa lingkungan menggunakan helmfile sangat langka, dan saya menyukai IaC (Infrastruktur-as-Code) dan ingin memiliki gambaran yang jelas tentang status penerapan.

Sebagai kesimpulan, saya ingin menambahkan bahwa variabel untuk lingkungan default, pada gilirannya, dapat diparameterisasi dengan variabel lingkungan OS dari pelari tertentu tempat penerapan akan diluncurkan, dan dengan demikian memperoleh lingkungan yang dinamis.

helmfile.yaml

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

Sumber: www.habr.com

Tambah komentar