在 Kubernetes 生態系統中,Helm 已經成為標準的應用佈署工具,它透過範本化的方式簡化了 Kubernetes 資源的管理。作為一位長期從事容器化技術的開發者,我發現 Helm 的真正威力在於它的範本化能力和可重用性。這篇文章將探討如何建立結構良好的 Helm 圖表,並運用範本化技術提高佈署效率。

圖表.yaml 檔案:圖表 的核心定義

圖表.yaml 是 Helm 圖表 的核心元件,它定義了 圖表 的基本資訊。在開發過程中,這個檔案通常是第一個需要建立的:

apiVersion: v2
name: pacman
description: A Helm chart for Pacman
type: application
version: 0.1.0
appVersion: "1.0.0"

這個檔案包含了幾個關鍵元素:

  • apiVersion: 指定使用的 Helm API 版本,v2 是目前主流版本
  • name: 圖表 的名稱,這會反映在佈署的資源名稱中
  • version: 圖表 本身的版本號,當 圖表 定義變更時應更新此值
  • appVersion: 應用程式的版本,這是獨立於 圖表 版本的
  • type: 指定這是一個應用程式 圖表,而非函式庫表

在我的實踐中,清晰定義這些元素對於版本管理和依賴追蹤至關重要,特別是在複雜的微服務架構中。

建立佈署範本:實作資源定義的靈活性

Helm 的核心價值在於範本化,讓我們來看如何建立一個靈活的佈署範本。以下是一個 deployment.yaml 範例:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: {{ .圖表.Name}}
  labels:
    app.kubernetes.io/name: {{ .圖表.Name}}
    {{- if .圖表.AppVersion }}
    app.kubernetes.io/version: {{ .圖表.AppVersion | quote }}
    {{- end }}
spec:
  replicas: {{ .Values.replicaCount }}
  selector:
    matchLabels:
      app.kubernetes.io/name: {{ .圖表.Name}}
  template:
    metadata:
      labels:
        app.kubernetes.io/name: {{ .圖表.Name}}
    spec:
      containers:
      - image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .圖表.AppVersion}}"
        imagePullPolicy: {{ .Values.image.pullPolicy }}
        securityContext:
          {{- toYaml .Values.securityContext | nindent 14 }}
        name: {{ .圖表.Name}}
        ports:
        - containerPort: {{ .Values.image.containerPort }}
          name: http
          protocol: TCP

這個佈署範本展示了 Helm 範本化的強大功能:

  • 使用 {{ .圖表.Name}} 從 圖表.yaml 注入名稱
  • 條件式加入版本標籤 {{- if .圖表.AppVersion }}
  • 使用 | quote 管道函式對值進行引號處理
  • 從 values.yaml 提取 replicaCount 設定複製數量
  • 使用 toYaml 函式將 YAML 物件插入範本
  • 使用 nindent 函式確保正確的縮排

這種範本化方式讓佈署設定變得極為靈活,可以根據不同環境輕鬆調整引數。

服務範本:暴露應用程式

接下來,讓我們看如何定義服務範本 service.yaml

apiVersion: v1
kind: Service
metadata:
  labels:
    app.kubernetes.io/name: {{ .圖表.Name }}
  name: {{ .圖表.Name }}
spec:
  ports:
  - name: http
    port: {{ .Values.image.containerPort }}
    targetPort: {{ .Values.image.containerPort }}
  selector:
    app.kubernetes.io/name: {{ .圖表.Name }}

服務範本相對簡單:

  • 使用一致的命名方式與佈署資源保持一致
  • 從 values.yaml 取得容器連線埠設定
  • 確保 selector 與佈署中的標籤比對,實作正確的服務發現

在實際工作中,我發現維持這種一致性對於排錯和維護至關重要,尤其是在大型微服務架構中。

values.yaml:提供預設設定

values.yaml 檔案提供了 圖表 的預設值,這些值可以在佈署時被覆寫:

image:
  repository: quay.io/gitops-cookbook/pacman-kikd
  tag: "1.0.0"
  pullPolicy: Always
  containerPort: 8080
replicaCount: 1
securityContext: {}

