云计算
悠悠
2026年6月23日

CI/CD,如何优雅地拥抱云计算

我最近在帮一个初创团队改造他们的发布流程。他们之前用 Jenkins 跑在自己的服务器上,每次部署都得 SSH 登到机器手动检查日志,有时候还会翻车。后来我们逐步把整套系统搬到了 AWS,用 GitHub Actions + CodePipeline + ECS,现在一个 git push 就能自动走完从构建到上线的全过程。这个过程中我学到了很多关于 CI/CD 与云计算结合的妙处。

从自建 Jenkins 到云上的自动化

说实话,自建 Jenkins 的时代确实很折腾。你需要维护 Jenkins 服务器本身、管理磁盘空间、备份构建历史、处理执行器的故障……这些事情都不直接产生业务价值,但却占用了大量精力。最烦的是,当构建任务突然暴增时,自建的基础设施经常顶不住,你只能去扩容,但扩容又需要时间。

云计算改变了这一切。AWS CodePipeline 这样的托管服务,天生就具有弹性。你定义好 pipeline 的各个阶段,剩下的交给云平台处理——它会自动扩展、自动管理,你不用操心基础设施,只需要关注业务流程。

我们的做法是这样的:代码推送到 GitHub,GitHub Actions 触发单元测试和代码质量检查(这部分很快,通常 5 分钟内完成)。测试通过后自动构建 Docker 镜像,推送到 ECR(AWS 的容器镜像仓库)。然后 CodePipeline 接手,先部署到测试环境,跑集成测试,通过后再部署到预发布和生产。整个流程大约 20 分钟,全程零人工介入。

GitHub Actions vs CodePipeline:我的选择

这两个工具有重叠,但适用场景不同,我来说说我的体会。

GitHub Actions 更轻,直接在 repository 里配置 workflow,天生和 GitHub 深度整合。如果你的整个工作流都在 GitHub 生态里(代码、issue、PR、release),用 Actions 很顺手。我们用它来做本地验证、单元测试、代码风格检查这些快速反馈。

CodePipeline 是 AWS 的托管 CI/CD 服务,优势在于和其他 AWS 服务无缝连接。CodeBuild 可以在 Docker 容器里跑构建,CodeDeploy 可以直接部署到 EC2、ECS、Lambda,CloudFormation 可以自动更新基础设施。如果你的应用需要复杂的多环境部署、跨账户部署、或者需要 Blue/Green 发布策略,CodePipeline 就显得很强大。

我们最后的决策是:GitHub Actions 负责快速反馈和初步验证,CodePipeline 负责多环境编排和正式发布。这样既保留了 GitHub 原生工作流的便利,又借助 CodePipeline 的强大编排能力。

容器化部署的转变

以前我们部署应用,经常遇到"在我的机器上能跑"这个老问题。有时候本地 Python 版本是 3.8,测试环境是 3.9,生产环境又是 3.10,依赖库的版本也不一样……每次上线前都得额外验证。还有一个隐藏的坑:某个环境装了旧版本的依赖包,跑的还是老代码,但没人发现。

容器彻底解决了这个问题。我们把应用打成 Docker 镜像,环境就冻结了——本地、测试、生产用的镜像完全一样,只是配置参数不同。这是 DevOps 理想中的"build once, run everywhere"。

Artifact 和 Cache:CodePipeline 的隐形优化

这里我想细说一个很多人忽视的点。CodePipeline 在各个 stage 之间传递的是 artifact(通常是压缩包),这些文件都存在 S3 里。第一次看到账单时我有点吓到:这些 artifact 占了不少空间,而且每次部署都要从 S3 读写一遍。

后来我发现,CodeBuild 有个 Docker layer caching 机制。简单说就是:构建 Docker 镜像时,如果某一层的内容没变,就直接用上次构建缓存的层,不用重新 build。这能把构建时间从十几分钟降到几分钟,成本也下降 50-70%。不过要启用这个功能需要在 buildspec.yml 里配置 cache 模式,而且 CodeBuild 需要有权限访问 S3(存放缓存)。

我们的做法是给 CodeBuild project 配置 S3 本地缓存,指定要缓存哪些目录。比如 node_modules 和 pip packages,这两个目录通常最大,缓存效果最明显。这样一来,如果只改了应用代码,依赖没变,构建就能直接用缓存,速度快得多。

ECS 的滚动更新和版本一致性

现在的流程是这样的:

  1. 开发提交代码到 GitHub
  2. Actions 自动构建镜像,跑单元测试(直接在容器里)
  3. 镜像推送到 ECR
  4. CodePipeline 从 ECR 拉镜像,部署到 ECS(AWS 的容器编排服务)
  5. ECS 基于任务定义启动容器,自动处理负载均衡、健康检查、自动扩缩容

