1. 程式人生 > >helm簡介、安裝、應用

helm簡介、安裝、應用

Helm 是 Kubernetes 生態系統中的一個軟體包管理工具。本文將介紹 Helm 中的相關概念和基本工作原理,並通過一個具體的示例學習如何使用 Helm 打包、分發、安裝、升級及回退 Kubernetes 應用。

Kubernetes 應用部署的挑戰

Kubernetes 是一個提供了基於容器的應用叢集管理解決方案,Kubernetes 為容器化應用提供了部署執行、資源排程、服務發現和動態伸縮等一系列完整功能。

Kubernetes 的核心設計理念是: 使用者定義要部署的應用程式的規則,而 Kubernetes 則負責按照定義的規則部署並執行應用程式。如果應用程式出現問題導致偏離了定義的規格,Kubernetes 負責對其進行自動修正。例如:定義的應用規則要求部署兩個例項(Pod),其中一個例項異常終止了,Kubernetes 會檢查到並重新啟動一個新的例項。

使用者通過使用 Kubernetes API 物件來描述應用程式規則,包括 Pod、Service、Volume、Namespace、ReplicaSet、Deployment、Job等等。一般這些資源物件的定義需要寫入一系列的 YAML 檔案中,然後通過 Kubernetes 命令列工具 Kubectl 調 Kubernetes API 進行部署。

以一個典型的三層應用 Wordpress 為例,該應用程式就涉及到多個 Kubernetes API 物件,而要描述這些 Kubernetes API 物件就可能要同時維護多個 YAML 檔案。

從上圖可以看到,在進行 Kubernetes 軟體部署時,我們面臨下述幾個問題:

  • 如何管理、編輯和更新這些這些分散的 Kubernetes 應用配置檔案。
  • 如何把一套相關的配置檔案作為一個應用進行管理。
  • 如何分發和重用 Kubernetes 的應用配置。

Helm 的出現就是為了很好地解決上面這些問題。

Helm 是什麼?

Helm 是 Deis 開發的一個用於 Kubernetes 應用的包管理工具,主要用來管理 Charts。有點類似於 Ubuntu 中的 APT 或 CentOS 中的 YUM。

Helm Chart 是用來封裝 Kubernetes 原生應用程式的一系列 YAML 檔案。可以在你部署應用的時候自定義應用程式的一些 Metadata,以便於應用程式的分發。

對於應用釋出者而言,可以通過 Helm 打包應用、管理應用依賴關係、管理應用版本併發布應用到軟體倉庫。

對於使用者而言,使用 Helm 後不用需要編寫複雜的應用部署檔案,可以以簡單的方式在 Kubernetes 上查詢、安裝、升級、回滾、解除安裝應用程式。

Helm 元件及相關術語

  • Helm

Helm 是一個命令列下的客戶端工具。主要用於 Kubernetes 應用程式 Chart 的建立、打包、釋出以及建立和管理本地和遠端的 Chart 倉庫。

  • Tiller

Tiller 是 Helm 的服務端,部署在 Kubernetes 叢集中。Tiller 用於接收 Helm 的請求,並根據 Chart 生成 Kubernetes 的部署檔案( Helm 稱為 Release ),然後提交給 Kubernetes 建立應用。Tiller 還提供了 Release 的升級、刪除、回滾等一系列功能。

  • Chart

Helm 的軟體包,採用 TAR 格式。類似於 APT 的 DEB 包或者 YUM 的 RPM 包,其包含了一組定義 Kubernetes 資源相關的 YAML 檔案。

  • Repoistory

Helm 的軟體倉庫,Repository 本質上是一個 Web 伺服器,該伺服器儲存了一系列的 Chart 軟體包以供使用者下載,並且提供了一個該 Repository 的 Chart 包的清單檔案以供查詢。Helm 可以同時管理多個不同的 Repository。

  • Release

使用 helm install 命令在 Kubernetes 叢集中部署的 Chart 稱為 Release。

注:需要注意的是:Helm 中提到的 Release 和我們通常概念中的版本有所不同,這裡的 Release 可以理解為 Helm 使用 Chart 包部署的一個應用例項。

Helm 工作原理

這張圖描述了 Helm 的幾個關鍵元件 Helm(客戶端)、Tiller(伺服器)、Repository(Chart 軟體倉庫)、Chart(軟體包)之間的關係。

