容器云多集群环境下如何实践 DevOps

时间:2022-10-17 10:08:50

从容器、Kubernetes 和 DevOps 等技术问世,业界一遍遍地质疑它们是否能够禁得住生产级别考验,到今天许多大型企业大规模采用 Kubernetes 已成事实。

而随着云原生技术的普及和落地,越来越多的云原生应用需要差异化的部署到不同的环境或不同的数据中心中,不同应用不同组件在不同的环境或集群会存在多个差异化配置,传统通过流水线进行持续交付的模式不再适合Kubernetes声明式和控制循环的模式,在这种情况下,应用的发布管理越复杂,业务系统将面临巨大的风险。以 ArgoCD 和 FluxCD 等持续交付为代表的 GitOps 为管理基础设施和应用程序提供了一种方法,以声明式描述整个系统并进行版本控制,提供了一个自动化的过程来确保部署的环境和存储库中期望的状态相匹配。

本文讨论了企业容器云在多集群情况下如何实践 DevOps。首先分析了如今容器云出现多集群的原因,然后介绍了云原生 DevOps 的落地方式——GitOps,并推荐了一种多集群 GitOps 工作流作为落地参考,最后部分介绍了在持续集成和持续交付中具体实践 GitOps 的主流方式,能有效地帮助读者了解和落地容器云多集群 DevOps 实践,帮助读者比较和选择众多 DevOps 工具和方法,少走弯路。

1 为什么需要多集群 Kubernetes

虽然 Kubernetes 成为容器编排领域的事实标准,解决了大多数容器编排领域的问题,但 Kubernetes 原生的管理能力仍然停留在但单集群级别。每一个集群可以稳定地自治运行,但是却缺乏横贯多个集群的统筹管理能力。企业内部出现多集群 Kubernetes 主要有以下几个原因。

1.1 Kubernetes 单个集群规模问题

单个 Kubernetes 集群存在规模性限制,并且在扩容的过程中,etcd、API Server、调度器以及控制器都有可能出现性能瓶颈。以 v1.23 版本 Kubernetes 为例,官方社区给出的单集群规模数据如下:

单个集群节点数不超过 5000;

每个节点的 Pod 数量不超过 110;

Pod 总数不超过 150000;

容器总数不超过 300000。

社区中也有一些开发者试图突破该规模上限,例如在节点上增加缓存降低 API Server 的负载。但其缺乏官方社区支持,暂时没有被业界广泛接受。

1.2 高可用架构

为了提高业务应用的可用性,避免单个集群或单个数据中心故障导致业务应用暂时不可用,影响用户正常使用,大型企业通常会对业务应用进行灾备甚至多数据中心多活部署,这也会导致业务应用被部署在多个不同的 Kubernetes 集群中。

除此之外,企业内外部也常有开发、测试和 QA 等多个不同环境,一个企业可能存在有以下环境:

(1)开发测试环境

(2)QA 环境

(3)预发环境

(4)生产环境

同时,按照高可用架构,生产环境还会部署在三个数据中心或云上环境,这样算下来至少有 6 个不同的集群环境——这还只是一个部门或一个应用的情况。

1.3 混合云架构

如今企业还会采用内部基础架构、私有云和公有云的混合云基础架构,自然也会引入多集群 Kubernetes。

2 容器云多集群管理

容器云多集群管理就是通过统一的控制平台纳管多个 Kubernetes 集群。通过容器云平台,平台管理人员能够获知多集群节点健康状态、资源使用情况和集群使用情况等信息;业务应用负责人和开发能够决策如何调配应用服务在各个集群中的部署分布;应用的运维人员能够获知服务状态。因此,多集群管理涉及资源管理、跨集群资源访问和调度以及运维和管理三大块。

多集群管理暂无统一成熟的事实标准,开源社区和各大厂商都已对这一方向进行了长时间探索,社区中的多集群兴趣小组(SIG Multi-Cluster)和,以及 RedHat、蚂蚁、华为和腾讯等厂商都提出自己的方案。

多集群管理项目众多,但我们可以从集群联邦和非集群联邦来归类,我们来简单对比下两种方案。

2.1 基于 KubeFed 的多集群管理

