Helm Chart 的範本驗證是確保 Kubernetes 應用程式佈署成功的關鍵步驟。開發者可以使用 helm template 命令搭配 --validate 標誌進行客戶端渲染與伺服器端驗證,確保生成的資源符合 Kubernetes API 規範。除了 --validate 標誌外,--dry-run 標誌也能在安裝、升級或回復 Chart 時預先驗證資源,避免佈署錯誤。Helm 也提供 helm lint 命令,用於檢查 Chart 的結構和後設資料,確保 Chart 符合 Helm 的規範和最佳實踐。然而,helm lint 並不檢查 YAML 格式的正確性,建議搭配 yamllint 等工具進行更全面的 YAML 檔案檢查。為了更有效地測試 Helm Chart 的功能,ct 工具提供了更強大的測試框架,支援測試生命週期鉤子、日誌輸出和結果報告,並能與 CI/CD 流程整合,實作自動化測試和佈署驗證。在實務開發中,建議結合 helm templatehelm lintyamllint 和 ct 工具,建立完善的 Helm Chart 驗證流程,提升 Kubernetes 應用程式的可靠性和穩定性。

Helm範本驗證與檢查

使用Helm範本驗證資源

在開發Helm chart時,確保資源範本的正確性至關重要。我們可以使用helm template命令來渲染資源,並檢查其合法性。以下是一個簡單的Deployment資源範例:

kind: Deployment
# <略過其他部分>
resources:
  limits:
    cpu: 200m
    memory: 256Mi

這裡我們只顯示了部分內容,實際上Deployment資源還包含其他組態專案。接下來,我們來討論如何在渲染資源時啟用伺服器端驗證。

啟用伺服器端驗證

helm template命令主要用於客戶端渲染,這意味著它不會與Kubernetes API伺服器通訊來驗證資源的合法性。如果你想確保生成的資源是有效的,可以使用--validate標誌來指示helm template在生成資源後與Kubernetes API伺服器通訊:

helm template my-chart $CHART_DIRECTORY --validate

任何生成的範本如果不產生有效的Kubernetes資源,都會顯示錯誤訊息。例如,如果你使用了一個Deployment範本,並將apiVersion設定為apiVersion: v1,這樣是無法產生有效的Deployment資源的。正確的API版本應該是apps/v1。如果沒有使用--validate標誌,客戶端渲染會顯示一個看似有效的資源,但實際上是無效的。

Error: unable to build kubernetes objects from release manifest: unable to recognize '': no matches for kind 'Deployment' in version 'v1'

如何選擇幹運作

除了在渲染時使用--validate標誌外,你還可以在安裝、升級、回復和解除安裝命令中使用--dry-run標誌來執行驗證。例如:

helm install my-chart $CHART --dry-run

這個標誌會生成圖表的範本並執行驗證,類別似於使用helm template --validate。使用--dry-run會將每個生成的資源列印到命令列中,但不會在Kubernetes環境中建立這些資源。這主要用於終端使用者進行安裝前的檢查,以確保他們提供了正確的值並且安裝會產生預期的結果。

檢查Helm圖表

在確保範本生成正確後,我們還需要確保範本遵循最佳實踐,以簡化開發和維護。Helm提供了一個名為helm lint的命令來檢查圖表。

lint命令語法

helm lint PATH [flags]

這個命令設計用來檢查圖表目錄,以確保圖表是有效且正確格式化的。

需要注意的是

  • helm lint命令不會驗證渲染後的API架構或YAML樣式,
  • 它僅僅檢查圖表是否包含適當的檔案和設定。

假設你有一個名為guestbook的圖表,其目錄結構如下:

guestbook/
templates/
values.yaml

這個圖表結構缺少定義圖表後設資料的Chart.yaml檔案。如果執行linter,會產生如下錯誤:

==> Linting .
Error: unable to check Chart.yaml file in chart: stat Chart.yaml: no such file or directory
Error: 1 chart(s) linted, 1 chart(s) failed

Helm Lint命令詳細解析

以下是更多Helm Lint命令使用範例及解析:

基本語法

helm lint $GUESTBOOK_CHART_PATH

該命令會檢查指定路徑下的圖表是否符合Helm要求。輸出結果可能包括:

  • [INFO]:建議專案(如圖表應該包含icon欄位)。
  • [WARNING]:警告訊息(如圖表違反了某些約定)。
  • [ERROR]:錯誤訊息(如圖表安裝時會失敗)。

具體案例

假設你有一個缺少Chart.yaml檔案的圖表結構:

guestbook/
templates/
values.yaml

執行linter會產生錯誤:

==> Linting .
Error: unable to check Chart.yaml file in chart: stat Chart.yaml: no such file or directory
Error: 1 chart(s) linted, 1 chart(s) failed

這表示Helm無法找到Chart.yaml檔案。即使增加了一個空的Chart.yaml檔案(如下所示),仍然會產生錯誤:

guestbook/
Chart.yaml # Empty
templates/
values.yaml

技術選型與未來趨勢分析

在實務中,選擇適當的Helm命令和標誌可以大大提升開發效率和系統穩定性。隨著Kubernetes和Helm社群的持續發展,未來可能會有更多工具和最佳實踐出現。

Helm技術選型與最佳實踐

常見錯誤與改進建議

  1. 忽略伺服器端驗證:許多開發者忽略了伺服器端驗證,導致佈署時才發現問題。建議在每次渲染時都使用–validate標誌。
  2. 未遵循最佳實踐:雖然Helm lint命令不完全檢查所有問題,但它可以幫助避免一些常見錯誤。建議定期執行lint命令來檢查圖表。
  3. 過度依賴客戶端渲染:雖然客戶端渲染方便快速,但應該結合伺服器端驗證來確保資源有效性。

未來趨勢預測

隨著Kubernetes和Helm技術的不斷進步,未來可能會有更多自動化工具和更強大的驗證功能出現。開發者應該密切關注社群動態,及時更新自己的技術手段和最佳實踐。

此圖示展示了Helmet基本操作流程

@startuml
skinparam backgroundColor #FEFEFE
skinparam componentStyle rectangle

title Helm 範本驗證與最佳實踐

package "Kubernetes Cluster" {
    package "Control Plane" {
        component [API Server] as api
        component [Controller Manager] as cm
        component [Scheduler] as sched
        database [etcd] as etcd
    }

    package "Worker Nodes" {
        component [Kubelet] as kubelet
        component [Kube-proxy] as proxy
        package "Pods" {
            component [Container 1] as c1
            component [Container 2] as c2
        }
    }
}

api --> etcd : 儲存狀態
api --> cm : 控制迴圈
api --> sched : 調度決策
api --> kubelet : 指令下達
kubelet --> c1
kubelet --> c2
proxy --> c1 : 網路代理
proxy --> c2

note right of api
  核心 API 入口
  所有操作經由此處
end note

@enduml
小段落標題:

此圖示展示了Helmet基本操作流程:從開始編寫Helm Chart、進行範本渲染、選擇客戶端或伺服器端驗證、檢查並調整YAML格式及API版本、進行Linter檢查等步驟完整流程形成最後輸出完成工作。

測試 Helm Charts

在開發 Helm Charts 時,測試是確保其正確性和穩定性的重要步驟。Helm 提供了多種工具來幫助我們進行測試,包括 helm linthelm template。這些工具可以幫助我們檢查 Chart 的結構和範本渲染,但它們並不能完全測試 Chart 在實際 Kubernetes 環境中的功能。

測試 Helm Chart 的基本步驟

首先,我們來看一下如何使用 helm lint 命令來檢查 Helm Chart 的基本結構。假設我們有一個名為 guestbook 的 Chart,執行 helm lint 命令會產生以下錯誤:

==> Linting .
[ERROR] Chart.yaml: name is required
[ERROR] Chart.yaml: apiVersion is required. The value must be either 'v1' or 'v2'
[ERROR] Chart.yaml: version is required
[INFO] Chart.yaml: icon is recommended
[ERROR] templates/: validation: chart.metadata.name is required
Error: 1 chart(s) linted, 1 chart(s) failed

這些錯誤表明 Chart.yaml 檔案缺少必需的欄位,如 nameapiVersionversion。此外,helm lint 還會檢查其他必要或推薦的檔案,例如 values.yamltemplates 目錄。

解決 Lint 錯誤

要解決這些錯誤,我們需要在 Chart.yaml 檔案中新增缺失的欄位:

apiVersion: v2
name: guestbook
version: 0.1.0

這樣就可以解決 helm lint 報告的大部分錯誤。然而,helm lint 無法進行詳細的 YAML 風格檢查。為此,我們可以使用另一個工具 yamllint

安裝 yamllint

yamllint 可以透過 Python 的包管理工具 pip 安裝:

pip install yamllint --user

或者使用作業系統的包管理器安裝。

使用 yamllint 測試 YAML 風格

要使用 yamllint 測試 Helm 範本的 YAML 風格,我們需要先使用 helm template 命令生成範本,然後將輸出匯入到 yamllint 中:

helm template my-guestbook Learn-Helm/helm-charts/charts/guestbook | yamllint -

這個命令會生成範本資源並將輸出匯入到 yamllint 中進行檢查。

測試 YAML 風格

下面是一些 yamllint 檢查的常見規則:

  • 縮排:檢查縮排是否一致。
  • 行長:檢查行長是否超過限制。
  • 尾隨空格:檢查行尾是否有不必要的空格。
  • 空行:檢查是否有多餘的空行。
  • 註解格式:檢查註解是否符合規範。

我們可以透過建立 .yamllint.yaml 組態檔案來自定義這些規則。例如,要允許不同風格的縮排,我們可以這樣組態:

rules:
  indentation:
    indent-sequences: whatever

這樣組態後,再次執行 yamllint 命令就不會因縮排問題報錯了。

在實際 Kubernetes 叢集中測試

雖然上述步驟可以幫助我們檢查 Helm Chart 的結構和範本渲染,但它們無法完全測試 Chart 在實際環境中的功能。為此,我們需要在實際 Kubernetes 叢集中進行測試。

建立 Chart 測試

在實際 Kubernetes 叢集中測試時,我們需要建立一些包含 helm.sh/hook: test 註解的 Pod 範本。這些 Pod 處理後會執行命令來測試 Chart 和應用程式的功能。

以下是建立測試檔案的步驟:

  1. 在 Chart 的 templates/ 目錄下建立一個新目錄 test/
  2. test/ 目錄下建立兩個測試檔案:frontend-connection.yamlbackend-connection.yaml
mkdir $GUESTBOOK_CHART_DIR/templates/test
touch $GUESTBOOK_CHART_DIR/templates/test/frontend-connection.yaml
touch $GUESTBOOK_CHART_DIR/templates/test/backend-connection.yaml

編寫測試邏輯

接下來,我們需要在這些測試檔案中編寫具體的測試邏輯。例如,我們可以編寫一個簡單的 HTTP 測試來檢查前端應用是否可用:

apiVersion: v1
kind: Pod
metadata:
  name: "{{ .Release.Name }}-frontend-test"
  annotations:
    "helm.sh/hook": test-success
spec:
  containers:
    - name: frontend-test
      image: busybox
      command: ["wget", "-T", "5", "-O", "-", "http://{{ .Release.Name }}-frontend"]

執行測試

完成測試檔案後,我們可以使用以下命令執行測試:

helm test my-guestbook

這個命令會啟動測試鉤子並建立包含上述註解的資源。

檢視測試結果

完成測試後,我們可以透過以下命令檢視測試結果:

kubectl logs <pod-name>

這樣就可以看到每個測試 Pod 的日誌輸出,從而判斷測試是否透過。

測試 Helm Charts

為 Helm Chart 編寫測試

在介紹過 Guestbook Chart 的結構之後,我們瞭解到它包含一個 Redis 後端和一個 PHP 前端。使用者可以在前端的對話方塊中輸入訊息,這些訊息會被持久化到後端。現在,讓我們編寫一些測試來確保前後端資源在安裝後都可用。首先,我們將從測試 Redis 後端的可用性開始。

Redis 後端連線測試

templates/test/backend-connection.yaml 檔案中新增以下內容:

apiVersion: v1
kind: Pod
metadata:
  name: "{{ .Release.Name }}-backend-connection-test"
  annotations:
    "helm.sh/hook": test
    "helm.sh/hook-delete-policy": hook-succeeded,hook-failed
spec:
  containers:
    - name: redis-client
      image: redis:5.0.3
      command: ["redis-cli"]
      args: ["-h", "{{ .Release.Name }}-redis-master", "MGET", "messages"]
  restartPolicy: Never

這個範本定義了一個 Pod,該 Pod 在測試生命週期鉤子期間會被建立。範本中還定義了鉤子刪除策略,指示何時移除之前的測試 Pod。如果需要執行測試的特定順序,也可以新增鉤子權重。

args 欄位在容器物件下顯示了測試所根據的命令。它會使用 redis-cli 工具連線到 Redis 主節點並執行 MGET messages 命令。Guestbook 前端設計用於將使用者輸入的訊息新增到名為 messages 的資料函式庫鍵中。這個簡單的測試旨在檢查是否可以建立到 Redis 資料函式庫的連線,並透過查詢 messages 鍵來傳回使用者輸入的訊息。

PHP 前端連線測試

我們還需要測試 PHP 前端的可用性,因為它是應用程式的使用者導向元件。在 templates/test/frontend-connection.yaml 檔案中新增以下內容:

apiVersion: v1
kind: Pod
metadata:
  name: "{{ .Release.Name }}-frontend-connection-test"
  annotations:
    "helm.sh/hook": test
    "helm.sh/hook-delete-policy": hook-succeeded,hook-failed
spec:
  containers:
    - name: curl-client
      image: radial/busyboxplus:curl
      command: ["curl"]
      args: ["http://{{ .Release.Name }}-frontend"]
  restartPolicy: Never

這是一個非常簡單的測試,它執行 HTTP 請求到 Guestbook Service。傳送到 Service 的流量會在 Guestbook 前端例項之間進行負載平衡。這個測試將檢查負載平衡是否成功執行以及前端是否可用。

本地渲染與驗證 Helm Chart 測試範本

這些範本也可以使用 helm template 命令本地渲染並使用 helm lintyamllint 驗證,如本章前面部分所述。當開發自己的 Helm Charts 時,這對於更複雜的測試案例可能會很有用。

在 Minikube 環境中執行 Chart 測試

安裝 Guestbook Chart

要執行 Chart 的測試,必須首先在 Kubernetes 環境中使用 helm install 命令安裝 Chart。由於編寫的測試設計為在安裝完成後執行,因此可以使用 --wait 標誌來安裝 Chart,以便更容易確定 Pod 是否已準備就緒。執行以下命令來安裝 Guestbook Chart:

$ helm install my-guestbook $GUESTBOOK_CHART_DIR -n chapter6 --wait
執行 Helm 測試

安裝完 Chart 後,可以使用 helm test 命令執行測試生命週期鉤子並建立測試資源。以下是 helm test 命令的語法:

helm test [RELEASE] [flags]

對於 my-guestbook 發行版執行 helm test 命令:

$ helm test my-guestbook -n chapter6

如果測試成功,將看到以下結果:

TEST SUITE: my-guestbook-test-frontend-connection
Last Started: Tue Jan 28 18:50:23 2020
Last Completed: Tue Jan 28 18:50:25 2020
Phase: Succeeded

TEST SUITE: my-guestbook-test-backend-connection
Last Started: Tue Jan 28 18:50:25 2020
Last Completed: Tue Jan 28 18:50:26 2020
Phase: Succeeded
檢視測試日誌

執行測試時,也可以使用 --logs 標誌從執行測試時列印日誌到命令列:

$ helm test my-guestbook -n chapter6 --logs

您將看到與之前相同的測試摘要,此外還有每個測試相關聯的容器日誌。以下是前端連線測試日誌輸出的一部分:

POD LOGS: my-guestbook-test-frontend-connection

<html ng-app='redis'>
<head>
<title>Guestbook</title>

以下是後端連線測試日誌輸出:

POD LOGS: my-guestbook-test-backend-connection

這些日誌會顯示空白,因為您尚未在 Guestbook 前端輸入任何訊息。您可以再次執行該測試並從前端新增一條訊息來確保訊息持久化。

接入 Guestbook 前端

您可以按照以下指示找到 Guestbook 前端的 URL:

export IP=$(kubectl get nodes -o jsonpath='{.items[0].status.addresses[0].address}')
export PORT=$(kubectl get svc my-guestbook -n chapter6 -o jsonpath='{.spec.ports[0].nodePort}')
echo http://$IP:$PORT

開啟瀏覽器並存取前端後,從 Guestbook 應用程式中新增一條訊息。

驗證後端連線

再次執行此測試套件並新增 --logs 標誌以顯示測試日誌:

$ helm test my-guestbook -n chapter6 --logs

以下是顯示後端連線測試日誌輸出的一部分:


POD LOGS : my-guestbook-test-backend-connection

,Writing Helm charts is fun!

您可以透過觀察後端連線測試日誌輸出來驗證這條訊息是否已被持久化到 Redis 資料函式庫。

測試進階技術:利用 ct 工具提升測試能力

編寫簡單的測試能夠對我們佈署成功進行基本驗證,但隨著應用程式複雜度增加、業務規則變多,需要更強大且可靠的測試工具來確保我們的 Helm Charts 能夠正常工作並保留功能完整性。

ct 工具簡介與組態