Chart Install 過程

  • Helm 從指定的目錄或者 TAR 檔案中解析出 Chart 結構資訊。
  • Helm 將指定的 Chart 結構和 Values 資訊通過 gRPC 傳遞給 Tiller。
  • Tiller 根據 Chart 和 Values 生成一個 Release。
  • Tiller 將 Release 傳送給 Kubernetes 用於生成 Release。

Chart Update 過程

  • Helm 從指定的目錄或者 TAR 檔案中解析出 Chart 結構資訊。
  • Helm 將需要更新的 Release 的名稱、Chart 結構和 Values 資訊傳遞給 Tiller。
  • Tiller 生成 Release 並更新指定名稱的 Release 的 History。
  • Tiller 將 Release 傳送給 Kubernetes 用於更新 Release。

Chart Rollback 過程

  • Helm 將要回滾的 Release 的名稱傳遞給 Tiller。
  • Tiller 根據 Release 的名稱查詢 History。
  • Tiller 從 History 中獲取上一個 Release。
  • Tiller 將上一個 Release 傳送給 Kubernetes 用於替換當前 Release。

Chart 處理依賴說明

Tiller 在處理 Chart 時,直接將 Chart 以及其依賴的所有 Charts 合併為一個 Release,同時傳遞給 Kubernetes。因此 Tiller 並不負責管理依賴之間的啟動順序。Chart 中的應用需要能夠自行處理依賴關係。

部署 Helm

安裝 Helm 客戶端

Helm 的安裝方式很多,這裡採用二進位制的方式安裝。更多安裝方法可以參考 Helm 的官方幫助文件

  • 使用官方提供的指令碼一鍵安裝
1
2
3
$ curl https://raw.githubusercontent.com/kubernetes/helm/master/scripts/get > get_helm.sh
$ chmod 700 get_helm.sh
$ ./get_helm.sh
  • 手動下載安裝
1
2
3
4
5
6
# 下載 Helm 
$ wget https://storage.googleapis.com/kubernetes-helm/helm-v2.9.1-linux-amd64.tar.gz
# 解壓 Helm
$ tar -zxvf helm-v2.9.1-linux-amd64.tar.gz
# 複製客戶端執行檔案到 bin 目錄下
$ cp linux-amd64/helm /usr/local/bin/

注:storage.googleapis.com 預設是不能訪問的,該問題請自行解決。

安裝 Helm 伺服器端 Tiller

Tiller 是以 Deployment 方式部署在 Kubernetes 叢集中的,只需使用以下指令便可簡單的完成安裝。

1
$ helm init

由於 Helm 預設會去 storage.googleapis.com 拉取映象,如果你當前執行的機器不能訪問該域名的話可以使用以下命令來安裝:

1
2
# 使用阿里雲映象安裝並把預設倉庫設定為阿里雲上的映象倉庫
$ helm init --upgrade --tiller-image registry.cn-hangzhou.aliyuncs.com/google_containers/tiller:v2.9.1 --stable-repo-url https://kubernetes.oss-cn-hangzhou.aliyuncs.com/charts

給 Tiller 授權

因為 Helm 的服務端 Tiller 是一個部署在 Kubernetes 中 Kube-System Namespace 下 的 Deployment,它會去連線 Kube-Api 在 Kubernetes 裡建立和刪除應用。

而從 Kubernetes 1.6 版本開始,API Server 啟用了 RBAC 授權。目前的 Tiller 部署時預設沒有定義授權的 ServiceAccount,這會導致訪問 API Server 時被拒絕。所以我們需要明確為 Tiller 部署新增授權。

  • 建立 Kubernetes 的服務帳號和繫結角色
1
2
3
4
5
$ kubectl get deployment --all-namespaces
NAMESPACE     NAME                   DESIRED   CURRENT   UP-TO-DATE   AVAILABLE   AGE
kube-system   tiller-deploy          1         1         1            1           1h
$ kubectl create serviceaccount --namespace kube-system tiller
$ kubectl create clusterrolebinding tiller-cluster-rule --clusterrole=cluster-admin --serviceaccount=kube-system:tiller
  • 為 Tiller 設定帳號
1
2
3
# 使用 kubectl patch 更新 API 物件
$ kubectl patch deploy --namespace kube-system tiller-deploy -p '{"spec":{"template":{"spec":{"serviceAccount":"tiller"}}}}'
deployment.extensions "tiller-deploy" patched
  • 檢視是否授權成功
1
2
3
$ kubectl get deploy --namespace kube-system   tiller-deploy  --output yaml|grep  serviceAccount
serviceAccount: tiller
serviceAccountName: tiller