這個設定檔案定義了:

  • 容器映像資訊,包括倉函式庫、標籤和提取策略
  • 容器連線埠設定
  • 預設的副本數量
  • 空的安全上下文(可以根據需要擴充套件)

空的 securityContext 允許在需要時提供完整的安全設定,例如:

securityContext:
  capabilities:
    drop:
    - ALL
  readOnlyRootFilesystem: true
  runAsNonRoot: true
  runAsUser: 1000

Helm 元素之間的關係

在 Helm 中,圖表.yaml、templates 目錄和 values.yaml 之間存在緊密的關係。圖表.yaml 提供中繼資料,templates 包含範本檔案,而 values.yaml 提供預設值。這三者協同工作,形成了一個完整的佈署包。

最終的目錄結構看起來像這樣:

pacman
├── 圖表.yaml
├── templates
│   ├── deployment.yaml
│   ├── service.yaml
└── values.yaml

本地渲染與佈署 Helm 圖表

本地渲染 圖表

使用 Helm 的一個強大功能是能夠在佈署前預覽渲染後的 YAML。這對於驗證範本和值的結合是否如預期非常有用:

helm template .

這個命令會輸出最終的 YAML 設定,包括服務和佈署資源。透過檢查這個輸出,我們可以確認範本變數是否被正確替換。

覆寫預設值

Helm 允許在佈署或渲染時覆寫預設值。例如,我們可以增加副本數量:

helm template --set replicaCount=3 .

這種能力使得同一個 圖表 可以適應不同的環境和需求,是 Helm 最實用的特性之一。

佈署到 Kubernetes 叢集

當我們對渲染的結果滿意後,可以將 圖表 佈署到 Kubernetes 叢集:

helm install pacman .

佈署後,我們可以檢視相關資源:

kubectl get pods
kubectl get deployment
kubectl get services

Helm 還提供了檢視佈署歷史的能力:

helm history pacman

這對於追蹤佈署變更和回復非常有用。

解除安裝 圖表

如需解除安裝 圖表,可以使用:

helm uninstall pacman

提高範本重用性:使用 _helpers.tpl

在開發 Helm 圖表 時,我經常遇到需要在多個範本檔案中重複使用相同設定片段的情況。這就是 _helpers.tpl 檔案發揮作用的地方。

識別重用機會

在前面的例子中,我們在多處使用了相同的標籤選擇器:

app.kubernetes.io/name: {{ .圖表.Name}}

這種重複不僅增加了維護負擔,也提高了出錯風險。如果需要更改選擇器邏輯,就需要在多處進行修改。

建立 _helpers.tpl 檔案

為瞭解決這個問題,我們可以建立一個 _helpers.tpl 檔案來定義可重用的範本片段:

{{- define "pacman.selectorLabels" -}}
app.kubernetes.io/name: {{ .圖表.Name}}
{{- end }}

這個範本定義了一個名為 pacman.selectorLabels 的片段,它生成應用程式的選擇器標籤。使用名稱空間(這裡是 pacman)作為字首是一個很好的實踐,可以避免在引入依賴時發生名稱衝突。

在範本中使用 helpers

一旦定義了 helper,我們可以在範本檔案中使用 include 函式來參照它:

spec:
  replicas: {{ .Values.replicaCount }}
  selector:
    matchLabels:
      {{- include "pacman.selectorLabels" . | nindent 6 }}
  template:
    metadata:
      labels:
        {{- include "pacman.selectorLabels" . | nindent 8 }}

這裡使用 include 函式引入我們定義的 helper,並透過 nindent 函式進行適當的縮排:

  • include "pacman.selectorLabels" . 執行 helper 並傳入當前上下文 .
  • | nindent 6 將結果縮排 6 個空格,確保 YAML 格式正確

這種方法有幾個關鍵優勢:

  1. 減少重複程式碼
  2. 集中管理共用邏輯
  3. 簡化維護工作
  4. 提高一致性

在實際工作中,我經常使用 helpers 來定義更複雜的邏輯,例如條件標籤、通用註解或環境變數設定。這極大地提高了 圖表 的可維護性和一致性。

Helm 進階範本化技巧

在開發複雜的 Helm 圖表 時,還有一些進階技巧值得掌握:

使用命名範本組織複雜邏輯

