天天看點

Kubernetes學習之路(二十五)之Helm程式包管理器

目錄

  • 1、Helm的概念和架構
  • 2、部署Helm
    • (1)下載下傳helm
    • (2)部署Tiller
  • 3、helm的使用
  • 4、chart 目錄結構
  • 5、chart模闆
  • 6、定制安裝MySQL chart
    • (1)chart安裝準備
    • (2)定制化安裝chart
    • (3)更新和復原release
  • 7、自定義chart
    • (1)建立chart
    • (2)調試chart
    • (3)安裝chart
    • (4)将chart添加到倉庫
  • 8、總結

每個成功的軟體平台都有一個優秀的打包系統,比如 Debian、Ubuntu 的 apt,Redhat、Centos 的 yum。而 Helm 則是 Kubernetes 上的包管理器。

思考??Helm 到底解決了什麼問題?為什麼 Kubernetes 需要 Helm?

Kubernetes 能夠很好地組織和編排容器,但它缺少一個更高層次的應用打包工具,而 Helm 就是來幹這件事的。

舉個例子,我們需要部署一個MySQL服務,Kubernetes則需要部署以下對象:

① 為了能夠讓外界通路到MySQL,需要部署一個mysql的service;

②需要進行定義MySQL的密碼,則需要部署一個Secret;

③Mysql的運作需要持久化的資料存儲,此時還需要部署PVC;

④保證後端mysql的運作,還需要部署一個Deployment,以支援以上的對象。

針對以上對象,我們可以使用YAML檔案進行定義并部署,但是僅僅對于單個的服務支援,如果應用需要由一個甚至幾十個這樣的服務組成,并且還需要考慮各種服務的依賴問題,可想而知,這樣的組織管理應用的方式就顯得繁瑣。為此就誕生了一個工具Helm,就是為了解決Kubernetes這種應用部署繁重的現象。

Helm的核心術語:

  • Chart:一個helm程式包,是建立一個應用的資訊集合,包含各種Kubernetes對象的配置模闆、參數定義、依賴關系、文檔說明等。可以将Chart比喻為yum中的軟體安裝包;
  • Repository:Charts倉庫,用于集中存儲和分發Charts;
  • Config:應用程式執行個體化安裝運作時所需要的配置資訊;
  • Release:特定的Chart部署于目标叢集上的一個執行個體,代表這一個正在運作的應用。當chart被安裝到Kubernetes叢集,就會生成一個release,chart可以多次安裝到同一個叢集,每次安裝都是一個release。

Helm的程式架構:

Helm主要由Helm用戶端、Tiller伺服器和Charts倉庫組成,如下圖:

  • helm:用戶端,GO語言編寫,實作管理本地的Chart倉庫,可管理Chart,與Tiller服務進行互動,用于發送Chart,執行個體安裝、查詢、解除安裝等操作。
  • Tiller:服務端,通常運作在K8S叢集之上。用于接收helm發來的Charts和Conifg,合并生成release,完成部署。

簡單的說:Helm 用戶端負責管理 chart;Tiller 伺服器負責管理 release。

helm部署文檔

Helm的部署方式有兩種:預編譯的二進制程式和源碼編譯安裝,這裡使用二進制的方式進行安裝

[root@k8s-master ~]# wget https://storage.googleapis.com/kubernetes-helm/helm-v2.9.1-linux-amd64.tar.gz --no-check-certificate
[root@k8s-master ~]# tar -xf helm-v2.9.1-linux-amd64.tar.gz 
[root@k8s-master ~]# cd linux-amd64/
[root@k8s-master linux-amd64]# ls
helm  LICENSE  README.md
[root@k8s-master linux-amd64]# mv helm /usr/bin
[root@k8s-master linux-amd64]# helm version
Client: &version.Version{SemVer:"v2.9.1", GitCommit:"20adb27c7c5868466912eebdf6664e7390ebe710", GitTreeState:"clean"}
           

helm第一次init時,需要連結api-server并進行認證,是以在運作helm時,會去讀取kube-config檔案,是以必須确認目前使用者存在kube-config檔案。

Tiller運作在K8s叢集之上,也必須擁有叢集的管理權限,也就是需要一個serviceaccount,進行一個clusterrolebinding到cluster-admin。

Tiller的RBAC配置示例連結:

https://github.com/helm/helm/blob/master/docs/rbac.md

#建立tiller的rbac清單
[root@k8s-master ~]# cd mainfests/
[root@k8s-master mainfests]# mkdir helm
[root@k8s-master mainfests]# cd helm/
[root@k8s-master helm]# vim tiller-rbac.yaml
apiVersion: v1
kind: ServiceAccount
metadata:
  name: tiller
  namespace: kube-system
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: tiller
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: cluster-admin
subjects:
  - kind: ServiceAccount
    name: tiller
    namespace: kube-system

[root@k8s-master helm]# kubectl apply -f tiller-rbac.yaml 
serviceaccount/tiller created
clusterrolebinding.rbac.authorization.k8s.io/tiller created
[root@k8s-master helm]# kubectl get sa -n kube-system |grep tiller
tiller                               1         18s