驗證 Tiller 是否安裝成功

1
2
3
4
5
6
$ kubectl -n kube-system get pods|grep tiller
tiller-deploy-6d68f5c78f-nql2z          1/1       Running   0          5m

$ helm version
Client: &version.Version{SemVer:"v2.9.1", GitCommit:"20adb27c7c5868466912eebdf6664e7390ebe710", GitTreeState:"clean"}
Server: &version.Version{SemVer:"v2.9.1", GitCommit:"20adb27c7c5868466912eebdf6664e7390ebe710", GitTreeState:"clean"}

解除安裝 Helm 伺服器端 Tiller

如果你需要在 Kubernetes 中解除安裝已部署的 Tiller,可使用以下命令完成解除安裝。

1
$ helm reset

構建一個 Helm Chart

下面我們通過一個完整的示例來學習如何使用 Helm 建立、打包、分發、安裝、升級及回退Kubernetes應用。

建立一個名為 mychart 的 Chart

1
$ helm create mychart

該命令建立了一個 mychart 目錄,該目錄結構如下所示。這裡我們主要關注目錄中的 Chart.yaml、values.yaml、NOTES.txt 和 Templates 目錄。

1
2
3
4
5
6
7
8
9
10
11
12
13
$ tree mychart/
mychart/
├── charts
├── Chart.yaml
├── templates
│   ├── deployment.yaml
│   ├── _helpers.tpl
│   ├── ingress.yaml
│   ├── NOTES.txt
│   └── service.yaml
└── values.yaml

2 directories, 7 files
  • Chart.yaml 用於描述這個 Chart的相關資訊,包括名字、描述資訊以及版本等。
  • values.yaml 用於儲存 templates 目錄中模板檔案中用到變數的值。
  • NOTES.txt 用於介紹 Chart 部署後的一些資訊,例如:如何使用這個 Chart、列出預設的設定等。
  • Templates 目錄下是 YAML 檔案的模板,該模板檔案遵循 Go template 語法。

Templates 目錄下 YAML 檔案模板的值預設都是在 values.yaml 裡定義的,比如在 deployment.yaml 中定義的容器映象。

1
image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"

其中的 .Values.image.repository 的值就是在 values.yaml 裡定義的 nginx,.Values.image.tag的值就是 stable。

1
2
3
4
5
$ cat mychart/values.yaml|grep repository
repository: nginx

$ cat mychart/values.yaml|grep tag
tag: stable

以上兩個變數值是在 create chart 的時候就自動生成的預設值,你可以根據實際情況進行修改。

如果你需要了解更多關於 Go 模板的相關資訊,可以檢視 Hugo 的一個關於 Go 模板 的介紹。

編寫應用的介紹資訊

開啟 Chart.yaml, 填寫你部署的應用的詳細資訊,以 mychart 為例:

1
2
3
4
5
6
$ cat mychart/Chart.yaml
apiVersion: v1
appVersion: "1.0"
description: A Helm chart for Kubernetes
name: mychart
version: 0.1.0

編寫應用具體部署資訊

編輯 values.yaml,它預設會在 Kubernetes 部署一個 Nginx。下面是 mychart 應用的 values.yaml 檔案的內容:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
$ cat mychart/values.yaml
# Default values for mychart.
# This is a YAML-formatted file.
# Declare variables to be passed into your templates.

replicaCount: 1

image:
  repository: nginx
  tag: stable
  pullPolicy: IfNotPresent

service:
  type: ClusterIP
  port: 80

ingress:
  enabled: false
  annotations: {}
    # kubernetes.io/ingress.class: nginx
    # kubernetes.io/tls-acme: "true"
  path: /
  hosts:
    - chart-example.local
  tls: []
  #  - secretName: chart-example-tls
  #    hosts:
  #      - chart-example.local

resources: {}
  # We usually recommend not to specify default resources and to leave this as a conscious
  # choice for the user. This also increases chances charts run on environments with little
  # resources, such as Minikube. If you do want to specify resources, uncomment the following
  # lines, adjust them as necessary, and remove the curly braces after 'resources:'.
  # limits:
  #  cpu: 100m
  #  memory: 128Mi
  # requests:
  #  cpu: 100m
  #  memory: 128Mi

nodeSelector: {}

tolerations: []

affinity: {}

檢查依賴和模板配置是否正確

1
2
3
4
5
$ helm lint mychart/
==> Linting .
[INFO] Chart.yaml: icon is recommended

1 chart(s) linted, no failures

如果檔案格式錯誤,可以根據提示進行修改。

