【DevOps】GitOps之痛 -不完美的GitOps

news2025/1/22 13:09:44

前言

在前两篇文章中,我们对GitOps进行了大致的介绍:
【DevOps】GitOps初识(上) - 让DevOps变得更好
【DevOps】GitOps初识(下) - 让DevOps变得更好

GitOps 作为软件发布实践方式,有着许多的优点,然而,世上并没有完美无缺的事物, GitOps也是如此。当我们已经开始GipOps的探索,体验到它的美妙后,也必然体会到了使用它的痛苦。在这蜜月期已经结束的时候,我们需要开始审慎地探讨 GitOps 所存在的缺陷,才能更好地推进软件开发的进程。

GipOps只能覆盖软件开发的部分生命周期

当前的GitOps工具只关注应用程序的部署部分,而没有覆盖到其他的方面
在这里插入图片描述

GitOps并非像许多人宣传的那样无所不能,它关注的部分非常有限,很多重要的步骤它都没有覆盖,比如:

  • 代码编译/构建
  • 单元测试/集成测试
  • 代码安全扫描
  • 静态分析

甚至,几个部署过程中应该关心的重要问题,GitOps也没有纳入它的关注范畴,如秘钥管理,跨环境版本发布,冒烟测试等。想要采用GitOps的技术团队,还需要自己妥善的设计一整套流程,与GitOps互相结合,才能形成最适合他们的最佳实践。

分离CI和CD并不如想象中简单

GitOps被誉为一种将CI与部署解耦的方法。在传统的CI/CD系统中,流程的最后一步通常是部署操作。采用GitOps的好处在于能够保持CI流程的独立性。Git提交将被监控Git仓库的GitOps组件捕捉,并通过在集群中拉取更改来进行实际部署。

在简单的场景下,这不失为一种行之有效的方案,但在大型组织采用的高级部署方案中,它可能会存在一些问题。举例来说,在进行Smoke Test之后,您可能需要根据测试结果来决定是否进行回滚操作。这种情况下,将CI和CD分离将变得非常困难,因为您需要在部署完成后立即运行Smoke Test,并快速准确地做出是否回滚的决策。
在这里插入图片描述

GitOps通常只处理CI过程产生的构件,如容器镜像,二进制包等,通常不能直接获取或调用源代码。但为了运行单元测试,通常我们是要获取并调用程序的源代码。目前我们采用的GitOps工具都没有能力获取到源代码,当然也不具备测试所需的框架和第三方库,因此不具备单元测试或集成测试的能力,它只负责将CI产物拉取并部署到环境中。 为了进行Smoke Test,我们将不得不再次使用CI流程中的方案来运行测试。

这样的结果就是CI-CD-CI-CD组件和过程产生了混合,这与我们使用GitOps的初衷背道而驰。在上图的方案中,还存在其他一些问题,例如,在Smoke Test开始前,如何准备的判断部署完成的时机,以触发测试。

在这样的场景下,如果放弃GitOps,采用传统的CICD方式,问题似乎就会迎刃而解。

难以自动推进跨环境的版本发布

一旦开始实践GitOps, 这几乎是每个人首先面临的诸多挑战之一。在大型的组织结构中,应用必然会部署到多个环境中。
请添加图片描述
正如上图所示,当代码提交后,会触发CI流程,得到一个可部署的产物,dev环境中的GitOps组件检测到了git仓库变化,于是触发了dev环境的部署。 那么怎么在dev环境完成部署后,进一步将新的版本发布部署到stage, 进而到production环境呢?

有人说可以通过CI的流程来实现,当然这就意味着放弃了GitOps。还有人说我们只有一个环境,不需要考虑这样的问题,当然,小企业中这是有可能的。 还有人说,我们用branch来区分不同的环境,每当要部署一个环境时,我们就在对应的branch新建一个Pull Request, 以触发CI/CD流程,那么流程就不再是上图那样了,而是像这样:
请添加图片描述
这种方案相信也是多数人第一时间能想到的最好方式,也是一种非常流行的做法,但是却经不起时间的考验,长久下来,我们就会发现其中存在很多的问题:

  1. 在环境对应的分支上提交业务代码,这意味着代码仓库需要包含特定环境的信息, 这就使得各个分支的代码与各自的环境相耦合,各分支的代码不一致;
  2. 各分支的代码需要花费大量精力进行同步,例如经常发生的hostfix和配置变更,且有些配置还是与环境相关的,很容易出错;
  3. CI系统会增加额外的压力,因为每个分支都会执行CI, 去运行其中的构件/测试等步骤。