#helm init指令進行初始化時,會用到gcr.io/kubernetes-helm中的景象,需要提前下載下傳,鏡像标簽和Helm同版本号
[root@k8s-node01 ~]# docker pull jmgao1983/tiller:v2.9.1
v2.9.1: Pulling from jmgao1983/tiller
53969ec691ff: Pull complete 
ea45de95cb26: Pull complete 
495df31ed85a: Pull complete 
Digest: sha256:417aae19a0709075df9cc87e2fcac599b39d8f73ac95e668d9627fec9d341af2
Status: Downloaded newer image for jmgao1983/tiller:v2.9.1
[root@k8s-node01 ~]# docker tag jmgao1983/tiller:v2.9.1 gcr.io/kubernetes-helm/tiller:v2.9.1

[root@k8s-master ~]# helm init
Creating /root/.helm 
Creating /root/.helm/repository 
Creating /root/.helm/repository/cache 
Creating /root/.helm/repository/local 
Creating /root/.helm/plugins 
Creating /root/.helm/starters 
Creating /root/.helm/cache/archive 
Creating /root/.helm/repository/repositories.yaml 
Adding stable repo with URL: https://kubernetes-charts.storage.googleapis.com 
Adding local repo with URL: http://127.0.0.1:8879/charts 
$HELM_HOME has been configured at /root/.helm.

Tiller (the Helm server-side component) has been installed into your Kubernetes Cluster.

Please note: by default, Tiller is deployed with an insecure 'allow unauthenticated users' policy.
For more information on securing your installation see: https://docs.helm.sh/using_helm/#securing-your-helm-installation
Happy Helming!


[root@k8s-master ~]# kubectl get pods -n kube-system |grep tiller
tiller-deploy-759cb9df9-ls47p          1/1       Running   0          16m

#安裝完成後,執行helm version可以看到用戶端和服務端的版本号,兩個都顯示表示正常安裝。
[root@k8s-master ~]# helm version
Client: &version.Version{SemVer:"v2.9.1", GitCommit:"20adb27c7c5868466912eebdf6664e7390ebe710", GitTreeState:"clean"}
Server: &version.Version{SemVer:"v2.9.1", GitCommit:"20adb27c7c5868466912eebdf6664e7390ebe710", GitTreeState:"clean"}
           

如果希望在安裝時自定義一些參數,可以參考一下的一些參數:

  • --canary-image:安裝canary分支,即項目的Master分支
  • --tiller-image:安裝指定版本的鏡像,預設和helm同版本
  • --kube-context:安裝到指定的Kubernetes叢集
  • --tiller-namespace:安裝到指定的名稱空間,預設為kube-system

Tiller将資料存儲在ConfigMap資源當中,解除安裝或重裝不會導緻資料丢失,解除安裝Tiller的方法有以下兩種:

(1)kubectl delete deployment tiller-deploy --n kube-system
(2)heml reset
           

官方可用的Chart清單:

https://hub.kubeapps.com

helm常用指令:
- helm search:    搜尋charts
- helm fetch:     下載下傳charts到本地目錄
- helm install:   安裝charts
- helm list:      列出charts的所有版本

用法:
  helm [command]

指令可用選項:
  completion  為指定的shell生成自動補全腳本(bash或zsh)
  create      建立一個新的charts
  delete      删除指定版本的release
  dependency  管理charts的依賴
  fetch       下載下傳charts并解壓到本地目錄
  get         下載下傳一個release
  history     release曆史資訊
  home        顯示helm的家目錄
  init        在用戶端和服務端初始化helm
  inspect     檢視charts的詳細資訊
  install     安裝charts
  lint        檢測包的存在問題
  list        列出release
  package     将chart目錄進行打包
  plugin      add(增加), list(列出), or remove(移除) Helm 插件
  repo        add(增加), list(列出), remove(移除), update(更新), and index(索引) chart倉庫
  reset       解除安裝tiller
  rollback    release版本復原
  search      關鍵字搜尋chart
  serve       啟動一個本地的http server
  status      檢視release狀态資訊
  template    本地模闆
  test        release測試
  upgrade     release更新
  verify      驗證chart的簽名和有效期
  version     列印用戶端和服務端的版本資訊
           

Charts是Helm的程式包,它們都存在在Charts倉庫當中。Kubernetes官方的倉庫儲存了一系列的Charts,倉庫預設的名稱為

stable

。安裝Charts到叢集時,Helm首先會到官方倉庫擷取相關的Charts,并建立release。可執行 

helm search

 檢視目前可安裝的 chart 。

[root@k8s-master ~]# helm search
NAME                          	CHART VERSION	APP VERSION  	DESCRIPTION                                       
stable/acs-engine-autoscaler  	2.1.3        	2.1.1        	Scales worker nodes within agent pools            
stable/aerospike              	0.1.7        	v3.14.1.2    	A Helm chart for Aerospike in Kubernetes          
stable/anchore-engine         	0.1.3        	0.1.6        	Anchore container analysis and policy evaluatio...
......
           