將應用打包

1
2
$ helm package mychart
Successfully packaged chart and saved it to: /home/k8s/mychart-0.1.0.tgz

mychart 目錄會被打包為一個 mychart-0.1.0.tgz 格式的壓縮包,該壓縮包會被放到當前目錄下,並同時被儲存到了 Helm 的本地預設倉庫目錄中。

如果你想看到更詳細的輸出,可以加上 --debug 引數來檢視打包的輸出,輸出內容應該類似如下:

1
2
3
$ helm package mychart --debug
Successfully packaged chart and saved it to: /home/k8s/mychart-0.1.0.tgz
[debug] Successfully saved /home/k8s/mychart-0.1.0.tgz to /home/k8s/.helm/repository/local

將應用釋出到 Repository

雖然我們已經打包了 Chart 併發布到了 Helm 的本地目錄中,但通過 helm search 命令查詢,並不能找不到剛才生成的 mychart包。

1
2
$ helm search mychart
No results found

這是因為 Repository 目錄中的 Chart 包還沒有被 Helm 管理。通過 helm repo list 命令可以看到目前 Helm 中已配置的 Repository 的資訊。

1
2
3
$ helm repo list
NAME    URL
stable  https://kubernetes.oss-cn-hangzhou.aliyuncs.com/charts

注:新版本中執行 helm init 命令後預設會配置一個名為 local 的本地倉庫。

我們可以在本地啟動一個 Repository Server,並將其加入到 Helm Repo 列表中。Helm Repository 必須以 Web 服務的方式提供,這裡我們就使用 helm serve 命令啟動一個 Repository Server,該 Server 預設使用 $HOME/.helm/repository/local 目錄作為 Chart 儲存,並在 8879 埠上提供服務。

1
2
$ helm serve &
Now serving you on 127.0.0.1:8879

預設情況下該服務只監聽 127.0.0.1,如果你要繫結到其它網路介面,可使用以下命令:

1
$ helm serve --address 192.168.100.211:8879 &

如果你想使用指定目錄來做為 Helm Repository 的儲存目錄,可以加上 --repo-path 引數:

1
$ helm serve --address 192.168.100.211:8879 --repo-path /data/helm/repository/ --url http://192.168.100.211:8879/charts/

通過 helm repo index 命令將 Chart 的 Metadata 記錄更新在 index.yaml 檔案中:

1
2
3
# 更新 Helm Repository 的索引檔案
$ cd /home/k8s/.helm/repository/local
$ helm repo index --url=http://192.168.100.211:8879 .

完成啟動本地 Helm Repository Server 後,就可以將本地 Repository 加入 Helm 的 Repo 列表。

1
2
$ helm repo add local http://127.0.0.1:8879
"local" has been added to your repositories

現在再次查詢 mychart 包,就可以搜尋到了。

1
2
3
4
$ helm repo update
$ helm search mychart
NAME         	CHART VERSION	APP VERSION	DESCRIPTION
local/mychart	0.1.0        	1.0        	A Helm chart for Kubernetes

在 Kubernetes 中部署應用

部署一個應用

Chart 被髮布到倉儲後,就可以通過 helm install 命令部署該 Chart。

  • 檢查配置和模板是否有效

當使用 helm install 命令部署應用時,實際上就是將 templates 目錄下的模板檔案渲染成 Kubernetes 能夠識別的 YAML 格式。

在部署前我們可以使用 helm install --dry-run --debug <chart_dir> --name <release_name>命令來驗證 Chart 的配置。該輸出中包含了模板的變數配置與最終渲染的 YAML 檔案。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
$ helm install --dry-run --debug local/mychart --name mike-test
[debug] Created tunnel using local port: '46649'

[debug] SERVER: "127.0.0.1:46649"

[debug] Original chart version: ""
[debug] Fetched local/mychart to /home/k8s/.helm/cache/archive/mychart-0.1.0.tgz

[debug] CHART PATH: /home/k8s/.helm/cache/archive/mychart-0.1.0.tgz

NAME:   mike-test
REVISION: 1
RELEASED: Mon Jul 23 10:39:49 2018
CHART: mychart-0.1.0
USER-SUPPLIED VALUES:
{}

COMPUTED VALUES:
affinity: {}
image:
  pullPolicy: IfNotPresent
  repository: nginx
  tag: stable
ingress:
  annotations: {}
  enabled: false
  hosts:
  - chart-example.local
  path: /
  tls: []
