在 Kubernetes 環境中佈署應用程式,Helm Chart 提供了便捷的封裝和管理方式。本文將引導讀者使用 Helm 佈署 Guestbook 應用,並探討 Redis 和 Guestbook 前端的組態細節。首先,我們會調整 Redis 的持久化設定,並透過生命週期鉤子實作資料備份和還原的功能。接著,我們會修改 Guestbook 前端的容器映像和服務型別,以適應不同的佈署環境。最後,我們會逐步講解如何安裝、升級和移除 Guestbook Chart,並提供一些除錯技巧和注意事項,確保應用程式順利執行。透過實際操作和組態說明,讀者可以更深入地理解 Helm Chart 的使用方法,並將其應用於更複雜的應用程式佈署場景。

Kubernetes Helm 佈署 Guestbook 應用

在 Kubernetes 中佈署應用程式,Helm 是一個強大的工具。透過 Helm,我們可以方便地管理和佈署 Kubernetes 應用。這篇文章將帶領我們建立一個 Guestbook Helm chart,並且針對 Redis 和 Guestbook 前端進行相關的組態和修改。

Redis 組態

在預設的 ConfigMap 值中,我們會啟用 Redis 的兩種持久化方式:Append Only File (AOF) 和 Redis Database File (RDF) 持久化。AOF 持久化方式是將新的資料條目追加到一個變更日誌樣式的檔案中,以提供變更歷史紀錄。RDF 持久化方式則是定期將資料複製到檔案中,從而建立資料快照。

接下來,我們會建立簡單的生命週期鉤子(hooks),允許使用者備份和還原 Redis 資料函式庫到之前的快照。因為只有 RDB 持久化與快照檔案相容,所以我們會覆寫 ConfigMap 值,將 appendonly 設為 no,從而停用 AOF 持久化。

這裡是完整的 values.yaml 修改範例:

redis:
  # Override the redis.fullname template
  fullnameOverride: redis
  # Enable unauthenticated access to Redis
  usePassword: false
  # Disable AOF persistence
  configmap: |-
    appendonly no

這些值會被新增到你的 chart 的 values.yaml 檔案中。每個值都必須被放在 redis: 專案下面,這是因為 Helm 要求覆寫 chart 依賴的值時需要符合此結構。

Guestbook 前端組態

當我們執行 helm create 命令時,會生成一些預設範本和值檔案。以下是生成的一些預設範本:

  • deployment.yaml:用來將 Guestbook 應用佈署到 Kubernetes。
  • ingress.yaml:提供從 Kubernetes 叢集外部存取 Guestbook 應用的一個選項。
  • serviceaccount.yaml:為 Guestbook 應用建立專用的 ServiceAccount。
  • service.yaml:在多個 Guestbook 應使用案例項之間進行負載平衡。也可以提供從外部存取 Guestbook 應用的一個選項。
  • _helpers.tpl:提供 Helm chart 中使用的一組通用範本。
  • NOTES.txt:提供在安裝應用後存取應用的指示。

接下來我們需要修改這些範本中的值。首先是 deployment.yaml 中的容器映像組態:

image: '{{ .Values.image.repository }}:{{ .Chart.AppVersion }}'

這裡的映像組態是由 image.repository 值和 AppVersion chart 設定決定的。在你的 values.yaml 中,預設會組態為佈署 nginx 映像:

image:
  repository: nginx

同時在 Chart.yaml 中,預設的應用版本號為 1.16.0:

appVersion: 1.16.0

根據 Kubernetes 的教程檔案,Guestbook 應用的特定映像需要如下組態:

image: gcr.io/google-samples/gb-frontend:v4

因此我們需要修改 image.repository 值和 AppVersion chart 設定:

image:
  repository: gcr.io/google-samples/gb-frontend
  pullPolicy: IfNotPresent
appVersion: v4

接著是在 service.yaml 中修改服務型別:

type: {{ .Values.service.type }}

根據預設值,這個服務會使用 ClusterIP 型別:

service:
  type: ClusterIP

為了方便在 minikube 環境中存取應用程式,我們將其修改為 NodePort 型別:

service:
  type: NodePort
  port: 80

安裝 Guestbook Chart

完成上述修改後,我們可以開始安裝 Guestbook Chart。首先更新 values.yamlChart.yaml 的相關內容:

values.yaml

image:
  repository: gcr.io/google-samples/gb-frontend