這些 chart 都是從哪裡來的?

前面說過,Helm 可以像 yum 管理軟體包一樣管理 chart。 yum 的軟體包存放在倉庫中,同樣的,Helm 也有倉庫。

[root@k8s-master ~]# helm repo list
NAME  	URL                                                   
local 	http://127.0.0.1:8879/charts                          
stable	https://kubernetes-charts.storage.googleapis.com
           

Helm 安裝時已經預設配置好了兩個倉庫:

stable

local

stable

是官方倉庫,

local

是使用者存放自己開發的

chart

的本地倉庫。可以通過

helm repo list

進行檢視。由于網絡原因,國内無法更新倉庫源,這裡更改為阿裡雲的倉庫源。

[root@k8s-master helm]# helm repo update 		#倉庫更新有時會提示無法連接配接
Hang tight while we grab the latest from your chart repositories...
...Skip local chart repository
...Unable to get an update from the "stable" chart repository (https://kubernetes-charts.storage.googleapis.com):
	Get https://kubernetes-charts.storage.googleapis.com/index.yaml: dial tcp 216.58.220.208:443: connect: connection refused
Update Complete. ⎈ Happy Helming!⎈ 

[root@k8s-master helm]# helm repo list
NAME  	URL                                             
stable	https://kubernetes-charts.storage.googleapis.com
local 	http://127.0.0.1:8879/charts     

[root@k8s-master helm]# helm repo remove stable #移除stable repo
"stable" has been removed from your repositories
[root@k8s-master helm]# helm repo list
NAME 	URL                         
local	http://127.0.0.1:8879/charts

#增加阿裡雲的charts倉庫
[root@k8s-master helm]# helm repo add stable https://kubernetes.oss-cn-hangzhou.aliyuncs.com/charts 
"stable" has been added to your repositories
[root@k8s-master helm]# helm repo list
NAME  	URL                                                   
local 	http://127.0.0.1:8879/charts                          
stable	https://kubernetes.oss-cn-hangzhou.aliyuncs.com/charts
[root@k8s-master helm]# helm repo update #再次更新repo
Hang tight while we grab the latest from your chart repositories...
...Skip local chart repository
...Successfully got an update from the "stable" chart repository
Update Complete. ⎈ Happy Helming!⎈ 
           

與 yum 一樣,helm 也支援關鍵字搜尋:

[root@k8s-master ~]# helm search mysql
NAME                         	CHART VERSION	APP VERSION	DESCRIPTION                                       
stable/mysql                 	0.3.5        	           	Fast, reliable, scalable, and easy to use open-...
stable/percona               	0.3.0        	           	free, fully compatible, enhanced, open source d...
stable/percona-xtradb-cluster	0.0.2        	5.7.19     	free, fully compatible, enhanced, open source d...
stable/gcloud-sqlproxy       	0.2.3        	           	Google Cloud SQL Proxy                            
stable/mariadb               	2.1.6        	10.1.31    	Fast, reliable, scalable, and easy to use open-...
           

包括 DESCRIPTION 在内的所有資訊,隻要跟關鍵字比對,都會顯示在結果清單中。

安裝 chart 也很簡單,執行如下指令可以安裝 MySQL。

[root@k8s-master ~]# helm install stable/mysql
Error: no available release name found

#如果看到上面的報錯,通常是因為 Tiller 伺服器的權限不足。執行以下指令添權重限:
kubectl create serviceaccount --namespace kube-system tiller
kubectl create clusterrolebinding tiller-cluster-rule --clusterrole=cluster-admin --serviceaccount=kube-system:tiller
kubectl patch deploy --namespace kube-system tiller-deploy -p '{"spec":{"template":{"spec":{"serviceAccount":"tiller"}}}}'


#helm安裝mysql
[root@k8s-master helm]# helm install stable/mysql
NAME:   reeling-bronco	①
LAST DEPLOYED: Wed Mar 27 03:10:31 2019
NAMESPACE: default
STATUS: DEPLOYED

RESOURCES:	②
==> v1/Secret
NAME                  TYPE    DATA  AGE
reeling-bronco-mysql  Opaque  2     0s

==> v1/PersistentVolumeClaim
NAME                  STATUS   VOLUME  CAPACITY  ACCESS MODES  STORAGECLASS  AGE
reeling-bronco-mysql  Pending  0s

==> v1/Service
NAME                  TYPE       CLUSTER-IP     EXTERNAL-IP  PORT(S)   AGE
reeling-bronco-mysql  ClusterIP  10.99.245.169  <none>       3306/TCP  0s

==> v1beta1/Deployment
NAME                  DESIRED  CURRENT  UP-TO-DATE  AVAILABLE  AGE
reeling-bronco-mysql  1        1        1           0          0s

==> v1/Pod(related)
NAME                                   READY  STATUS   RESTARTS  AGE
reeling-bronco-mysql-84b897b676-59qhh  0/1    Pending  0         0s


NOTES:	③
MySQL can be accessed via port 3306 on the following DNS name from within your cluster:
reeling-bronco-mysql.default.svc.cluster.local

To get your root password run:

    MYSQL_ROOT_PASSWORD=$(kubectl get secret --namespace default reeling-bronco-mysql -o jsonpath="{.data.mysql-root-password}" | base64 --decode; echo)

To connect to your database:

1. Run an Ubuntu pod that you can use as a client:

    kubectl run -i --tty ubuntu --image=ubuntu:16.04 --restart=Never -- bash -il

2. Install the mysql client:

    $ apt-get update && apt-get install mysql-client -y

3. Connect using the mysql cli, then provide your password:
    $ mysql -h reeling-bronco-mysql -p

To connect to your database directly from outside the K8s cluster:
    MYSQL_HOST=127.0.0.1
    MYSQL_PORT=3306

    # Execute the following commands to route the connection:
    export POD_NAME=$(kubectl get pods --namespace default -l "app=reeling-bronco-mysql" -o jsonpath="{.items[0].metadata.name}")
    kubectl port-forward $POD_NAME 3306:3306

    mysql -h ${MYSQL_HOST} -P${MYSQL_PORT} -u root -p${MYSQL_ROOT_PASSWORD}

           

輸出分為三部分:

  • ① chart 本次部署的描述資訊:

NAME

是 release 的名字,因為我們沒用

-n

參數指定,Helm 随機生成了一個,這裡是

reeling-bronco

NAMESPACE

是 release 部署的 namespace,預設是

default

,也可以通過

--namespace

指定。

STATUS

DEPLOYED

,表示已經将 chart 部署到叢集。

  • ② 目前 release 包含的資源:Service、Deployment、Secret 和 PersistentVolumeClaim,其名字都是

    reeling-bronco-mysql

    ,命名的格式為

    ReleasName

    -

    ChartName

  • NOTES

    部分顯示的是 release 的使用方法。比如如何通路 Service,如何擷取資料庫密碼,以及如何連接配接資料庫等。

通過 

kubectl get

 可以檢視組成 release 的各個對象:

[root@k8s-master helm]# kubectl get service reeling-bronco-mysql
NAME                   TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)    AGE
reeling-bronco-mysql   ClusterIP   10.99.245.169   <none>        3306/TCP   3m