nodeSelector: {}
replicaCount: 1
resources: {}
service:
  port: 80
  type: ClusterIP
tolerations: []

HOOKS:
MANIFEST:

---
# Source: mychart/templates/service.yaml
apiVersion: v1
kind: Service
metadata:
  name: mike-test-mychart
  labels:
    app: mychart
    chart: mychart-0.1.0
    release: mike-test
    heritage: Tiller
spec:
  type: ClusterIP
  ports:
    - port: 80
      targetPort: http
      protocol: TCP
      name: http
  selector:
    app: mychart
    release: mike-test
---
# Source: mychart/templates/deployment.yaml
apiVersion: apps/v1beta2
kind: Deployment
metadata:
  name: mike-test-mychart
  labels:
    app: mychart
    chart: mychart-0.1.0
    release: mike-test
    heritage: Tiller
spec:
  replicas: 1
  selector:
    matchLabels:
      app: mychart
      release: mike-test
  template:
    metadata:
      labels:
        app: mychart
        release: mike-test
    spec:
      containers:
        - name: mychart
          image: "nginx:stable"
          imagePullPolicy: IfNotPresent
          ports:
            - name: http
              containerPort: 80
              protocol: TCP
          livenessProbe:
            httpGet:
              path: /
              port: http
          readinessProbe:
            httpGet:
              path: /
              port: http
          resources:
            {}

驗證完成沒有問題後,我們就可以使用以下命令將其部署到 Kubernetes 上了。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
# 部署時需指定 Chart 名及 Release(部署的例項)名。
$ helm install local/mychart --name mike-test
NAME:   mike-test
LAST DEPLOYED: Mon Jul 23 10:41:20 2018
NAMESPACE: default
STATUS: DEPLOYED

RESOURCES:
==> v1/Service
NAME               TYPE       CLUSTER-IP      EXTERNAL-IP  PORT(S)  AGE
mike-test-mychart  ClusterIP  10.254.120.177  <none>       80/TCP   1s

==> v1beta2/Deployment
NAME               DESIRED  CURRENT  UP-TO-DATE  AVAILABLE  AGE
mike-test-mychart  1        0        0           0          0s

==> v1/Pod(related)
NAME                                READY  STATUS   RESTARTS  AGE
mike-test-mychart-6d56f8c8c9-d685v  0/1    Pending  0         0s


NOTES:
1. Get the application URL by running these commands:
  export POD_NAME=$(kubectl get pods --namespace default -l "app=mychart,release=mike-test" -o jsonpath="{.items[0].metadata.name}")
  echo "Visit http://127.0.0.1:8080 to use your application"
  kubectl port-forward $POD_NAME 8080:80

注:helm install 預設會用到 socat,需要在所有節點上安裝 socat 軟體包。

完成部署後,現在 Nginx 就已經部署到 Kubernetes 叢集上。在本地主機上執行提示中的命令後,就可在本機訪問到該 Nginx 例項。

1
2
3
$ export POD_NAME=$(kubectl get pods --namespace default -l "app=mychart,release=mike-test" -o jsonpath="{.items[0].metadata.name}")
$ echo "Visit http://127.0.0.1:8080 to use your application"
$ kubectl port-forward $POD_NAME 8080:80

在本地訪問 Nginx

1
2
3
4
5
6
7
8
$ curl http://127.0.0.1:8080
.....
<title>Welcome to nginx!</title>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>
......

使用下面的命令列出的所有已部署的 Release 以及其對應的 Chart。

1
2
3
$ helm list
NAME     	REVISION	UPDATED                 	STATUS  	CHART        	NAMESPACE
mike-test	1       	Mon Jul 23 10:41:20 2018	DEPLOYED	mychart-0.1.0	default

你還可以使用 helm status 查詢一個特定的 Release 的狀態。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
$ helm status mike-test
LAST DEPLOYED: Mon Jul 23 10:41:20 2018
NAMESPACE: default
STATUS: DEPLOYED

RESOURCES:
==> v1/Pod(related)
NAME                                READY  STATUS   RESTARTS  AGE
mike-test-mychart-6d56f8c8c9-d685v  1/1    Running  0         1m

==> v1/Service
NAME               TYPE       CLUSTER-IP      EXTERNAL-IP  PORT(S)  AGE
mike-test-mychart  ClusterIP  10.254.120.177  <none>       80/TCP   1m

==> v1beta2/Deployment
NAME               DESIRED  CURRENT  UP-TO-DATE  AVAILABLE  AGE
mike-test-mychart  1        1        1           1          1m


