使用 helmfile 組織部署到多個 k8s 環境

頭盔文件 - 包裝器 ,它允許您在一個地方描述許多 helm 版本,針對多個環境參數化它們的圖表,並設置它們的部署順序。

您可以閱讀有關 helmfile 本身及其使用示例的信息 自述 и 最佳做法指南.

我們將熟悉在 helmfile 中描述版本的非顯而易見的方式

假設我們有一組 Helm Charts(例如,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 個環境: 開發, 生產 — 每個都包含其自己的 helm 發布圖表值。 我們將像這樣部署到他們:

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

不同環境下不同版本的 Helm Chart

如果我們需要將不同版本的後端部署到不同的環境怎麼辦? 如何參數化發布版本? 環境價值可通過 {{ .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 版本甚至不會包含在生產描述中。 很舒服!

發布的可重寫全局值

當然,您可以為每個環境設置 helm 圖表的值,但是如果我們描述了多個環境,並且我們希望為所有環境設置相同的值,該怎麼辦? 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"

在環境級別定義所有版本的 Helm Chart 的全局值

假設我們在多個版本中創建多個入口 - 我們可以為每個圖表手動定義 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 }}

筆記

顯然,postgres 圖表中的 ingress 是非常可疑的東西,因此本文僅作為真空中的球形示例給出,以免僅僅為了描述 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 - helmfile 中 go 模板的特殊函數,即使 .Values.secrets 將不存在,不會拋出錯誤,但將允許使用該函數的結果 default 替換默認值

結論

描述的事情看起來很明顯,但是關於使用 helmfile 方便地描述部署到多個環境的信息非常稀缺,而且我喜歡 IaC(基礎設施即代碼)並且希望對部署狀態有清晰的描述。

最後,我想補充一點,默認環境的變量可以反過來用將啟動部署的某個運行器的操作系統的環境變量進行參數化,從而獲得動態環境

helmfile.yaml

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

來源: www.habr.com

添加評論