Helm 是 Kubernetes 的軟件包管理工具臀栈。本文需要讀者對 Docker梭灿、Kubernetes 等相關知識有一定的了解咽白。 本文將介紹 Helm 中的相關概念和基本工作原理祥绞,并通過一些簡單的示例來演示如何使用Helm來安裝、升級未状、回滾一個 Kubernetes 應用俯画。
Helm 是什么?司草?
Helm 是 Kubernetes 的包管理器艰垂。包管理器類似于我們在 Ubuntu 中使用的apt、Centos中使用的yum 或者Python中的 pip 一樣翻伺,能快速查找材泄、下載和安裝軟件包。Helm 由客戶端組件 helm 和服務端組件 Tiller 組成, 能夠將一組K8S資源打包統(tǒng)一管理, 是查找吨岭、共享和使用為Kubernetes構建的軟件的最佳方式拉宗。
Helm 解決了什么痛點?
在 Kubernetes中部署一個可以使用的應用辣辫,需要涉及到很多的 Kubernetes 資源的共同協(xié)作旦事。比如你安裝一個 WordPress 博客,用到了一些 Kubernetes (下面全部簡稱k8s)的一些資源對象急灭,包括 Deployment 用于部署應用姐浮、Service 提供服務發(fā)現(xiàn)、Secret 配置 WordPress 的用戶名和密碼葬馋,可能還需要 pv 和 pvc 來提供持久化服務卖鲤。并且 WordPress 數(shù)據是存儲在mariadb里面的,所以需要 mariadb 啟動就緒后才能啟動 WordPress畴嘶。這些 k8s 資源過于分散蛋逾,不方便進行管理,直接通過 kubectl 來管理一個應用窗悯,你會發(fā)現(xiàn)這十分蛋疼区匣。
所以總結以上,我們在 k8s 中部署一個應用蒋院,通常面臨以下幾個問題:
- 如何統(tǒng)一管理亏钩、配置和更新這些分散的 k8s 的應用資源文件
- 如何分發(fā)和復用一套應用模板
- 如何將應用的一系列資源當做一個軟件包管理
Helm 相關組件及概念
Helm 包含兩個組件,分別是 helm 客戶端 和 Tiller 服務器:
- helm 是一個命令行工具欺旧,用于本地開發(fā)及管理chart姑丑,chart倉庫管理等
- Tiller 是 Helm 的服務端。Tiller 負責接收 Helm 的請求辞友,與 k8s 的 apiserver 交互栅哀,根據chart 來生成一個 release 并管理 release
- chart Helm的打包格式叫做chart,所謂chart就是一系列文件, 它描述了一組相關的 k8s 集群資源
- release 使用 helm install 命令在 Kubernetes 集群中部署的 Chart 稱為 Release
- Repoistory Helm chart 的倉庫,Helm 客戶端通過 HTTP 協(xié)議來訪問存儲庫中 chart 的索引文件和壓縮包
Helm 原理
下面兩張圖描述了 Helm 的幾個關鍵組件 Helm(客戶端)昌屉、Tiller(服務器)、Repository(Chart 軟件倉庫)茵瀑、Chart(軟件包)之間的關系以及它們之間如何通信
創(chuàng)建release
- helm 客戶端從指定的目錄或本地tar文件或遠程repo倉庫解析出chart的結構信息
- helm 客戶端指定的 chart 結構和 values 信息通過 gRPC 傳遞給 Tiller
- Tiller 服務端根據 chart 和 values 生成一個 release
- Tiller 將install release請求直接傳遞給 kube-apiserver
刪除release
- helm 客戶端從指定的目錄或本地tar文件或遠程repo倉庫解析出chart的結構信息
- helm 客戶端指定的 chart 結構和 values 信息通過 gRPC 傳遞給 Tiller
- Tiller 服務端根據 chart 和 values 生成一個 release
- Tiller 將delete release請求直接傳遞給 kube-apiserver
更新release
- helm 客戶端將需要更新的 chart 的 release 名稱 chart 結構和 value 信息傳給 Tiller
- Tiller 將收到的信息生成新的 release间驮,并同時更新這個 release 的 history
- Tiller 將新的 release 傳遞給 kube-apiserver 進行更新
chart 的基本結構
Helm的打包格式叫做chart,所謂chart就是一系列文件, 它描述了一組相關的 k8s 集群資源马昨。Chart中的文件安裝特定的目錄結構組織, 最簡單的chart 目錄如下所示:
- charts 目錄存放依賴的chart
- Chart.yaml 包含Chart的基本信息竞帽,包括chart版本,名稱等
- templates 目錄下存放應用一系列 k8s 資源的 yaml 模板
- _helpers.tpl 此文件中定義一些可重用的模板片斷鸿捧,此文件中的定義在任何資源定義模板中可用
- NOTES.txt 介紹chart 部署后的幫助信息屹篓,如何使用chart等
- values.yaml 包含了必要的值定義(默認值), 用于存儲 templates 目錄中模板文件中用到變量的值
安裝Helm
Helm 提供了幾種安裝方式,本文提供兩種安裝方式匙奴,想要查看更多安裝方式堆巧,請閱讀 Helm 的官方文檔:
- 手動安裝方式
$ 下載 Helm 二進制文件
$ wget https://storage.googleapis.com/kubernetes-helm/helm-v2.9.1-linux-amd64.tar.gz
$ 解壓縮
$ tar -zxvf helm-v2.9.1-linux-amd64.tar.gz
$ 復制 helm 二進制 到bin目錄下
$cp linux-amd64/helm /usr/local/bin/
- 使用官方提供的腳本一鍵安裝
$ curl https://raw.githubusercontent.com/kubernetes/helm/master/scripts/get > get_helm.sh
$ chmod 700 get_helm.sh
$ ./get_helm.sh
你還可以通過 Helm 的 github 項目下找到你想要的 Helm 版本的二進制,然后通過手動安裝方式一樣安裝即可
安裝 Tiller
安裝好 helm 客戶端后泼菌,就可以通過以下命令將 Tiller 安裝在 kubernetes 集群中:
helm init
這個地方默認使用 “https://kubernetes-charts.storage.googleapis.com” 作為缺省的 stable repository 的地址谍肤,但由于國內有一張無形的墻的存在,googleapis.com 是不能訪問的哗伯』拇В可以使用阿里云的源來配置:
helm init --upgrade -i registry.cn-hangzhou.aliyuncs.com/google_containers/tiller:v2.9.1 --stable-repo-url https://kubernetes.oss-cn-hangzhou.aliyuncs.com/charts
執(zhí)行上面命令后,可以通過 kubectl get po -n kube-system 來查看 tiller 的安裝情況焊刹。
由于 kubernetes 從1.6 版本開始加入了 RBAC 授權系任。當前的 Tiller 沒有定義用于授權的 ServiceAccount, 訪問 API Server 時會被拒絕虐块,需要給 Tiller 加入授權俩滥。
- 創(chuàng)建 Kubernetes 的服務帳號和綁定角色
$ kubectl create serviceaccount --namespace kube-system tiller
serviceaccount "tiller" created
$ kubectl create clusterrolebinding tiller-cluster-rule --clusterrole=cluster-admin --serviceaccount=kube-system:tiller
clusterrolebinding.rbac.authorization.k8s.io "tiller-cluster-rule" created
- 給 Tiller 的 deployments 添加剛才創(chuàng)建的 ServiceAccount
# 給 Tiller 的 deployments 添加剛才創(chuàng)建的 ServiceAccount
$ kubectl patch deploy --namespace kube-system tiller-deploy -p '{"spec":{"template":{"spec":{"serviceAccount":"tiller"}}}}'
deployment.extensions "tiller-deploy" patched
- 查看 Tiller deployments 資源是否綁定 ServiceAccount
$ kubectl get deploy -n kube-system tiller-deploy -o yaml | grep serviceAccount
serviceAccount: tiller
serviceAccountName: tiller
- 查看 Tiller 是否安裝成功
$ 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 install xxx 來安裝 helm 應用非凌。如果需要刪除 Tiller举农,可以通過 kubectl delete deployment tiller-deploy --namespace kube-system 來刪除 Tiller 的 deployment 或者使用 helm reset 來刪除。
使用 Helm 操作 Chart
這一節(jié)將介紹如何使用 helm 來操作 chart敞嗡,包括創(chuàng)建颁糟、刪除、打包喉悴、安裝等使用棱貌。
先介紹一下 Helm 的核心命令:
- helm create 創(chuàng)建一個 Chart 模板
$ helm create test
Creating test
- helm package 打包一個 Chart 模板
$ helm package test
Successfully packaged chart and saved it to: /root/test-0.1.0.tgz
- helm search 查找可用的 Chart 模板
$ helm search nginx
NAME CHART VERSION APP VERSION DESCRIPTION
stable/nginx-ingress 0.9.5 0.10.2 An nginx Ingress controller that uses ConfigMap...
stable/nginx-lego 0.3.1 Chart for nginx-ingress-controller and kube-lego
stable/gcloud-endpoints 0.1.0 Develop, deploy, protect and monitor your APIs ...
- helm inspect 查看指定 Chart 的基本信息
apiVersion: v1
appVersion: "1.0"
description: A Helm chart for Kubernetes
name: test
version: 0.1.0
略...(省略一大段信息)
- helm install 根據指定的 Chart 部署一個 Release 到 Kubernetes 集群
Chart 模板示例
Chart 文件結構
wordpress
├── charts
├── Chart.yaml
├── README.md
├── requirements.lock
├── requirements.yaml
├── templates
│ ├── deployment.yaml
│ ├── externaldb-secrets.yaml
│ ├── _helpers.tpl
│ ├── ingress.yaml
│ ├── NOTES.txt
│ ├── pvc.yaml
│ ├── secrets.yaml
│ ├── svc.yaml
│ └── tls-secrets.yaml
└── values.yaml
一個 wordpress chart 如上(去除部分 test 和 charts 依賴), 基本結構由以下幾個部分組成:
- charts 存放子Chart (Subchart) 的定義箕肃,Subchart 指的是當前 Chart 依賴的 Chart 婚脱, 在 requirements.yaml 中定義
- Chart.yaml 包含 Chart 信息的 YAML 文件, 包括 Chart 的版本、名稱等障贸,在 DCE Helm 插件中還包含 Chart 的 團隊授權 信息 和 是否公開 的信息
- README.md 可選:Chart 的介紹信息等(該文件對于一個大型 Chart 來說十分重要)
- Requirements.yaml 可選:列舉當前 Chart 的需要依賴的 Chart
- templates
- 該目錄下存放 Chart 所有的 K8s 資源定義模板错森,通常不同的資源放在不同的文件中,DCE Helm 插件中自定義模板的 K8s 資源統(tǒng)一放在 all_sources.yaml 文件中
- _helpers.tpl 篮洁, 通常這個文件存放可重用的模板片段涩维,該文件中的定義可以在 Chart 其它資源定義模板中使用
- NOTES.txt,可選:一段簡短使用說明的文本文件袁波,用于安裝 Release 后提示用戶使用
- values.yaml 當前 Chart 的默認配置的值
編寫一個簡單的 Chart 示例
本節(jié)以構建一個名稱為 nginx-test Chart 為示例瓦阐,來描述一個 chart 必要條件。
1篷牌、Chart.yaml 文件是 一個 chart 必要文件睡蟋, 該文件可以簡單包括以下字段(具體字段請參考Helm官網)
apiVersion: v1 (chart 的API版本, 總是"v1", 必要)
name: hello (chart 的名稱, 必要)
version: 0.0.1 (chart 的版本,這個版本必須必要遵循 SemVer 2標準)
description: A Helm chart for Kubernetes (chart 模板的簡介描述)
...
下面省略一些字段枷颊,默認情況下有這幾個字段定義就可以了
2戳杀、values.yaml 文件是 chart 的必要文件,以 nginx 為示例:
# Default values for test.
# 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: {}
從示例中可以看出偷卧,values.yaml 中定義了一些當前chart 的一些默認值豺瘤,用于 templates 下的 K8s 資源 yaml 渲染時填充默認值。不過需要注意的是听诸,如果使用 helm install 來部署一個 Release , 可以通過下面命令指定一份yaml 文件作為填充值:
$ helm install --values=myvals.yaml nginx
3坐求、創(chuàng)建 templates 下的模板文件, 用于生成 Kubernetes 資源清單(manifests) 如下所示:
# nginx-test/templates/deployments.yaml
apiVersion: apps/v1beta2
kind: Deployment
metadata:
name: {{ template "nginx-test.fullname" . }}
labels:
app: {{ template "nginx-test.name" . }}
chart: {{ template "nginx-test.chart" . }}
release: {{ .Release.Name }}
heritage: {{ .Release.Service }}
spec:
replicas: {{ .Values.replicaCount }}
selector:
matchLabels:
app: {{ template "nginx-test.name" . }}
release: {{ .Release.Name }}
template:
metadata:
labels:
app: {{ template "nginx-test.name" . }}
release: {{ .Release.Name }}
spec:
containers:
- name: {{ .Chart.Name }}
image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"
imagePullPolicy: {{ .Values.image.pullPolicy }}
ports:
- name: http
containerPort: 80
protocol: TCP
livenessProbe:
httpGet:
path: /
port: http
readinessProbe:
httpGet:
path: /
port: http
resources:
{{ toYaml .Values.resources | indent 12 }}
{{- with .Values.nodeSelector }}
nodeSelector:
{{ toYaml . | indent 8 }}
{{- end }}
{{- with .Values.affinity }}
affinity:
{{ toYaml . | indent 8 }}
{{- end }}
{{- with .Values.tolerations }}
tolerations:
{{ toYaml . | indent 8 }}
{{- end }}
# nginx-test/templates/service.yaml
apiVersion: v1
kind: Service
metadata:
name: {{ template "nginx-test.fullname" . }}
labels:
app: {{ template "nginx-test.name" . }}
chart: {{ template "nginx-test.chart" . }}
release: {{ .Release.Name }}
heritage: {{ .Release.Service }}
spec:
type: {{ .Values.service.type }}
ports:
- port: {{ .Values.service.port }}
targetPort: http
protocol: TCP
name: http
selector:
app: {{ template "nginx-test.name" . }}
release: {{ .Release.Name }}
上面定義了 一個 deployments.yaml 和 service.yaml 資源文件晌梨,里面使用 {{ }} 符號的是 Go 模板語言的標準桥嗤。其中可以通過:
- .Values 對象訪問 values.yaml 文件的內容, 前面的dot(.) 表示從頂層命名空間開始仔蝌,找到 Values 對象(下同)
- .Release泛领、.Chart 開頭的預定義值可用于任何的模板中
- .Chart 對象用來訪問 Chart.yaml 文件的內容
- .Release 對象是 Helm的內置對象之一, 使用 Helm 安裝一個 release 時敛惊,由 Tiller 分配 release 的名稱
4渊鞋、命名模板(_helper.tpl) :可以從上面看到有 {{ template "nginx-test.fullname" . }} 定義。該定義由 _helper.tpl 文件定義的字段來實現(xiàn)瞧挤,比如下面一個 _helper.tpl :
{{/* vim: set filetype=mustache: */}}
{{/*
Expand the name of the chart.
*/}}
{{- define "nginx-test.name" -}}
{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" -}}
{{- end -}}
{{/*
Create a default fully qualified app name.
We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec).
If release name contains chart name it will be used as a full name.
*/}}
{{- define "nginx-test.fullname" -}}
{{- if .Values.fullnameOverride -}}
{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" -}}
{{- else -}}
{{- $name := default .Chart.Name .Values.nameOverride -}}
{{- if contains $name .Release.Name -}}
{{- .Release.Name | trunc 63 | trimSuffix "-" -}}
{{- else -}}
{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" -}}
{{- end -}}
{{- end -}}
{{- end -}}
{{/*
Create chart name and version as used by the chart label.
*/}}
{{- define "nginx-test.chart" -}}
{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" -}}
{{- end -}}
該模板定義了 "nginx-test.name"锡宋、"nginx-test.fullname"、"nginx-test.chart" 等可重用模板部分特恬,當模板引擎讀取該文件時执俩,它存儲對 nginx-test.name等的引用, 直到調用 template "nginx-test.name" 為止癌刽。然后把值渲染到模板中役首。
注意 {{ template "nginx-test.chart" . }} 后面有個dot(.)尝丐,這是因為一個已命名的模板(用于創(chuàng)建 define) 被渲染時,它將接收由該 template 調用傳入的范圍(scope)衡奥。沒有范圍傳入爹袁,在模板中無法訪問任何內容,因此在:
{{- define "nginx-test.chart" -}}
這里面的 .Chart 將無法訪問矮固,導致在模板中無法看到內容呢簸,因為這里值為空
{{- end -}}
因此在模板中將 范圍(scope) 傳入即可正常使用:
# nginx-test/templates/service.yaml
apiVersion: v1
kind: Service
metadata:
name: {{ template "nginx-test.fullname" . }}
在末尾傳遞了 . 這樣就可以使用 .Values 或者 .Chart 或其它范圍(scope)
5、Chart 依賴(requirements.yaml):比如 WordPress Chart 依賴于 mariadb Chart乏屯, 下面是 WordPress 的依賴(requirements.yaml):
dependencies:
- name: mariadb
version: 5.x.x
repository: https://kubernetes-charts.storage.googleapis.com/
condition: mariadb.enabled
tags:
- wordpress-database
該文件列舉當前 Chart 所有的 依賴(subchart)。有幾個字段是必要的:
- name: 依賴 Chart 的名稱(必要)
- version: 依賴 Chart 的版本號(必要)
- repository: 依賴 Chart 的存儲庫完整URL瘦赫,必須通過 helm repo add 添加 repository(存儲庫)到本地