NOTES:
1. Get the application URL by running these commands:
  export POD_NAME=$(kubectl get pods --namespace default -l "app=mychart,release=mike-test" -o jsonpath="{.items[0].metadata.name}")
  echo "Visit http://127.0.0.1:8080 to use your application"
  kubectl port-forward $POD_NAME 8080:80

升級和回退一個應用

從上面 helm list 輸出的結果中我們可以看到有一個 Revision(更改歷史)欄位,該欄位用於表示某一個 Release 被更新的次數,我們可以用該特性對已部署的 Release 進行回滾。

  • 修改 Chart.yaml 檔案

將版本號從 0.1.0 修改為 0.2.0, 然後使用 helm package 命令打包併發布到本地倉庫。

1
2
3
4
5
6
7
8
9
$ cat mychart/Chart.yaml
apiVersion: v1
appVersion: "1.0"
description: A Helm chart for Kubernetes
name: mychart
version: 0.2.0

$ helm package mychart
Successfully packaged chart and saved it to: /home/k8s/mychart-0.2.0.tgz
  • 查詢本地倉庫中的 Chart 資訊

我們可以看到在本地倉庫中 mychart 有兩個版本。

1
2
3
4
$ helm search mychart -l
NAME         	CHART VERSION	APP VERSION	DESCRIPTION
local/mychart	0.2.0        	1.0        	A Helm chart for Kubernetes
local/mychart	0.1.0        	1.0        	A Helm chart for Kubernetes
  • 升級一個應用

現在用 helm upgrade 命令將已部署的 mike-test 升級到新版本。你可以通過 --version 引數指定需要升級的版本號,如果沒有指定版本號,則預設使用最新版本。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
$ helm upgrade mike-test local/mychart
Release "mike-test" has been upgraded. Happy Helming!
LAST DEPLOYED: Mon Jul 23 10:50:25 2018
NAMESPACE: default
STATUS: DEPLOYED

RESOURCES:
==> v1/Pod(related)
NAME                                READY  STATUS   RESTARTS  AGE
mike-test-mychart-6d56f8c8c9-d685v  1/1    Running  0         9m

==> v1/Service
NAME               TYPE       CLUSTER-IP      EXTERNAL-IP  PORT(S)  AGE
mike-test-mychart  ClusterIP  10.254.120.177  <none>       80/TCP   9m

==> v1beta2/Deployment
NAME               DESIRED  CURRENT  UP-TO-DATE  AVAILABLE  AGE
mike-test-mychart  1        1        1           1          9m


NOTES:
1. Get the application URL by running these commands:
  export POD_NAME=$(kubectl get pods --namespace default -l "app=mychart,release=mike-test" -o jsonpath="{.items[0].metadata.name}")
  echo "Visit http://127.0.0.1:8080 to use your application"
  kubectl port-forward $POD_NAME 8080:80

完成後,可以看到已部署的 mike-test 被升級到 0.2.0 版本。

1
2
3
$ helm list
NAME     	REVISION	UPDATED                 	STATUS  	CHART        	NAMESPACE
mike-test	2       	Mon Jul 23 10:50:25 2018	DEPLOYED	mychart-0.2.0	default
  • 回退一個應用

如果更新後的程式由於某些原因執行有問題,需要回退到舊版本的應用。首先我們可以使用 helm history 命令檢視一個 Release 的所有變更記錄。

1
2
3
4
$ helm history mike-test
REVISION	UPDATED                 	STATUS    	CHART        	DESCRIPTION
1       	Mon Jul 23 10:41:20 2018	SUPERSEDED	mychart-0.1.0	Install complete
2       	Mon Jul 23 10:50:25 2018	DEPLOYED  	mychart-0.2.0	Upgrade complete

其次,我們可以使用下面的命令對指定的應用進行回退。

1
2
$ helm rollback mike-test 1
Rollback was a success! Happy Helming!

注:其中的引數 1 是 helm history 檢視到 Release 的歷史記錄中 REVISION 對應的值。

最後,我們使用 helm list 和 helm history 命令都可以看到 mychart 的版本已經回退到 0.1.0 版本。

1
2
3
4
5
6
7
8
9
$ helm list
NAME     	REVISION	UPDATED                 	STATUS  	CHART        	NAMESPACE
mike-test	3       	Mon Jul 23 10:53:42 2018	DEPLOYED	mychart-0.1.0	default

