ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

为什么我劝你扔掉Jenkins做CD?

为什么我劝你扔掉Jenkins做CD?

你是不是也处于这样的状况呢? 在每一个工作日, 当正式投入办公的时候, 你首先会去查看是否有掉线的情况发生, 随后对插件是否得到了更新进行必要的核查, 到了最后阶段, 你还不得不带着恳切的语气去请求运维部门不要执行重启操作。

尽管它本来的角色是一个自动化的处理工具, 但实际上它所呈现出来的结果却是成为了整个团队当中最显得拖累整体进度的存在, 也就是大家口中所说的最让人敬而远之的“祖宗”级别的存在。

特别是当时间的刻度停留在二零二四年这个特定的时间节点之际, 云原生架构和微服务技术满天飞舞般普及的当下, 如果你依然采用着属于二十年之前的单体化部署架构来进行运作, 难道你的内心不会对这种状态产生一种强烈的别扭感吗。

请不要产生误解, 在持续集成这一方面, 目前的状况确实是具备竞争力的。但是, 如果拿它来执行持续部署的任务, 这从本质上来讲就是用处理极其复杂繁重任务的大型工具去解决微小简单的问题, 而且在这个过程中还有可能对操作者自身造成不利的影响。

接下来, 大家所关注的话题是如何将该工具负责持续部署的具体职责进行完全移除, 并且替换为更加轻量的解决方案。

我们先来谈一谈做CD的这个六大硬伤到底是咋回事, 第一点, 是它的架构实在太老了, 那个啥主节点加上代理的那种模式, 说白了还是停留在静态服务器时代的一种老思路罢了, 但是现在容器化部署还有动态扩缩这些, 那才是大家眼中的常态, 你却非得靠那些个插件去强行凑合, 这不仅性能差得一塌糊涂, 而且哪怕只是重启一次, 它都得把整个磁盘给扫描一遍, 简直是把粉丝的那份心态都给磨没了。

第二, 插件生态表面看着很繁荣, 实际上是一个大坑。插件数量虽然很多, 但质量参差不齐, 依赖关系复杂得像蜘蛛网一样。许多插件长期没有人维护, 甚至带着已知的漏洞存在。

你为了搞定CD, 需要安装一大堆第三方插件, 结果在这些东西里嵌入YAML, 修改一个配置都让人感到心惊胆战。一旦爆出安全漏洞, 补丁也无法打上, 最后只能“带病运行”。

第三个方面是安全黑洞。使用它的Web UI让你能够在界面上配置并执行远程脚本。这一操作等同于把你的SSH端口以及登录凭据直接暴露在外面。一旦系统被攻破, 攻击者就可以利用获取到的SSH证书来攻击所有的业务服务器。

相反地, 像 这样的现代工具采用了不同的设计思路。这些工具使用的是所谓的“拉取式”架构。在这种架构下, 执行端需要主动去领取任务指令。此时目标环境中完全不需要开放任何接收连接的入站端口。这样的处理方式直接把安全性提升到了一个很高的水平。

第四, 脚本依赖这个方面的问题。它本身是一个脚本的集合。因为没有开箱即用的金丝雀发布功能, 也没有灰度发布的功能。所以你必须自己编写大量的自定义脚本。这些代码难以复用, 也很难维护。一旦环境发生变化的时候, 系统就会崩溃。说的直接一点, 所谓的灵活性最后变成了一片代码的沼泽。

第五点是, 用户体验比较差。原生的用户界面看起来就像是上个世纪的产物。Blue Ocean界面虽然好一些, 但是需要额外安装才可以使用。非开发人员根本玩不转这个软件。

团队里面必须配备一个专职的管理员来负责这件事。而在使用 CI 的时候, 可以通过 YAML 文件来定义流程。开发者对这些东西是很熟悉的。可视化面板也比较清晰。所以用起来上手要快得多。

第六点, 维护方面的成本实在是太高了。中小型团队的话, 本来在手上的工程师人数就很少, 他们还得花上两到五个人力, 去管那些插件更新的事情, 去搞磁盘清理的事情, 去操作Agent管理的事情, 还要配置并发方面的事项。

稍微有一点小心思不对的话, 系统就可能当场卡死, 甚至就会直接崩溃掉。您好好算一算这笔账, 这些精力拿去干些别的什么事情不好呢?

说到这里, 有人可能就会去提出这个问题了: 那个CI和那个CD这两个东西, 为啥非得一定要分开来算呢? 其实这个里面的道理还是特别简单的, 就是因为它们各自负责的活儿不一样, 那就必须得要各自管好各自的那摊子事情。