pullPolicy: IfNotPresent

service:
  type: NodePort
port: 80

Chart.yaml

appVersion: v4

然後執行以下命令來安裝 Guestbook Chart:

$ helm install my-guestbook guestbook -n chapter5

如果安裝成功,會顯示如下資訊:

NAME: my-guestbook
LAST DEPLOYED: Sun Apr 26 09:57:52 2020
NAMESPACE: chapter5
STATUS: deployed
REVISION: 1
NOTES:
1. Get the application URL by running these commands:
export NODE_PORT=$(kubectl get --namespace chapter5 -o jsonpath='{.spec.ports[0].nodePort}' services my-guestbook)
export NODE_IP=$(kubectl get nodes --namespace chapter5 -o jsonpath='{.items[0].status.addresses[0].address}')
echo http://$NODE_IP:$NODE_PORT

如果 Pod 未準備好,可以使用 --wait--timeout 單位秒數來等待 Pod 準備完成。你也可以手動檢查每個 Pod 的狀態:

$ kubectl get pods -n chapter5

當所有 Pod 準備好時,你會看到每個 Pod 的 READY 欄位顯示為 1/1。這意味著應用已經準備好供使用了。

本篇文章所需圖示:

此圖示展示了 Kubernetes 中 Pod 的狀態檢查指令,確認每個 Pod 是否已經準備就緒。

  graph TD;
    A[安裝 Helm Chart] --> B{Pod 是否準備好?};
    B -- 是 --> C[存取應用];
    B --否 --> D{等待超時?};
    D -- 是 --> E[重試安裝];
    D --否 --> B;
補充說明:

此圖展示了 Pod 準備過程中的決策流程圖,幫助理解當 Pod 未準備好時該如何處理。

透過上述步驟,玄貓帶領大家成功佈署了一個完整的 Guestbook Helm chart。希望對大家有所幫助!

自建您的第一個 Helm Chart

驗證 Pod 執行狀態

在 Pod 就緒後,您可以執行在釋放資訊中顯示的指令。若有需要,可以再次顯示這些指令:

helm get notes my-guestbook -n chapter5

釋放資訊中的指令會提供應用程式的 URL,您可以將這個 URL 複製到瀏覽器中,應該會顯示 Guestbook 的使用者介面(UI)。

檢視 Guestbook 前端

嘗試在對話方塊中輸入一則訊息並點選「提交」。Guestbook 前端會在「提交」按鈕下方顯示這則訊息,表示這則訊息已成功儲存到 Redis 資料函式庫。

如果您能夠撰寫訊息並看到它顯示在螢幕上,那麼恭喜您,您已成功建置並佈署了第一個 Helm Chart!如果您無法看到訊息,可能是因為 Redis 相依性未正確設定。請確認 Redis 值已正確組態,並且 Redis 相依性已在 Chart.yaml 檔案中正確宣告。

移除 Helm Chart

當您準備好時,可以使用 helm uninstall 指令來移除這個 Chart:

helm uninstall my-guestbook -n chapter5

由於 Redis 相依性透過 StatefulSet 使資料函式庫持久化(這不會自動移除 PersistentVolumeClaims(PVCs)),因此您需要手動移除 Redis PVCs。執行以下指令來移除 Redis PVCs:

kubectl delete pvc -l app=redis -n chapter5

接下來,我們將探討如何改進 Guestbook Chart。

改進 Guestbook Helm Chart

前一節中建立的 Chart 已成功佈署了 Guestbook 應用程式。然而,就像任何軟體一樣,Helm Chart 永遠可以改進。本文將專注於兩個功能,以提升 Guestbook Chart 的品質:

  • 生命週期掛勾(hooks)以備份和還原 Redis 資料函式庫
  • 輸入驗證以確保只提供有效值

首先,讓我們來新增生命週期掛勾。

建立升級前和回復前的生命週期掛勾

本文將建立兩個生命週期掛勾:

  1. 升級前掛勾:此掛勾發生在升級生命週期階段,即 helm upgrade 指令執行後、但尚未修改任何 Kubernetes 資源之前。此掛勾將在進行升級前對 Redis 資料函式庫進行資料快照備份,以防止升級出錯。

  2. 回復前掛勾:此掛勾發生在回復生命週期階段,即 helm rollback 指令執行後、但尚未還原任何 Kubernetes 資源之前。此掛勾將還原 Redis 資料函式庫到之前的資料快照,並確保 Kubernetes 資源組態與快照時相符。