[root@k8s-master helm]# kubectl get deployment reeling-bronco-mysql
NAME                   DESIRED   CURRENT   UP-TO-DATE   AVAILABLE   AGE
reeling-bronco-mysql   1         1         1            0           3m

[root@k8s-master helm]# kubectl get pvc  reeling-bronco-mysql
NAME                   STATUS    VOLUME    CAPACITY   ACCESS MODES   STORAGECLASS   AGE
reeling-bronco-mysql   Pending                                                      4m

[root@k8s-master helm]# kubectl get secret  reeling-bronco-mysql
NAME                   TYPE      DATA      AGE
reeling-bronco-mysql   Opaque    2         4m

           

由于我們還沒有準備 PersistentVolume,目前 release 還不可用。

helm list

顯示已經部署的 release,

helm delete

可以删除 release。

[root@k8s-master helm]# helm list
NAME          	REVISION	UPDATED                 	STATUS  	CHART      	NAMESPACE
reeling-bronco	1       	Wed Mar 27 03:10:31 2019	DEPLOYED	mysql-0.3.5	default  

[root@k8s-master helm]# helm delete reeling-bronco
release "reeling-bronco" deleted
           

chart 是 Helm 的應用打包格式。chart 由一系列檔案組成,這些檔案描述了 Kubernetes 部署應用時所需要的資源,比如 Service、Deployment、PersistentVolumeClaim、Secret、ConfigMap 等。

單個的 chart 可以非常簡單,隻用于部署一個服務,比如 Memcached;chart 也可以很複雜,部署整個應用,比如包含 HTTP Servers、 Database、消息中間件、cache 等。

chart 将這些檔案放置在預定義的目錄結構中,通常整個 chart 被打成 tar 包,而且标注上版本資訊,便于 Helm 部署。

以前面 MySQL chart 為例。一旦安裝了某個 chart,我們就可以在 ~/.helm/cache/archive 中找到 chart 的 tar 包。

