第11章 Helm—Kubernetes的包管理器
本章我们将学习Helm —— Kubernetes的包管理器。
每个成功的软件平台都有一个优秀的打包系统,比如Debian、Ubuntu的apt,Red Hat、CentOS的yum。Helm则是Kubernetes上的包管理器。
本章我们将讨论为什么需要Helm、它的架构和组件,以及如何使用Helm。
11.1 Why Helm
Helm到底解决了什么问题?为什么Kubernetes需要Helm?
答案是:Kubernetes能够很好地组织和编排容器,但它缺少一个更高层次的应用打包工具,而Helm就是来干这件事的。
先来看个例子。
比如对于一个MySQL服务,Kubernetes需要部署下面这些对象:
(1)Service,让外界能够访问到MySQL,如图11-1所示。

图11-1
(2)Secret,定义MySQL的密码,如图11-2所示。

图11-2
(3)PersistentVolumeClaim,为MySQL申请持久化存储空间,如图11-3所示。

图11-3
(4)Deployment,部署MySQL Pod,并使用上面的这些支持对象,如图11-4所示。

图11-4
我们可以将上面这些配置保存到对象各自的文件中,或者集中写进一个配置文件,然后通过kubectl apply -f部署。
到目前为止,Kubernetes对服务的部署支持得都挺好,如果应用只由一个或几个这样的服务组成,上面的部署方式完全足够了。
但是,如果我们开发的是微服务架构的应用,组成应用的服务可能多达十个甚至几十上百个,这种组织和管理应用的方式就不好使了:
(1)很难管理、编辑和维护如此多的服务。每个服务都有若干配置,缺乏一个更高层次的工具将这些配置组织起来。
(2)不容易将这些服务作为一个整体统一发布。部署人员需要首先理解应用都包含哪些服务,然后按照逻辑顺序依次执行kubectl apply,即缺少一种工具来定义应用与服务,以及服务与服务之间的依赖关系。
(3)不能高效地共享和重用服务。比如两个应用都要用到MySQL服务,但配置的参数不一样,这两个应用只能分别复制一套标准的MySQL配置文件,修改后通过kubectl apply部署。也就是说,不支持参数化配置和多环境部署。
(4)不支持应用级别的版本管理。虽然可以通过kubectl rollout undo进行回滚,但这只能针对单个Deployment,不支持整个应用的回滚。
(5)不支持对部署的应用状态进行验证。比如是否能通过预定义的账号访问MySQL。虽然Kubernetes有健康检查,但那是针对单个容器,我们需要应用(服务)级别的健康检查。
Helm能够解决上面这些问题,Helm帮助Kubernetes成为微服务架构应用理想的部署平台。
11.2 Helm架构
在实践之前,我们先来看看Helm的架构。
Helm有两个重要的概念:chart和release。
Helm是包管理工具,这里的包就是指的chart。Helm能够:
Helm包含两个组件:Helm客户端和Tiller服务器,如图11-5所示。

图11-5
Helm客户端是终端用户使用的命令行工具,用户可以:
Tiller服务器运行在Kubernetes集群中,它会处理Helm客户端的请求,与Kubernetes API Server交互。Tiller服务器负责:
简单地讲,Helm客户端负责管理chart,Tiller服务器负责管理release。
11.3 安装Helm
本节我们将依次安装Helm客户端和Tiller服务器。
11.3.1 Helm客户端
通常,我们将Helm客户端安装在能够执行kubectl命令的节点上,只需要下面一条命令:
curl https://raw.githubusercontent.com/kubernetes/helm/master/scripts/get | bash
结果如图11-6所示。

图11-6
执行helm version验证,如图11-7所示。

图11-7
目前只能查看到客户端的版本,服务器还没有安装。
helm有很多子命令和参数,为了提高使用命令行的效率,通常建议安装helm的bash命令补全脚本,方法如下:
helm completion bash > .helmrc echo "source .helmrc" >> .bashrc
重新登录后就可以通过Tab键补全helm子命令和参数了,如图11-8所示。

图11-8
11.3.2 Tiller服务器
Tiller服务器安装非常简单,只需要执行helm init即可,如图11-9所示。

图11-9
Tiller本身也是作为容器化应用运行在Kubernetes Cluster中的,如图11-10所示。

图11-10
可以看到Tiller的Service、Deployment和Pod。
现在,helm version已经能够查看到服务器的版本信息了,如图11-11所示。

