最新資訊
科技新聞

雲端整合專家,提供全方位雲端顧問服務

科技趨勢

CKA - Chapter 10 Helm

導讀

在前面的幾個章節, 我們已經知道如何部署 Deployment, StatefulSet, DaemonSet, service 等等. 從v1.4版開始, 設定的目標就是為部署軟體規範一個特定的位置. Helm其實就是K8S的包管理工具(package manager tool), 只是Helm用的是Chart而非package, 功能類似Linux 上的apt yum,Mac 上的brew 等等.

一個典型的容器化應用程序,通常會有多個清單(manifests)例如: Deployment清單, Service清單, ConfigMaps 清單等等. 又或者你會創建 secret, ingress, 及其他的物件. 每個物件都會需要一張清單.

使用Helm, 你可以

  • 將所有的清單打包起來並壓縮成一個tarball. 然後將這個tarball 放上儲存庫(repository)
  • 搜索儲存庫找你要的應用程序
  • 然後只要一行指令, 你就可以完成部署.

Helm的服務器運行在kubernetes的叢集之中, 不過客戶端(client side)卻可以運行在任何地方, 例如: 桌機或是筆電上. 透過helm的指令可以連結多個不同的儲存庫. Helm不僅僅是安裝而已, 你也可以用Helm來升級(upgrade)或回滾(roll-back)部署.

Helm v2 與 Tiller


這個圖是Helm v2與k8s叢集的溝通方式, 這個設計需要安裝一個Tiller的pod在叢集裡面, Helm的安裝命令由Tiller接收,接著Tiller會依照需求來創建物件例如:Pod, Service, ConfigMaps等等.

咦!? 這個設計似乎有點問題, 由於Tiller具有root用戶的權限, 可能會有人在未經授權下, 訪問你的kubernetes服務器, 也因此構成巨大的資安風險.

Tiller 通常會有如上的RBAC設定. 為了要讓Helm部署變得靈活好用, Tiller有cluster-admin的權限, 這樣的架構可能暫時讓你的容器管理工作變得容易, 但是衍生出來的資安問題確實令人頭痛. 後來, Rimas(helm的作者)推出了一個tillerless的解決方案, 這個方式是把tiller 移出叢集,在客戶端運行, 這邊就不深究了, 因為後面就要講Helm v3, 這個版本是可以直接與K8s API溝通, tiller 整個被移除.

如果還是對helm-tiller有興趣的, 可以看這裡

Helm v3

  • 跟v2比, 有很多的改變, 詳細的內容可以看這裡
  • 再也沒有Tiller Pod
  • 3-way Strategic merge patches 三方策略合併補丁
  • 在安裝時需要給名稱(name), 不然就要加選項 --generated-name
  • 有一些指令已經棄用 例如: helm serve
  • Helm v3 也不用helm init囉~

什麼事三方策略合併補丁?

In Helm 3, we now use a three-way strategic merge patch. Helm considers the old manifest, its live state, and the new manifest when generating a patch.

如同字面所言, Helm會考慮最早的清單,正在運行的清單及最新要部署的清單. 舉例來說:

最早的清單 - memory跟cpu的需求

kind: Deployment
spec:
  containers:
  - resources:
       requests:
       memory: "64Mi"
       cpu: "250m"

正在運行的清單

kind: Deployment
spec:
  containers:
  - resources:
       requests:
       memory: "128Mi"
       cpu: "750m"

最新要部署的清單

kind: Deployment
spec:
  containers:
  - resources:
       requests:
       memory: "512Mi"
       cpu: "250m"

最終版本清單 - 會將真實的最大所需納入考量.
這個清單取自最新版的memory 需求及運行版的cpu需求

kind: Deployment
spec:
  containers:
  - resources:
       requests:
       memory: "512Mi"
       cpu: "750m"

Chart Contents

Chart是一包資源清單用來建構成K8s分佈式應用程序. Kubernetes社群有自行維護的chart儲存庫(repository), 也有廠商自行提供的儲存庫(repository), 當然, 你也可以自建自己的儲存庫.

我們接著來看看一個Chart裡面有包含哪些清單, 這裡我們看一個wordpress的chart

  • Chart.yaml: [必要]包含了跟這個Chart相關的所有資訊, 還有開頭的C是大寫
  • License: [非必要]許可資訊
  • README.md: [非必要]跟這個chart相關的資訊, md 格式供大家可以簡易地閱讀
  • values.yaml: 編寫chart的各項預設值
  • charts/ 這是一個目錄, 裡面包含了所有依存的chart
  • crds/ 客製化的資源定義 (custom resource definitions)
  • templates/ 儲存模版的目錄, 模板裡面的變數與values.yaml設定有關.

想知道更多? 請按這裡

templates and values 模板與給值

我們來看看一個template 的 yaml檔, 若你原本就是Golang的開發者的話, 它其實用的就是Go的template 語法. 在模板裡, 用兩個大括弧 ({{ }})包起來的是要渲染的變數, 而渲染過程中會去values.yaml取得變數的數值. 如下所示, MariaDB 的 password 會去values.yaml裡面的變數(Values.externalDatabase.password)取得並存成Secret

  • mariadb-password

