写点什么

vivo 大规模 Kubernetes 集群自动化运维实践

  • 2022 年 6 月 13 日
  • 本文字数:4384 字

    阅读完需:约 14 分钟

作者:vivo 互联网服务器团队-Zhang Rong

一、背景


随着 vivo 业务迁移到 K8s 的增长,我们需要将 K8s 部署到多个数据中心。如何高效、可靠的在数据中心管理多个大规模的 K8s 集群是我们面临的关键挑战。kubernetes 的节点需要对 OS、Docker、etcd、K8s、CNI 和网络插件的安装和配置,维护这些依赖关系繁琐又容易出错。


以前集群的部署和扩缩容主要通过 ansible 编排任务,黑屏化操作、配置集群的 inventory 和 vars 执行 ansible playbook。集群运维的主要困难点如下:

  • 需要人工黑屏化集群运维操作,存在操作失误和集群配置差异。

  • 部署脚本工具没有具体的版本控制,不利于集群的升级和配置变更。

  • 部署脚本上线需要花费大量的时间验证,没有具体的测试用例和 CI 验证。

  • ansible 任务没有拆分为模块化安装,应该化整为零。具体到 K8s、etcd、addons 的等角色的模块化管理,可以单独执行 ansible 任务。

  • 主要是通过二进制部署,需要自己维护一套集群管理体系。部署流程繁琐,效率较低。

  • 组件的参数管理比较混乱,通过命令行指定参数。K8s 的组件最多有 100 以上的参数配置。每个大版本的迭代都在变化。


本文将分享我们开发的 Kubernetes-Operator,采用 K8s 的声明式 API 设计,可以让集群管理员和 Kubernetes-Operator 的 CR 资源进行交互,以简化、降低任务风险性。只需要一个集群管理员就可以维护成千上万个 K8s 节点。

二、集群部署实践

2.1 集群部署介绍

主要基于 ansible 定义的 OS、Docker、etcd、k8s 和 addons 等集群部署任务。

主要流程如下:

  1. Bootstrap OS

  2. Preinstall step

  3. Install Docker

  4. Install etcd

  5. Install Kubernetes Master

  6. Install Kubernetes node

  7. Configure network plugin

  8. Install Addons

  9. Postinstall setup


上面看到是集群一键部署关键流程。当在多个数据中心部署完 K8s 集群后,比如集群组件的安全漏洞、新功能的上线、组件的升级等对线上集群进行变更时,需要小心谨慎的去处理。我们做到了化整为零,对单个模块去处理。避免全量的去执行 ansible 脚本,增加维护的难度。针对如 Docker、etcd、K8s、network-plugin 和 addons 的模块化管理和运维,需提供单独的 ansible 脚本入口,更加精细的运维操作,覆盖到集群大部分的生命周期管理。同时 kubernetes-operator 的 api 设计的时候可以方便选择对应操作 yml 去执行操作。


集群部署优化操作如下:


(1)K8s 的组件参数管理通过 ConmponentConfig[1]提供的 API 去标识配置文件。

  • 【可维护性】当组件参数超过 50 个以上时配置变得难以管理。

  • 【可升级性】对于升级,版本化配置的参数更容易管理。因为社区一个大版本的参数没有变化。

  • 【可编程性】可以对组件(JSON/YAML)对象的模板进行修补。如果你启用动态 kubelet 配置选项,修改参数会自动生效,不需要重启服务。

  • 【可配置性】许多类型的配置不能表示为 key-value 形式。


(2)计划切换到 kubeadm 部署

  • 使用 kubeadm 对 K8s 集群的生命周期管理,减少自身维护集群的成本。

  • 使用 kubeadm 的证书管理,如证书上传到 secret 里减少证书在主机拷贝的时间消耗和重新生成证书功能等。

  • 使用 kubeadm 的 kubeconfig 生成 admin kubeconfig 文件。

  • kubeadm 其它功能如 image 管理、配置中心 upload-config、自动给控制节点打标签和污点等。

  • 安装 coredns 和 kube-proxy addons。


(3)ansible 使用规范

  • 使用 ansible 自带模块处理部署逻辑。

  • 避免使用 hostvars。

  • 避免使用 delegate_to。

  • 启用–limit 模式。

  • 等等。

2.2 CI 矩阵测试


部署出来的集群,需要进行大量的场景测试和模拟。保证线上环境变更的可靠性和稳定性。


CI 矩阵部分测试案例如下。

(1)语法测试:

  • ansible-lint

  • shellcheck

  • yamllint

  • syntax-check

  • pep8


(2)集群部署测试:

  • 部署集群

  • 扩缩容控制节点、计算节点、etcd

  • 升级集群

  • etcd、Docker、K8s 和 addons 参数变更等