图11-11
11.4 使用Helm
Helm安装成功后,可执行helm search查看当前可安装的chart,如图11-12所示。

图11-12
这个列表很长,这里只截取了一部分。大家不禁会问,这些chart都是从哪里来的?
前面说过,Helm可以像apt和yum管理软件包一样管理chart。apt和yum的软件包存放在仓库中,同样的,Helm也有仓库,如图11-13所示。

图11-13
Helm安装时已经默认配置好了两个仓库:stable和local。stable是官方仓库,local是用户存放自己开发的chart的本地仓库。
helm search会显示chart位于哪个仓库,比如local/cool-chart和stable/acs-engineautoscaler。
用户可以通过helm repo add添加更多的仓库,比如企业的私有仓库,仓库的管理和维护方法请参考官网文档https://docs.helm.sh。
与apt和yum一样,helm也支持关键字搜索,如图11-14所示。包括DESCRIPTION在内的所有信息,只要跟关键字匹配,都会显示在结果列表中。

图11-14
安装chart也很简单,执行如下命令就可以安装MySQL。
helm install stable/mysql
如果看到如图11-15所示的报错,通常是因为Tiller服务器的权限不足。

图11-15
执行如下命名添加权限:
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"}}}}'
然后再次执行下面的命令,结果如图11-16所示。
helm install stable/mysql

图11-16
输出分为三部分:
① chart本次部署的描述信息。
② 当前release包含的资源:Service、Deployment、Secret和PersistentVolumeClaim,其名字都是fun-zorse-mysql,命名的格式为ReleasName-ChartName。
③ NOTES部分显示的是release的使用方法,比如如何访问Service、如何获取数据库密码以及如何连接数据库等。
通过kubectl get可以查看组成release的各个对象,如图11-17所示。

图11-17
因为我们还没有准备PersistentVolume,所以当前release还不可用。
helm list显示已经部署的release,helm delete可以删除release,如图11-18所示。

图11-18
Helm的使用方法像极了apt和yum,用Helm来管理Kubernetes应用非常方便。
11.5 chart详解
chart是Helm的应用打包格式。chart由一系列文件组成,这些文件描述了Kubernetes部署应用时所需要的资源,比如Service、Deployment、PersistentVolumeClaim、Secret、ConfigMap等。
单个的chart可以非常简单,只用于部署一个服务,比如Memcached。chart也可以很复杂,部署整个应用,比如包含HTTP Servers、Database、消息中间件、Cache等。
chart将这些文件放置在预定义的目录结构中,通常整个chart被打成tar包,而且标注上版本信息,便于Helm部署。
下面我们将详细讨论chart的目录结构以及包含的各类文件。
11.5.1 chart目录结构
以前面MySQL chart为例。一旦安装了某个chart,我们就可以在~/.helm/cache/archive中找到chart的tar包,如图11-19所示。

图11-19
解压后,MySQL chart目录结构如图11-20所示。

图11-20
目录名就是chart的名字(不带版本信息),这里是mysql,包含如下内容。
(1)Chart.yaml
YAML文件,描述chart的概要信息,如图11-21所示。

图11-21
name和version是必填项,其他都是可选项。
(2)README.md
Markdown格式的README文件,相当于chart的使用文档,此文件为可选,如图11-22所示。

图11-22
(3)LICENSE
文本文件,描述chart的许可信息,此文件为可选。
(4)requirements.yaml
chart可能依赖其他的chart,这些依赖关系可通过requirements.yaml指定,如图11-23所示。

图11-23
在安装过程中,依赖的chart也会被一起安装。
(5)values.yaml
chart支持在安装时根据参数进行定制化配置,而values.yaml则提供了这些配置参数的默认值,如图11-24所示。

图11-24
(6)templates目录
各类Kubernetes资源的配置模板都放置在这里。Helm会将values.yaml中的参数值注入模板中,生成标准的YAML配置文件。
模板是chart最重要的部分,也是Helm最强大的地方。模板增加了应用部署的灵活性,能够适用不同的环境,我们后面会详细讨论。
(7)templates/NOTES.txt
chart的简易使用文档,chart安装成功后会显示此文档内容,如图11-25所示。

图11-25
与模板一样,可以在NOTE.txt中插入配置参数,Helm会动态注入参数值。
11.5.2 chart模板
Helm通过模板创建Kubernetes能够理解的YAML格式的资源配置文件,我们将通过例子来学习如何使用模板。
以templates/secrets.yaml为例,如图11-26所示。