这里的妙处在于,你不需要再手工登到服务器 scp 文件或 git pull。整个部署都是声明式的:我在代码里定义好"我需要 2 个副本、每个副本分配 512MB 内存",ECS 会自动满足这个声明,还会监控容器健康状态,挂掉的自动重启。

更有意思的是,ECS 的滚动更新机制。传统部署通常是"停止旧容器,启动新容器",这会导致短暂的服务不可用。ECS 不一样,它用 minimumHealthyPercentmaximumPercent 这两个参数来控制:

  • minimumHealthyPercent 保证在更新过程中,至少有 X% 的任务在运行(比如设成 100%,就是不能一个都停,得新旧并行)
  • maximumPercent 则允许暂时超过目标副本数(比如设成 150%,部署时可以最多跑 3 个副本——2 个旧的 + 1 个新的)

这样新旧版本并行跑一段时间,新版本没问题再杀掉旧的。整个过程应用一直在线,用户无感知。还有个更强的特性叫"版本一致性"——ECS 会自动把镜像 tag(比如 "latest")解析成不可变的 SHA256 digest,确保一次部署里的所有任务用的镜像完全一致,不会出现"有的任务用新镜像有的用旧镜像"这种诡异情况。

ECR 的镜像清理

Docker 镜像存在 ECR 里,不清理的话会逐月累积。我们一开始没在意,结果三个月下来 ECR 里堆了几百个镜像,存储费用变多了。后来我们配置了 ECR 的生命周期策略,自动删除超过 30 天的旧镜像(除了标记为"latest"的)。这是个很小的配置,却能显著降低成本,尤其是频繁发布的应用。

GitOps 的新思路

最近我们又接触了 GitOps 这个概念,简单说就是:Git 仓库是唯一的真实来源。不仅代码在 Git 里,基础设施配置、部署配置也都在 Git 里。你想改什么,就改 YAML 文件,提交 PR,合并后自动生效。

我们用的是 ArgoCD,一个 Kubernetes 的 GitOps 工具。它的原理是:你在 Git 仓库维护 Kubernetes manifests(deployment、service 等资源定义),ArgoCD 持续监听这个仓库,一旦发现不一致(比如有人直接 kubectl apply 了新的 yaml),ArgoCD 就把集群拉回到 Git 定义的状态。

这听起来像是"过度工程",但在多人协作的场景里特别有用。为什么?因为部署历史完全透明:谁改了什么、什么时候改的、为什么改的,全在 Git commit 里。需要回滚?checkout 到上一个 commit 就行。需要审查部署?PR review 就能搞定,不用登服务器查看。

成本的隐形杀手

我想特别提醒一点:用云计算做 CI/CD,成本往往是隐形的。

比如 CodeBuild,按构建时间计费,用的计算资源越多越贵。我们一开始没注意,给每个构建分配 4GB 内存的环境,结果账单一个月就几千块。后来改成 1GB 内存(对于大多数应用构建是够的),账单立即下降。另外,Docker 镜像也要存储在 ECR,虽然不贵,但如果你不定期清理旧镜像,几个月下来也是钱。

GitHub Actions 是按分钟计费的,但如果你用的是自己的 runner(不用 GitHub 的托管 runner),成本会低很多,尤其是高频构建的场景。

还有一个隐藏成本:数据传输。如果你的镜像库和应用集群不在同一个区域,每次拉镜像都要跨区域传输,这会产生传输费。我们的做法是用 ECR 跨区域复制,把镜像在多个区域保持副本,这样每个区域的部署都从本区域的 ECR 拉镜像。

小建议

如果你也在考虑改造 CI/CD 流程,我的建议是:

不要一步到位。先从 GitHub Actions 开始,把基本的构建和测试自动化起来,这个成本很低。等到你真正需要复杂的多环境编排、跨账户部署时,再引入 CodePipeline。如果用 Kubernetes,GitOps(比如 ArgoCD)能大大提高可维护性。

监控成本。云平台的便利会诱使你消费更多资源。建立成本告警,定期审查账单,看哪些资源闲置了、哪些流程太冗长了。

保留本地调试能力。即便有了自动化 pipeline,开发还是需要在本地快速迭代。确保 Dockerfile、测试命令、部署脚本都能在本地跑通,这样开发的反馈循环才够快。

最后一个感受:CI/CD 和云计算的结合,不是简单地把旧流程搬到新平台,而是一次思想的升级。从"我如何手动部署"到"我如何声明期望状态让系统自动满足",这个转变会让你的运维工作轻松很多。


公众号:耕云躬行录

个人博客:躬行笔记

关注我们,一起探索云计算和运维的有趣之处~

文章目录

博主介绍

热爱技术的云计算运维工程师,Python全栈工程师,分享开发经验与生活感悟。
欢迎关注我的微信公众号@运维躬行录,领取海量学习资料

微信二维码