这些缺点会随着环境数量变多,变得越来越明显,让人疲于应付。

没有规范的多环境配置管理方法

根据上节所述,如果你的应用有多个环境的话。 GitOps不仅不能帮助你,还会造成许多的困扰。假设你的应用有10个环境,每个环境对应一个需部署的地区。 你想在这些地区间逐个部署应用(比如先部署中国,再部署印度,再部署德国,再部署美国 …)。那你会有以下几种方案可以选择:

  • 一个git repo, 10个bracnh, 这意味着每次版本发布,都需要提交十次PR, 进行10次代码合并。
  • 10个git repo,那你需要对10个repo都提交commit, 或自己编写脚本来自动提交commit到不同的repo, 或者是在不同的repo间提交pull request
  • 1个单分支的repo, 每个环境对应一个文件目录, 这样的话你需要额外的方案来保证这些目录间的更改可以同步。

上述的每个方案,其实都需要繁琐的额外工作,很难说哪一个方案更好。

GitOps会破坏一些特殊资源(如自动伸缩等动态资源)

GitOps会在部署时,完全按照Git仓库中的配置调整环境的实际配置,这本是它的一大卖点,但在一些复杂的场景中,这反而会成为一个令人头疼的大麻烦,特别是在那些可能拥有动态变化的值的资源中,尤其如此:

  • 在配置了autoscaler的资源中, replica会成为一个动态变化的配置;
  • 在配置了optimizer的资源中, resource limit会成为一个动态变化的配置;
  • 其他一些由于第三方工具的作用,可能会出现的动态变化的配置(特别是有些跟日期和时间戳有关的配置);

试想这样一种情况, git仓库中某个deploymentreplica字段配置为2, 由于autoscaler的作用, 目前环境中实际的replica字段的值为3, 此时, 如果git仓库有改动(假设改动的是某个ingress的配置,与这个deployment并无关系),此时会触发GitOps的部署,GitOps会尝试应用git仓库中的所有配置, 环境中该deploymentreplica数量将被强制的设置为2。 这显然不是我们想要的效果。

针对这个问题,ArgoCD支持custom diff, 但只能做为一个workaround。 这种方案其实破坏了GitOps的设计初衷,并且会引入一些其他的问题。

GitOps没有标准的回滚流程

事实上,在GitOps中执行回滚操作是非常方便的,只需要在GitOps执行同步操作时指定想要回滚到的目标版本的commit即可,但是,在实践中,如何"使用之前的commit"是一个问题, 不同的人会有不同的理解:

  1. 直接在GitOps上执行回滚操作,指定commit号。 但这样做的问题是,实际环境中的应用版本与Git仓库中的最新版本不一致,与GitOps的设计初衷不一致;
  2. 在Git仓库中执行revert操作,回滚到之前的代码版本,触发CI 和 GitOps部署,这样的话就遵循了GitOps的原则, 但是显然需要一些手动的操作;
  3. 将上面两种方式结合起来,在GitOps执行回滚操作的同时,由GitOps向Git仓库提交一个回滚的commitrevert操作, 使得环境和Git仓库的代码保持一致。 但显然会存在一些安全隐患,相信大多数人都不会允许GitOps这样的部署系统对Git仓库拥有修改的权限。

如上所述, 不同的人可能对于回滚有着不同的想法和实践。 目前为止, 现有的GitOps工具都没有提供一套标准的流程建议来执行回滚。

可观测性尚不完善

这一点主要是从业务角度出发来看的, 从运维和开发人员这些技术角色的角度出发, GitOps的可观测性已经非常棒了,可以看到Git的提交和哈希值,确保他们和代码仓库中的一致。然而,业务负责人的关注点却不在这些地方,从一个软件的功能角度来说,更重要的可能是下面这些问题:

  • production环境中是否包含某个特定的feature
  • 某个feature是否已经在staging环境中测试通过了?
  • 某些特定的bug是否只出现在某几个特定的环境中?

这些问题通常是业务负责人或者项目经理非常关心的,他们会希望通过某种方式快速的得到这些信息。 目前GitOps的工具都关注在技术的最底层次,也就是Git Commit Hash, 并且没有提供任何与业务特征关联的方法。 想要找出代码与业务的关联, 还是需要开发或运维这些技术角色去人工判断。