图11-26
从结构上看,文件的内容非常像Secret配置,只是大部分属性值变成了{{ xxx }}。这些{{ xxx }}实际上是模板的语法。Helm采用了Go语言的模板来编写chart。Go模板非常强大,支持变量、对象、函数、流控制等功能。下面我们通过解析templates/secrets.yaml快速学习模板。
① {{ template "mysql.fullname" . }}定义Secret的name。关键字template的作用是引用一个子模板mysql.fullname。这个子模板是在templates/_helpers.tpl文件中定义的,如图11-27所示。

图11-27
这个定义还是很复杂的,因为它用到了模板语言中的对象、函数、流控制等概念。现在看不懂没关系,这里我们学习的重点是:如果存在一些信息多个模板都会用到,则可在templates/_helpers.tpl中将其定义为子模板,然后通过templates函数引用。
这里mysql.fullname是由release与chart二者名字拼接组成的。
根据chart的最佳实践,所有资源的名称都应该保持一致。对于我们这个chart,无论Secret还是Deployment、PersistentVolumeClaim、Service,它们的名字都是子模板mysql.fullname的值。
② Chart和Release是Helm预定义的对象,每个对象都有自己的属性,可以在模板中使用。如果使用下面的命令安装chart:
helm install stable/mysql -n my
那么:
③ 这里指定mysql-root-password的值,不过使用了if-else的流控制,其逻辑为:如果.Values.mysqlRootPassword有值,就对其进行base64编码,否则随机生成一个10位的字符串并编码。
Values也是预定义的对象,代表的是values.yaml文件。.Values.mysqlRootPassword则是values.yaml中定义的mysqlRootPassword参数,如图11-28所示。

图11-28
因为mysqlRootPassword被注释掉了,没有赋值,所以逻辑判断会走else,即随机生成密码。
randAlphaNum、b64enc、quote都是Go模板语言支持的函数,函数之间可以通过管道|连接。{{ randAlphaNum 10 | b64enc | quote }}的作用是首先随机产生一个长度为10的字符串,然后将其base64编码,最后两边加上双引号。
templates/secrets.yaml这个例子展示了chart模板主要的功能,我们最大的收获应该是:模板将chart参数化了,通过values.yaml可以灵活定制应用。
无论多复杂的应用,用户都可以用Go模板语言编写出chart。无非是使用到更多的函数、对象和流控制。对于初学者,建议尽量参考官方的chart。根据二八定律,这些chart已经覆盖了绝大部分情况,而且采用了最佳实践。如何遇到不懂的函数、对象和其他语法,可参考官网文档https://docs.helm.sh。
11.5.3 再次实践MySQL chart
学习了chart结构和模板的知识后,现在重新实践一次MySQL chart,相信会有更多收获。
1. chart安装前的准备
作为准备工作,安装之前需要先清楚chart的使用方法。这些信息通常记录在values.yaml和README.md中。除了下载源文件查看,执行helm inspect values可能是更方便的方法,如图11-29所示。

图11-29
输出的实际上是values.yaml的内容。阅读注释就可以知道MySQL chart支持哪些参数,安装之前需要做哪些准备。其中有一部分是关于存储的,如图11-30所示。

图11-30
chart定义了一个PersistentVolumeClaim,申请8GB的PersistentVolume。由于我们的实验环境不支持动态供给,因此要预先创建好相应的PV,其配置文件mysql-pv.yml的内容如图11-31所示。

图11-31
创建PV mysql-pv,如图11-32所示。

图11-32
接下来就可以安装chart了。
2. 定制化安装chart
除了接受values.yaml的默认值,我们还可以定制化chart,比如设置mysqlRootPassword。
Helm有两种方式传递配置参数:
(1)指定自己的values文件。通常的做法是首先通过helm inspect values mysql >myvalues.yaml生成values文件,然后设置mysqlRootPassword,最后执行helm install--values=myvalues.yaml mysql。
(2)通过--set直接传入参数值,如图11-33所示。

图11-33
mysqlRootPassword设置为abc123。另外,-n设置release为my,各类资源的名称即为my-mysql。
通过helm list和helm status可以查看chart的最新状态,如图11-34所示。

