作者 | 淮右、临石
导读:单 K8s 集群为用户提供了 Namespace 级别的隔离能力,理论上支持不超过 5K Node、15W Pod。多 K8s 集群则解决了单集群的资源隔离、故障隔离难题,打破可支持节点数、Pod 数的限制,但与此同时也带来了集群管理复杂度的上升;尤其在专有云场景中,K8s 工程师不可能像在公有云中一样快速触达客户环境,运维成本被进一步放大。因此如何低成本、高效率、自动化低管理多套 K8s 集群,成为业内普遍难题。
背景
多集群主要应用在如下场景:
1.产品本身需要多集群能力。产品的管控需要部署在 K8s 集群内,同时,该产品还需要提供 K8s 集群给用户使用,从故障隔离、稳定性、安全多重角度考虑,容器服务的管控和业务应该分别部署在不同的集群内;
2.用户在使用 K8s 的时候,也希望具备生产多套集群供不同业务使用,从而进行资源隔离、故障隔离;
3.同一用户可能需要多种类型集群的能力,以边缘计算 IOT 为例,它需要一个定制的边缘 K8s 集群,如果按照普通的独立 K8s 集群来创建,一方面会存在资源浪费,另一方面独立的集群为用户增加了运维的成本。
我们总结了运维 K8s 集群的难点,可以分为两部分:
难点 1:运维 K8s 集群的管控面
- 如何支持用户一键弹出新的 Kubernetes 集群?
- 如何升级多个 K8s 集群的版本,当社区重大 CVE 发现时,是否要一个个升级集群?
- 如何自动修复多个 K8s 集群运行时发生的故障?
- 如何对集群的 etcd 进行维护,包括升级、备份、恢复、节点迁移?
难点 2:运维 Worker 节点
- 如何快速扩缩容 Worker 节点?同时需要确保每个节点的 on-host 软件(例如 docker、kubelet 等无法被 K8s 托管的组件)版本、配置和其他节点拉齐。
- 如何升级若干 Worker 节点上的 on-host 软件?如何灰度发布 Worker 节点上的软件包?
- 如何自动修复若干 Worker 节点可能出现的 on-host 软件故障?比如要是 docker/kubelet 发生 panic,我们是否能自动化的处理?
K8s 作为一个复杂的自动化运维系统,支撑了上层业务的发布、升级、生命周期管理,但 K8s 本身的运维在业内却往往还是由一个工作流(ansible、argo 等)来执行。这个过程的自动化程度不高,需要运维人员具备比较专业的 K8s 知识。而当需要运维多套 K8s 集群后,运维成本在理想情况下也会线性上升,在专有云场景下成本还会被再次放大。
阿里内部很早就遇到了运维大量 K8s 集群的难题,我们摒弃了传统工作流的模式,探索另外一条路径:使用 K8s 管理 K8s,CNCF 的文章《Demystifying Kubernetes as a Service – How Alibaba Cloud Manages 10,000s of Kubernetes Clusters》介绍了阿里巴巴在大规模 K8s 集群管理上的探索与经验。
当然,专有云场景和阿里巴巴内部场景还是有较大不同,阿里集团内使用 Kube-On-Kube 技术主要看重它的规模效应,可以使用一个元 K8s 集群来管理成百上千的业务 K8s 集群,而专有云场景的规模效应小,专有云主要看重的是Kube-On-Kube 技术自动化运维 K8s 集群和兼容多种 K8s 集群的能力,在提高稳定性的同时丰富了用户的使用场景。
K8s 声明式运维哲学:用 K8s 管理 K8s
K8s 的声明式 API 颠覆了传统的过程式运维模式,声明式 API 对应的是面向终态的运维模式:使用者将在 Spec 里定义自己所期望的状态,K8s 的 Controller 会进行一系列操作帮助使用者达到期望状态,只要不满足要求,Controller 会一直尝试。
对于 Deployment 等 K8s 原生资源,由 K8s 的 Controller 负责终态维护,而对于用户自定义的资源,例如一个 Cluster,K8s 提供了强大易用的 CRD+Operator 机制,只需要简单几步就可以实现自定义的面向终态运维:
1.定义自己的资源类型(CRD),实现自己的 Operator,Operator 中包含了自定义 Controller;
2.用户只需要提交自己的 CR,表现形式为一个 yaml 或者 json;
3.Operator 监听到 CR 的变化,Controller 开始执行对应的运维逻辑;
4.在运行过程中,当终态不满足要求时,Operator 也能够监听到变化,并做出相应的恢复操作。
Operator 是用代码运维应用最好的实践之一。当然,这只是一个框架,它节省了使用者的一些重复性劳动,如事件监听机制、RESTful API 监听,但核心的运维逻辑,还是需要 case by case 由使用者编写。
云原生的 KOK 架构
Kube-On-Kube 不是新概念,业内已有很多优秀的解决方案:
- 蚂蚁
- 社区项目
但是以上方案对公有云基础设施有较强依赖,专有云的特殊性让我们要考虑:
- 足够轻量化用户才会买单,客户通常很排斥独占的管理节点开销;
- 不依赖公有云和阿里集团内部的差异性基础设施;
- 采用云原生架构。
在考虑到这 3 个因素后,我们设计出更为通用的 KOK 方案:
名词解释:
- Meta Cluster:元集群,即 Kube-On-Kube 的下层 Kube;
- Production Cluster:业务集群,即 Kube-On-Kube 的上层 Kube;
- etcd cluster:由运行在元集群中的 etcd operator 创建和维护的 etcd 集群,可以每个业务集群独占一个 etcd,或者多个业务集群共享;
- PC-master-pod:业务集群管控 pod,实际上是 apiserver/scheduler/controller-manager 这 3 种 pod,由运行在元集群的 Cluster Operator 维护;
- PC-nodes:业务集群的 Node 节点,由 Machine Operator 负责初始化并加入到业务集群,由 Machine Operator 维护;
etcd Operator
etcd Operator 负责 etcd 集群的创建、销毁、升级、故障恢复等,还提供了 etcd 集群的状态监控,包括集群健康状态、member 健康状态、存储数据量等。
阿里云-云原生应用平台-SRE 团队对开源版 etcd Operator 进行了改进,增强了运维功能和稳定性,该 Operator 负责阿里内部大量 etcd 集群的运维管理,运行稳定,久经考验。
Cluster Operator
Cluster Operator 负责业务集群 K8s 管控组件(Apiserver、Controller Manager、Scheduler)的创建、维护,以及相应的证书生成、kubeconfig 生成。
我们和蚂蚁集团-PaaS 引擎与专有云产品团队共建了 Cluster Operator,具备自定义渲染、版本溯源、动态增加可支持版本等能力。
业务集群的 K8s 管控组件部署在元集群,从元集群的视角看就是一堆普通的 Resource,包括 Deployment、Secret、Pod、PVC 等,因此,业务集群不具备 Master 节点的概念:
- kube-apiserver:由 1 个 Deployment +1 个 Service 组成。kube-apiserver 本身无状态,Deployment 可以满足要求,同时,Apiserver 需要对接 etcd Operator 拉起的 etcd cluster;Service 用于对业务集群其他组件以及对外暴露 Apiserver 的服务,此处我们考虑了,如果用户环境具备 LoadBalancer Service 的能力,建议优先使用 LoadBalancer 暴露 Apiserver,如果没有此能力,我们也提供了 NodePort 的暴露形态;
- kube-controller-manager:1 个 Deployment,无状态应用;
- kube-scheduler:1 个 Deployment 即可,无状态应用;
但是,只部署以上 3 个组件还不能提供一个可用 K8s,我们还需要满足以下场景:
1.一个可用的业务 K8s 除了 etcd、3 大件之外,还需要部署 coredns、kube-proxy 或者其他任意组件;
2.部分组件需要和 etcd、3 大件一样的部署在元集群,例如 Machine Operator 是拉起节点的组件,它必须在业务集群有节点之前就能运作,所以它不能部署在业务集群;
3.组件版本的升级。
因此,为了应对扩展性要求,我们设计了 addons 热插拔能力,只需一条命令即可导入所有 Addon 组件;同时 addons 支持动态渲染能力,可自定义 addons 的配置项,细节不再赘述。
Machine Operator
Machine Operator 负责对节点做必要的初始化操作,然后创建节点的 docker、k8s、NVIDIA 等组件并维护其终态;最后,将节点加入业务集群。
我们采用了阿里云-云原生应用平台-Serverless 节点管理团队维护的 KubeNode 组件,该 Operator 负责集团内节点的上下线,实现了一个面向终态的运维框架,可以针对不同 Arch 或者不同 OS 定制运维 CRD,比较适合在环境多变的专有云环境使用。
KubeNode 简而言之实现了一个面向终态的运维框架,它主要包含 Component+Machine 两个概念。
1.使用者按模板提供运维脚本,生成 Component CR;
2.如果要上线节点,就生成一个 Machine CR,Machine CR 里会指定需要部署哪些 Component;
3.KubeNode 监听到 Machine CR,会到对应节点进行运维操作。
这种设计理论上可以针对不同 Arch 或者不同 OS 可以在不改动 Operator 源码的前提下进行扩展,灵活度很高。同时,我们也在探索如何结合 IaaS provider,最终实现 RunAnyWhere 的目标。
多集群方案成本对比
在使用自动化工具(也是一个云原生的 Operator,后续会有文章介绍)串接上述流程后,我们可以将一个集群的生产时间压缩到分钟级。
下图列举了平铺式多集群解决方案(直接部署多套)和 KOK 多集群解决方案的成本分析:
平铺式多集群解决方案 | KOK多集群解决方案 | |
---|---|---|
交付成本 | TKG | TG+tG*(K-1) |
升级成本 | UGP*K | UGP+uGP*(K-1) |
用户使用成本 | T*K | t*K |
其中,T 为单个 K8s 集群部署时间,t 为单个业务集群的部署时间,K 为集群数,G 为局点数,U 为升级元集群时间,u 为升级业务集群时间,P 为升级次数。
从我们的实践经验得到,正常情况下,T、U 为约为 1 小时,t、u 约为 10 分钟,我们预计:
- 交付多集群(集群数为 3)时间将由 > 3小时降为 1 小时降为 10 分钟;
- 用户自建 1 套新集群的时间开销将由 >2 小时降为 10 分钟。
总结
平铺式多集群势必带来运维复杂度的线性上升,难以维护;而 KOK 多集群将 K8s 集群本身视为一个 K8s 资源,利用 K8s 强大的 CRD+Operator 能力,将 K8s 的运维本身也从传统的过程式升级为声明式,对 K8s 集群的运维复杂度实行了降维打击。
与此同时,本文介绍的多集群设计方案,在借鉴阿里巴巴集团内多年运维经验的基础上,采用云原生的架构,摆脱了对差异性基础设施的依赖,实现了 RunAnyWhere。使用者只需要提供普通的 IaaS 设施,就可以享受到易用、稳定、轻量的 K8s 多集群能力。
“阿里巴巴云原生关注微服务、Serverless、容器、Service Mesh 等技术领域、聚焦云原生流行技术趋势、云原生大规模的落地实践,做最懂云原生开发者的公众号。”