天天看点

深度 | 蚂蚁金服自动化运维大规模 Kubernetes 集群的实践之路

导读

此文章分享了蚂蚁金服如何自动化运维大规模 Kubernetes 集群的实践干货。

"大规模 Kubernetes 集群"主要体现在几十个 Kubernetes 集群,十万级别的 Kubernetes Worker 节点。

蚂蚁金服使用 Operator 的模式去运维 Kubernetes 集群,能便捷、自动化的管理 Kubernetes 集群生命周期,做到 " Kubernetes as a Service " 。

此文适合 Kubernetes 爱好者,Kubernetes 架构师,以及 PE/SRE 阅读。

前序知识

Kubernetes 架构介绍

此章节简单介绍 Kubernetes 集群的架构。主要是为了面向刚学习 Kubernetes 的同学,对于熟悉 Kubernetes 的同学,此章节可以跳过。

深度 | 蚂蚁金服自动化运维大规模 Kubernetes 集群的实践之路

如上图,一个 Kubernetes 集群由 Master 节点和 Worker 节点组成。

在一个高可用 Kubernetes 集群下面,Master 节点一般为3台,在它们上面需要运行Kubernetes Master 组件。Kubernetes Master 组件包括 etcd, Apsierver, Scheduler 和 Controller-Manager。每个 Master 组件一般都是 3 个实例,以保证它们的高可用。Master 节点使用 Static Pod 方式启动 Master 组件,即将每个组件的 Pod 描述文件放入 Master 节点的指定目录,Kubelet 会在启动时将他们读取,并以 Static Pod 方式启动。

Kubernetes Worker 节点为 Kubernetes 集群提供调度资源和应用运行环境。即所有的 Pod(可以理解为应用的一个个最小化部署单元)都运行在 Worker 节点上。一个Worker 节点需要将 Pod 运行上去,需要一些 on-host 软件,这些软件包括: kubelet, Runtime Service(docker, pouch 等实现方案), CNI 插件等。

Operator 介绍

我们在这里将花很少的篇幅向刚学习 Kubernetes 的同学介绍 Operator。如果期望获得更详细的解读请参考 coreos 上关于 Operator 的介绍。

一个 Operator 实际上是为了解决某个复杂应用在 Kubernetes 的自动化部署、恢复。有了Operator,用户只需要向Kubernetes Apiserver提交一个CRD Resource(yaml或者JSON,一个CRD Resource其实就是对应一个应用实例,CRD Resource用于描述这个应用实例的配置),Operator 就会根据用户的需求去完成这个应用实例的初始化,在应用某个模块发生故障时,Operator 也会做出自动恢复功能。Operator 是用代码运维应用最好的实践之一。

深度 | 蚂蚁金服自动化运维大规模 Kubernetes 集群的实践之路

比如我们有一个etcd-operator,我们只需要用户根据需求向 Kubernetes Apiserer 提交如下的 CRD Resource,etcd-operator 就能初始化完成一个 etcd 集群:

apiVersion: etcd.database.coreos.com/v1beta2
kind: EtcdCluster
metadata:
  name: xxx-etcd-cluster
spec:
  size: 5           

其中,上面的Spec.Size=5 代表了我们需要一个由 5 个 etcd 节点组成的 etcd 集群。etcd-operator 会根据上面的配置,初始化完成 etcd 集群。相应的,如果你又需要另一个 3 节点的etcd 集群,你只需要提交新的一个Spec.Size=3的 CRD Resource 即可。

背景

在蚂蚁金服,我们面临着需要运维几十个 Kubernetes 集群,以及十万级别以上的Kubernetes Worker 节点的难题。

我们将运维 Kubernetes 的工作拆分两部分,一部分是运维 Kubernetes 集群的 Master 组件(etcd, Apiserver, controller-manager, scheduler等),一部分是运维 Kubernetes Worker 节点。我们总结了这两部分运维的难点。

难点1:运维 Kubernetes 集群 Master 角色

如何快速新建、下线一个 Kubernetes 集群 (初始化、删除 Master 角色)。由于蚂蚁业务的快速增长,我们随时面临着需要在新机房新建、下线一个 Kubernetes集群;CI 和测试也有快速新建、删除一个 Kubernetes 集群的需求。

如何管理几十个 Kubernetes 集群 Master 组件版本。比如我们需要升级某几个Kubernetes 集群的 Apiserver,Scheduler 等组件。

