本文由 3 月 7 日晚李平辉,Rancher Labs 研发工程师所做的技术分享整理而成。
李平辉熟悉应用容器化解决方案设计和实施,熟悉持续集成方案,关注并参与 K8S 生态的发展,负责 Rancher 中国区持续集成服务研发。
搜索微信号 RancherLabsChina,或文末扫码,添加 Rancher 小助手为好友,可加入 官方技术交流群,实时参加下一次分享~
大家好,今天我们分享的内容是基于 Helm 和 Operator 的 K8S 应用管理。我们知道,Kubernetes 基于服务粒度提供了多种资源描述类型。描述一个应用系统尤其是微服务架构系统,需要组合使用大量的 Kubernetes 资源。针对有状态应用,常常还需要复杂的运维管理操作以及更多的领域知识。
今晚的分享就将介绍如何用 Helm 这一 Kubernetes 应用包管理的社区主导方案来简化应用的部署管理,如何制作应用模板以及打造 Kubernetes 版应用商店,以及如何利用 operator 自动化应用的运维。
我们知道在 K8S 社区里面,根据不同的领域,分成了不同的兴趣小组,英文叫 SIG。今晚的话题属于 APP 这个领域。它们是为了解决 K8S 的应用管理里面的一些问题而生的。
一、Helm
让我们从零开始吧。比如说我们现在已经部署了一个 K8S 的集群。不管是用 GKE 或者是 EKS,都不是难事,因为现在部署 K8S 已经不是以前那么麻烦的事情了。然后我们做了应用的容器化。接下来,我们要试着去把我们的应用部署到 K8S 上面去。
其实在 K8S 里面,资源对象是很多的:
对于一些微服务架构来说,会有不同的服务在上面运行,你可能要管理诸如 deployment、service、有状态的 Statefulset、权限的控制等等。你会发现,部署应用后还会有很多其他关联的东西以及你需要考虑的点:比如说你的不同团队,要去管理这样一个应用,从开发到测试再到生产,在不同的环境中,同样一套东西可能都需要不同的配置。例如,你在开发的时候,不需要用到 PV,而是用一些暂时的存储就行了;但是在生产环境中,你必须要持久存储;并且你可能会在团队之间做共享,然后去存档。
另外,你不仅仅要部署这个应用资源,你还要去管理其生命周期,包括升级、更新换代、后续的删除等。我们知道,K8S 里面的 deployment 是有版本管理的,但是从整个应用或某个应用模块来考虑的话,除了 deployment,可能还会有其他的 configmap 之类的去跟其关联。这时我们会想,是否有这样一个工具可以在更上层的维度去管理这些应用呢?这个时候我们就有了社区的一个包管理工具:Helm。
我们知道 K8S 的意思是舵手,即掌控船舵的那个人。而 Helm 其实就是那个舵。在 Helm 里面,它的一个应用包叫 Charts,Charts 其实是航海图的意思。它是什么东西呢?
它其实就是一个应用的定义描述。里面包括了这个应用的一些元数据,以及该应用的 K8S 资源定义的模板及其配置。其次,Charts 还可以包括一些文档的说明,这些可以存储在 chart 的仓库里面。
怎么用 Helm 这个工具呢?Helm 其实就是一个二进制工具。你只要把它下载下来,已经配置好了 kubeconfig 的一些相关配置信息,就可以在 K8S 中做应用的部署和管理了。
用 Helm 可以做什么事情呢?其实 Helm 分为服务端跟客户端两部分,你在 helm init 之后,它会把一个叫做 Tiller 的服务端,部署在 K8S 里面。这个服务端可以帮你管理 Helm Chart 应用包的一个完整生命周期。
Release == Chart 的安装实例:
接着说说 Helm Chart。它本质上是一个应用包,你可以把它理解成 dpkg 或者像 rpm 这样的包。只不过,它是基于 K8S 领域的一个应用包的概念。你可以对同一个 chart 包进行多次部署,每次安装它都会产生一个 Release。这个 Release 相当于一个 chart 中的安装实例。
现在我们已经把 Tiller 部署进去了,那么就可以去做我们应用的管理了:
关于一些常用的命令例如安装一个应用包,可以用 install,它其实是可以支持不同格式的:比如说本地的一些 chart 包,或者说你的远程仓库路径。
对于应用的更新,用 Helm upgrade。
如果要删除的话,就用 Helm Delete。
Helm 的一个 Release 会生成对应的 Configmap,由它去存储这个 Release 的信息,并存在 K8S 里面。它相当于把应用的一个生命周期的迭代,直接跟 K8S 去做关联,哪怕 Tiller 挂了,但只要你的配置信息还在,这个应用的发布和迭代历程不会丢失:例如想回滚到以前的版本,或者是查看它的升级路径等。
接下来我们看一个 chart 的结构。
用 Helm create 的话,它会提供一个大概的框架,你可以去创建自己的一个应用。比如说这个应用就叫做 Demoapp,里面会有如下内容:
其中最核心的是 templates,即模板化的 K8S manifests 文件,这里面会包括资源的定义,例如 deployment、service 等。现在我们 create 出来的是一个默认的、用一个 nginx deployment 去部署的应用。
它本质上就是一个 Go 的 template 模板。Helm 在 Go template 模板的基础上,还会增加很多东西。如一些自定义的元数据信息、扩展的库以及一些类似于编程形式的工作流,例如条件语句、管道等等。这些东西都会使得我们的模板变得非常丰富。
有了模板,我们怎么把我们的配置融入进去呢?用的就是这个 values 文件。这两部分内容其实就是 chart 的核心功能。
这个 deployment,就是一个 Go template 的模板。里面可以定义一些预设的配置变量。这些变量就是从 values 文件中读取出来的。这样一来,我们就有了一个应用包的模板,可以用不同的配置将这个应用包部署在不同的环境中去。除此之外,在 Helm install/upgrade 时候,可以使用不同的 value。
配置选项:
比如说你可以 set 某个单独的变量,你可以用整个 File 去做一个部署,它会用你现在的配置覆盖掉它的默认配置。因此我们可以在不同的团队之间,直接用不同的配置文件,并用同样的应用包去做应用管理。Chart.yaml 即 chart 的元数据,描述的就是这个 chart 包的信息。
另外还有一些文档的说明,例如 NOTES.txt,一般放在 templates 里面,它是在你安装或者说你察看这个部署详情之时(helm status),自动列出来的。通常会放一些部署了的应用和如何访问等一些描述性的信息。
除了模板以外,Helm chart 的另一个作用就是管理依赖。
比如说你部署一个 Wordpress,它可以依赖一些数据库服务。你可以把数据库服务作为一个 chart 形式,放在一个依赖的目录下面。这样的话应用之间的依赖管理就可以做的很方便了。
假如现在已经创建了我们自己的应用包,想要有一个仓库去管理这个包,在团队之间共享应该怎么做?
chart 的仓库其实就是一个 HTTP 服务器。只要你把你的 chart 以及它的索引文件放到上面,在 Helm install 的时候,就可以通过上面的路径去拿。
Helm 工具本身也提供一个简单的指令,叫 Helm serve,帮你去做一个开发调试用的仓库。
例如 https://example.com/charts 的仓库目录结构:
关于 Helm,社区版其实已经有了很多的应用包,一般放在 K8S 下面的一些项目中,比如安装 Helm 时候,它默认就有一个 Stable 的项目。里面会有各种各样的应用包。Stable 和 incubator chart 仓库:https://github.com/kubernetes/charts
另外,社区版还会提供类似于 Rancher Catalog 应用商店的这样一个概念的 UI,你可以在这上面做管理。它叫 Monocular,即单筒望远镜的意思,这些项目的开发都非常的活跃,一直在随着 K8S 的迭代做着更新。
Monocular: chart 的 UI 管理项目:https://github.com/kubernetes-helm/monocular
那么怎么去部署 K8S 版的应用商店呢?其实也非常简单。因为有了 Helm 之后,你只要使用 Helm install 这个 Monocular,先把它的仓库加进来,再 install 一下,就可以把这个应用部署到你的 K8S 集群之中了。它其实也是利用了 Helm Tiller 去做部署。我们可以在上面去搜索一些 chart,管理你的仓库,例如官方的 stable,或者是 incubator 里面的一些项目。
你也可以管理一些已经部署的应用。比如说你要搜索一个应用,点一下部署,就可以把它部署上去了。不过这其中还有很多亟待完善的东西,比如这里的部署不能配置各种不同的参数,它只能输入 namespace。其次,里面的一些管理依然存在局限性,比如不能很方便地在 UI 上做更新。
围绕 Helm chart 我们也会跟一些公有云厂商有相关的合作。因为 Helm chart 的好处就是:一个应用包可以在多个地方部署。比如公有云的服务,可以基于它去实现应用的编排和管理,把一个服务便利地提供给不同的用户。Rancher 也会在 2.0 的应用商店中加入对 helm chart 的支持,希望帮助用户在方便利用已有模板的同时提供良好的体验。
在 stable 的仓库里面已经有很多 chart,其实并不是特别完善,还有很多应用是可以补充和增强的。就我们的实践经验来说,什么都可以 chart 化,不管是分布式的数据库集群,还是并行计算框架,都可以以这样的形式在 K8S 上部署和管理起来。
另外一点就是 Helm 是插件化的,helm 的插件有 Helm-templates, helm-github,等等。
比如你在 Helm install 的时候,它可以调用插件去做扩展。它没有官方的仓库,但是已经有一些功能可用。其实是把 Restless/release 的信息以及你的 chart 信息以及 Tiller 的连接信息交给插件去处理。Helm 本身不管插件是用什么形式去实现的,只要它是应用包,则对传入的这些参数做它自己的处理就行。
Helm 的好处,大概就有这些:
利用已有的 Chart 快速部署进行实验
创建自定义 Chart,方便地在团队间共享
便于管理应用的生命周期
便于应用的依赖管理和重用
将 K8S 集群作为应用发布协作中心
二、Operator
我们接下来说说 Operator。为什么讲 Operator 呢?Operator 其实并不是一个工具,而是为了解决一个问题而存在的一个思路。什么问题?就是我们在管理应用时,会遇到无状态和有状态的应用。管理无状态的应用是相对来说比较简单的,但是有状态的应用则比较复杂。在 Helm chart 的 stable 仓库里面,很多数据库的 chart 其实是单节点的,因为分布式的数据库做起来会较为麻烦。
Operator 的理念是希望注入领域知识,用软件管理复杂的应用。例如对于有状态应用来说,每一个东西都不一样,都可能需要你有专业的知识去处理。对于不同的数据库服务,扩容缩容以及备份等方式各有区别。能不能利用 K8S 便捷的特性去把这些复杂的东西简单化呢?这就是 Operator 想做的事情。
以无状态应用来说,把它做成一个 Scale UP 的话是比较简单的:扩充一下它的数量就行了。
接着在 deployment 或者是说 ReplicaSet 的 controller 中,会去判断它当前的状态,并向目标状态进行迁移。对有状态的应用来说,我们常常需要考虑很多复杂的事情,包括升级、配置更新、备份、灾难恢复、Scale 调整数量等等,有时相当于将整个配置刷一遍,甚至可能要重启一些服务。
比如像 Zookeeper315 以前不能实时更新集群状态,想要扩容非常麻烦,可能需要把整个节点重启一轮。有些数据库可能方便一点,到 master 那里注册一下就好。因此每个服务都会有它自己的特点。
拿 etcd 来说,它是 K8S 里面主要的存储。如果对它做一个 Scale up 的话,需要往集群中添加一些新节点的连接信息,从而获取到集群的不同 Member 的配置连接。然后用它的集群信息去启动一个新的 etcd 节点。
如果有了 etcd Operator,会怎么样?Operator 其实是 CoreOS 布道的东西。CoreOS 给社区出了几个开源的 Operator,包括 etcd,那么如何在这种情况下去扩容一个 etcd 集群?
首先可以以 deployment 的形式把 etcd Operator 部署到 K8S 中。部署完这个 Operator 之后,想要部署一个 etcd 的集群,其实很方便。因为不需要再去管理这个集群的配置信息了,你只要告诉我,你需要多少的节点,你需要什么版本的 etcd,然后创建这样一个自定义的资源,Operator 会监听你的需求,帮你创建出配置信息来。
要扩容的话也很简单,只要更新数量(比如从 3 改到 5),再 apply 一下,它同样会监听这个自定义资源的变动,去做对应的更新。
这样就相当于把以前需要运维人员去处理集群的一些工作全部都交付给 Operator 去完成了。如何做到的呢?即应用了 K8S 的一个扩展性的 API——CRD(在以前称为第三方资源)。
在部署了一个 etcd Operator 之后,通过 kubernetes API 去管理和维护目标的应用状态。本质上走的就是 K8S 里面的 Controller 的模式。K8S Controller 会对它的 resource 做这样的一个管理:去监听或者是说检查它预期的状态,然后跟当前的状态作对比。如果其中它会有一些差异的话,它会去做对应的更新。
Kubernetes Controller 模式:
etcd 的做法是在拉起一个 etcd Operator 的时候,创建一个叫 etcd cluster 的自定义资源,监听应用的变化。比如你的声明你的更新,它都会去产生对应的一个事件,去做对应的更新,将你的 etcd 集群维护在这样的状态。
除了 etcd 以外,社区比如还有普罗米修斯 Operator 都可以以这种方便的形式,去帮你管理一些有状态的应用。
值得一提的是,Rancher2.0 广泛采用了 Kubernetes-native 的 Controller 模式,去管理应用负载乃至 K8S 集群,调侃地说,是个 Kubernetes operator。
三、Helm 和 Operator 的对比
这两个东西讲完了,我们来对比一下二者吧。
Operator 本质上是针对特定的场景去做有状态服务,或者说针对拥有复杂应用的应用场景去简化其运维管理的工具。Helm 的话,它其实是一个比较普适的工具,想法也很简单,就是把你的 K8S 资源模板化,方便共享,然后在不同的配置中重用。
其实 Operator 做的东西 Helm 大部分也可以做。用 Operator 去监控更新 etcd 的集群状态,也可以用定制的 Chart 做同样的事情。只不过你可能需要一些更复杂的处理而已,例如在 etcd 没有建立起来时候,你可能需要一些 init Container 去做配置的更新,去检查状态,然后把这个节点用对应的信息给拉起来。删除的时候,则加一些 PostHook 去做一些处理。所以说 Helm 是一个更加普适的工具。两者甚至可以结合使用,比如 stable 仓库里就有 etcd-operator chart。
就个人理解来说,在 K8S 这个庞然大物之上,他们两者都诞生于简单但自然的想法,helm 是为了配置分离,operator 则是针对复杂应用的自动化管理。
QA 环节
Q1:像 Rancher 有自带的应用商店 Catalog,那 Helm 是相当于 K8S 的应用商店吗?
A1:是的,Rancher 大概是在早期版本、Rancher 1.3 开始支持 Helm 了。用户在 Rancher 部署 K8S 的时候,Rancher 会把 Helm 工具都给装好给用户使用。现在的 Rancher 在 K8S 里面是没有应用商店的,我们就是考虑到 Helm 社区很活跃与成熟了,用户可以直接用 Helm 这个工具,所以 K8S 里面的应用商店其实是拿掉了的。Rancher 1.x 版本,用户使用 helm chart 并没有 cattle catalog 那么好,不过 2.0 里这一点就极大改善了。
Q2:如何将本地的 chart 包 push 到远程仓库?
A2:chart repository 就是普通的 http web 服务器带特定的 index 文件,把 chart 包按对应格式传到 host 的目录就可以了,具体可以参考:https://docs.helm.sh/developing_charts/#the-chart-repository-guide
Q3:想添加本地某个目录(包含 index.yaml)作为私有仓库该怎么做?
A3:最简单的用 helm 提供的 serve 命令。
Q4:helm 是一个图形化管理工具吗?
A4:不是图形化管理工具,但是有对应的 ui 项目。
Q5:helm 架构中的 tiller 是指什么?
A5:tiller 就是部署在 k8s 中的服务端,实际执行部署更新等操作,你用的 helm binary 是 client 端会向它发请求。
Q6:helm 目前国内使用不是很方便,目前所有的 charts 都是放在 google 服务器的, 国内用什么好用的 repository 么?
A6:可以翻墙或者自己搭,我没怎么了解过国内的源(捂脸)。
Q7:所以 operator 是一种管理有状态应用的软件架构模式?
A7:通常用作管理有状态应用,就是利用 k8s 的 crd 扩展及声明式定义的方式做应用管理的模式。
Q8:operator 业界有通用框架吗?
A8:在 k8s 的世界就是 controller 模式那一套,可以参考之前的一篇 go-client 相关的文章:如何在GO语言中使用Kubernetes API?
评论