對於更複雜的情況,可以在 _helpers.tpl 中定義多個相關的 helpers:

{{- define "pacman.labels" -}}
app.kubernetes.io/name: {{ .圖表.Name }}
app.kubernetes.io/instance: {{ .Release.Name }}
app.kubernetes.io/version: {{ .圖表.AppVersion | quote }}
app.kubernetes.io/managed-by: {{ .Release.Service }}
{{- end }}

{{- define "pacman.selectorLabels" -}}
app.kubernetes.io/name: {{ .圖表.Name }}
app.kubernetes.io/instance: {{ .Release.Name }}
{{- end }}

這樣,可以為不同用途定義不同的標籤集,同時保持程式碼的組織性和可維護性。

利用 Sprig 函式增強範本能力

Helm 整合了 Sprig 函式庫供了許多強大的函式來處理字元串、列表、字典等:

{{- define "pacman.fullname" -}}
{{- if .Values.fullnameOverride }}
{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" }}
{{- else }}
{{- printf "%s-%s" .Release.Name .圖表.Name | trunc 63 | trimSuffix "-" }}
{{- end }}
{{- end }}

這個例子結合了條件邏輯、字元串格式化和截斷函式,建立了一個符合 Kubernetes 命名規則的資源名稱。

使用 with 簡化深層次存取

對於深層次的值存取,可以使用 with 來簡化範本:

{{- with .Values.resources }}
resources:
  {{- toYaml . | nindent 10 }}
{{- end }}

這比直接使用 .Values.resources 更簡潔,特別是當需要多次參照同一個深層路徑時。

Helm 圖表 開發是一門結合了 Kubernetes 資源管理和範本程式設計的藝術。透過掌握 圖表 結構、範本化技巧和 helpers 重用,我們可以建立既靈活又易於維護的應用佈署方案。

在實際工作中,我發現良好的範本設計能夠顯著減少維護負擔,並提高團隊協作效率。從簡單的佈署開始,逐步引入範本化和重用技術,最終能夠構建出適應各種環境和需求的 Helm 圖表。

無論是單體應用還是複雜的微服務架構,這些 Helm 技巧都能幫助我們更高效地管理 Kubernetes 資源,實作真正的基礎架構即程式碼。

Helm 選擇器標籤管理:靈活調整應用識別方式

在 Kubernetes 的世界中,標籤選擇器是連線服務與佈署的關鍵橋樑。當我們使用 Helm 管理應用佈署時,瞭解如何正確設定和更新這些選擇器至關重要。讓我們來看如何透過 Helm 範本實作這一點。

選擇器標籤的重要性與實作方式

選擇器標籤在 Kubernetes 中扮演著核心角色,它們定義了服務如何找到並路由流量到正確的 Pod。在 Helm 中,我們可以透過範本化這些標籤來實作更靈活的設定。

以下是一個基本的 Pacman 應用程式服務定義:

apiVersion: v1
kind: Service
metadata:
  labels:
    app.kubernetes.io/name: pacman
  name: pacman
spec:
  ports:
  - name: http
    port: 8080
    targetPort: 8080
  selector:
    app.kubernetes.io/name: pacman

對應的佈署定義如下:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: pacman
  labels:
    app.kubernetes.io/name: pacman
    app.kubernetes.io/version: "1.0.0"
spec:
  replicas: 1
  selector:
    matchLabels:
      app.kubernetes.io/name: pacman
  template:
    metadata:
      labels:
        app.kubernetes.io/name: pacman
    spec:
      containers:
      - image: "quay.io/gitops-cookbook/pacman-kikd:1.0.0"
        imagePullPolicy: Always
        securityContext:
          {}
        name: pacman
        ports:
        - containerPort: 8080
          name: http
          protocol: TCP

這些 YAML 定義了一個 Pacman 應用的服務和佈署。服務透過 app.kubernetes.io/name: pacman 選擇器標籤將流量引導到具有相同標籤的 Pod。佈署確保這些 Pod 執行並具有正確的標籤。這種標籤策略遵循 Kubernetes 推薦的標籤命名規範,使用 app.kubernetes.io 字首。

使用 Helm 範本增強標籤管理

若要更新選擇器標籤,最有效的方法是修改 Helm 圖表 中的 _helpers.tpl 檔案。這個檔案包含可重用的範本片段,用於生成一致的標籤。

{{- define "pacman.selectorLabels" -}}
app.kubernetes.io/name: {{ .圖表.Name}}
app.kubernetes.io/version: {{ .圖表.AppVersion}}
{{- end }}

這個範本片段定義了一個名為 pacman.selectorLabels 的函式,它會生成包含應用名稱和版本的標籤。.圖表.Name.圖表.AppVersion 是從 圖表.yaml 檔案中自動讀取的值。這種方法確保了標籤的一致性,並允許透過簡單修改 圖表.yaml 來更新整個應用的標籤。

當我們使用 helm template . 命令渲染範本時,輸出將包含更新後的選擇器:

# Source: pacman/templates/service.yaml
apiVersion: v1
kind: Service
metadata:
  # ... 其他中繼資料
spec:
  # ... 其他規格
  selector:
    app.kubernetes.io/name: pacman
    app.kubernetes.io/version: 1.0.0
---
# Source: pacman/templates/deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: pacman
  labels:
    app.kubernetes.io/name: pacman
    app.kubernetes.io/version: "1.0.0"
spec:
  replicas: 1
  selector:
    matchLabels:
      app.kubernetes.io/name: pacman
      app.kubernetes.io/version: 1.0.0
  template:
    metadata:
      labels:
        app.kubernetes.io/name: pacman
        app.kubernetes.io/version: 1.0.0
    spec:
      # ... 容器規格

在開發 Helm 圖表 時,我發現雖然 _helpers.tpl 是定義函式的常見檔案名,但實際上 Helm 會讀取任何以 __ (雙底線) 開頭的檔案中的函式定義。這提供了更大的組織靈活性,特別是當你的 圖表 變得複雜時。

使用 Helm 更新容器映像版本

在微服務架構中,頻繁更新容器映像是常見需求。Helm 提供了簡單而強大的機制來管理這些更新。

佈署與升級應用程式版本

首先,讓我們佈署 Pacman 應用的 1.0.0 版本:

helm install pacman .

佈署後,我們可以檢查當前版本狀態:

helm history pacman

輸出顯示:

REVISION  UPDATED                   STATUS      CHART         APP VERSION  DESCRIPTION
1         Sun Jan 23 16:00:09 2022  deployed    pacman-0.1.0  1.0.0        Install complete

要更新容器映像,我們需要修改 values.yaml 檔案中的 image.tag 欄位:

image:
  repository: quay.io/gitops-cookbook/pacman-kikd
  tag: "1.1.0"
  pullPolicy: Always
containerPort: 8080
replicaCount: 1
securityContext: {}

同時,也應更新 圖表.yaml 中的 appVersion 欄位:

apiVersion: v2
name: pacman
description: A Helm chart for Pacman
type: application
version: 0.1.0
appVersion: "1.1.0"

這裡我們做了兩處關鍵更改:

  1. values.yaml 中將容器映像標籤從 “1.0.0” 更新為 “1.1.0”
  2. 圖表.yaml 中更新 appVersion 以反映應用程式的新版本

值得注意的是,我們保留了 圖表 版本 (0.1.0),因為 圖表 結構本身沒有變化,只是更新了應用程式版本。這反映了 Helm 中的兩層版本控制概念:圖表 版本和應用程式版本。

版本控制策略與最佳實踐

在管理 Helm 圖表 時,我注意到很多團隊混淆了 versionappVersion 的用途。從實踐經驗來看,它們有明確的區別:

  • appVersion:表示應用程式的版本,當應用程式碼更新時應該更改
  • version:表示 圖表 本身的版本,當範本或 圖表 結構變化時應該更改

有些團隊選擇將 appVersion 直接用作容器標籤,而不是在 values.yaml 中單獨指定。這種方法可以簡化版本管理,但取決於你的版本控制策略和軟體生命週期管理方式。

更新設定後,執行升級命令:

helm upgrade pacman .

系統會顯示升級成功,並提供新的版本資訊:

Release "pacman" has been upgraded. Happy Helming!
NAME: pacman
LAST DEPLOYED: Mon Jan 24 11:39:28 2022
NAMESPACE: asotobue-dev
STATUS: deployed
REVISION: 2
TEST SUITE: None

使用 helm history 命令可以檢視所有版本的歷史記錄:

REVISION  UPDATED                   STATUS      CHART         APP VERSION  DESCRIPTION
1         Mon Jan 24 10:22:06 2022  superseded  pacman-0.1.0  1.0.0        Install complete
2         Mon Jan 24 11:39:28 2022  deployed    pacman-0.1.0  1.1.0        Upgrade complete

回復到先前版本

Helm 的強大之處在於它不僅支援升級,還支援回復到之前的版本。這在發現新版本問題時非常有用。

helm rollback pacman 1

執行回復後,歷史記錄會反映這一變化:

REVISION  UPDATED                   STATUS      CHART         APP VERSION  DESCRIPTION
1         Mon Jan 24 10:22:06 2022  superseded  pacman-0.1.0  1.0.0        Install complete
2         Mon Jan 24 11:39:28 2022  superseded  pacman-0.1.0  1.1.0        Upgrade complete
3         Mon Jan 24 12:31:58 2022  deployed    pacman-0.1.0  1.0.0        Rollback to 1

使用外部值檔案覆寫設定

除了直接修改 values.yaml 或使用 --set 引數外,Helm 還允許使用外部值檔案來覆寫設定,這在不同環境間切換時特別有用。

建立一個名為 newvalues.yaml 的檔案:

image:
  tag: "1.2.0"

然後使用此檔案渲染範本:

helm template pacman -f newvalues.yaml .

輸出中的佈署將使用新指定的映像標籤:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: pacman
  # ... 其他中繼資料
spec:
  # ... 其他規格
  template:
    # ... 其他範本設定
    spec:
      containers:
      - image: "quay.io/gitops-cookbook/pacman-kikd:1.2.0"
        # ... 其他容器設定

Helm 圖表 的封裝與分發

隨著 Helm 圖表 數量的增加,組織和分享這些 圖表 變得至關重要。Helm 提供了完整的封裝和分發機制。

封裝 Helm 圖表

封裝 Helm 圖表 非常簡單,只需在 圖表 目錄中執行一個命令:

helm package .

系統會生成一個 .tgz 檔案:

Successfully packaged chart and saved it to: gitops-cookbook/code/05_helm/04_package/pacman/pacman-0.1.0.tgz

建立 圖表 倉函式庫Helm 圖表 倉函式庫上是一個 HTTP 伺服器,其中包含:

  • 封裝好的 圖表 (.tgz 檔案)
  • 一個 index.yaml 檔案,包含所有可用 圖表 的中繼資料

倉函式庫錄結構通常如下:

repo
├── index.yaml
├── pacman-0.1.0.tgz

index.yaml 檔案包含每個 圖表 的詳細訊息:

apiVersion: v1
entries:
  pacman:
    - apiVersion: v2
      appVersion: 1.0.0
      created: "2022-01-24T16:42:54.080959+01:00"
      description: A Helm chart for Pacman
      digest: aa3cce809ffcca86172fc793d7804d1c61f157b9b247680a67d5b16b18a0798d
      name: pacman
      type: application
      urls:
        - pacman-0.1.0.tgz
      version: 0.1.0
generated: "2022-01-24T16:42:54.080485+01:00"

index.yaml 檔案是 Helm 倉函式庫心,它提供了所有可用 圖表 的詳細訊息。每個 圖表 條目包含:

  • apiVersion:圖表 API 版本
  • appVersion:應用程式版本
  • created:建立時間戳
  • description:圖表 描述
  • digest:SHA256 校驗和,用於驗證下載的完整性
  • urls:圖表 包的相對或絕對 URL
  • version:圖表 版本

可以使用 helm repo index 命令在包含封裝 圖表 的目錄中自動生成這個索引檔案,大簡化了倉函式庫工作。

增強安全性:簽署 Helm 圖表

在企業環境中,確保 圖表 的完整性和真實性至關重要。Helm 支援使用 GPG 金鑰對 圖表 包進行簽名。

假設你已有 GPG 金鑰對,可以這樣簽署

helm package --sign --key 'me@example.com' --keyring /home/me/.gnupg/secring.gpg .

這將生成兩個檔案:

  • 圖表 包 (.tgz)
  • 簽名檔案 (.tgz.prov)
.
├── 圖表.yaml
├── pacman-0.1.0.tgz        # 圖表 包
├── pacman-0.1.0.tgz.prov   # 簽名檔案
├── templates
│   ├── deployment.yaml
│   └── service.yaml
└── values.yaml

.prov 檔案包含 圖表 包的加密簽名和摘要訊息。當使用者安裝 圖表 時,可以使用

Helm 圖表的完整性驗證:確保應用安全

在Kubernetes環境中,確保佈署的Helm 圖表沒有被篡改是系統安全的關鍵一環。當我們從網路上下載圖表或從團隊成員處接收圖表時,驗證其完整性變得尤為重要。

使用verify命令進行圖表驗證

Helm提供了專用的verify命令來檢查圖表的有效性:

helm verify pacman-0.1.0.tgz

成功的驗證會顯示以下訊息:

  • 簽名者訊息
  • 使用的金鑰指紋
  • 圖表的雜湊值確認

當一切正常時,系統會顯示「It’s valid」的確認訊息,表示該圖表未被篡改與來源可信。

驗證過程背後的原理

驗證過程實際上是檢查數位簽名與圖表內容的一致性。在分散式團隊中工作時,這一步驟非常關鍵,可以確保開發環境的穩定性和安全性。當我在管理多環境佈署時,總是將驗證作為標準流程的一部分,可以有效防止佈署被篡改的應用。

從儲存函式庫Helm 圖表

在實際工作中,直接從儲存函式庫圖表是最常見的使用場景,這種方式更加方便與安全。

增加和管理圖表儲存函式庫首先,需要將儲存函式庫到Helm的設定中:

helm repo add bitnami https://charts.bitnami.com/bitnami

增加後,可以檢視已註冊的儲存函式庫:

helm repo list

這會顯示所有已註冊的儲存函式庫URL:

NAME    URL
stable  https://charts.helm.sh/stable
bitnami https://charts.bitnami.com/bitnami

搜尋可用的圖表

要找到特定的應用圖表,可以使用search命令:

helm search repo postgresql

系統會回傳所有符合條件的圖表,包括版本訊息和簡短描述:

NAME                               CHART VERSION  APP VERSION  DESCRIPTION
bitnami/postgresql                 10.16.2        11.14.0      圖表 for PostgreSQL, an object-relational data...
bitnami/postgresql-ha              8.2.6          11.14.0      圖表 for PostgreSQL with HA architecture (usin...
stable/postgresql                  8.6.4          11.7.0       DEPRECATED 圖表 for PostgreSQL, an object-rela...
stable/pgadmin                     1.2.2          4.18.0       pgAdmin is a web based administration tool for ...
...

從儲存函式庫圖表

確定要安裝的圖表後,使用install命令進行佈署:

helm install my-db \
  --set postgresql.postgresqlUsername=my-default,postgresql.postgresqlPassword=postgres,postgresql.postgresqlDatabase=mydb,postgresql.persistence.enabled=false \
  bitnami/postgresql

這個命令會:

  1. 將佈署命名為「my-db」
  2. 透過--set引數覆寫預設設定
  3. 指定使用Bitnami儲存函式庫PostgreSQL 圖表

這條命令是佈署PostgreSQL資料函式庫鍵。--set引數允許我們在不修改原始圖表的情況下自定義設定,這裡我們設定了:

  • 使用者名:my-default
  • 密碼:postgres
  • 資料函式庫mydb
  • 關閉持久化儲存(適合測試環境)

在生產環境中,我通常會啟用持久化儲存並使用更複雜的密碼策略。

檢查佈署狀態

佈署完成後,可以檢查相關的Kubernetes資源:

kubectl get pods
kubectl get services
kubectl get statefulset
kubectl get secrets

這些命令會顯示佈署產生的所有資源,包括執行中的Pod、伺服器端點、有狀態集合和包含密碼的Secrets。

檢檢視表的可設定引數

當使用第三方圖表時,瞭解所有可設定的引數非常重要:

helm show values bitnami/postgresql

這會顯示圖表的所有可設定引數及其說明,便於我們根據需求進行自定義。