(3)性能和功能测试:

  • 检查 kube-apiserver 是否正常工作

  • 检查节点之间网络是否正常

  • 检查计算节点是否正常

  • K8s e2e 测试

  • K8s conformance 测试

  • 其他测试


这里利用了 GitLab、gitlab-runner[2]、ansible 和 kubevirt[3]等开源软件构建了 CI 流程。


详细的部署步骤如下:

  1. 在 K8s 集群部署 gitlab-runner,并对接 GitLab 仓库。

  2. 在 K8s 集群部署 Containerized-Data-Importer (CDI)[4]组件,用于创建 pvc 的存储虚拟机的映像文件。

  3. 在 K8s 集群部署 kubevirt,用于创建虚拟机。

  4. 在代码仓库编写 gitlab-ci.yaml[5], 规划集群测试矩阵。


如上图所示,当开发人员在 GitLab 提交 PR 时会触发一系列操作。这里主要展示了创建虚拟机和集群部署。其实在我们的集群还部署了语法检查和性能测试 gitlab-runner,通过这些 gitlab-runner 创建 CI 的 job 去执行 CI 流程。


具体 CI 流程如下:

  1. 开发人员提交 PR。

  2. 触发 CI 自动进行 ansible 语法检查。

  3. 执行 ansible 脚本去创建 namespace,pvc 和 kubevirt 的虚拟机模板,最终虚拟机在 K8s 上运行。这里主要用到 ansible 的 K8s 模块[6]去管理这些资源的创建和销毁。

  4. 调用 ansible 脚本去部署 K8s 集群。

  5. 集群部署完进行功能验证和性能测试等。

  6. 销毁 kubevirt、pvc 等资源。即删除虚拟机,释放资源。



如上图所示,当开发人员提交多个 PR 时,会在 K8s 集群中创建多个 job,每个 job 都会执行上述的 CI 测试,互相不会产生影响。这种主要使用 kubevirt 的能力,实现了 K8s on K8s 的架构。


kubevirt 主要能力如下:

  • 提供标准的 K8s API,通过 ansible 的 K8s 模块就可以管理这些资源的生命周期。

  • 复用了 K8s 的调度能力,对资源进行了管控。

  • 复用了 K8s 的网络能力,以 namespace 隔离,每个集群网络互相不影响。


三、Kubernetes-Operator 实践

3.1 Operator 介绍


Operator 是一种用于特定应用的控制器,可以扩展 K8s API 的功能,来代表 K8s 的用户创建、配置和管理复杂应用的实例。基于 K8s 的资源和控制器概念构建,又涵盖了特定领域或应用本身的知识。用于实现其所管理的应用生命周期的自动化。


总结 Operator 功能如下:

  1. kubernetes controller

  2. 部署或者管理一个应用,如数据库、etcd 等

  3. 用户自定义的应用生命周期管理

  • 部署

  • 升级

  • 扩缩容

  • 备份

  • 自我修复

  • 等等

3.2 Kubernetes-Operator CR 介绍


kubernetes-operator 的使用很多自定义的 CR 资源和控制器,这里简单的介绍功能和作用。


【ClusterDeployment】:  管理员配置的唯一的 CR,其中 MachineSet、Machine 和 Cluster 它的子资源或者关联资源。ClusterDeployment 是所有的配置参数入口,定义了如 etcd、K8s、lb、集群版本、网路和 addons 等所有配置。

【MachineSet】:集群角色的集合包括控制节点、计算节点和 etcd 的配置和执行状态。

【Machine】:每台机器的具体信息,包括所属的角色、节点本身信息和执行的状态。

【Cluster】:和 ClusterDeployment 对应,它的 status 定义为 subresource,减少

clusterDeployment 的触发压力。主要用于存储 ansible 执行器执行脚本的状态。

【ansible 执行器】:主要包括 K8s 自身的 job、configMap、Secret 和自研的 job 控制器。其中 job 主要用来执行 ansible 的脚本,因为 K8s 的 job 的状态有成功和失败,这样 job 控制器很好观察到 ansible 执行的成功或者失败,同时也可以通过 job 对应 pod 日志去查看 ansible 的执行详细流程。configmap 主要用于存储 ansible 执行时依赖的 inventory 和变量,挂在到 job 上。secret 主要存储登陆主机的密钥,也是挂载到 job 上。

【扩展控制器】:主要用于扩展集群管理的功能的附加控制器,在部署 kubernetes-operator 我们做了定制,可以选择自己需要的扩展控制器。比如 addons 控制器主要负责 addon 插件的安装和管理。clusterinstall 主要生成 ansible 执行器。remoteMachineSet 用于多集群管理,同步元数据集群和业务集群的 machine 状态。还有其它的如对接公有云、dns、lb 等控制器。