CI这边主要追求的就是那种速度又快又准又好的一种效果, 也就是我们说的短平快, 它干的事儿就是把代码拿去编译一下,再跑一下测试, 还有构建出来那些制品, 这些都搞完了就完事了。

但是CD就不一样了, 它得要去管多个环境里的发布情况, 还得去做一些灰度验证的活儿, 最后如果真出了啥问题, 还得负责进行回滚操作, 这一系列的事儿都涉及到大量的基础设施, 而且运行的时间会拉得很长, 风险也是比较高的。

分开之后, 安全性就提升了, CD系统不用再保存主账号的凭据, 采用拉取的方式来避免暴露密钥, 弹性扩展方面, CD是独立于CI去伸缩的, 支持多云和异构的情况, 遇到故障时, 还有故障隔离的功能, CI挂了也不会影响到已经做的部署工作, 另外还能标准化, 用一个统一的CD服务来管理所有的发布流程。

关于那个替代方案具体选谁这个问题, 如果你的公司已经在使用托管代码了, 那么它就是一个成本最低而且收益最高的选择。因为它本身就是在执行 CI/CD 这个任务的组件, 它可以跟代码仓库、制品库以及安全扫描功能进行无缝集成。

你所要做的事情只需要在仓库的根目录下面放一个 .ci.yml 文件就行了, 通过这样你就可以定义整个流程。安装过程也是一件比较简单的事情, 你使用单个二进制文件的方式或者是在分钟级内就可以完成安装的部署工作。

我们来对两者情况进行一个比较分析, 一方面是架构采用了单体模式结合Agent的方式, 同时文件需要存储, 另外还必须对外开放Web端口以及SSH服务;另一方面则具备轻量级客户端的特点, 并且状态是无意义的, 基于任务轮询机制运行, 不会暴露任何入站端口。

在配置层面, 前一种方式需要使用脚本加插件组合进行设置, 后一种方式使用声明式的YAML格式, 这样既直观又方便版本控制。从维护方面来看, 前者需要持续更新插件、清理磁盘空间以及重启服务才可以保证正常运作, 后者几乎零维护, 只需要在注册的时候配置一次令牌就行。

在扩展方面来说, 如果是选择手动地去管理Agent的数量, 这种情况下的资源利用率比较低;如果是选择了自动的扩缩容功能, 那么它能够支持和按需进行运行。至于学习成本这件事, 那更是没法比了, 一个是高一个低。

具体怎么做迁移呢? 其实可以分三步来进行。第一步, 要做评估工作。你要去盘点一下现有的管道里面有哪些属于持续交付的环节, 举例子来说, 就是把代码部署到测试环境和生产环境的那些脚本之类的东西。

接着要在系统上面创建一个新项目, 并且要确保这个项目的仓库里有那个名为`.-ci.yml`的东西。最后一步是安装什么东西, 这里推荐用运行器, 把它注册到目标项目里面或者共享池之中。

第二步就是要把那个CD流水线给编写出来。比如说可以把它分好构建还有别的这几个阶段。然后用YAML这种格式去定义一下那个脚本怎么写。它只对那些特定的分支才会触发。执行的时候需要手动去点一下, 而且它也只会作用在特定的分支上。这样操作起来呢, 既安全也很灵活。

在第三步, 也就是验证与优化的这个阶段, 需要在首次运行之后, 去检查 CI/CD 面板里面的日志内容还有状态信息。要把内置的密钥管理替换方案用起来, 从而把那些写在代码里的硬编码凭据给去掉。

然后要逐步让正在进行的 CD 任务慢慢地停下来并最终下线, 最后只保留 CI 构建这一步, 或者彻底决定不再使用它。

现在的人必须承认, 敌人这个说法是不准确的, 但是用一套工具去把什么活儿都包揽下来做的那个年代已经没有了尽头。在持续集成的时候它还能剩下一点用处, 不过到了持续部署的地方面来说, 坏毛病远好过好处。

因为它是轻量的、它也是安全的、它是合在一起的、它还几乎不用维护, 所以它就变成了二零二四年里头最值得人们拿去做持续部署的一个办法。大家赶快把持续部署这个流程从那个东西里分出来, 让大家伙儿一心一意只想着怎么把值钱的成果交出去, 就别老在那里给工具当奴役了。

你的团队现在仍然还在使用做CD吗, 你踩过哪些坑了, 请在评论区进行一下聊天, 不要让其他人再继续掉进这个里面去。

RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进