iT邦幫忙

2024 iThome 鐵人賽

DAY 18
0

本次目標

  1. helm lint
  2. Kubeconform
  3. helm unit test
  4. package chart to Docker hub

helm lint

驗證 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

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、prettytaptext。另外, kubeconform 預設是針對原生 Kubernetes 資源驗證,環境常常可能會有非原始 Kubernetes 資源的 CRD,要做驗證時可以搭配 -ignore-missing-schemas略過或是用-schema-location` 方式去做處理,這部分可以參閱官說明

Chart 單元測試

可用於驗證 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 參數進行替換,可以是 JUnitNUnitXUnit

本範例撰寫了以下

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

打包 Chart 至 DockerHub

打包時可以設定 .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 開發的流程。

參考資源


上一篇
為 Quarkus 建立 Helm Chart
下一篇
來看看 Kustomize
系列文
當 Quarkus 想要騎乘駱駝並用8腳章魚掌控舵手 31
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言