3.3 Kubernetes-Operator 架构

vivo 的应用分布在数据中心的多个 K8s 集群上,提供了具有集中式多云管理、统一调度、高可用性、故障恢复等关键特性。主要搭建了一个元数据集群的 pass 平台去管理多个业务 K8s 集群。在众多关键组件中,其中 kubernetes-operator 就部署在元数据集群中,同时单独运行了 machine 控制器去管理物理资源。


下面举例部分场景如下:


场景一:

当大量应用迁移到 kubernets 上,管理员评估需要扩容集群。首先需要审批物理资源并通过 pass 平台生成对应 machine 的 CR 资源,此时的物理机处于备机池里,machine CR 的状态为空闲状态。当管理员创建 ClusterDeploment 时所属的 MachineSet 会去关联空闲状态的 machine,拿到空闲的 machine 资源,我们就可以观测到当前需要操作机器的 IP 地址生成对应的 inventory 和变量,并创建 configmap 并挂载给 job。执行扩容的 ansible 脚本,如果 job 成功执行完会去更新 machine 的状态为 deployed。同时跨集群同步 node 的控制器会检查当前的扩容的 node 是否为 ready,如果为 ready,会更新当前的 machine 为 Ready 状态,才完成整个扩容流程。


场景二:

当其中一个业务集群出现故障,无法提供服务,触发故障恢复流程,走统一资源调度。同时业务的策略是分配在多个业务集群,同时配置了一个备用集群,并没有在备用集群上分配实例,备用集群并不实际存在。


有如下 2 种情况:

  1. 其它的业务集群可以承载故障集群的业务,kubernetes-operator 不需要执行任何操作。

  2. 如果其他业务集群不能承载故障集群的业务。容器平台开始预估资源,调用 kubernetes-operator 创建集群,即创建 clusterDeployment 从备机池里选择物理机器,观测到当前需要操作机器的 IP 地址生成对应的 inventory 和变量,创建 configmap 并挂载给 job。执行集群安装的 ansible 脚本, 集群正常部署完成后开始业务的迁移。

3.4 Kubernetes-Operator 执行流程


  1. 集群管理员或者容器平台触发创建 ClusterDeployment 的 CR,去定义当前集群的操作。

  2. ClusterDeployment 控制器感知到变化进入控制器。

  3. 开始创建 machineSet 和关联 machine 资源。

  4. ClusterInstall 控制器感知 ClusterDeployment 和 Machineset 的变化,开始统计 machine 资源,创建 configmap 和 job,参数指定操作的 ansible yml 入口,执行扩缩容、升级和安装等操作。

  5. 调度器感知到 job 创建的 pod 资源,进行调度。

  6. 调度器调用 K8s 客户端更新 pod 的 binding 资源。

  7. kubelet 感知到 pod 的调度结果,创建 pod 开始执行 ansible playbook。

  8. job controller 感知 job 的执行状态,更新 ClusterDeployment 状态。一般策略下 job controller 会去清理 configmap 和 job 资源。

  9. NodeHealthy 感知 K8s 的 node 是否为 ready,并同步 machine 的状态。

  10. addons 控制器感知集群是否 ready,如果为 ready 去执行相关的 addons 插件的安装和升级。

四、总结


vivo 大规模的 K8s 集群运维实践中,从底层的集群部署工具的优化,到大量的 CI 矩阵测试保证了我们线上集群运维的安全和稳定性。采用了 K8s 托管 K8s 的方式来自动化管理集群(K8s as a service),当 operator 检测当前的集群状态,判断是否与目标一致,出现不一致时,operator 会发起具体的操作流程,驱动整个集群达到目标状态。


当前 vivo 的应用主要分布在自建的数据中心的多个 K8s 集群中,随着应用的不断的增长和复杂的业务场景,需要提供跨自建机房和云的多个 K8s 集群去运行原云生的应用程序。就需要 Kubernetes-Operator 提供对接公有云基础设施、apiserver 的负载均衡、网络、dns 和 Cloud Provider 等。需要后续不断完善,降低 K8s 集群的运维难度。

发布于: 刚刚阅读数: 3
用户头像

官方公众号:vivo互联网技术,ID:vivoVMIC 2020.07.10 加入

分享 vivo 互联网技术干货与沙龙活动,推荐最新行业动态与热门会议。

评论

发布
暂无评论
vivo大规模 Kubernetes 集群自动化运维实践_Kubernetes_vivo互联网技术_InfoQ写作社区