审计仍是问题

尽管通过Git仓库我们可以获取到所有的提交历史记录和部署记录, 但是正如上面一点提到的,从这些信息上,并不能轻易的映射到应用功能的变更,如果想从业务和功能的角度进行审计,仍然是非常困难的。

在相对简单的环境中,也许可以通过commit的文字信息来映射到某个应用或功能的变更。但这只适用于简单的场景。在企业级的应用环境中, Git仓库和配置文件的数量都是非常多的。 再简单的通过结合commit的文字信息来判断功能变更是不太可能实现的。在复杂的环境下,某个代码变更可能对应到多个应用,也可能只对应到一个应用,有的设置只影响一些无关紧要的配置,谈不上版本变更。

类似于可观测性不足的问题,从审计角度看,下面这些问题可能也是GitOps无法轻易回答的:

  • 某个特定feature从预发布环境到生产环境用了多长时间;
  • 过去两个月中,各个feature的最长,最短和平均开发周期是多少(从第一个commit提交到上线生产环境);
  • 某个特定环境的部署成功率是多少?导致回滚的原因是什么?
  • 哪些各个环境中的应用feature有哪些差别?

在稍成规模的软件团队中,这些问题实际上是普遍需要关注的。 而GitOps还没有能力去统计这些信息。

难以大规模的应用GitOps

随着公司规模的增大以及应用程序和环境数量的增加,采用GitOps会导致Git存储库数量急剧增加,给管理带来困难。

例如,如果有20个存储库(假设对应20个环境)包含kubernetes配置,现在,需要对一些公共的配置进行修改(例如在每个部署中添加新的公司级标签),就需要手动进行20次Git提交。前文已经提到, 如果将所有环境和集群都放在单个Git存储库中,可能会出现Git冲突的问题,且单一的巨大Git存储库也会成为GitOps过程中的性能瓶颈,因为GitOps会扫描Git仓库,仓库中的内容过多会导致扫描的性能消耗过大。

因此,在采用GitOps的过程中,需要在方便管理和避免冲突之间进行权衡。一种方式是将相似的环境和应用程序放在同一个存储库中,但是不要将所有东西都放在一个存储库中。总之,我们需要通过权衡,才可以更好地实现GitOps的效益。

与Helm的结合不顺利

众所周知,helm被称为kubernetes的包管理器, 可以方便的在集群中部署各种的第三方应用,当然,也可以用于部署我们自己的业务系统和应用。 helm的工作原理是用一组value去渲染一组kubernetes manifests模版, 用其得到的结果作为kubernetes配置清单,将其中声明的应用和配置部署到环境中去。

在运行helm命令进行部署时,会提供一个values.yml文件作为输入,最佳实践是把这个文件也提交到git仓库中去。 对于不同的环境(dev/staging/production),其对应的values.yml的内容应有所不同。