$ helm history mike-test
REVISION	UPDATED                 	STATUS    	CHART        	DESCRIPTION
1       	Mon Jul 23 10:41:20 2018	SUPERSEDED	mychart-0.1.0	Install complete
2       	Mon Jul 23 10:50:25 2018	SUPERSEDED	mychart-0.2.0	Upgrade complete
3       	Mon Jul 23 10:53:42 2018	DEPLOYED  	mychart-0.1.0	Rollback to 1

刪除一個應用

如果需要刪除一個已部署的 Release,可以利用 helm delete 命令來完成刪除。

1
2
$ helm delete mike-test
release "mike-test" deleted

確認應用是否刪除,該應用已被標記為 DELETED 狀態。

1
2
3
$ helm ls -a mike-test
NAME     	REVISION	UPDATED                 	STATUS 	CHART        	NAMESPACE
mike-test	3       	Mon Jul 23 10:53:42 2018	DELETED	mychart-0.1.0	default

也可以使用 --deleted 引數來列出已經刪除的 Release

1
2
3
$ helm ls --deleted
NAME     	REVISION	UPDATED                 	STATUS 	CHART        	NAMESPACE
mike-test	3       	Mon Jul 23 10:53:42 2018	DELETED	mychart-0.1.0	default

從上面的結果也可以看出,預設情況下已經刪除的 Release 只是將狀態標識為 DELETED 了 ,但該 Release 的歷史資訊還是繼續被儲存的。

1
2
3
4
5
$ helm hist mike-test
REVISION	UPDATED                 	STATUS    	CHART        	DESCRIPTION
1       	Mon Jul 23 10:41:20 2018	SUPERSEDED	mychart-0.1.0	Install complete
2       	Mon Jul 23 10:50:25 2018	SUPERSEDED	mychart-0.2.0	Upgrade complete
3       	Mon Jul 23 10:53:42 2018	DELETED   	mychart-0.1.0	Deletion complete

如果要移除指定 Release 所有相關的 Kubernetes 資源和 Release 的歷史記錄,可以用如下命令:

1
2
$ helm delete --purge mike-test
release "mike-test" deleted

再次檢視已刪除的 Release,已經無法找到相關資訊。

1
2
3
4
5
6
$ helm hist mike-test
Error: release: "mike-test" not found

# helm ls 命令也已均無查詢記錄。
$ helm ls --deleted
$ helm ls -a mike-test

Helm 部署應用例項

部署 Wordpress

這裡以一個典型的三層應用 Wordpress 為例,包括 MySQL、PHP 和 Apache。

由於測試環境沒有可用的 PersistentVolume(持久卷,簡稱 PV),這裡暫時將其關閉。關於 Persistent Volumes 的相關資訊我們會在後續的相關文章進行講解。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
$ helm install --name wordpress-test --set "persistence.enabled=false,mariadb.persistence.enabled=false,serviceType=NodePort"  stable/wordpress

NAMESPACE: default
STATUS: DEPLOYED

RESOURCES:
==> v1beta1/Deployment
NAME                      DESIRED  CURRENT  UP-TO-DATE  AVAILABLE  AGE
wordpress-test-mariadb    1        1        1           1          26m
wordpress-test-wordpress  1        1        1           1          26m

==> v1/Pod(related)
NAME                                       READY  STATUS   RESTARTS  AGE
wordpress-test-mariadb-84b866bf95-n26ff    1/1    Running  1         26m
wordpress-test-wordpress-5ff8c64b6c-sgtvv  1/1    Running  6         26m

==> v1/Secret
NAME                      TYPE    DATA  AGE
wordpress-test-mariadb    Opaque  2     26m
wordpress-test-wordpress  Opaque  2     26m

==> v1/ConfigMap
NAME                          DATA  AGE
wordpress-test-mariadb        1     26m
wordpress-test-mariadb-tests  1     26m

==> v1/Service
NAME                      TYPE       CLUSTER-IP     EXTERNAL-IP  PORT(S)                   AGE
wordpress-test-mariadb    ClusterIP  10.254.99.67   <none>       3306/TCP                  26m
wordpress-test-wordpress  NodePort   10.254.175.16  <none>       80:8563/TCP,443:8839/TCP  26m


NOTES:
1. Get the WordPress URL:

  Or running:

  export NODE_PORT=$(kubectl get --namespace default -o jsonpath="{.spec.ports[0].nodePort}" services wordpress-test-wordpress)
  export NODE_IP=$(kubectl get nodes --namespace default -o jsonpath="{.items[0].status.addresses[0].address}")
  echo http://$NODE_IP:$NODE_PORT/admin