[root@k8s-master ~]# cd .helm/cache/archive/
[root@k8s-master archive]# ll
-rw-r--r-- 1 root root 5536 Oct 29 22:04 mysql-0.3.5.tgz
-rw-r--r-- 1 root root 6189 Oct 29 05:03 redis-1.1.15.tgz
[root@k8s-master archive]# tar -xf mysql-0.3.5.tgz
[root@k8s-master archive]# tree mysql
mysql
├── Chart.yaml	
├── README.md	
├── templates
│   ├── configmap.yaml
│   ├── deployment.yaml
│   ├── _helpers.tpl
│   ├── NOTES.txt
│   ├── pvc.yaml
│   ├── secrets.yaml
│   └── svc.yaml
└── values.yaml	
           
  • Chart.yaml:YAML 檔案,描述 chart 的概要資訊。
  • README.md:Markdown 格式的 README 檔案,相當于 chart 的使用文檔,此檔案為可選。
  • LICENSE:文本檔案,描述 chart 的許可資訊,此檔案為可選。
  • requirements.yaml :chart 可能依賴其他的 chart,這些依賴關系可通過 requirements.yaml 指定。
  • values.yaml:chart 支援在安裝的時根據參數進行定制化配置,而 values.yaml 則提供了這些配置參數的預設值。
  • templates目錄:各類 Kubernetes 資源的配置模闆都放置在這裡。Helm 會将 values.yaml 中的參數值注入到模闆中生成标準的 YAML 配置檔案。
  • templates/NOTES.txt:chart 的簡易使用文檔,chart 安裝成功後會顯示此文檔内容。 與模闆一樣,可以在 NOTE.txt 中插入配置參數,Helm 會動态注入參數值。

Helm 通過模闆建立 Kubernetes 能夠了解的 YAML 格式的資源配置檔案,我們将通過例子來學習如何使用模闆。

templates/secrets.yaml

為例:

Kubernetes學習之路(二十五)之Helm程式包管理器

從結構上看,檔案的内容和我們在定義Secret的配置上大緻相似,隻是大部分的屬性值變成了{{ xxx }}。這些{{ xx }}實際上是模闆的文法。Helm采用了Go語言的模闆來編寫chart。

  • ① 

    {{ template "mysql.fullname" . }}

     定義 Secret 的 

    name

關鍵字 

template

 的作用是引用一個子模闆 

mysql.fullname

。這個子模闆是在 

templates/_helpers.tpl

 檔案中定義的。

Kubernetes學習之路(二十五)之Helm程式包管理器

這個定義還是很複雜的,因為它用到了模闆語言中的對象、函數、流控制等概念。現在看不懂沒關系,這裡我們學習的重點是:如果存在一些資訊多個模闆都會用到,則可在

templates/_helpers.tpl

中将其定義為子模闆,然後通過

templates

函數引用。

這裡

mysql.fullname

是由 release 與 chart 二者名字拼接組成。

根據 chart 的最佳實踐,所有資源的名稱都應該保持一緻,對于我們這個 chart,無論 Secret 還是 Deployment、PersistentVolumeClaim、Service,它們的名字都是子模闆 

mysql.fullname

 的值。

  • ② 

    Chart

     和 

    Release

     是 Helm 預定義的對象,每個對象都有自己的屬性,可以在模闆中使用。如果使用下面指令安裝 chart:
[root@k8s-master templates]# helm search stable/mysql
NAME        	CHART VERSION	APP VERSION	DESCRIPTION                                       
stable/mysql	0.3.5        	           	Fast, reliable, scalable, and easy to use open-...
[root@k8s-master templates]# helm install stable/mysql -n my
           

那麼:

{{ .Chart.Name }}

 的值為 

mysql

{{ .Chart.Version }}

0.3.5。

{{ .Release.Name }}

my

{{ .Release.Service }}

 始終取值為 

Tiller

{{ template "mysql.fullname" . }}

 計算結果為 

my-mysql

  • ③ 這裡指定

    mysql-root-password

    的值,不過使用了

    if-else

    的流控制,其邏輯為:

如果

.Values.mysqlRootPassword

有值,則對其進行 base64 編碼;否則随機生成一個 10 位的字元串并編碼。

Values

也是預定義的對象,代表的是

values.yaml

檔案。而

.Values.mysqlRootPassword

則是

values.yaml

中定義的

mysqlRootPassword

參數:

Kubernetes學習之路(二十五)之Helm程式包管理器

因為

mysqlRootPassword

被注釋掉了,沒有指派,是以邏輯判斷會走

else

,即随機生成密碼。

randAlphaNum

b64enc

quote

都是 Go 模闆語言支援的函數,函數之間可以通過管道

|

連接配接。

{{ randAlphaNum 10 | b64enc | quote }}

的作用是首先随機産生一個長度為 10 的字元串,然後将其 base64 編碼,最後兩邊加上雙引号。

templates/secrets.yaml

這個例子展示了 chart 模闆主要的功能,我們最大的收獲應該是:模闆将 chart 參數化了,通過

values.yaml

可以靈活定制應用。

無論多複雜的應用,使用者都可以用 Go 模闆語言編寫出 chart。無非是使用到更多的函數、對象和流控制

作為準備工作,安裝之前需要先清楚 chart 的使用方法。這些資訊通常記錄在 values.yaml 和 README.md 中。除了下載下傳源檔案檢視,執行 

helm inspect values

 可能是更友善的方法。

[root@k8s-master ~]# helm inspect values stable/mysql
## mysql image version
## ref: https://hub.docker.com/r/library/mysql/tags/
##
image: "mysql"
imageTag: "5.7.14"

## Specify password for root user
##
## Default: random 10 character string
# mysqlRootPassword: testing