helm部署有三个关键部分,分别是:

  • 源代码: 用于构建镜像
  • 配置清单模版(chart
  • 用于渲染模版的输入值(values.yml

helm本身并没有规定这三部分需要存放的具体位置。我们可以把它们全都存到同一个git仓库中,也可以分别存到3个不同的git仓库中。由于不同的环境应有不同的value.yml, 而模版文件是各个环境共享的,因此推荐的做法是不要把values.yml和模版文件放在同一个仓库中。推荐将模版文件存到一个仓库中,将不同环境的values.yml存到另一个仓库中。

那么,我们可以想象,用GitOps进行helm部署的大致流程应该如下:

  1. 从模版仓库中下载模版文件;
  2. 从value仓库中下载对应环境的values.yml;
  3. values.yml渲染模版文件,得到kubernetes manifests(资源清单);
  4. 将生成的kubernetes manifests应用到环境中去。

上面的步骤应该是应用首次部署时的步骤。 依照GitOps的范例,两个仓库都应该被监测,而且监测的应该是用values.yml渲染模版后得到的manifests是否有变化。目前为止,各种GitOps工具都还不支持这样的功能,尽管如ArgoCD和Flux这样的工具提供了一些workaround, 但同样也有很多的限制,如果你希望在GitOps流程中应用helm,可能会使得整个流程变得更加的复杂。

GitOps并不等于CD(持续发布)

GitOps是一种优秀的持续交付方案,每次源代码仓库的提交,只会触发CI流程,生成一个可发布的版本包,但不会直接部署到生产环境。而持续发布意味着,每次对源代码仓库的提交,都会直接推送到生产环境。

根据GitOps的定义和标准流程, 只有在配置仓库的PR才会触发GitOps的部署,而源代码仓库的提交并不会触发。在大多数情况下,配置仓库的PR还是会被人为的审批的。这意味着在GitOps部署的流程中还是多多少少会存在人工操作的步骤来处理这些PR。理论上说,如果能把对配置仓库的PR的审批流程自动化,那么GitOps也可以变成完全自动化的持续发布。但是GitOps工具本身并没有提供这方面的自动化能力,想要达到这样的效果,还是需要我们自己进行额外的设计。

当然,并不是全自动,无人干预的持续发布就一定是更好的选择。由于政策以及合规的要求,有很多组织就要求在部署前必须要有人工的审查步骤,从而禁止完全的自动部署流程出现。但如果你的目的是尽量快速的使代码上线,那GitOps就不是你的最佳选择了。

秘钥管理

在GitOps的世界中,秘钥管理本身就是一个悖论, 然而秘钥管理在任何的软件部署系统中都是一个必须解决的问题,可GitOps却没办法处理。众所周知,处于安全性的考虑,秘钥是不能直接存放在Git中的。但如果不存放在Git中,又违背了GitOps的初衷 – 集群状态与Git中声明的状态保持一致(当然也包括秘钥)。

总结

虽然GitOps有这么多令人头疼的问题,但是仍然不失为一种优秀的持续交付方案,并且越来越收到欢迎,上面说到的这些问题,相信在将来也会被不断地完善。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/414150.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【Linux】Centos安装mvn命令(maven)

🍁博主简介 🏅云计算领域优质创作者   🏅华为云开发者社区专家博主   🏅阿里云开发者社区专家博主 💊交流社区:运维交流社区 欢迎大家的加入! 文章目录一、下载maven包方法一:官…

CTF流量分析

在CTF里,一些pcapng或pcap文件后缀的数据 不同的数据包有不同的协议,常见的有HTTP,TCP协议 Wireshark 简介 是一个网络封包分析软件。网络封包分析软件的功能是获取网络封包,并尽可能显示出最为详细的网络封包资料 使用WinPC…

舔狗日记:学姐生日快到了,使用Python把她的照片做成视频当礼物

舔狗日记1前言一、需要调入的模块二、实现合并多张图片转成 mp4 视频三、优化改进一下总结前言 这不是学姐生日快到了,于是我学了一手使用Python来把学姐的照片生成为视频,到时候给她一个惊喜! 好了先不舔了,下面分享一下用pytho…

基于朴素贝叶斯分类器的钞票真伪识别模型

基于朴素贝叶斯分类器的钞票真伪识别模型 内容 本实验通过实现钞票真伪判别案例来展开学习朴素贝叶斯分类器的原理及应用。 本实验的主要技能点: 1、 朴素贝叶斯分类器模型的构建 2、 模型的评估与预测 3、 分类概率的输出 源码下载 环境 操作系统&#xf…

Leetcode.130 被围绕的区域

题目链接 Leetcode.130 被围绕的区域 mid 题目描述 给你一个 m x n的矩阵 board,由若干字符 X和 O,找到所有被 X围绕的区域,并将这些区域里所有的 O用 X填充。 示例 1: 输入:board [[“X”,“X”,“X”,“X”],[“X…

stm32霸道-lvgl移植学习(一)

文章目录效果有用链接要求创建工程屏幕驱动以及触屏驱动LVGL PortWidgets demo其它效果 目前显示驱动显示较慢,后续会优化。 有用链接 LVGL官网 代码下载 要求 要求最低要求 建议要求架构16、32、64位微控制器或微处理器时钟 > 16 MHz > 48 MHzFlash/RO…

《低代码PaaS驱动集团企业数字化创新白皮书》-平台化加低代码提供破解之道(1)

平台化加低代码提供破解之道 大型企业亟需通过下一代平台开发技术实现软件创新,实现对海量数据的采集加工,以及企业内部数据的互联互通,帮助客户以低成本、短周期、高效率的方式实现数字化应用,进而赋能业务创新。基于此&#xf…

408--计算机网络--网络层总结1

目录 一、网络层概述: 1、网络层的主要任务: 2、网络层向上提供两种服务: 二、IPV4地址分类与子网划分: 1、分类编址: 一、网络层概述: 1、网络层的主要任务: 络层的主要任务就是将分组从…

【数据库基操】启动与连接MySQL数据库

一、启动与关闭 只介绍一种方法: 打开命令行工具,以管理员身份运行 1.启动数据库 net start mysql80 //80是在安装的时候设置的名字(默认),不用在意 2.关闭数据库 net stop mysql80 如题已经成功&#…

java获取本机ip的方法

Java中有一个类叫 Application,可以用来获取本机 ip,也可以用来获取网络连接的信息,例如网络上有什么主机、需要访问本机的主机名等。但是这个类只能在本机上使用,如果要访问外部的主机,还需要使用其它的方法。 首先在…

教育大数据总体解决方案(5)

(4)错题整理 将学生的本次考试错题进行集中整理,提炼出所有题目的题干和正确的答案。 (5)提高方案 分析学生对知识点掌握情况,推算出学生的进步空间以及下次考试的预测拔高分数。根据学生本次考试错误知识点…

你的APP内存还在暴增吗?试着用Bitmap管理下内存~

作者:layz4android 相信伙伴们在日常的开发中,一定对图片加载有所涉猎,而且对于图片加载现有的第三方库也很多,例如Glide、coil等,使用这些三方库我们好像就没有啥担忧的,他们内部的内存管理和缓存策略做的…

Java垃圾回收机制GC完全指南,让你彻底理解JVM运行原理

1、GC过程 1)先判断对象是否存活(是否是垃圾) 可以通过引用计数算法和可达性分析算法来判断,由于引用计数算法无法解决循环引用的问题,所以目前使用的都是可达性分析算法 2)再遍历并回收对象(回收垃圾) 可以通过垃圾收集器&…

使用Schrödinger Python API系列教程 -- 介绍 (一)

使用Schrdinger Python API系列教程 – 介绍 (一) 本文档可从Schrdinger网站www.schrodinger.com/pythonapi访问。 从Python文档字符串生成的完整API文档可以在这里访问 介绍 在最高级别上,Schrdinger Python API提供了一个基本的分子结构类,并允许与…

redis总结之-jedis

redis总结之-jedis4. Jedis4.1 Jedis简介4.1.1 编程语言与redis4.1.2 准备工作4.1.3 代码实现4.2 Jedis简易工具类开发4.2.1 基于连接池获取连接4.2.2 封装连接参数4.2.3 加载配置信息4.2.4 获取连接4.3 可视化客户端总结计划 1. Redis 入 门(了解)&…

LNMP网站框架搭建(编译安装的方式)

1. Nginx的工作原理 php-fpm.conf 是控制php-fpm守护进程的 php.ini是php解析器 工作进程: 1.客户端通过域名进行请求访问时,会找Nginx对应的虚拟主机 2. Nginx对该请求进行判断,如果是静态请求,Nginx会自行处理,并将处理结果…

因果推断14--DRNet论文和代码学习

目录 论文介绍 代码实现 DRNet ReadMe 因果森林 论文介绍 因果推断3--DRNet(个人笔记)_万三豹的博客-CSDN博客 摘要:估计个体在不同程度的治疗暴露下的潜在反应,对于医疗保健、经济学和公共政策等几个重要领域具有很高的实…

ERP系统有什么用?主要是这三方面

ERP 是Enterprise Resource Planning 的缩写,即企业资源计划系统,是建立在信息技术基础上,以系统化的管理思想,为企业决策层及员工提供决策运行手段的管理平台。它实现了企业内部资源和企业相关的外部资源的整合。通过软件把企业的人、财、物、产、供、销及相应的物…

socket 到底是个啥

哈喽大家好,我是咸鱼 我相信大家在面试过程中或多或少都会被问到这样一个问题:你能解释一下什么是 socket 吗 我记得我当初的回答很是浅显:socket 也叫套接字,用来负责不同主机程序之间的网络通信连接,socket 的表现…

整柜海运到美国的规格和收费标准是什么

整柜海运是指将所有货物安装在一个整箱内,由发货人和收货人共同操作,而目的港的收货人一般只有一个,方便操作。整柜海运到美国的主要流程有以下几个步骤:订舱、装柜、报关、海运、清关、提柜和送货。实际上,国际物流出…