2. Login with the following credentials to see your blog

  echo Username: user
  echo Password: $(kubectl get secret --namespace default wordpress-test-wordpress -o jsonpath="{.data.wordpress-password}" | base64 --decode)

訪問 Wordpress

部署完成後,我們可以通過上面的提示資訊生成相應的訪問地址和使用者名稱、密碼等相關資訊。

1
2
3
4
5
6
7
8
9
10
11
# 生成 Wordpress 管理後臺地址
$ export NODE_PORT=$(kubectl get --namespace default -o jsonpath="{.spec.ports[0].nodePort}" services wordpress-test-wordpress)
$ export NODE_IP=$(kubectl get nodes --namespace default -o jsonpath="{.items[0].status.addresses[0].address}")
$ echo http://$NODE_IP:$NODE_PORT/admin
http://192.168.100.211:8433/admin

# 生成 Wordpress 管理帳號和密碼
$ echo Username: user
Username: user
$ echo Password: $(kubectl get secret --namespace default wordpress-test-wordpress -o jsonpath="{.data.wordpress-password}" | base64 --decode)
Password: 9jEXJgnVAY

給一張訪問效果圖吧:

Helm 其它使用技巧

  • 如何設定 helm 命令自動補全?

為了方便 helm 命令的使用,Helm 提供了自動補全功能,如果使用 ZSH 請執行:

1
$ source <(helm completion zsh)

如果使用 BASH 請執行:

1
$ source <(helm completion bash)
  • 如何使用第三方的 Chart 儲存庫?

隨著 Helm 越來越普及,除了使用預置官方儲存庫,三方倉庫也越來越多了(前提是網路是可達的)。你可以使用如下命令格式新增三方 Chart 儲存庫。

1
2
$ helm repo add 儲存庫名 儲存庫URL
$ helm repo update

一些三方儲存庫資源:

1
2
3
4
5
6
7
8
9
10
11
12
# Prometheus Operator
https://github.com/coreos/prometheus-operator/tree/master/helm

# Bitnami Library for Kubernetes
https://github.com/bitnami/charts

# Openstack-Helm
https://github.com/att-comdev/openstack-helm
https://github.com/sapcc/openstack-helm

# Tick-Charts
https://github.com/jackzampolin/tick-charts
  • Helm 如何結合 CI/CD ?

採用 Helm 可以把零散的 Kubernetes 應用配置檔案作為一個 Chart 管理,Chart 原始碼可以和原始碼一起放到 Git 庫中管理。通過把 Chart 引數化,可以在測試環境和生產環境採用不同的 Chart 引數配置。

下圖是採用了 Helm 的一個 CI/CD 流程

  • Helm 如何管理多環境下 (Test、Staging、Production) 的業務配置?

Chart 是支援引數替換的,可以把業務配置相關的引數設定為模板變數。使用 helm install 命令部署的時候指定一個引數值檔案,這樣就可以把業務引數從 Chart 中剝離了。例如: helm install --values=values-production.yaml wordpress

  • Helm 如何解決服務依賴?

在 Chart 裡可以通過 requirements.yaml 宣告對其它 Chart 的依賴關係。如下面宣告表明 Chart 依賴 Apache 和 MySQL 這兩個第三方 Chart。

1
2
3
4
5
6
7
8
9
10
dependencies:
- name: mariadb
  version: 2.1.1
  repository: https://kubernetes-charts.storage.googleapis.com/
  condition: mariadb.enabled
  tags:
    - wordpress-database
- name: apache
    version: 1.4.0
    repository: https://kubernetes-charts.storage.googleapis.com/
  • 如何讓 Helm 連線到指定 Kubernetes 叢集?

Helm 預設使用和 kubectl 命令相同的配置訪問 Kubernetes 叢集,其配置預設在 ~/.kube/config中。

  • 如何在部署時指定名稱空間?

helm install 預設情況下是部署在 default 這個名稱空間的。如果想部署到指定的命令空間,可以加上 --namespace 引數,比如:

1
$ helm install local/mychart --name mike-test --namespace mynamespace
  • 如何檢視已部署應用的詳細資訊?
1
$ helm get wordpress-test

預設情況下會顯示最新的版本的相關資訊,如果想要檢視指定釋出版本的資訊可加上 --revision 引數。

1
$ helm get  --revision 1  wordpress-test

參考文件

http://www.google.com
http://t.cn/RgEE0dm
http://t.cn/RgE3MyP
http://t.cn/RgpiUAz