externalDatabaseSecret.yaml

{{- if not (or .Values.mariadb.enabled .Values.externalDatabase.existingSecret) }}
apiVersion: v1
kind: Secret
metadata:
  name: {{ printf "%s-externaldb" (include "common.names.fullname" .) | trunc 63 | trimSuffix "-" }}
  namespace: {{ .Release.Namespace | quote }}
  labels: {{- include "common.labels.standard" . | nindent 4 }}
    {{- if .Values.commonLabels }}
    {{- include "common.tplvalues.render" ( dict "value" .Values.commonLabels "context" $ ) | nindent 4 }}
    {{- end }}
  {{- if .Values.commonAnnotations }}
  annotations: {{- include "common.tplvalues.render" ( dict "value" .Values.commonAnnotations "context" $ ) | nindent 4 }}
  {{- end }}
type: Opaque
data:
  mariadb-password: {{ .Values.externalDatabase.password | b64enc | quote }}
{{- end }}

values.yaml: 本文內容太長, 僅擷取跟Password相關的設定. 剛剛Secret 那邊要取得的mariadb-password 的值就在這裡設定.

有興趣想更深入研究這個values.yaml的同學,可以點這裡

安裝 Helm

這邊我只有提供Linux的apt安裝方式, 想要知道其他作業系統的安裝方式, 可以點這裡

Ubuntu - 安裝helm v3在我們的實驗環境

$ curl https://baltocdn.com/helm/signing.asc | sudo apt-key add -
$ sudo apt-get install apt-transport-https --yes
$ echo "deb https://baltocdn.com/helm/stable/debian/ all main" | sudo tee /etc/apt/sources.list.d/helm-stable-debian.list
$ sudo apt-get update
$ sudo apt-get install helm

檢查一下安裝的版本, 這邊我安裝的是Helm v3.7.2

Add Helm Repos 加入儲存庫

若想要透過Helm來安裝應用程序在K8s的叢集裡, 必須要加入儲存庫. 下面兩行指令用來增加repo與刷新repo

$ helm repo add [repo名稱] [連結]

$ helm repo update

舉例來說, 要用binami的封裝的wordpress chart, 首先要加入binami的repo, 然後安裝wordpress

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

$ helm install my-release bitnami/wordpress

列出與helm repo 相關的使用文檔
$ helm repo -h 

列出所有的repo 
$ helm repo list

用關鍵字搜尋 可以用的chart
$ helm repo search [關鍵字]

例如:
$ helm repo search redis

這個是在binami這個repo上找到跟redis 相關的chart. 大家在使用repo的時候,一定要注意的:

  • 是否是被驗證過的發布者
  • 資安驗證等級
  • 下載量

因為人人都可以發行chart, 是否有定期的維護使用的映像檔或是設定會是我們選擇chart的關鍵, 裝錯chart 很可能會讓你麻煩不斷.


如果想要客製化一些設定, 透過 --set 的方式

$ helm install my-release \
  --set wordpressUsername=admin \
  --set wordpressPassword=password \
  --set mariadb.auth.rootPassword=secretpassword \
    bitnami/wordpress
    
透過 values.yaml的方式, \
將要調整的設定寫在values.yaml裡面, \
然後執行下面的指令

$ helm install my-release -f \
values.yaml bitnami/wordpress

可以參考這裡

透過Helm進行第一次的部署

這裡我們透過helm的方式安裝redis

安裝參考這個repo

$ helm install redis pascaliske/redis

$ helm status redis 

$ k get deploy,po

大家記得要詳細閱讀helm 安裝完成的訊息, 通常部署完成後, 如何使用的資訊都會列出如下.

這邊筆者特別把輸出列出如下, 按照給的步驟一步步指行後就可以使用剛剛部署的redis

$ export POD_NAME=$(kubectl get pods --namespace default -l "app.kubernetes.io/name=redis,app.kubernetes.io/instance=redis" -o jsonpath="{.items[0].metadata.name}")

$ export CONTAINER_PORT=$(kubectl get pod --namespace default $POD_NAME -o jsonpath="{.spec.containers[0].ports[0].containerPort}")

$ echo "Visit http://127.0.0.1:6379 to use your application"

這邊筆者稍微改動一下, 讓指令在背景執行,\
這裡我們用了port-forward的方式, \
等等連接需要使用redis-cli \
且 port 已經被轉到本機的8080

$ kubectl --namespace default port-forward $POD_NAME 8080:$CONTAINER_PORT &

$ sudo apt install redis-tools

$ redis-cli -h 127.0.0.1 -p 8080

查看 redis 的資訊
> info

離開redis 介面
> exit 

好拉~這就是透過helm 來安裝及測試redis連線 的流程. 其實helm有很多包好的應用, 安裝跟設定都非常的方便. 最後, 用Helm指令來移除剛剛的 redis 部署

$ helm uninstall redis 
$ helm list 

或者
$ helm ls

移除後將看不到你部署的chart