CI/CD 流水线工程化:从 Jenkinsfile 到 Dagger
背景与问题界定 一个维护了三年的微服务 CI/CD 平台,累积了 2000+ 行 Jenkinsfile,分布在 80 多个仓库中。每次修改 Jenkins 共享库都需要全量回归测试,Pipline 中的 Groovy 代码缺乏 IDE 支持和单元测试能力,一个语法错误就能堵塞整个团队的部署流程。更痛苦的是,本地开发环境和 CI 执行环境的不一致——开发者 Mac 上跑的 Shell 脚本在 Jenkins Agent 的 Linux 容器里表现完全不同。2024 年的 DevOps 报告指出 67% 的团队认为流水线维护成本是 DevEx 的最大负反馈因素。我们需要一种可以本地运行、可编程、可测试的流水线范式。 目标拆解与工程约束 本地可执行性:流水线必须能在开发者的笔记本电脑上用 docker run 或直接执行的方式复现,无需依赖 Jenkins Master 或 GitLab Runner 等中心化调度系统,实现 “What You Run Is What’s Deployed”。 类型安全与可测试性:流水线定义使用通用编程语言而非 DSL,支持 IDE 的自动补全、类型检查和单元测试框架,消除 Groovy 脚本的黑盒调试模式。 容器化执行环境:每个流水线步骤在独立的容器中执行,步骤间通过一致的挂载卷和缓存机制共享数据,彻底消除环境不一致问题,同时支持任意语言的工具链镜像。 组件化与复用:流水线步骤应该像 SDK 函数一样可以包管理、版本化和复用,而不是通过 Jenkins 共享库的全局变量注入,支持按 namespace 或团队粒度发布流水线组件。 方案设计 我们选择 Dagger 作为流水线引擎的核心。Dagger 使用 Go 或 TypeScript 定义流水线,每个步骤通过 Container API 在一个隔离的容器中执行。核心思路是将流水线视为一个有向无环图(DAG)的任务编排,每个任务在特定容器镜像中运行,依赖关系由 Dagger Engine 自动解析和并行调度。 ...