作者|vivo互联网服务器团队-张榕1.背景随着vivo业务向k8s迁移的增长,我们需要将k8s部署到多个数据中心。如何高效可靠地管理数据中心内的多个大型k8s集群是我们面临的关键挑战。kubernetes的节点需要安装配置os、docker、etcd、k8s、cni和网络插件。维护这些依赖关系既麻烦又容易出错。以往集群的部署和扩缩容主要是通过ansible编排任务、黑屏操作、集群inventory和vars的配置、ansibleplaybook的执行。集群运维的难点主要有:需要人工黑屏集群运维操作,存在操作错误和集群配置差异。部署脚本工具没有特定的版本控制,不利于集群升级和配置变更。验证部署脚本上线需要花费大量时间,也没有具体的测试用例和CI验证。Ansible任务不会拆分为模块化安装,应该分解成多个部分。具体到k8s、etcd、addons等角色的模块化管理,ansible任务可以独立执行。主要通过二进制部署,需要自己维护一个集群管理系统。部署过程繁琐且效率低下。组件的参数管理比较混乱,通过命令行指定参数。k8s组件最多有100多个参数配置。每个主要版本迭代都会进行更改。本文将分享我们开发的Kubernetes-Operator,它采用了K8s的声明式API设计,可以让集群管理员与Kubernetes-Operator的CR资源进行交互,简化并降低任务的风险。只需一名集群管理员即可维护数千个k8s节点。2.集群部署实践2.1集群部署介绍主要是基于ansible定义的OS、docker、etcd、k8s、addons等集群部署任务。主要流程如下:BootstrapOSPreinstallstepInstallDockerInstalletcdInstallKubernetesMasterInstallKubernetesnodeConfigurenetworkpluginInstallAddonsPostinstallsetup以上就是集群一键部署的关键流程。当k8s集群部署在多个数据中心时,如集群组件存在安全漏洞、新功能上线、组件升级等,需要谨慎处理线上集群的变更。我们设法将其分解成多个部分并处理单个模块。避免完整执行ansible脚本,增加维护难度。对于docker、etcd、k8s、network-plugin、addons的模块化管理运维,需要提供单独的ansible脚本入口,更细化的运维操作,覆盖集群大部分的生命周期管理。同时在设计kubernetes-operator的api时,可以方便的选择对应的操作yml进行操作。集群部署优化操作如下:(1)k8s组件参数管理使用ComponentConfig[1]提供的API来识别配置文件。[可维护性]当组件参数超过50个或更多时,配置变得难以管理。【可升级性】对于升级,版本化配置的参数更易于管理。因为社区一个大版本的参数都没有变。[可编程性]可以修补组件(JSON/YAML)对象的模板。如果启用动态kubelet配置选项,修改后的参数将自动生效,无需重启服务。【可配置性】很多类型的配置不能用key-value的形式表达。(2)计划转为kubeadm部署,使用kubeadm管理k8s集群的生命周期,降低维护集群的成本。使用kubeadm的证书管理,比如将证书上传到secret,减少在主机上复制证书和重新生成证书的时间消耗。使用kubeadm的kubeconfig生成管理员kubeconfig文件。kubeadm的其他功能包括镜像管理、配置中心upload-config、控制节点的自动标记和染色等。安装coredns和kube-proxyaddons。(3)Ansible使用规范使用ansible自带的模块来处理部署逻辑。避免使用主机变量。避免使用delegate_to。启用--limit模式。etc.2.2CIMatrix测试部署的集群需要进行大量的场景测试和模拟。保证线上环境变化的可靠性和稳定性。CI矩阵的一些测试用例如下。(1)语法测试:ansible-lintshellcheckyamllintsyntax-checkpep8(2)集群部署测试:部署集群扩缩容控制节点、计算节点、etcd升级集群etcd、docker、k8s和addons参数变更等(3)性能与功能测试:检查kube-apiserver是否正常工作检查节点间网络是否正常检查计算节点是否正常k8se2e测试k8s一致性测试其他测试使用GitLab、gitlab-runner[2]等开源软件构建,ansible和kubevirt[3]CI进程。详细部署步骤如下:在k8s集群上部署gitlab-runner,连接GitLab仓库。在k8s集群中部署Containerized-Data-Importer(CDI)[4]组件,创建pv??c存储虚拟机的镜像文件。在k8s集群中部署kubevirt创建虚拟机。在代码仓库写入gitlab-ci.yaml[5],规划集群测试矩阵。如上图所示,当开发者在GitLab中提交PR时,会触发一系列动作。这里主要展示了虚拟机的创建和集群的部署。其实我们的集群中也部署了用于语法检查和性能测试的gitlab-runner,通过这些gitlab-runners创建CI作业来执行CI流程。具体CI流程如下:开发者提交PR。触发CI自动执行ansible语法检查。执行ansible脚本创建namespace、pvc和kubevirt虚拟机模板,最终虚拟机运行在k8s上。这里主要使用ansiblek8s模块[6]来管理这些资源的创建和销毁。调用ansible脚本部署k8s集群。集群部署完成后,进行功能验证和性能测试。销毁kubevirt、pvc等资源。即删除虚拟机,释放资源。如上图所示,当一个开发者提交多个PR时,k8s集群中会创建多个作业,每个作业都会执行上述CI测试,互不影响。这种主要使用kubevirt的能力在k8s上实现了k8s的架构。kubevirt的主要能力如下:提供标准的K8sAPI,通过ansible的k8s模块管理这些资源的生命周期。复用k8s的调度能力来控制资源。k8s的网络能力被复用,通过命名空间进行隔离,各个集群网络互不影响。3.Kubernetes-Operator实践3.1Operator介绍Operator是针对具体应用的控制器,可以扩展K8sAPI的功能,代表k8s用户创建、配置和管理复杂应用的实例。基于k8s资源和控制器概念,它还涵盖特定领域或应用程序知识。用于自动化它管理的应用程序生命周期。Operator的功能总结如下:kubernetescontroller部署或管理一个应用,如数据库,etcd,自定义应用生命周期管理,部署,升级,伸缩,备份,自修复等。3.2Kubernetes-OperatorCR介绍kubernetes-operator的使用。CR资源和控制器,这里简单介绍一下功能和作用。【ClusterDeployment】:管理员配置的唯一CR,包括MachineSet、Machine和Cluster及其子资源或关联资源。ClusterDeployment是所有配置参数的入口点,定义了etcd、k8s、lb、集群版本、网络和addons等所有配置。[MachineSet]:集群角色的集合,包括控制节点、计算节点、etcd的配置和执行状态。【机器】:每台机器的具体信息,包括所属角色、节点自身信息、执行状态等。[Cluster]:对应ClusterDeployment,其状态定义为subresource,减少clusterDeployment的触发压力。主要用来存放ansibleexecutor执行脚本的状态。【ansibleexecutor】:主要包括k8s自带的job、configMap、Secret和自研的jobcontroller。其中job主要是用来执行ansible脚本的,因为k8s的job状态有成功和失败,所以jobcontroller可以方便的观察到ansible执行成功或者失败,同时可以查看执行情况通过job进程对应的podlog查看ansible的详细信息。configmap主要用来存放ansible在执行过程中依赖的库存和变量,挂在job上。secret主要存放登录host的key,也挂载在job上。【扩展控制器】:一个额外的控制器,主要用于扩展集群管理功能。我们定制了kubernetes-operator的部署,您可以选择您需要的扩展控制器。比如addonscontroller,主要负责addon插件的安装和管理。clusterinstall主要生成ansibleexecutors。remoteMachineSet用于多集群管理,同步元数据集群和业务集群的机器状态。3.3Kubernetes-Operator架构vivo的应用分布在数据中心的多个k8s集群上,提供多云集中管理、统一调度等关键特性、高可用性和故障恢复。主要搭建元数据集群的通证平台,管理多个业务k8s集群。在众多关键组件中,kubernetes-operator部署在metadata集群中,machinecontroller单独运行,管理物理资源。以下是部分场景的示例:场景一:大量应用迁移到kubernets时,管理员评估是否需要扩容集群。首先需要通过通证平台对物理资源进行审批,生成机器对应的CR资源。此时物理机在备机池中,机器CR的状态为空闲。当管理员创建一个ClusterDeploment时,其所属的MachineSet会关联闲置机器,获取闲置机器资源。我们可以观察需要操作的机器的IP地址,生成相应的清单和变量,创建一个configmap挂载到job上。执行扩容的ansible脚本。如果作业成功执行,它会将机器的状态更新为已部署。同时,跨集群同步节点控制器会检查当前扩展的节点是否就绪。如果就绪,则将当前机器更新为Ready状态,完成整个扩容过程。场景二:当其中一个业务集群出现故障,无法提供服务时,触发故障恢复流程,实现资源统一调度。同时,业务策略是分配给多个业务集群,同时配置一个备集群,实例没有分配给备集群,备集群实际上并不存在。有两种情况:其他业务集群可以承载故障集群的业务,kubernetes-operator不需要做任何操作。如果其他业务集群无法承载故障集群的业务。容器平台开始预估资源,调用kubernetes-operator创建集群,即创建clusterDeployment从备机池中选择一台物理机,观察需要操作的机器的IP地址,生成对应的inventory和variables,创建一个configmap并将其安装到作业中。执行集群安装的ansible脚本,集群正常部署完成后开始业务的迁移。3.4Kubernetes-Operator执行过程集群管理员或容器平台触发创建ClusterDeployment的CR来定义当前集群的操作。ClusterDeployment控制器知道进入控制器的更改。开始创建machineSet和关联的机器资源。ClusterInstall控制器感知ClusterDeployment和Machineset的变化,开始统计机器资源,创建configmaps和jobs,指定操作的ansibleyml入口,进行伸缩、升级、安装等操作。调度器感知作业创建的pod资源并进行调度。调度器调用k8s客户端更新pod的绑定资源。kubelet感知pod的调度结果,创建pod并开始执行ansibleplaybook。作业控制器感知作业的执行状态并更新ClusterDeployment状态。一般策略下,jobcontroller会清理configmap和job资源。NodeHealthy感知k8s的节点是否就绪,同步机器状态。addonscontroller感知集群是否就绪,如果是,则安装和升级相关的addons。4.总结在vivo大规模K8s集群运维实践中,从底层集群部署工具的优化,到大量的CI矩阵测试,保证了我们线上集群运维的安全稳定。K8s用于管理K8s自动管理集群(K8sasaservice)。当operator检测当前集群状态,判断是否与目标一致,如果不一致,operator会启动特定的操作流程,驱动整个集群达到目标状态。目前vivo的应用主要分布在自建数据中心的多个K8s集群中。随着应用的不断增长和复杂的业务场景,需要提供多个跨自建机房和云的K8s集群来运行原有的云。应用程序。Kubernetes-Operator需要提供与公有云基础设施的连接,apiserver、网络、dns和CloudProvider的负载均衡等,未来需要不断完善,降低K8s集群的运维难度.