(1) RedHat 和 Kubernetes 社区牵头的 KubeFed

KubeFed 是最早的 Kubernetes 集群联邦项目,主要支持:跨集群的资源同步与伸缩、跨集群的服务发现。KubeFed 能够根据负载情况,调度并调节各集群的资源分布,同时能够提供跨集群的应用故障转移,以及跨集群的服务发现。实现了方便的跨地区、跨服务商配置并管理多个 Kubernetes 集群,以及多集群资源的统一管理。但是,其 API 复杂、CRD 编写不规范等缺点,也成为掣肘其推广的关键。

Kubefed 项目今天基本处于停止维护的状态,项目也鲜有更新。

(2) RedHat、蚂蚁和阿里云共同发起并开源的 OCM(Open Cluster Management)

OCM 旨在解决多集群、混合环境下资源、应用、配置、策略等对象的生命周期管理问题。OCM 基于 KubeFed 优化而来,它将管理开销从中枢集群下放到每个被管理集群上的代理(Agent)上,让它在整个基础设施中分布式自治并维护稳定。这使得 OCM 理论上能管理的集群数量至少比 KubeFed 多一个数量级。到目前为止,官方宣称可同时管理多达 1000 个集群。

(3) 此外,同样继承自 KubeFed 的还有华为云开源的 Karmada,腾讯也开源了兼具多集群管理和跨集群应用编排的云原生项目 ClusterNet。

2.2 非集群联邦的多集群管理

另外一类非集群联邦的多集群管理相对就简单很多,这类管理系统主要是为了进行资源管理、运维管理和用户管理,提供导入集群功能,并通过统一 Web 界面进行查看和管理。

这类工具不引入额外集群联邦的复杂性(自然在跨集群调度方面就弱一些),保持每个集群的独立性,同时通过统一的 Web 界面来查看多个集群的资源使用情况,支持通过 Web 界面创建 Deployment、Service 和负载均衡等,并且会集成持续集成、持续交付和监控告警等功能。由于集群联邦技术还在发展,大多数企业倾向于使用这种方式来运维和管理多集群 Kubernetes 环境。

3 多集群 DevOps 工作流

通过上述分析,既然企业内部多套 Kubernetes 集群已成不可避免的事实,那么容器云多集群 DevOps 实践就成了关注的焦点,如何在多集群 Kubernetes 环境下让构建和部署流程自动化,确保部署任务的可重复性,减少部署出错的可能性,也减少开发和运维人员无营养无价值的重复劳动,成为 DevOps 团队或研发效能团队的主要目标。

3.1 DevOps 简介

DevOps(Development 和 Operations 的组合词)是一种重视“软件开发人员(Dev)”和“运维技术人员(Ops)”之间沟通合作的文化、运动或惯例。通过自动化“软件交付”和“架构变更”的流程,来使得构建、测试、发布软件能够更加地快捷、频繁和可靠。

如果说单体架构尚可以通过几个开发或运维直接手动部署,微服务架构兴起后,其架构更复杂,涉及组件更多,变更次数也更多,手动部署变得费时费力,还伴随着许多不为人知的隐患。

随着虚拟化和云计算基础设施(可能来自内部或外部供应商)日益普遍,自动化技术和工具的普及,微服务架构的盛行,DevOps 的重要性日益显著。

3.2 多集群下的 DevOps

如前文所述,由于企业内部可能存在多集群 Kubernetes,那么 DevOps 就必须涉及多集群 Kubernetes 环境下的使用场景。我们如何去实现这样的目标呢?不妨先回过头思考下“云原生”下部署方式演进的过程。

随着以“云原生”为基础的基础架构和应用框架爆炸性增长,基于 Kubernetes 所衍生的现代化基础平台可谓应有尽有,原本系统管理员用来部署、配置、管理这些平台的脚本开始力不从心,自此也演变成出了叫做“基础架构即代码”(Infrastructure as Code, IaC) 的新模式。

基础架构即代码,意味着应用程序的基础架构、部署、状态和配置等信息都被显示描述,并且保存在 Git 仓库中。IaC 采用声明式方法来管理基础架构,定义系统的期望状态,并跟踪系统的实际状态,这样做的好处有:

可重复性(Repeatability):应用程序可以快速、可重复地部署到多个数据中心的多个环境;

可靠性(Reliability):自动化 IaC 可以大大减少人为错误的机会;

高效(Efficiency):通过 CI/CD 高效提高团队生产力;

可视化(Visibility):开发人员很容易看到应用程序的基础架构、部署方式等,不需要一遍遍去口述,更透明也更利于协作。

回想在没有 IaC 的时候,运维 A 通过某种方式部署了应用,但是运维 B 并不知道 A 是如何部署的,那此时运维 B 要么通过文档学习部署应用的方式,要么找运维 A 请教如何部署——无论哪种方式,既无法保证应用重复部署的成功率,也不利于团队之间进行协作。

更进一步,虽然传统的 Chef、Ansible 和 Puppet 等自动化工具,也可以通过配置模板或脚本,将基础架构或应用程序推到目标服务器上,实现自动化部署。但这仍达不到理想的效果,主要是因为在一台服务器的生命周期中,可能会发生很多次更新,有时还会存在运维人员手工修改某些配置,久而久之,部分服务器可能与其他服务器略有不同。而通过 Terraform 或 Kubernetes Yaml 等方式,每次会通过镜像创建新服务器、新基础设施或新应用。如果需要更新服务器,就要用新服务器替换它们——这一理念即“不可变基础设施”,是应用向云原生转型非常重要的一步,能够构建容错性好、易于管理和便于观察的松耦合系统。

综上,为了实现“基础架构即代码”和“不可变基础设施”,云原生应用部署清单和基础架构往往以代码的方式保存在 Git 仓库中,并通过 CI/CD 去获取这些代码进行相应的处理,渐渐地,一种新的 DevOps 模式也诞生了——GitOps。

Kubernetes 在设计之初就采用声明式对象管理,简单来说,Kubernetes 通过 Yaml 来定义系统的最终状态应该是什么样子的,包括应用的副本数、配置、镜像和策略等等部署信息都一目了然,可以说 Kubernetes 契合 GitOps。

多集群 Kubernetes 下的 DevOps 通常通过 GitOps 来实现。GitOps 依赖声明式管理的基础架构,与 Kubernetes 的声明式编程的清单文件不谋而合,两者相结合能发挥出巨大的潜力。GitOps 通过 Git 来实现协作、CI/CD 和版本控制,并将其应用于基础架构自动化和应用部署中,最后生成的部署文件交由 Kubernetes 进行部署工作。

因此,在多集群 Kubernetes 下通过 GitOps 来实现 DevOps 成为首选。在开始介绍如何实施容器云多集群 DevOps 之前,需要设计规划一套行之有效的多集群 Git 工作流。

3.3 GitOps 工作流参考

多集群 GitOps 推荐使用基于主干(trunk based)的工作流,而非每个分支一个环境的模式。

可能在直觉上,不同集群、不同环境采用不同分支是很自然的,例如生产环境是 master 分支,而开发测试、预发和 QA 又是各自不同的分支,看起来很适合。

可是,这样做的弊端很多,包括:

转生产容易出错。假如开发测试、QA 和预发各自做了互相冲突的变更,这时候想简单合并到生产是比较困难的,我们希望部署清单尽量少产生冲突;

容易造成配置漂移。预发环境和生产环境的配置一般不同,如果预发上的业务代码改动想合并到主干,此时正好连带配置一起进行合并,那么可能会把预发环境的配置带到生产。你可能会说,合并代码时为什么不仔细地 Code Review。实际上,合并可能会有大量的应用和大量的配置,我们不可能每一项都依赖于人工检查。

一旦环境增多,分支管理维护会更加复杂,合并也更为复杂,如果互相冲突的变更难以合并处理,这时只能通过频繁的 cherry-pick 进行选择合并,费时费力。

与 Kubernetes 生态相违背。以 Kubernetes 最常见的两种编排发布工具 Helm 和 Kustomize 为例,Helm 通过 values.yaml 指定配置参数,如果是不同的环境,则使用不同的 values.yaml 文件;Kustomize 则是先创建一个 base 配置,然后再将每个环境建模为一个 overlay 去覆盖变更的配置项。

