Tổ chức triển khai trên nhiều môi trường k8 bằng helmfile

Helmfile - giấy gói cho cầm lái, cho phép bạn mô tả nhiều bản phát hành helm ở một nơi, tham số hóa biểu đồ của chúng cho một số môi trường và cũng đặt thứ tự triển khai chúng.

Bạn có thể đọc về chính helmfile và các ví dụ về việc sử dụng nó trong readme и hướng dẫn thực hành tốt nhất.

Chúng ta sẽ làm quen với những cách không rõ ràng để mô tả các bản phát hành trong helmfile

Giả sử chúng ta có một gói biểu đồ trợ giúp (ví dụ: giả sử postgres và một số ứng dụng phụ trợ) và một số môi trường (một số cụm kubernetes, một số không gian tên hoặc một số cả hai). Chúng tôi lấy helmfile, đọc tài liệu và bắt đầu mô tả môi trường và bản phát hành của chúng tôi:

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

Chúng tôi đã kết thúc với 2 môi trường: devel, sản xuất — mỗi cái chứa các giá trị riêng cho biểu đồ phát hành mũ bảo hiểm. Chúng tôi sẽ triển khai cho họ như thế này:

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

Các phiên bản khác nhau của biểu đồ trợ giúp trong các môi trường khác nhau

Điều gì sẽ xảy ra nếu chúng ta cần triển khai các phiên bản phụ trợ khác nhau cho các môi trường khác nhau? Làm cách nào để tham số hóa phiên bản phát hành? Các giá trị môi trường có sẵn thông qua {{ .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 }}
...

Bộ ứng dụng khác nhau trong các môi trường khác nhau

Tuyệt vời, nhưng nếu chúng ta không cần thì sao production triển khai postgres, bởi vì chúng tôi biết rằng chúng tôi không cần đẩy cơ sở dữ liệu vào k8 và để bán, chúng tôi có một cụm postgres riêng biệt tuyệt vời? Để giải quyết vấn đề này chúng ta có nhãn

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

Điều này thật tuyệt, nhưng cá nhân tôi thích mô tả những ứng dụng nào sẽ triển khai trong môi trường không sử dụng các đối số khởi chạy mà trong phần mô tả chính các môi trường đó. Phải làm gì? Bạn có thể đặt các mô tả phát hành vào một thư mục riêng, tạo danh sách các bản phát hành cần thiết trong phần mô tả môi trường và chỉ “chọn” những bản phát hành cần thiết, bỏ qua phần còn lại

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

Ghi chú

Khi sử dụng bases: cần phải sử dụng dấu phân cách yaml ---, để bạn có thể tạo mẫu các bản phát hành (và các phần khác, chẳng hạn như helmDefaults) với các giá trị từ môi trường

Trong trường hợp này, bản phát hành postgres thậm chí sẽ không được đưa vào mô tả để sản xuất. Rất thoải mái!

Giá trị toàn cầu có thể ghi đè cho các bản phát hành

Tất nhiên, thật tuyệt khi bạn có thể đặt giá trị cho biểu đồ hỗ trợ cho từng môi trường, nhưng điều gì sẽ xảy ra nếu chúng ta có một số môi trường được mô tả và chẳng hạn như chúng ta muốn đặt giống nhau cho tất cả affinity, nhưng chúng tôi không muốn định cấu hình nó theo mặc định trong chính các biểu đồ được lưu trữ trong củ cải.

Trong trường hợp này, đối với mỗi bản phát hành, chúng tôi có thể chỉ định 2 tệp có giá trị: tệp đầu tiên có giá trị mặc định, tệp này sẽ xác định các giá trị của chính biểu đồ và tệp thứ hai có các giá trị cho môi trường, do đó sẽ ghi đè những cái mặc định.

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

Xác định giá trị chung cho biểu đồ hỗ trợ của tất cả các bản phát hành ở cấp độ môi trường

Giả sử chúng tôi tạo một số lần nhập trong một số bản phát hành - chúng tôi có thể xác định thủ công cho từng biểu đồ hosts:, nhưng trong trường hợp của chúng ta, tên miền giống nhau, vậy tại sao không đặt nó vào một biến toàn cục nào đó và chỉ cần thay thế giá trị của nó vào biểu đồ? Để làm được điều này, những file có giá trị mà chúng ta muốn tham số hóa sẽ phải có phần mở rộng .gotmpl, để helmfile biết rằng nó cần được chạy qua công cụ tạo mẫu.

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

Ghi chú

Rõ ràng, việc xâm nhập vào biểu đồ postgres là một điều gì đó cực kỳ đáng ngờ nên bài viết này được đưa ra đơn giản như một ví dụ hình cầu trong chân không và nhằm không đưa một số bản phát hành mới vào bài viết chỉ nhằm mục đích mô tả việc xâm nhập.

Thay thế bí mật từ các giá trị môi trường

Bằng cách tương tự với ví dụ trên, bạn có thể thay thế những cái được mã hóa bằng cách sử dụng bí mật cầm lái ý nghĩa. Thay vì tạo tệp bí mật của riêng chúng tôi cho mỗi bản phát hành, trong đó chúng tôi có thể xác định các giá trị được mã hóa cho biểu đồ, chúng tôi có thể chỉ cần xác định trong bản phát hành default.yaml.gotmpl các giá trị sẽ được lấy từ các biến được xác định tại cấp độ môi trường. Và các giá trị mà chúng ta không cần ẩn với bất kỳ ai có thể dễ dàng xác định lại trong các giá trị phát hành trong một môi trường cụ thể.

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

Ghi chú

Ngẫu nhiên, getOrNil - một chức năng đặc biệt dành cho các mẫu đi trong helmfile, ngay cả khi .Values.secrets sẽ không tồn tại, sẽ không đưa ra lỗi, nhưng sẽ cho phép kết quả bằng cách sử dụng hàm default thay thế giá trị mặc định

Kết luận

Những điều được mô tả có vẻ khá rõ ràng, nhưng thông tin về mô tả thuận tiện cho việc triển khai đến một số môi trường bằng helmfile thì rất khan hiếm và tôi yêu thích IaC (Infrastructure-as-Code) và muốn có mô tả rõ ràng về trạng thái triển khai.

Để kết luận, tôi muốn nói thêm rằng các biến cho môi trường mặc định có thể được tham số hóa bằng các biến môi trường của HĐH của một trình chạy nhất định mà từ đó quá trình triển khai sẽ được khởi chạy và do đó có được môi trường động

helmfile.yaml

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

Nguồn: www.habr.com

Thêm một lời nhận xét