如何自动化处理几十个 Kubernetes 集群 Master 组件发生的故障。

如何能获取几十个 Kubernetes 集群 Master 组件的统一视图。我们希望有一个统一的接口,一下就能获取每个 Kubernetes 集群 Master 角色的版本、状态等信息。

难点2:运维 Kubernetes Worker 节点

如何快速上线、下线 Kubernetes Worker 节点。上线时,我们需要保证 Kubernetes Worker 节点所需要的on-host软件版本、配置正确。

如何升级十万级别的 Kubernetes Worker 节点上的 on-host 软件。如我们需要将所有Work节点的 docker、cni 版本升级到某个版本。

如何优雅的执行灰度发布 Kubernetes Worker 节点上的软件包。在 on-host 软件新版本上线前,我们需要对它做小范围的灰度发布,即挑选 N 台 Worker 节点发布新版本软件包,执行验证,最后根据验证结果决定是否全规模的发布新版本,或者回滚这个灰度发布。

如果自动化处理十万级别的 Kubernetes Worker 节点可能出现的 on-host 软件故障。比如 dockerkubelet 发生 panic,我们是否能自动化得处理。

实现方案

在蚂蚁,我们使用 Kube-on-Kube-Operator 和 Node-Operator 组合使用解决上述的难题。

首先,我们需要借助工具,使用Kubernetes官方提供的方案( Static Pod 方式)部署“ Kubernetes 元集群”(后面简称元集群)到 “元集群”的 Master 节点上。

然后,我们将 Kube-on-Kube-Operator 部署到 “ Kubernetes 元集群”。我们将一个 Kubernetes 集群所需的一系列 Master 组件当成一个复杂的应用。当我们需要一个“ Kubernetes 业务集群”(后面简称业务集群),我们只需要向元集群 Apiserver 提交用于描述“ Kubernetes 业务集群”的 Cluster CRD Resource (下文会介绍我们如何设计 CRD 结构),Kube-on-Kube-Operator 就为我们准备好了一个可以工作的“Kubernetes 业务集群”("业务集群" Master 组件都已经Ready,需要扩容 Worker 节点)。

之后我们在“ Kubernetes 业务集群”上,部署上 Node-Operator。Node-Operator 负责 Worker 节点的生命周期。当我们需要扩容一个 Worker 节点,我们只需要提交描述 Worker 节点的元数据( IP, Hostname, 机器运维登录方式等)的 Machine CRD Resource (下文会介绍我们如何设计 CRD 结构),Node-Operator 就会将 Worker 节点初始化完成,并成功加入到 “ Kubernetes 业务集群” 中。

深度 | 蚂蚁金服自动化运维大规模 Kubernetes 集群的实践之路

“元集群” 只用于管理所有“业务集群”所需的 Master 组件。“业务集群”是真正提供给业务方运行 Pod 的 Kubernetes 集群。也就说,在蚂蚁金服,我们只有一个 “元集群”, 在这个 “元集群”中,我们使用 Kube-on-Kube-Operator 自动化管理了蚂蚁金服所有的 “ Kubernetes 业务集群” 的 Master 组件。

当然,“元集群”也会部署 Node-Operator,用于“元集群” Worker 节点的上下线,“元集群”的 Worker 节点也是各个 “业务集群” 的 Master 节点。

Kube-on-Kube-Operator

Kube-on-Kube-Operator 用于 Watch Cluster CRD Resource的变更,将"Cluster"所描述表示的 Kubernetes 业务集群的所有 Master 组件 达到最终状态。如下图,是“元集群”和它所管理的两个“Kubernetes 业务集群”的最终状态:

深度 | 蚂蚁金服自动化运维大规模 Kubernetes 集群的实践之路

Cluster CRD 的定义包含如下一些信息:

业务集群名。

业务集群部署模式: 分为标准生产和最小化。标准生产提供Master组件都是3副本的部署,最小化则都是1个副本的部署。

业务集群 Master 节点 NodeSelector,即表示如何在元集群内如何选择业务集群Master 节点。

业务集群各 Master 组件版本,自定义参数等

业务集群所使用的 etcd 启动配置,主要涉及 etcd data volume 的设置。有ClaimTemplate 和 VolumeSource 两种模式,即使用 ClaimTemplate 模式就使用PVC 来初始化 etcd volume,而使用 VolumeSource 模式,即使用 VolumeSource 所表示的 volume 来挂载 etcd volume。

