资讯动态

从手工上线到3分钟自动发布:CI/CD流水线改造实践

发布时间:2026/10/7 4:33:08 来源:尧图企业网站定制
周四下午四点半我提交了这周的上线申请。按流程运维同事会在周五晚上操作顺利的话凌晨前能发完然后我守着手机等告警——这已经算快的了。遇到测试环境跟生产环境有差异、配置文件漏改、流量切不过来这些问题一个晚上就交代进去了。后来我把这套流程从头到尾重做了一遍从提交代码到生产环境新的服务实例真正开始接流量现在稳定在3分钟左右而且全程不用人工盯着。这篇文章把我当时的改造思路、每一步的取舍、以及跑起来之后踩过的坑都写清楚给还在手工上线泥潭里的团队一个参考。1. 动手改造前先算清一天时间都花在了哪里很多团队一提上线提速第一反应就是去买Jenkins、买GitLab CI、上K8s结果工具买了一堆流程还是慢。我的经验恰恰相反先别急着上工具先把一天这24小时拆开看看到底被什么东西吃掉了。我当时让团队把一次完整上线的全过程记录下来从提交代码到线上验证通过为止每一段操作都标上人和时间。整理出来大概是这样的环节耗时谁在做时间去哪了打包20分钟开发本地Maven下载依赖本地环境不一致导致反复打包上传服务器10分钟开发scp传jar包网络波动重传备份旧包15分钟运维手动cp、记录版本号、写回滚说明停服5分钟运维通知在线用户、kill进程替换配置30分钟开发运维逐个核对环境差异经常漏改启动日志确认20分钟运维启动失败回滚再来一遍冒烟测试40分钟测试手工点主流程发现bug再返工等待与沟通6小时以上所有人等审批、等别人干完、半夜被叫醒确认这个表列完所有人都沉默了。真正花在打包上传上的时间其实不到1小时剩下的全在等待、沟通、重复劳动和返工上。其中最致命的三件事环境不一致导致我本地是好的这个问题反复出现一出现就是半小时起步的排查。配置散落在服务器上每次上线都要人工改改错一个端口或开关就是一次事故。没有自动化的验证手段上线后靠人肉点页面发现问题时已经过去了半小时。所以后面所有改造本质上都是在解决这三个问题。自动化只是手段不是目的。2. 提速的地基先把可变的东西全部固化很多人一上来就搭流水线流水线跑通了但上线还是慢因为他在流水线里做的还是以前那套手工操作——只不过手动变成了半自动。我没有急着写pipeline而是先花了两周时间做标准化。这一部分看着不性感但恰恰是后面能把时间压到3分钟的关键。2.1 镜像化让环境差异这个词从字典里消失以前每个环境都有一台有感情的服务器配置改来改去谁也说不清生产上到底是什么状态。我做的第一件事是把应用直接容器化所有环境跑同一个镜像。具体来说代码里只保留一套配置模板环境相关的变量全部提取成环境变量或者配置中心条目。Dockerfile只做一件事把构建好的产物打进镜像不包含任何环境信息。开发、测试、预发、生产这四个环境用同一份镜像启动差异只体现在环境变量上。这样做的好处表面上是环境更一致了实际上是把排查环境问题的成本从每次上线的常规操作里彻底删掉了。测试好好的上生产就挂这种事镜像化之后再也没发生过因为跑的东西物理上就是同一个。2.2 基础设施代码化服务器不是改出来的是定义出来的服务器上乱七八糟的部署目录、启动脚本、定时任务以前靠人肉维护。我把这些都收编成了代码放在仓库里用IaC工具去管理。每次要改什么先改代码、走评审、再应用到目标环境。这一步的收益不是马上能看到的但它是后面自动化流水线的唯一地基。没有它流水线就算能自动部署也依然是盲人摸象——不知道线上最终长什么样。2.3 一键回滚能力敢提速的前提做完了标准化我还特意做了个一键回滚的预案。回滚这个能力平时用不上但没有它谁都不敢把上线流程改成全自动。我当时的做法是保留最近N个镜像版本回滚操作就是重新拉起前一个版本的镜像整个操作在流水线里是一个已封装好的回滚按钮。这个按钮我一直到后面才公开给团队用但它的存在让所有人对自动化上线有了信心。3. 流水线怎么设计从push到生产中间只留关键关卡标准化做完之后我才开始搭真正的发布流水线。这条流水线从开发者git push触发到生产环境滚动更新完成前后一共跑11个步骤其中需要人工确认的只有一步。3.1 流水线的整体结构我用的是GitLab CI但也无所谓具体工具思路是一样的。整个流程如下stages: - lint - test - build - scan - image - release - deploy - health每一步具体做什么lint阶段跑静态代码检查发现低级错误直接拦截MR都合不进来。test阶段跑单元测试。我们要求核心模块覆盖率不低于80%低于就失败。build阶段编译打包这一步的结果会被后面直接使用。scan阶段镜像安全扫描检查基础镜像和依赖库有没有已知漏洞有高危的就卡住。image阶段把构建产物打进镜像push到私有镜像仓库打上git短SHA的tag。release阶段生成发布单记录本次变更的commit范围、镜像地址、涉及的配置项。到这里会等一个负责人的approval这是全程唯一的人工关卡。deploy阶段K8s滚动更新新的Pod先起来Ready之后再摘旧的。health阶段自动跑健康检查和冒烟接口全部通过才标记本次上线成功。这条流水线从代码push到镜像推完大概需要2分钟出头后面细说为什么这么快。人工批准后部署和健康检查总共花不到1分钟。所以整体下来真正的手按按钮到完成就是3分钟的量级。3.2 为什么只保留一道人工关卡以前上线要经过好几道审批开发领导签、测试领导签、运维领导签签完黄花菜都凉了。我保留了release阶段的一次人工确认原因是自动化能保证无故障但保证不了这件事该不该此刻做。比如周五晚上十一点发起上线哪怕流水线全绿也未必该发。所以流程可以自动化决策依然要留给人。这道关卡我设计成跟流水线解耦的负责人在手机上点一下就放行不用登录服务器、不用看日志所有的信息——改了哪些代码、哪些服务受影响、回滚方案是什么——都已经在发布单里自动生成好了。决策者只需要回答一个问题现在发可以吗4. 3分钟账单每一步从多少秒压到了多少秒很多人不信3分钟能上线觉得构建一个Java应用都不止3分钟。我当时的优化思路不是拼命压每一个环节而是搞清楚哪些环节可以砍掉哪些环节可以并行哪些环节必须保留。4.1 砍掉的环节从源头消灭等待原来的流程里打包、上传、备份、改配置、停服、启动、冒烟这些步骤之间存在大量的串行等待A做完了要通知BB做完了再通知C。流水线把这些环节全部串起来自动跑步骤之间零等待。这是最粗暴也最有效的一刀。4.2 压下去的环节构建从20分钟到80秒构建是整个流水线里最耗时的一环。我做了三件事依赖缓存挂到持久化存储上Maven/Gradle的依赖不用每次重新下载直接命中缓存。这一步省掉的时间最多光依赖下载就占了原来构建时间的80%。多模块并行编译以前串行编的模块改成并行吃满机器的CPU。镜像分层缓存基础镜像不动业务代码只打最后一层push镜像的时候只传增量部分。这三样做完单次构建从20分钟压到了80秒左右镜像推送从几分钟压到了30秒内。4.3 并行化能同时做的绝不排队流水线里安全扫描和构建是并行跑的。扫描不通过会拦截后面的部署但不会拖慢构建本身。另外测试阶段和代码检查也是并行的互不等待。整体算下来并行大约省了整条流水线1/3的时间。下面是优化后的实际耗时明细环节优化后耗时关键优化点代码检查10秒只查变动文件不查全量单元测试25秒并行跑差异测试先行编译打包60秒依赖缓存多模块并行镜像构建推送30秒分层缓存增量推送安全扫描并行不额外占时边构建边扫部署滚动更新40秒K8s滚动不断流量自动健康检查20秒接口探活核心链路冒烟加起来流水线全绿到生产就绪平均3分07秒。这个数字不是我拍脑袋估的是跑了接近一个月之后从CI系统里导出的平均值。5. 跑起来之后踩过的坑自动化上线不是一劳永逸流水线从能跑到稳定跑之间隔着一堆坑。我把踩过的有代表性的几个记录下来你们未来大概率也会遇到。5.1 流水线全绿数据库却漏了脚本第一次自动化上线成功的半个月后有一次发版流水线全绿但线上查询直接报错。排查了半天发现某个SQL迁移脚本没有执行。以前手工上线时这一步是记得跑一下的自动化之后没人记得机器也不会替你记得。我的解决办法是数据库变更也纳入同一个发布单用专门的方式管理版本化SQL脚本流水线在部署前自动检测并执行未应用的脚本。注意这个话题本身很复杂微信篇幅未必装得下但你们在做自动化时一定记得把数据库变更纳入流程不要放在脑子或聊天记录里。5.2 滚动更新确实不断流量但连接没刷新K8s滚动更新确实能做到不中断服务但我们的网关、本地连接池、长连接这些不会因为Pod被替换就自动重新连。第一次自动化发布之后我们收到用户反馈页面偶尔白屏。排查下来是旧的Pod还在处理存量连接新的Pod起来了但入口流量还往老Pod上打而老Pod在优雅终止期被强制干掉了。解决办法有两个一是把优雅终止时间拉长给存量请求足够的处理时间二是在preStop钩子里主动把Pod从服务发现里摘掉再等几秒才真正退出。这两步做完白屏问题再没出现过。5.3 权限越大事故越大自动化上线意味着任何能触发流水线的人理论上都拥有直接发生产的权限。我们发生过一次乌龙有人想跑测试环境的流水线参数选错把生产环境覆盖了。虽然回滚很快但这事儿吓出了我一身冷汗。后续做了三件事环境隔离测试流水线和生产流水线分开生产环境只能由特定的受保护分支触发。敏感操作加二次确认生产环境的部署除了release阶段的人工审批还需要操作人在群里报备。理由很简单让团队看到谁在什么时候发了什么。审计日志全留每一次上线自动生成一份完整记录包括谁触发的、哪个commit、哪个镜像、部署结果如何。自动化提升的是效率但权限和审计的能力必须跟着提升不然效率提升反而会放大风险。6. 上线提速这件事真正难的不是技术最后想聊点题外话。这套东西的技术含量说实话不算高CI、容器化、K8s滚动更新每一块都有大量现成文档。真正难的是两点第一团队愿不愿意为看不见的功夫花时间。我做标准化那两周流水线一条没搭看起来毫无进展团队成员每天的活还是照旧但上线速度一点没变。如果没有管理层的信任你这两天在干嘛这句话就能让整个改造胎死腹中。第二每个人愿不愿意改变工作习惯。以前上线是开发者把包丢给运维就行现在开发者要自己写Dockerfile、要关心健康检查要不要加、要理解滚动更新的机制。对一些人来说这是额外负担但对我而言谁写代码谁就该对怎么把代码跑起来负全责。这个理念贯通之后整个团队的发布能力和质量意识都上了一个台阶。现在每次发布docker构建日志刷完然后看到K8s滚动更新起新Pod、等Ready、摘老Pod一套操作在眼前自动走完最后钉钉弹出一条v2.3.1发布成功耗时3分02秒的机器人消息。说实话第一次跑通那天我在屏幕前愣了挺久——同一个上线以前是一群人折腾一整天现在是一个人在手机上点一下确认。这个体感差异值得任何团队去折腾一次。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