软件开发中,CI/CD 往往也扮演着重要的职责,写再多的代码,最终的目的是变成可交付的产品。全称 Continuous Integration/Continuous Delivery,即持续的集成,持续的交付。集成简单讲就是把代码的构建、打包做好。可以简单做如下拆分:
- 源码管理 (版本控制,权限控制,包管理,开发流程等)
- 构建管理 (即如何 build 程序,最终生成目标文件,或者可执行文件)
- 镜像管理 (可执行文件如何存储,访问权限,版本控制等)
交付简单的说就是程序运行达到了可交付,这里边细节涉及到很多。可以简单拆分为:
- 服务部署 (常见的滚动部署、蓝绿部署)
- 容错能力 (回滚,数据安全,可移植)
- 可追溯
基于 AWS 的 ECS CI 流
几乎每个技术栈都有自己的 CI/CD 流程和相应的技术方案,也都有相应的包管理工具;各个云服务厂商都会针对 CI/CD 做一些定制的产品。我自己比较熟悉的是 AWS 的 ECS 工作流。与 ECS 对应还有 EKS,这个我不熟悉。所以本篇重点讨论 ECS。
ECS (Elastic Compute Service) 通常被认为是某种云服务产品,提供可伸缩的计算能力。但厂商一般会给其中集成很多自家产品。当开发团队比较大的时候,可以考虑使用 ECS。如果你使用的是 AWS ECS,而且底层实例选择了 Fargate,一切都比较顺畅:
- AWS Codebuild 进行代码 build,Codebuild 可以实现三方 Git仓库的授权,从而把代码接入其中。
- AWS ECR (Elastic Container Registry),Codebuild 后的产物(一般是一个 Docker 镜像)需要找个地方存储,方便访问,ECR 就是这个镜像的存储仓库。
- AWS IAM,使用 Codebuild 和 ECR 来进行代码构建和镜像存储很方便,AWS 都有相应的文档,和构建脚本供参考,很快就能完成,唯一需要注意的是 IAM 角色管理,Codebuild 过程如果需要访问 ECR,就需要给 Codebuild 一个 Role 角色,给这个角色附加一个能访问 ECR 的策略,就可以实现用脚本实现自动化的 Docker 镜像部署。
镜像准备好后,就可以开始启动实例,运行这个镜像了,通常都是从创建一个 ECS 集群开始:
- 在 ECS 创建集群,选择启动的实例类型(实例指具体执行计算的硬件类型),AWS 提供了两种,分别是 EC2 和 Fargate。如果使用 Fargate 一切都很顺畅。
- 创建任务定义 task,任务定义是服务运行的上下文,这里可以指向一个 ECR 镜像实例,定义一些系统级别的环境变量,设置安全组,网络等,在这里可以指定部署的规则(滚动部署,还是蓝绿部署)。
- 使用刚才创建好的任务定义创建服务,开始执行任务。这里可以指定负载均衡器,具体的启动实例,目标组等。
一切就绪后,接下里就轻松了,如果有新的代码功能提交,直接在 AWS 上点击构建,构建完成后,再创建一个新的任务定义,更新服务,done。
决定迁移到阿里云的 ECS
我之前一直在 AWS 上使用 Fargate 做为启动实例,后来我发现 Fargate 的费用太高,想切到 EC2 上,毕竟 EC2 是有免费套餐的,虽然 1cpu 1G 内存。结果并没有想象的简单。
我的后端服务一直使用 AWS 的 Appconfig 进行服务配置,很多配置信息(例如订单过期时间,支付密钥等),只需要更改 Appconfig 的配置,无需重启服务。
再迁移到 EC2 实例后,才意识到,EC2 上默认不能使用 Appconfig,需要自己安装 Appconfig Agent,不仅如此。Appconfig Agent 对 Linux 的内核最低版本有要求,我看了下基本大部分的低配 EC2 都不可用。我只好改代码,不使用 Appconfig 服务。但是还没完,部署后发现,EC2 默认不能使用其他的邮件服务(出站的SMTP 端口被限流,可是我的出站规则没有任何限制),原因是防止垃圾邮件。解决办法,一,使用 AWS 的 SES 邮件服务;二,给官方发邮件,填声明,放开 25 端口的限制。
所以我决定迁移到阿里云上。
回到解放前的手动部署,并不是坏事
我突然意识到,我一个人开发,根本就不需要做那么多的 CI/CD 配置,直接使用最原始的部署方式就是最高效的。
- 在阿里云的 ECS 上启动一个 Docker 私有镜像库(使用官方的 Registry 镜像)。
- 本地电脑 build 好镜像,然后把镜像 push 到服务器上,需要注意,如果你本地的 CPU 架构(例如 M1 Chip)和服务器的不一致,构建 docker 镜像的时候需要指定平台指令:
docker build --platform linux/amd64 -t go-server:1.0.2 .
- 创建一个
docker-compose.yml
管理容器实例,然后docker-compose -d up
。done。
整个事情在 1 天就可以完成,并且后续的部署也很方便(对个人来讲),这件事,给我的启发:很多时候我们都是在为了使用某个技术而使用这个技术,但实际它不一定适合当前的业务。