Appearance
CI/CD 到底怎么落地:从提交、构建、制品到发布的完整流水线思维
很多人第一次接触 CI/CD 时,最容易把它理解成一句话:
- 提交代码后自动执行几条命令
这不算错,但太浅了。
真正要把 CI/CD 用好,关键不是“自动化”三个字,而是把代码从提交到上线这一整条链路做成稳定、可重复、可追踪的流程。
先说结论
一条像样的 CI/CD 流水线,通常至少要回答下面几个问题:
- 代码什么时候触发构建
- 构建后产物放在哪里
- 哪些检查必须先通过
- 不同环境怎么区分
- 发布失败后怎么回滚
如果这些问题没有想清楚,只是把 mvn package 或 npm run build 放进流水线里,自动化程度可能上去了,但整体交付质量未必更稳。
一、现在应该怎么理解 CI 和 CD
1. CI 是持续集成
它更关心“代码合进来之后,能不能尽快发现问题”。
典型动作包括:
- 拉代码
- 安装依赖
- 编译构建
- 运行单元测试
- 做静态检查
- 生成制品
2. CD 是持续交付或持续部署
它更关心“已经通过验证的产物,怎么稳定进入环境”。
典型动作包括:
- 推送镜像或打包产物
- 部署到测试环境
- 部署到预发环境
- 灰度或全量发布到生产
- 发布后验证
- 失败回滚
所以更准确地说:
CI解决的是代码质量和构建一致性CD解决的是交付效率和发布稳定性
二、个人博客和 Java 服务的 CI/CD 有什么差异
1. 个人博客
像 VitePress 这类项目,本质上是:
- Markdown 内容
- 主题配置
- 静态站点构建
它的发布路径通常比较简单:
text
提交内容 -> 触发构建 -> 生成 dist -> 同步到 Nginx 静态目录重点在于:
- 构建是否成功
- 发布目录是否正确
- 新旧静态文件是否一致
2. Java 服务
Java 服务的链路通常更长:
text
提交代码 -> 编译测试 -> 打包 jar 或镜像 -> 推送制品库 -> 部署到环境 -> 健康检查 -> 灰度/全量发布重点会更多落在:
- 依赖是否稳定
- 多环境配置是否隔离
- 数据库变更是否兼容
- 回滚是否方便
如果放到你当前这套知识库站点上,实际最重要的三个点通常是:
- 构建目录有没有固定
- 发布目标路径有没有固定
- 校验是不是直接走真实 HTTPS 入口
三、一条更完整的流水线通常长什么样
可以先把它拆成下面几个阶段。
1. 代码检查
最常见的是:
- 代码格式检查
- 单元测试
- 安全扫描
- 静态分析
这一步的目标不是把一切问题都拦住,而是尽早发现明显错误。
2. 构建与打包
例如:
- Java 项目执行
mvn clean package - Node 项目执行
npm ci && npm run build - Docker 场景构建镜像
这一步最重要的是“可重复”,也就是:
- 换一台机器执行结果仍然一致
- 不依赖人工先做某些本地准备
3. 制品管理
构建完之后,产物不能只留在构建机临时目录里。
常见做法:
- Jar 包上传到制品库
- Docker 镜像推送到镜像仓库
- 静态站点产物归档或直接同步
制品管理做得好,回滚才会顺。
4. 环境发布
这一层通常会区分:
- 开发环境
- 测试环境
- 预发环境
- 生产环境
不同环境要解决的不是“命令写得不一样”,而是:
- 配置隔离
- 权限隔离
- 发布策略隔离
5. 发布后校验
很多团队把流水线写到“命令执行完成”就结束,这其实不够。
更稳的做法是增加:
- 健康检查接口
- 日志关键字检查
- 核心页面访问校验
- 关键链路冒烟验证
像当前这类静态站点,最少也建议校验三类页面:
- 首页
- 一个专题页
- 一篇代表性文章页
四、把它放回当前个人站点,最容易漏掉什么
如果是 VitePress 知识库继续往上做 CI/CD,最常见的漏项反而不是构建命令,而是下面这些细节:
1. 发布路径没有收紧到子站目录
如果服务器上有多个站点,就不该直接把产物覆盖到 Nginx 根目录。
像当前这套结构,更稳的目标路径应该明确成:
text
/mydata/nginx/html/mumu-wiki2. 只校验 127.0.0.1,不校验真实子域名
如果机器上不止一个站点,直接 curl http://127.0.0.1/ 很可能命中默认站点,不能代表真实线上效果。
3. 备份动作没有先行
个人站点常被低估的一点是:内容更新频率高,回滚需求其实并不低。
所以每次发布前先做静态目录备份,价值非常高。
五、最容易被忽略的三个关键点
1. 制品不可变
构建出来的同一个版本,应该尽量在不同环境复用同一份产物,而不是每到一个环境再重新打包。
否则你很难回答:
- 线上跑的到底是不是测试通过的那个版本
2. 配置和代码分离
不同环境下常变的是:
- 数据库地址
- Redis 地址
- MQ 地址
- 开关项
- 密钥
这些不应该硬编码进包里。
3. 回滚路径要先设计
很多团队上线时只设计“怎么发”,没设计“怎么退”。
但真正出问题时,最值钱的不是重新分析,而是:
- 有没有上一版本制品
- 能不能一条命令切回去
- 数据库变更是否兼容旧版本
六、常见流水线分层思路
如果项目逐渐变多,推荐把流水线拆成三层理解:
1. 通用模板层
解决共性动作,例如:
- 拉代码
- 设置缓存
- 执行测试
- 统一构建镜像
2. 项目实现层
解决项目差异,例如:
- Java 是
maven还是gradle - 前端是
vite还是next - 部署目标是 Nginx 还是 K8s
3. 环境策略层
解决环境差异,例如:
develop分支自动发测试main分支需要审批后发生产- 生产必须先灰度再全量
七、我更推荐的落地顺序
不要一上来就追求“企业级大而全”,更稳的路径通常是:
第一步:先把构建稳定下来
目标是任何人、任何机器都能稳定产出相同制品。
第二步:再把测试和检查接进去
先让明显错误提前暴露。
第三步:把发布动作脚本化
哪怕只是先做到:
- 构建完成后通过脚本同步到服务器
这也已经比纯手工稳很多。
第四步:最后再补审批、灰度、监控、告警
这些都重要,但前提是基础链路先跑顺。
如果放到当前知识库站点,更实际的落地顺序通常会变成:
- 先固定
npm run docs:build - 再固定备份和
rsync --delete - 然后补真实 HTTPS 校验
- 最后再考虑多环境和更复杂治理
八、常见误区
1. 以为上了 Jenkins 就等于有了 CI/CD
工具只是载体,流程设计才是核心。
2. 以为自动化越多越好
自动化当然重要,但错误流程自动化之后,只会更快地把问题放大。
3. 以为流水线只属于运维
对 Java 开发来说,CI/CD 其实和代码设计、配置设计、数据库设计都有关系。
一句话总结
CI/CD 的本质,不是“把命令搬到平台上执行”,而是把软件交付链路做成标准化、可复用、可回滚的工程流程。
对个人博客来说,它能帮你稳定发布内容;对 Java 服务来说,它能把“上线靠经验”逐步改造成“上线靠流程”。