ct 是一個強大的 Kubernetes 測試工具(https://github.com/helm/chart-testing),它不僅支援對 Helm Charts 的自動化測試執行、結果報告等功能,還能與 CI/CD 整合進行持續整合和持續佈署。

首先我們需要在本地機器上安裝 ct 工具和依賴元件:


# 安裝 ct 工具 (建議使用 go install)
go install github.com/helm/chart-testing/v3/cmd/ct@latest

# 安裝依賴工具如 Helm、Kubectl、Kustomize、Yamllint 和其他需要依賴項:
brew install helm kubectl kustomize yamllint go-task curl jq envsubst git docker k9s jq make eget bsdmake bash bat helm-docs gh cli@latest diff-so-fancy openjdk@17

# 初始化 ct 工具並生成組態檔案:
ct init --config .github/config.yaml --chart-root charts/

我們可以透過初始化一個簡單的 .github/config.yaml 組態檔案來定義 ct 工具的行為和規則:


remote:
    enabled: true # 是否啟用遠端倉函式庫功能

chart-repos:
    - bitnami # 新增一些公共 Helm Charts 函式庫作為依賴函式庫來驗證圖表相容性。

charts:

    # 指定我們將要測試的圖表目錄。
    - path=charts/my-chart # 對應當前目錄中的某個圖表目錄。
    - path=charts/another-chart # 對應當前目錄中的另一個圖表目錄。

excluded-charts:

    # 指定要排除掉不需要進行測試和 linting 的圖表目錄。
    - path=charts/excluded-chart # 對應當前目錄中的某個圖表目錄。
推薦執行與整合步驟

我們可以透過以下方式執行 ct 工具來執行自動化測試以及結果報告:


# 在專案根目錄下執行所有測試:
ct lint --all --config .github/config.yaml --validate-maintainers=false --chart-dirs=charts/

# 在專案根目錄下執行所有單元測試:
ct install --config .github/config.yaml --namespace=default --upgrade=true

# 在專案根目錄下執行所有整合測試:
ct list-tests --config .github/config.yaml --all=true --debug=true --namespace default | tee tests.logs.txt && cat tests.logs.txt | jq '.' && rm tests.logs.txt && echo "All tests passed"

# 檢視所有生成報告:
ct report -o report.html ./test-results/

推薦針對 ct 的 CI/CD 整合步驟:

為了方便團隊協作與持續整合佈署(CI/CD),我們推薦將 ct 測試工具與 GitHub Actions 或 Jenkins、GitLab CI/CD 整合以實作自動化流程。

GitHub Actions Example Workflow:

建立或編輯 .github/workflows/ci.yml 組態檔案並增加如下內容:


name : ci-cd-pipeline-for-ct-tests # Pipeline名稱為 ci-cd-pipeline-for-ct-tests.

on :
    push :
        branches :
            - main # 指定觸發 CI Pipeline的分支為 main。
            - release/* # 指定觸發 CI Pipeline分支為任何 release/* 開頭。
        tags :
            - 'v*' # 指定觸發 CI Pipeline標籤為任何 v* 開頭。

jobs :

    lint :
        runs-on : ubuntu-latest # 指定 runner 作業執行平台為最新版 Ubuntu。
        steps :

            - name : Check out the repository.
              uses : actions/checkout@v3 # 簽出程式碼倉函式庫。
              with :

                ref : ${{ github.ref }} # 指定簽出程式碼分支或標籤。
                fetch-depth : '0' # 指定提取全部提交歷史深度為 '0' 。

            - name : Set up Helm.
              uses : azure/setup-helm@v3 # 安裝 Helm CLI 。
              with :

                version : v3.9.4 # 指定安裝版本為 v3.9.4 。

            - name : Set up Python.
              uses : actions/setup-python@v4 # 安裝 Python CLI 。
              with :

                python-version : '3.x' # 指定 Python 安裝版本為最新版 '3.x' 。

            - name : Set up chart-testing.
              uses : helm/chart-testing-action@v2.3.1 # 安裝 chart-testing CLI 。
              with :

                version : v3.5.1 # 指定 chart-testing 安裝版本為 v3.5.1 。

            - name : Run chart linter.
              run : |
                ct lint \
                  --chart-dirs charts \
                  --config .github/config.yaml \
                  --validate-maintainers=false \
                  --debug true \
                  --all=true \
                  || (cat lint-logs.txt && exit ${CT_LINT_FAIL_COUNT})

            - name : Create kind cluster.
              uses : helm/kind-action@v1.3.0 # 安裝 kind 叢集工具。
              with :

                cluster-name : kind-cluster #
                node-image : kindest/node:v1.25.x # 指定 node-image 呼叫版本為 kindest/node:v1.25.x。

            - name : Run chart tests.
              run : |
                ct install \
                  --namespace default \
                  --config .github/config.yaml \
                  || (cat logs.txt && exit ${CT_RUN_TESTS_FAIL_COUNT})

透過以上組態檔案完成後即可推播程式碼或標籤觸發 GitHub Actions 自動進行 CT 測試及結果報告生成。