完成本文後,您將更熟悉生命週期掛勾及其強大功能。請記住,本文中的掛勾非常簡單且僅用於探索 Helm 掛勾的基本功能。不建議在生產環境中直接使用這些掛勾。

建立升級前掛勾以取得資料快照

在 Redis 中,資料快照包含在 dump.rdb 檔案中。我們可以透過建立一個掛勾來備份這個檔案。該掛勾首先在 Kubernetes 名稱空間中建立一個新的 PersistentVolumeClaim(PVC)。然後建立一個 job 資源來複製 dump.rdb 檔案到新的 PVC 中。

雖然 helm create 指令生成了一些強大的資源範本,允許快速建立初始 guestbook chart ,但它並未預設任何可用於此任務的範本。因此,您可以從頭開始建立升級前掛勍。

建立目錄和範本檔案

  1. 首先建立一個新目錄來包含掛勍範本。雖然這不是技術要求,但它有助於將掛勍範本與一般 chart 範本分開。同時也允許您按功能群組化掛勍範本。

    在 guestbook 檔案結構中建立名為 templates/backup 的新目錄:

    mkdir guestbook/templates/backup
    
  2. 接著鋪設兩個範本以執行備份操作:第一個是用於包含複製後 dump.rdb 檔案的 PersistentVolumeClaim 範本;第二個是用於執行複製操作的 job 範本。

    建立兩個空白範本檔案作為佔位符:

    touch guestbook/templates/backup/persistentvolumeclaim.yaml
    touch guestbook/templates/backup/job.yaml
    
  3. 您可以參考 Packt 儲存函式庫來驗證工作是否正確。檔案結構應與以下位址相同:Packt GitHub

  4. 接下來讓我們建立 persistentvolumeclaim.yaml 範本。將下面的內容複製到 backup/persistentvolumeclaim.yaml 檔案中(此檔案也可從 Packt 儲存函式庫複製)。請注意,空白為空格而非定位字元(tabs),遵循有效 YAML 語法。

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: redis-backup-pvc
spec:
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 1Gi

內容解密:

apiVersion: v1               # 指定 API 版本為 v1。
kind: PersistentVolumeClaim # 指定資源型別為 PersistentVolumeClaim。
metadata:                    # 後設資料部分。
  name: redis-backup-pvc     # PVC 名稱為 redis-backup-pvc。
spec:                        # 持久化卷宣告規格部分。
  accessModes:               # 指定存取模式。
    - ReadWriteOnce           # 單節點讀寫存取模式。
  resources:                 # 資源需求部分。
    requests:                # 資源需求詳細說明。
      storage: 1Gi           # 必須提供至少1Gi的儲存空間。

以上內容完成了 persistentvolumeclaim.yaml 範本的建立和詳細解說。接下來我們將繼續建立 job 範本來實作備份操作。

建立 job 範本

接下來我們需要建立一個 job 範本來完成從 Redis 主機複製 dump.rdb 檔案到新建立的 PVC 中。以下是完整的 job 範本內容:

apiVersion: batch/v1
kind: Job
metadata:
  name: redis-backup-job
spec:
  template:
    spec:
      containers:
      - name: backup-container
        image: busybox
        command: ["sh", "-c", "cp /data/dump.rdb /backup/dump.rdb"]
        volumeMounts:
        - mountPath: /data
          name: redis-data-volume
        - mountPath: /backup
          name: backup-volume
      volumes:
      - name: redis-data-volume
        persistentVolumeClaim:
          claimName: redis-data-pvc
      - name: backup-volume
        persistentVolumeClaim:
          claimName: redis-backup-pvc
      restartPolicy: OnFailure

內容解密:

apiVersion: batch/v1              # 指定 API 版本為 batch/v1。
kind: Job                        # 指定資源型別為 Job。
metadata:
  name: redis-backup-job         # Job 名稱為 redis-backup-job。