## Create a database user
##
# mysqlUser:
# mysqlPassword:

## Allow unauthenticated access, uncomment to enable
##
# mysqlAllowEmptyPassword: true
......
           

輸出的實際上是 values.yaml 的内容。閱讀注釋就可以知道 MySQL chart 支援哪些參數,安裝之前需要做哪些準備。其中有一部分是關于存儲的:

## Persist data to a persistent volume
persistence:
  enabled: true
  ## database data Persistent Volume Storage Class
  ## If defined, storageClassName: <storageClass>
  ## If set to "-", storageClassName: "", which disables dynamic provisioning
  ## If undefined (the default) or set to null, no storageClassName spec is
  ##   set, choosing the default provisioner.  (gp2 on AWS, standard on
  ##   GKE, AWS & OpenStack)
  ##
  # storageClass: "-"
  accessMode: ReadWriteOnce
  size: 8Gi
           

chart 定義了一個 PersistentVolumeClaim,申請 8G 的 PersistentVolume。由于我們的實驗環境不支援動态供給,是以得預先建立好相應的 PV,其配置檔案 

mysql-pv.yml

 内容為:

[root@k8s-master volumes]# pwd
/root/mainfests/volumes
[root@k8s-master volumes]# cat mysql-pv.yaml 
apiVersion: v1
kind: PersistentVolume
metadata:
  name: mysql-pv2
spec:
  accessModes:
    - ReadWriteOnce
  capacity:
    storage: 8Gi
  persistentVolumeReclaimPolicy: Retain
  nfs:
    path: /data/volume/db
    server: stor01

[root@k8s-master volumes]# kubectl apply -f mysql-pv.yaml 
persistentvolume/mysql-pv2 created

[root@k8s-master volumes]# kubectl get pv
NAME        CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS        CLAIM                       STORAGECLASS   REASON    AGE
mysql-pv2   8Gi        RWO            Retain           Available                                                          5s
           

除了接受 values.yaml 的預設值,我們還可以定制化 chart,比如設定

mysqlRootPassword

Helm 有兩種方式傳遞配置參數:

  1. 指定自己的 values 檔案。

    通常的做法是首先通過

    helm inspect values mysql > myvalues.yaml

    生成 values 檔案,然後設定

    mysqlRootPassword

    ,之後執行

    helm install --values=myvalues.yaml mysql

  2. 通過

    --set

    直接傳入參數值,比如:
[root@k8s-master ~]# helm install stable/mysql --set mysqlRootPassword=abc123 -n my
NAME:   my
LAST DEPLOYED: Tue Oct 30 22:55:22 2018
NAMESPACE: default
STATUS: DEPLOYED

RESOURCES:
==> v1/Secret
NAME      TYPE    DATA  AGE
my-mysql  Opaque  2     1s

==> v1/PersistentVolumeClaim
NAME      STATUS  VOLUME     CAPACITY  ACCESS MODES  STORAGECLASS  AGE
my-mysql  Bound   mysql-pv2  8Gi       RWO           1s

==> v1/Service
NAME      TYPE       CLUSTER-IP     EXTERNAL-IP  PORT(S)   AGE
my-mysql  ClusterIP  10.103.41.193  <none>       3306/TCP  1s

==> v1beta1/Deployment
NAME      DESIRED  CURRENT  UP-TO-DATE  AVAILABLE  AGE
my-mysql  1        1        1           0          1s

==> v1/Pod(related)
NAME                       READY  STATUS   RESTARTS  AGE
my-mysql-79b5d4fdcd-bj4mt  0/1    Pending  0         0s
......
           

mysqlRootPassword

 設定為 

abc123

。另外,

-n

 設定 release 為 

my

,各類資源的名稱即為

my-mysql

helm list

helm status

 可以檢視 chart 的最新狀态。

release 釋出後可以執行 

helm upgrade

 對其更新,通過 

--values

 或 

--set

應用新的配置。比如将目前的 MySQL 版本更新到 5.7.15:

[root@k8s-master ~]# helm upgrade --set imageTag=5.7.15 my stable/mysql
Release "my" has been upgraded. Happy Helming!
LAST DEPLOYED: Tue Oct 30 23:42:36 2018
......
[root@k8s-master ~]# kubectl get deployment my-mysql -o wide
NAME       DESIRED   CURRENT   UP-TO-DATE   AVAILABLE   AGE       CONTAINERS   IMAGES         SELECTOR
my-mysql   1         1         1            0           11m       my-mysql     mysql:5.7.15   app=my-mysql
           

helm history

 可以檢視 release 所有的版本。通過 

helm rollback

 可以復原到任何版本。

[root@k8s-master ~]# helm history my
REVISION	UPDATED                 	STATUS    	CHART      	DESCRIPTION     
1       	Tue Oct 30 23:31:42 2018	SUPERSEDED	mysql-0.3.5	Install complete
2       	Tue Oct 30 23:42:36 2018	DEPLOYED  	mysql-0.3.5	Upgrade complete
[root@k8s-master ~]# helm rollback my 1
Rollback was a success! Happy Helming!
復原成功,MySQL 恢複到 5.7.14。