容器云多集群环境下如何实践 DevOps

可见,无论是 Helm 还是 Kustomize 的配置文件设计模式都与 Git 分支无关,而是直接在不同环境使用不同的配置文件,抛弃掉 Git 分支的复杂性(越简单越不容易出错),直接通过不同的文件进行环境隔离,例如:直接创建几个不同的文件夹来代表不同的环境,各个环境单独管理。

主干开发模式最理想状态的是“主干开发,主干发布”,但目前部分企业的开发实践还无法达到这样的要求,所以有的企业退而求其次使用“分支开发,主干发布”,当分支生命周期很短时,基本不会产生代码合并冲突,就基本等同于主干开发。在主干分支出现 Bug 影响发布的时候也会临时采用分支发布的策略——但也要注意,控制分支环境的数量和作用。

基于主干模式的多分支多环境的 Git 工作流如下图所示:

容器云多集群环境下如何实践 DevOps

软件工程没有银弹,如何实践 GitOps 只有一个参考,并无一个标准答案,因此,企业内应根据自身实际情况进行调整。

云原生 GitOps 通常分为持续集成(CI)和持续交付(CD)两部分,持续集成部分主要负责编译出镜像、部署清单和配置文件等最终部署产物,持续交付部分负责将持续集成的产物以适合的方式部署到对应的集群或环境中。接下来我们将分别来讨论持续集成和持续交付部分的实践。

4 持续集成:流水线构建

开发人员完成功能开发并提交代码后,持续集成来处理剩下的工作,目前主流的持续工具有 Jenkins、Gitlab CI 和 Tekton 等,基本流程如下图所示:

容器云多集群环境下如何实践 DevOps

当开发人员提交代码后,会触发持续集成工具开始运行流水线,比较典型的云原生 GitOps 中的流水线常分为以下几个阶段:

阶段 1:从代码仓库检出源代码,切换到对应分支;

阶段 2:运行单元测试,失败则报错;测试通过后才能进行下一阶段;

阶段 3:SonarQube 代码质量分析;

阶段 4:编译代码,构建镜像,根据一定策略规则来设置镜像 tag,并推送新镜像;

阶段 5:更新代码仓库的部署清单,例如更新新的镜像 tag 和配置等信息。

流水线正常运行结束后,不仅构建出新镜像,还一并将 Yaml/Kustomize/Helm 等部署清单一并更新,构建出新版本的部署清单,而无需手动介入修改。

值得一提的是,以上流程简化了一些细节,GitOps 实施的细节繁多,包括还需要考虑 Git 凭证管理、镜像仓库凭证管理、构建镜像方式(DinD、kaniko 还是 Podman 等)、镜像 tag 设置规则等等,DevOps 团队统一配置成模板再暴露给开发人员使用,否则配置流水线可能依然会花费大量精力。

前文提到,云原生 GitOps 的持续集成部分只负责产出镜像、部署清单和配置文件等最终部署产物,而非像以前一样,直接把部署产物推到集群完成应用更新,接下来我们的持续交付部分将讨论为何如此拆分。

5 持续交付:多集群应用分发

多集群应用分发是持续交付工具关注的核心点,归结下来主要有两种模式:Push 模式和 Pull 模式。

Push 模式出现在传统的持续集成(CI)工具 Jenkins 和 Gitlab CI 中,这类工具直接将部署文件直接推到 Kubernetes 集群进行部署,相当于直接做环境更新。Push 模式基本原理如下图所示:

容器云多集群环境下如何实践 DevOps

Pull 模式则出现在一些持续交付(CD)工具例如 ArgoCD 和 FluxCD 中,这类工具会去检查集群中现在的状态是否和 git 仓库中文件指定的状态匹配,如果发现差异,则会将 git 仓库中的部署文件拉下来进行部署,将应用更新到期望状态。Pull 模式基本原理如下图所示:

容器云多集群环境下如何实践 DevOps

通常 ArgoCD 和 FluxCD 自身也运行在 Kubernetes 集群中。

另外,不建议通过 Kubectl 直接部署的行为,这让安全权限管控非常难做。

