PGO-CI/CD
或者是造轮子,或者是盲从?
我给自己的 Go 后端工程 pgo 编写了一个 CI/CD 工具,也是用 Go 编写的。
CI 部分包括常用的构建命令、ORM/Proto 代码生成等(本质上是调用 Makefile),
而 CD 部分则是通过 SSH 将文件同步到远端并运行或重启服务。
在构建这个工具的过程中,我一直在思考:这算真正的 CI/CD 吗?
PS: 整个部署方案记录于另一篇文章PGO-Deploy,本文包含CD工具只是包含基本的文件拷贝和部署命令的执行。明确区分“哪些内容由CD工具提供,哪些属于部署架构本身”很重要,要避免把所有工作都写到CD工具中。
为什么不直接用 GitHub Actions?
通常我们提到的 CI/CD(如 GitHub Actions, Jenkins),大都是基于Git 提交触发的。 这种模式在代码合并进主分支准备发布时非常完美。但在开发过程中,它甚至有点“迟钝”:
- 反馈慢:我必须 commit -> push -> 等待任务排队 -> 等待容器启动 -> 运行。
- 垃圾提交:为了在测试服验证一个改动,可能产生大量 “fix typo”, “try again” 的 commit。
- 技术栈割裂:为了写部署逻辑,我需要写大量的 YAML 和 Bash 脚本,而不是我也许更擅长的 Go。
对于私人项目或小团队,开发者往往兼任 DevOps。 我们需要的不仅仅是一个自动化的流水线,更需要一个在开发阶段能随时、快速同步代码到测试环境的“遥控器”。
设计思路:演进式落地
在这个项目中,我采取了分层策略:
- Level 1 手动挡(开发期):命令行工具。本地编译,交互式选择,一键热更测试服。
- Level 2 自动挡(发布期):平台级 CI/CD。由 GitHub Actions 触发,但它只是一个入口,底层依然调用 Level 1 中编写好的 Go 工具。
目前我正专注于 Level 1 的打磨。
代码实现与迭代回顾
最近经历了几次重要的迭代。
1. 构建系统的“可视化” (Make CLI)
项目根目录有一个 Makefile,包含各种 tag 注入、环境设置等变量。 为了避免死记硬背make命令,比如:
1
2
3
有些命令需要输入额外参数,如orm生成就需要mysql连接,需要密码
有些命令不复杂,但是会忘记,经常需要help或者查看makefile
我在 make_cli.go 中实现了一个解析器,它做了几件事:
- 解析 Makefile:通过正则提取 Target 和注释,生成可视化的选择菜单。
- 参数缓存:利用
cachePath记住你上次输入的变量值。 - 交互式配置:识别
?=赋值的变量,运行时询问是否需要修改。
这样,构建过程变成了:运行cicd工具 -> 选择 Build -> 回车确认参数 -> 等待完成。
2. 部署的双轨制 (Deploy CLI)
我将部署拆分为两种截然不同的场景。
场景 A:首次/全量部署 (Infrastructure)
搭建环境用的,读取一个json配置,记录了需要拷贝的文件列表,然后上传到目标服务器。
- 安全检查:在覆盖前计算 MD5。如果发现远程文件与本地不同(可能是服务器上临时改过),会发出警告或中断,防止意外覆盖。
- 容器编排:部署完成后,将询问是否一键启动,本质上是工具会自动探测目录下的脚本并赋权,然后执行
docker-compose up -d来拉起服务。
场景 B:服务热更新 (Hot Update)
这是我在开发中最常用的功能。当我在本地修改了某个微服务的 bug,我不需要全量部署,也不想重启整个 Docker 容器。我只需要把新的可执行程序拷贝到目标服务器。
配合 PM2 的 watch 机制,一旦二进制文件更新,服务会自动重启,实现秒级生效(5s轮询)。
遇到的问题1:
为什么是轮询而不是常规的watch?
因为通过容器内部PM2部署的服务,而更新SSH上传是以宿主机为目标的,容器不适合提供SSH服务。导致了PM2常规的watch无法检测到宿主机的文件变化,即使文件映射到了容器内,也不行。
遇到的问题2
经典的 Linux 问题:Text file busy,如果是正在运行的二进制文件,直接 scp 覆盖会失败。
简单处理:scp前用 rm -f删除文件,后续优化可以加日期作为后缀备份一下。
总结
当前为什么用 Go 写 CI/CD? 除了语言亲切感,最大的好处是复用。 这个 DevOps 工具的开发我可以直接使用我自己最熟悉的Go,尤其是我自己pkg封装好的功能。 我不需要在 Bash 脚本里重新发明轮子,也(暂时)不需要去学习其他CI/CD平台的语法。 这是我当前实现CI/CD最高效的方案。
目前的形态是一个运行在本地的 CLI, 未来它完全可以被打包进 Docker 镜像,或重构成bash脚本, 在 GitHub Actions 中被调用,成为连接开发与生产的统一桥梁。
正如文章副标题: 也许当前的CI/CD是造轮子,它是我当前能最快打造,又足够好用的轮子。 当前我选择了不“盲从”,而这个说法,也仅限于当下,未来需求出现,依然会拥抱“潮流”。