spec:
  template:
    spec:
      containers:
      - name: backup-container     # Container 名稱為 backup-container。
        image: busybox              # Container 根據 busybox images。
        command: ["sh", "-c", "cp /data/dump.rdb /backup/dump.rdb"]   # 執行複製操作命令。
        volumeMounts:
        - mountPath: /data         # 持久化卷掛載路徑。
          name: redis-data-volume   # 掛載名稱對應至持久化卷名稱。
        - mountPath: /backup       # 備份持久化卷掛載路徑。
          name: backup-volume       # 掛載名稱對應至備份持久化卷名稱。
      volumes:
      - name: redis-data-volume     # 持久化卷名稱。
        persistentVolumeClaim:
          claimName: redis-data-pvc   # 舊持久化卷宣告名稱(Redis 資料)。
      - name: backup-volume         # 備份持久化卷名稱。
        persistentVolumeClaim:
          claimName: redis-backup-pvc   # 新備份持久化卷宣告名稱(Redis 備份)。
      restartPolicy: OnFailure       # Job 啟動策略:當任務失敗時重啟 container。

此 job 範本完成了從 Redis 主機複製 dump.rdb 檔案到新建立 PVC 的操作設計。接下來我們必須確保這些範本被正確地引入至 Helm Chart 中並且遵循生命週期 hook 的組態方式。

組態 Helm Chart 生命週期 hook

為了讓 Helm 把這些 job 和 PVC 作為升級前 hook 命令運作起來,我們需要修改 Helm Chart 的一些組態檔案:

  1. 修改 Chart.yaml:檢查並修改 Chart.yaml 中是否已經包含了所需的 metadata 和 version 輸入。

  2. 修改 values.yaml:檢查並修改 values.yaml 中是否已經包含了所需的引數設定和 default 值輸入。

  3. 修改 templates/_helpers.tpl:如果需要使用任何 helper function 或 template variables 則可在此檔案進行定義和設定。

  4. 修改 hook annotation :對於每個 hook templates 副檔案都需加上 lifecycle annotation ,如以下例所示:

apiVersion: batch/v1                          # API version for the job resource.
kind: Job                                    #
metadata:
  name: "{{ .Release.Name }}-redis-backup-job"     #
  annotations:
    "helm.sh/hook": pre-upgrade               #
    "helm.sh/hook-weight": "0"                #
spec:
# (The rest of the spec remains unchanged)

組態 annotation 說明:

"helm.sh/hook": pre-upgrade                 # 指定該資源是一個升級前生命週期 hook。
"helm.sh/hook-weight": "0"                  # 點設 hook 啟動優先權值為零(最高優先權)。

以上步驟確保了 Helm 在進行升級時會執行指定的預先設定 hook 。接下來我們只需啟動 helm upgrade 操作即可測試是否成功完成資料備份操作。

測試及驗證 Hooks 功能

我們已經完成了預先設定 hook 的組態工作並且準備好測試其功能實作效果:

helm upgrade my-guestbook ./guestbook --namespace chapter5 --wait --debug --dry-run --timeout=5m0s --log-file=upgrade.log --output-dir=./upgrade-output/

測試及驗證 Hooks 說明:

helm upgrade my-guestbook ./guestbook          # 執行升級指令, 名稱為 my-guestbook, charts 路徑為 ./guestbook 。
--namespace chapter5                            #
--wait                                            #
--debug                                            #
--dry-run                                          #
--timeout=5m0s                                     #
--log-file=upgrade.log                             #
--output-dir=./upgrade-output                    #

在上述指令執行後我們需要檢視 log file (upgrade.log) ,看看其中記錄了何種執行步驟及結果:

Check if the pre-upgrade job was created successfully.
Ensure that the dump.rdb file was copied to the new PVC.
Verify that the application upgrades successfully after running the hooks.
Check if the new application version is running correctly.

測試結果解說:

  • Check if the pre-upgrade job was created successfully. : 必須確認預先設定 job 是否被成功建立和執行起來。你可以透過 kubectl 命令查詢具體狀態資訊: bash kubectl get jobs -n chapter5
  • Ensure that the dump.rdb file was copied to the new PVC. : 驗證新建立 PVC 中是否成功複製 dump.rdb 檔案並且檢查其完整性: bash kubectl exec <pod-name> -- ls /backup
  • Verify that the application upgrades successfully after running the hooks. : 必須確認應用程式完成更新後仍然正常執行,沒有出現異常或錯誤: bash kubectl get pods -n chapter5
  • Check if the new application version is running correctly. : 最終測試是確認更新版本是否正常執行且所有功能都無異常發生: bash kubectl logs <pod-name>

以上步驟完成了預先設定 hooks 的測試及驗證工作流程並且也說明瞭每一步驟需要執行哪些具體操作命令和如何檢視結果資訊