本次目標
驗證 Chart 是否有問題 helm lint {CHART_CONTEXT} -f {VALUES_YAML}
$ helm lint . -f values.yaml
==> Linting .
[INFO] Chart.yaml: icon is recommended
1 chart(s) linted, 0 chart(s) failed
Kubeconform 是 Kubernetes YAML 驗證工具。也就是說透過 helm template
產生的 YAML 可以透過此 Kubeconform 進行驗證,這可避免定義上細節的錯誤。將其導入 CI 流程,可以增強部署時穩健。
可以如下安裝
$ wget https://github.com/yannh/kubeconform/releases/download/v0.6.3/kubeconform-linux-amd64.tar.gz
$ tar xf kubeconform-linux-amd64.tar.gz
$ sudo mv kubeconform /usr/local/bin
驗證過程建議指定 Kubernetes 版本來進行驗證,Kubernetes 每個版本的 API 會有所不同,這樣可以明確知道 Chart 可以在哪個版本的 Kubernetes 環境運行,避免 Kubernetes 升級後帶來的災難。
從下面驗證結果來看,4 個資源被驗證,無任何錯誤。當有錯誤會跳出相對應的錯誤內容。
$ helm template --skip-tests --kube-version v1.23.0 ./ -f env/values-dev.yaml | kubeconform --summary -kubernetes-version 1.29.0
Summary: 4 resources found parsing stdin - Valid: 4, Invalid: 0, Errors: 0, Skipped: 0
對於 CI 建構如果需要數據的依據可以藉由 -output
參數輸出不同格式的內容,下面是使用 junit
格式。
$ helm template --skip-tests --kube-version v1.23.0 ./ -f env/values-dev.yaml | kubeconform --summary -kubernetes-version 1.29.0 -output junit
<testsuites name="kubeconform" time="0.501572304" tests="4" failures="0" disabled="0" errors="0">
<testsuite name="stdin" id="1" tests="4" failures="0" errors="0" disabled="0" skipped="0">
<testcase name="release-name-quarkus-dns-config" classname="ConfigMap@v1" time="0"></testcase>
<testcase name="quarkus-dns" classname="ServiceAccount@v1" time="0"></testcase>
<testcase name="release-name-quarkus-dns" classname="Service@v1" time="0"></testcase>
<testcase name="release-name-quarkus-dns" classname="Deployment@apps/v1" time="0"></testcase>
</testsuite>
</testsuites>
其它格式還資源 json
、pretty、
tap、
text。另外, kubeconform 預設是針對原生 Kubernetes 資源驗證,環境常常可能會有非原始 Kubernetes 資源的 CRD,要做驗證時可以搭配
-ignore-missing-schemas略過或是用
-schema-location` 方式去做處理,這部分可以參閱官說明。
可用於驗證 YAML 是不是能夠是你期望的內容。這邊使用 helm-unittest
屬於 Helm 的插件,安裝方式如下
$ helm plugin install https://github.com/helm-unittest/helm-unittest.git
$ helm plugin update unittest
在 Chart 目錄下建立 tests 目錄,並把該目錄新增自 .helmignore
中。要觸發測試可以使用 helm unittest CHART_NAME
下面是一個測試完成的結果,預設格式是 XUnit
,這可以使用 -t
參數進行替換,可以是 JUnit
、NUnit
或 XUnit
。
本範例撰寫了以下
quarkus-dns$ tree tests/
tests/
├── __snapshot__
├── configmap_test.yaml
├── deployment_test.yaml
├── service_test.yaml
└── serviceaccount_test.yam
撰寫完如何執行。但執行的方式取決於,Helm Charts 的目錄如何放置那些 Chart。本次範例就單純一個 Chart。
quarkus-dns$ helm unittest .
### Chart [ quarkus-dns ] .
PASS test configMap tests/configmap_test.yaml
PASS test deployment tests/deployment_test.yaml
PASS test service tests/service_test.yaml
PASS test serviceAccount tests/serviceaccount_test.yaml
Charts: 1 passed, 1 total
Test Suites: 4 passed, 4 total
Tests: 4 passed, 4 total
Snapshot: 0 passed, 0 total
Time: 9.637532ms
接著來看看,測試寫了什麼。以 deployment_test.yaml 為例。
suite: test deployment
values: # 定義要參考的 Values.yaml
- ../env/values-test.yaml
templates: # 要被驗證的 template。
- templates/deployment.yaml
- templates/configmap.yaml # 因為 deployment.yaml 會引用 ConfigMap 資源
release: # 模擬部署時的環境
name: test-release # 部署名稱
namespace: test # 部署的 namespace
chart: # chart 資訊
version: 0.1.0+test
appVersion: 1.16.0
tests:
- it: should pass all kinds of assertion
template: templates/deployment.yaml
documentIndex: 0
asserts: # 以下就是驗證欄位,基本上是使用 jsonPath 規範
- equal: # 是否相同
path: metadata.labels["app.kubernetes.io/managed-by"]
value: Helm
- equal:
path: metadata.labels["app.kubernetes.io/name"]
value: quarkus-dns
- isNotEmpty: # 非空,所以要有值
path: spec.template.metadata.annotations["checksum/configmap-env"]
- isNotEmpty:
path: spec.template.spec.containers[?(@.name == "quarkus-dns")].image
- isNotEmpty:
path: spec.template.spec.serviceAccountName
- matchRegex: # 規則表示驗證
path: metadata.name
pattern: ^.*-quarkus-dns$
- contains: # 比對當下 path 下的 YAML 內容
path: spec.template.spec.containers[?(@.name == "quarkus-dns")].ports
content:
containerPort: 8080
protocol: TCP
name: http
- notContains: # 比對當下 path 下的 YAML 內容,不該包含 content
path: spec.template.spec.containers[?(@.name == "quarkus-dns")].ports
content:
containerPort: 80
- isNotEmpty:
path: spec.template.spec.containers[?(@.name == "quarkus-dns")].livenessProbe
- isNotEmpty:
path: spec.template.spec.containers[?(@.name == "quarkus-dns")].readinessProbe
- isNotEmpty:
path: spec.template.spec.containers[?(@.name == "quarkus-dns")].resources
- isSubset: # 將物件斷言為包含內容的指定 path 的值
path: spec.template.spec.containers[?(@.name == "quarkus-dns")].securityContext
content:
privileged: false
capabilities:
drop:
- ALL
readOnlyRootFilesystem: true
allowPrivilegeEscalation: false
- isSubset:
path: spec.template.spec.securityContext
content:
fsGroup: 2000
runAsNonRoot: true
runAsUser: 1001
runAsGroup: 1001
- isKind:
of: Deployment
- isAPIVersion:
of: apps/v1
更多斷言的應用可以參考官方assertion-types。
打包時可以設定 .helmignore
把不必要的東西不打包進去。基本上和 .dockerignore
是類似。
如下,切至 Chart 中並使用 helm package
方式,而版本會參考 Chart.yaml 中 version 欄位。
/quarkus-dns$ helm package .
Successfully packaged chart and saved it to: /home/itachi/github/ithome2024/ithome2024lab/day16/helmchartlab/quarkus-dns/quarkus-dns-0.1.0.tgz
要將該 .tgz 的資源推送至 Docker Hub 時,先進行登入。會建議使用個人令牌。
$ export PAT=PERSONAL_ACCESS_TOKEN
$ export USERNAME=LOGIN_USERNAME
$ echo $PAT | docker login -u $USERNAME --password-stdin
使用 helm push
推送 Chart 至 Docker Hub,並指定要推送的 charts 和推送目標。
$helm push quarkus-dns-0.1.0.tgz oci://registry-1.docker.io/cch0124
Pushed: registry-1.docker.io/cch0124/quarkus-dns:0.1.0
Digest: sha256:b2fe848ad4c001c323e297f7c45cf96ed6de874a02cc62be8eae8f4e3811ef94
上一步驟,已經將資源上傳至 Docker Hub,因此透過以下方式可以讓 helm 去讀取上傳的 Chart 資源。
$ helm show chart oci://registry-1.docker.io/cch0124/quarkus-dns
Pulled: registry-1.docker.io/cch0124/quarkus-dns:0.1.0
Digest: sha256:b2fe848ad4c001c323e297f7c45cf96ed6de874a02cc62be8eae8f4e3811ef94
apiVersion: v2
appVersion: 1.16.0
description: A Helm chart for Kubernetes
name: quarkus-dns
type: application
version: 0.1.0
如果一個 Chart 要給其它團隊使用,則定義在 values.yaml 內容就必須詳細的說明參數用來做什麼。預設上 Helm 不會幫你產生豐富資訊的文件,但這些文件對於人來說卻是比直接看 YAML 內容還要直觀。要完成這些內容可以使用 helm-docs 工具來實作,也搭配著 pre-commite
方式。因為官方資訊其實很完整這邊就不再贅述。
綜合以上,它們是可以串聯出一個 CI 鏈,這樣就可以增強 Helm Chart 開發的流程。