[root@k8s-master ~]# helm history my
REVISION	UPDATED                 	STATUS    	CHART      	DESCRIPTION     
1       	Tue Oct 30 23:31:42 2018	SUPERSEDED	mysql-0.3.5	Install complete
2       	Tue Oct 30 23:42:36 2018	SUPERSEDED	mysql-0.3.5	Upgrade complete
3       	Tue Oct 30 23:44:28 2018	DEPLOYED  	mysql-0.3.5	Rollback to 1   
[root@k8s-master ~]# kubectl get deployment my-mysql -o wide
NAME       DESIRED   CURRENT   UP-TO-DATE   AVAILABLE   AGE       CONTAINERS   IMAGES         SELECTOR
my-mysql   1         1         1            1           13m       my-mysql     mysql:5.7.14   app=my-mysql
           

Kubernetes 給我們提供了大量官方 chart,不過要部署微服務應用,還是需要開發自己的 chart,下面就來實踐這個主題。

執行 

helm create mychart

 的指令建立 chart 

mychart

[root@k8s-master ~]# helm create -h
[root@k8s-master ~]# helm create mychart
Creating mychart
[root@k8s-master ~]# tree mychart/
mychart/
├── charts
├── Chart.yaml
├── templates
│   ├── deployment.yaml
│   ├── _helpers.tpl
│   ├── ingress.yaml
│   ├── NOTES.txt
│   └── service.yaml
└── values.yaml
           

Helm 會幫我們建立目錄

mychart

,并生成了各類 chart 檔案。這樣我們就可以在此基礎上開發自己的 chart 了。

隻要是程式就會有 bug,chart 也不例外。Helm 提供了 debug 的工具:

helm lint

helm install --dry-run --debug

helm lint

 會檢測 chart 的文法,報告錯誤以及給出建議。 故意修改mychart中的value.yaml,進行檢測:

helm lint mychart

 會指出這個文法錯誤。

[root@k8s-master ~]# helm lint mychart
==> Linting mychart
[INFO] Chart.yaml: icon is recommended
[ERROR] values.yaml: unable to parse YAML
	error converting YAML to JSON: yaml: line 11: could not find expected ':'

Error: 1 chart(s) linted, 1 chart(s) failed

mychart 目錄被作為參數傳遞給 helm lint。錯誤修複後則能通過檢測。

[root@k8s-master ~]# helm lint mychart
==> Linting mychart
[INFO] Chart.yaml: icon is recommended

1 chart(s) linted, no failures
           

helm install --dry-run --debug

 會模拟安裝 chart,并輸出每個模闆生成的 YAML 内容。

[root@k8s-master ~]# helm install --dry-run mychart --debug
[debug] Created tunnel using local port: '46807'

[debug] SERVER: "127.0.0.1:46807"

[debug] Original chart version: ""
[debug] CHART PATH: /root/mychart

NAME:   sad-orangutan
REVISION: 1
RELEASED: Wed Oct 31 01:55:03 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: sad-orangutan-mychart
  labels:
    app: mychart
    chart: mychart-0.1.0
    release: sad-orangutan
    heritage: Tiller
spec:
  type: ClusterIP
  ports:
    - port: 80
      targetPort: http
      protocol: TCP
      name: http
  selector:
    app: mychart
    release: sad-orangutan
---
# Source: mychart/templates/deployment.yaml
apiVersion: apps/v1beta2
kind: Deployment
metadata:
  name: sad-orangutan-mychart
  labels:
    app: mychart
    chart: mychart-0.1.0
    release: sad-orangutan
    heritage: Tiller
spec:
  replicas: 1
  selector:
    matchLabels:
      app: mychart
      release: sad-orangutan
  template:
    metadata:
      labels:
        app: mychart
        release: sad-orangutan
    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:
            {}
           

我們可以檢視這些輸出,判斷是否與預期相符。

安裝 chart,Helm 支援四種安裝方法:

  1. 安裝倉庫中的 chart,例如:

    helm install stable/nginx

  2. 通過 tar 包安裝,例如:

    helm install ./nginx-1.2.3.tgz

  3. 通過 chart 本地目錄安裝,例如:

    helm install ./nginx

  4. 通過 URL 安裝,例如:

    helm install https://example.com/charts/nginx-1.2.3.tgz

這裡通過使用本地目錄進行安裝:

[root@k8s-master ~]# helm install mychart
NAME:   anxious-wasp
LAST DEPLOYED: Wed Oct 31 01:57:15 2018
NAMESPACE: default
STATUS: DEPLOYED

RESOURCES:
==> v1/Pod(related)
NAME                                 READY  STATUS             RESTARTS  AGE
anxious-wasp-mychart-94fcbf7d-dg5qn  0/1    ContainerCreating  0         0s