业务集群 Master 组件证书过期时间: Master 组件所使用 kubeconfig 中的证书都有过期时间,以保证安全性。而 Kube-on-Kube-Operator 会在证书过期时自动完成滚动证书、Master 组件重新加载证书等操作。

业务集群额外用户 kubeconfig:即为 “额外用户”提供的用户名和组名,签出证书,并生成 kubeconfig 保存在元集群 Secret 中供读取。

业务集群状态: 这部分信息不需要用户提交,而是由 Kube-on-Kube-Operator 自动生成,用户反馈这个业务集群的状态,参考 Pod.Status 。

一个业务集群的 Master组件 部署 实际是元集群中的一系列 Resource 组成,即包括Deployment,Secret,Pod,PVC 等组合使用。各 Master 组件 所需要的部署 Resource 如下:

Apiserver: 一个 Deployment 即可,因为 Apiserver 是无状态应用,副本数和Cluster CRD 描述的一致即可。除此之外,需要为Apiserver创建两个 Service:

向同个业务集群的其它 Master 组件提供服务的 Service: 建议使用元集群内的 Headless Service。

向 Kubelet、外部组件提供服务的 Service: 建议使用机房 DNS RR Service (需要自己实现 Service Controller )。

etcd: 每个 etcd 实例(标准化部署是 3 个实例,最小化是 1 个实例)都建议单独使用 Pod + PV + PVC + Headless Service 部署。每个etcd 实例的 peer id 为对应的Headless Service 域名。当某个 etcd 实例发生故障时,需要手动删除掉故障对应实例的 Pod,Kube-on-Kube-Operator watch 到 etcd Pod 的减少,会重新建立 Pod,并执行 Remove old member (被删除的 Pod ), Add new member(新建的Pod)操作,但是他们的peer id还是保持一致的。

Controller-Manager: 一个 Deployment 即可,因为 Controller-Manager 是无状态应用。副本数和 Cluster CRD 描述的一致即可。

Scheduler: 一个 Deployment 即可,因为 Scheduler 是无状态应用。副本数和Cluster CRD 描述的一致即可。

Kube-on-Kube-Operator 除了能够部署上述的 Master 组件之外,还能维护任何扩展组件,如 kube-proxy,kube-dns 等。只需要用户提供 扩展组件部署模板 和 扩展插件版本,Kube-on-Kube-Operator 能渲染出部署 Resource,并保持这些部署 Resource 到最终态。由于篇幅原因,我们这里不再赘述。

Node-Operator

Node-Operator 用于 Watch Machine CRD Resource 的变更,将"Machine"所描述表示的 Worker 节点上的 on-host 软件(docker, kubelet, cni)达到最终态,最终能让 "Machine"所对应的"Node" 在 Kubernetes 集群中达到"Ready"状态。架构图如下:

深度 | 蚂蚁金服自动化运维大规模 Kubernetes 集群的实践之路

Machine CRD 的定义包含如下一些信息:

机器元数据: IP, Hostname, IDC 等

机器运维 ssh 登录方式和登录秘钥: 如最常见的 SSH Key;如果 Machine 是阿里云的 ECS, 那么登录方式和登录秘钥是阿里云提供的 SSH 接口和对应的鉴权信息等。

各个on-host 软件版本和自定义参数

Machine 状态: 这部分信息不需要用户提交,而是由 Node-Operator 生成,表示这个机器的当前状态,参考 Pod.Status 。

Node-Operator 还用 Watch Machine 对应 Node 的状态,当发生一些能处理的 Condition(比如 kubelet 运行中进程消失了)时,Node-Operator 会做出恢复处理。

Node-Operator 还会 Watch ClusterPackageVersion CRD 的变更,这个 CRD 表示整个Kubernetes 集群 kubelet、docker 等组件的默认版本,Node-Operator 会根据 ClusterPackageVersion 描述的信息,控制各个节点的 kubelet、docker 等组件的版本。

Node-Operator 还支持控制某些组件灰度发布到某些节点中。用户只要提交描述这个灰度发布的 CRD 到 Apiserver,Node-Operator 会有序的执行灰度发布,并将发布状态反馈到 CRD 中。由于篇幅原因,我们不再赘述。