图11-34
PVC已经Bound,Deployment也变为AVAILABLE。
11.5.4 升级和回滚release
release发布后可以执行helm upgrade对其进行升级,通过--values或--set应用新的配置。比如将当前的MySQL版本升级到5.7.15,如图11-35所示。

图11-35
等待一些时间,升级成功,如图11-36所示。

图11-36
helm history可以查看release所有的版本。通过helm rollback可以回滚到任何版本,如图11-37所示。

图11-37
回滚成功,MySQL恢复到5.7.14,如图11-38所示。

图11-38
11.5.5 开发自己的chart
Kubernetes给我们提供了大量官方chart,不过要部署微服务应用,还是需要开发自己的chart,下面就来实践这个主题。
1.创建chart
执行helm create mychart命令,创建chart mychart,如图11-39所示。

图11-39
Helm会帮我们创建目录mychart,并生成各类chart文件。这样我们就可以在此基础上开发自己的chart了。
新建的chart默认包含一个nginx应用示例,values.yaml内容如图11-40所示。

图11-40
开发时建议大家参考官方chart中的模板values.yaml、Chart.yaml,里面包含了大量最佳实践和最常用的函数、流控制,这里就不一一展开了。
2. 调试chart
只要是程序就会有bug,chart也不例外。Helm提供了debug的工具:helm lint和helm install --dry-run --debug。
helm lint会检测chart的语法,报告错误以及给出建议。
比如我们故意在values.yaml的第8行漏掉了行尾的那个冒号,如图11-41所示。

图11-41
helm lint mychart会指出这个语法错误,如图11-42所示。

图11-42
mychart目录被作为参数传递给helm lint。错误修复后则能通过检测,如图11-43所示。

图11-43
helm install --dry-run --debug会模拟安装chart,并输出每个模板生成的YAML内容,如图11-44、图11-45所示。

图11-44

图11-45
我们可以检测这些输出,判断是否与预期相符。
同样,mychart目录作为参数传递给helm install --dry-run --debug。
3. 安装chart
当我们准备就绪,就可以安装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。
这里我们使用本地目录安装,如图11-46所示。

图11-46
当chart部署到Kubernetes集群后,便可以对其进行更为全面的测试了。
4. 将chart添加到仓库
chart通过测试后可以添加到仓库中,团队其他成员就能够使用了。任何HTTP Server都可以用作chart仓库。下面演示在k8s-node1 192.168.56.106上搭建仓库。
(1)在k8s-node1上启动一个httpd容器,如图11-47所示。

图11-47
(2)通过helm package将mychart打包,如图11-48所示。

图11-48
(3)执行helm repo index生成仓库的index文件,如图11-49所示。

图11-49
Helm会扫描myrepo目录中的所有tgz包并生成index.yaml。--url指定的是新仓库的访问路径。新生成的index.yaml记录了当前仓库中所有chart的信息,如图11-50所示。

图11-50
当前只有mychart这一个chart。
(4)将mychart-0.1.0.tgz和index.yaml上传到k8s-node1的/var/www/charts目录,如图11-51所示。

图11-51
(5)通过helm repo add将新仓库添加到Helm,如图11-52所示。

图11-52
仓库命名为newrepo,Helm会从仓库下载index.yaml。
(6)现在已经可以repo search到mychart了,如图11-53所示。

图11-53
除了newrepo/mychart,这里还有一个local/mychart。这是因为在执行第2步打包操作的同时,mychart也被同步到了local的仓库。
(7)已经可以直接从新仓库安装mychart了,如图11-54所示。

图11-54
(8)若以后仓库添加了新的chart,则需要用helm repo update更新本地的index,如图11-55所示。

图11-55
这个操作相当于Ubutun的apt-get update。
11.6 小结
本章我们学习了Kubernetes包管理器Helm。
Helm让我们能够像apt管理deb包那样安装、部署、升级和删除容器化应用。
Helm由客户端和Tiller服务器组成。客户端负责管理chart,服务器负责管理release。
chart是Helm的应用打包格式,它由一组文件和目录构成。其中最重要的是模板,模板中定义了Kubernetes各类资源的配置信息,Helm在部署时通过values.yaml实例化模板。
Helm允许用户开发自己的chart,并为用户提供了调试工具。用户可以搭建自己的chart仓库,在团队中共享chart。
Helm帮助用户在Kubernetes上高效地运行和管理微服务架构应用,Helm非常重要。