综合对比一下 Push 模式和 Pull 模式。Push 模式是在代码变更后触发更新,如果有人手动修改了集群中的配置,集群中的配置就会和代码库中的配置有差异,这与“不可变基础设施”的理念相违背;而 Pull 模式则是检测集群和代码库中的配置,当发现不一致时,自动/手动触发更新,这相当于在代码仓库和 Kubernetes 集群状态之间多个一个控制器,不断让 Kubernetes 集群中的实际状态和代码库中部署清单的期望状态保持一致。

这里笔者更推荐使用 Pull 模式进行分发部署,因为 Pull 模式的工具功能更为纯粹,可以利用权限鉴权等信息做安全性及合规性保障,尤其是当你需要回滚时,只需要使用 git 将部署文件回滚到上个版本,部署文件被 ArgoCD 或 FluxCD 等工具检测到发现变化,应用又会回滚到之前的状态,而不需要流水线工具重新跑一边,由 GitOps 驱动的系统可以通过声明式表达其所需状态,这符合 Kubernetes 的声明式模式,更为推荐。

到了这一步,我们才真正开始思考,如果将部署清单分发、部署到对应的集群,多集群应用发布主要分为“集中式应用发布模式”和“分布式应用发布模式”,主要区别是统一使用一套持续交付工具统一分发,还是每个集群各一套持续交付工具分布式分发,如下图所示:

容器云多集群环境下如何实践 DevOps

综合比较两种方式,采用集中式的优点是架构简单,易于统一管理;但缺点是可能存在单点故障,并且各个集群的认证鉴权比较复杂,并且不适用于集群之间存在网络隔离的场景。

分布式应用发布模式的优点是可用性高,适用网络隔离场景;缺点是架构较为复杂,且目标集群需要部署持续交付组件。

企业需要根据自身网络架构和其他实际情况,若无网络隔离推荐采用集中式应用发布模式;若网络较为复杂,安全性有较高要求,推荐采用分布式应用发布模式。

6 总结

本文综述了如何通过 GitOps 来实现多集群 DevOps,并对流程中一些关键节点进行了分析,总结了容器云多集群 DevOps 常见的模式,以及一些实践。

此外,也有一些开源软件试图统一解决 GitOps 整个流程中的问题,包括 KubeSphere 在其 3.3 版本中加入 GitOps 支持,kubevela 也提出了一种新的 GitOps 方式。

虽然 DevOps 看上去很美好,但实际落地过程中则充满了细节上的挑战,步骤繁多,每个步骤都可能存在卡点,例如:多集群 Kubernetes 网络隔离或连通问题,多集群 Kubernetes 创建、管理和运维问题,应用流水线编写如何简单化,应用配置和环境配置如何拆分和管理,等等。这些问题在企业实施容器云多集群 DevOps 前都需要认真仔细地考虑,也欢迎读者多多交流!

【执笔专家】

唐伟志 容器云自动化运维用户委员会委员

twt社区云原生应用创新实践联盟——容器云自动化运维方向课题组专家。担任国信证券容器云平台负责人,目前负责国信证券容器、kubernetes等云原生相关技术架构和开发工作,专注于分布式系统、云原生、多集群管理和微服务治理等方向。曾在电子工业出版社出版技术书籍《深入理解分布式系统》。

【顾问专家】

孙洪轩 容器云自动化运维方向专家

twt社区云原生应用创新实践联盟——容器云自动化运维方向课题组特邀外部专家。多年IT研发经验,近几年一直深耕区块链,云原生等前沿技术领域。作为光大科技的自动化专家,先后为集团设计并建设了区块链云服务平台,容器云PaaS平台等中大型项目。具备丰富的软件架构设计,项目落地经验。

毛天明 容器云自动化运维用户委员会委员

twt社区云原生应用创新实践联盟——容器云自动化运维方向课题组专家。10年金融行业工作。太平洋保险容器工作前负责人,领导容器云平台的项目建设5年。电信翼支付容器工作负责人,领导容器云平台的项目建设3年。主要从事云原生架构建设、应用容器化改造、CICD工具链设计。2020 容器云职业技能大赛百位专家委员会成员。