==> v1/Service
NAME                  TYPE       CLUSTER-IP    EXTERNAL-IP  PORT(S)  AGE
anxious-wasp-mychart  ClusterIP  10.111.51.71  <none>       80/TCP   0s

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


NOTES:
1. Get the application URL by running these commands:
  export POD_NAME=$(kubectl get pods --namespace default -l "app=mychart,release=anxious-wasp" -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
           

當 chart 部署到 Kubernetes 叢集,便可以對其進行更為全面的測試。

chart 通過測試後可以将其添加到倉庫,團隊其他成員就能夠使用。任何 HTTP Server 都可以用作 chart 倉庫,下面示範在 

k8s-node1

192.168.56.12 上搭建倉庫。

(1)在 k8s-node1 上啟動一個 httpd 容器。
[root@k8s-node01 ~]# mkdir /var/www
[root@k8s-node01 ~]# docker run -d -p 8080:80 -v /var/www/:/usr/local/apache2/htdocs/ httpd

(2)通過 helm package 将 mychart 打包。
[root@k8s-master ~]# helm package mychart
Successfully packaged chart and saved it to: /root/mychart-0.1.0.tgz

(3)執行 helm repo index 生成倉庫的 index 檔案
[root@k8s-master ~]# mkdir myrepo
[root@k8s-master ~]# mv mychart-0.1.0.tgz myrepo/
[root@k8s-master ~]# 
[root@k8s-master ~]# helm repo index myrepo/ --url http://192.168.56.12:8080/charts
[root@k8s-master ~]# ls myrepo/
index.yaml  mychart-0.1.0.tgz

Helm 會掃描 myrepo 目錄中的所有 tgz 包并生成 index.yaml。--url指定的是新倉庫的通路路徑。新生成的 index.yaml 記錄了目前倉庫中所有 chart 的資訊:
目前隻有 mychart 這一個 chart。

[root@k8s-master ~]# cat myrepo/index.yaml 
apiVersion: v1
entries:
  mychart:
  - apiVersion: v1
    appVersion: "1.0"
    created: 2018-10-31T02:02:45.599264611-04:00
    description: A Helm chart for Kubernetes
    digest: 08abeb3542e8a9ab90df776d3a646199da8be0ebfc5198ef032190938d49e30a
    name: mychart
    urls:
    - http://192.168.56.12:8080/charts/mychart-0.1.0.tgz
    version: 0.1.0
generated: 2018-10-31T02:02:45.598450525-04:00

(4)将 mychart-0.1.0.tgz 和 index.yaml 上傳到 k8s-node1 的 /var/www/charts 目錄。
[root@k8s-master myrepo]# scp ./* root@k8s-node01:/var/www/charts/
[root@k8s-node01 ~]# ls /var/www/charts/
index.yaml  mychart-0.1.0.tgz

(5)通過 helm repo add 将新倉庫添加到 Helm。
[root@k8s-master ~]# helm repo add newrepo http://192.168.56.12:8080/charts
"newrepo" has been added to your repositories
[root@k8s-master ~]# helm repo list
NAME   	URL                                                   
local  	http://127.0.0.1:8879/charts                          
stable 	https://kubernetes.oss-cn-hangzhou.aliyuncs.com/charts
newrepo	http://192.168.56.12:8080/charts                      

(6)現在已經可以 repo search 到 mychart 了。
[root@k8s-master ~]# helm search mychart
NAME           	CHART VERSION	APP VERSION	DESCRIPTION                
local/mychart  	0.1.0        	1.0        	A Helm chart for Kubernetes
newrepo/mychart	0.1.0        	1.0        	A Helm chart for Kubernetes

除了 newrepo/mychart,這裡還有一個 local/mychart。這是因為在執行第 2 步打包操作的同時,mychart 也被同步到了 local 的倉庫。

(7)已經可以直接從新倉庫安裝 mychart 了。
[root@k8s-master ~]# helm install newrepo/mychart

(8)如果以後倉庫添加了新的 chart,需要用 helm repo update 更新本地的 index。
[root@k8s-master ~]# helm repo update
Hang tight while we grab the latest from your chart repositories...
...Skip local chart repository
...Successfully got an update from the "newrepo" chart repository
...Successfully got an update from the "stable" chart repository
Update Complete. ⎈ Happy Helming!⎈ 

這個操作相當于 Centos 的 yum update。
           

  • Helm是Kubernetes的包管理器,Helm 讓我們能夠像 yum 管理 rpm 包那樣安裝、部署、更新和删除容器化應用。
  • Helm 由用戶端和 Tiller 伺服器組成。用戶端負責管理 chart,伺服器負責管理 release。
  • chart 是 Helm 的應用打包格式,它由一組檔案和目錄構成。其中最重要的是模闆,模闆中定義了 Kubernetes 各類資源的配置資訊,Helm 在部署時通過 values.yaml 執行個體化模闆。
  • Helm 允許使用者開發自己的 chart,并為使用者提供了調試工具。使用者可以搭建自己的 chart 倉庫,在團隊中共享 chart。

Don't forget the beginner's mind