浅谈 CI/CD for kubernetes
生产环境如果准备上 kubernetes,那么必然绕不开如何高效进行 CI/CD 集成的话题。本文拟探讨常见的一些流程和方法,仅供参考。
本文不涉及到 CI/CD on kubernetes, 这是另一个话题,因为 prow 还不支持 gitlab, webhook的管理也略繁琐,暂时还没有进行研究。
最常见的 kubernetes 上的 app 发布方式
- kubectl apply -f app.yaml
- kubectl apply -k ./app
- helm template <app-name> ./app --set vaules.tag.name=tag -n <namespace> > app.yaml && kubectl apply -f app.yaml
- helm install <app-name> ./app --set vaules.tag.name=tag -n <namespace>
以上几种方式需要思虑的问题:
-
是否需要把每次发布的版本 tag 记录到 yaml 文件中。
-
项目的 kubectl manifest 或 helm chart 文件需要放到 git 仓库中管理,大多数的参数很少变动,每次发布变化的主要是容器的 tag 名。
-
每次发布的容器镜像 tag 不一样,如何优雅的进行修改。
修改 yaml 文件的常见方式:
- python 脚本修改 kubectl 的 yaml 文件
- python 脚本修改 helm chart 文件
- helm 使用变量来修改 tag ,修改后保存为 yaml,之后再由 kubectl 来发布。
- helm 使用变量来修改 tag ,helm install 部署,不涉及到文件的修改
以上方式各有千秋,前面三个方法比较符合 GitOps 的设计。具体大家可以根据实际的业务需求来定。
最常见的 GitOps CI 流水线
git push --> code repo --> unit test --> build package --> build image --> push artifact --> push image --> push deploy repo
代码提交到仓库后,CI 系统进行单元测试、代码编译、镜像制作、推送二进制文件到制品库、推送容器镜像到镜像库。
最后一步:将本项目本次编译的容器镜像 tag 更新到项目发布的 helm 或 kubectl manifest 发布仓库。
最后这一个步骤,是 GitOps 必要的步骤,不过由于实际开发和部署过程中,每次提交代码直接上线的情况不一定符合业务需求。通常的情况下可以把最后这一步再拆开若干步骤,并且由人工来触发。后文将进一步描述拆解的过程。
举例说明:
研发人员提交了一个 golang 的项目代码到 git 仓库,gitlab 的 custom hook 自动触发, gitlab 的钩子依次进行如下的逻辑处理:
- 判断此 group 是否需要进行CI 集成
- 检测 jeninks 是否有此项目,没有则从模板项目复制
- 触发 jenkins 编译项目
jenkins 编译进行如下处理 - 单元测试
- 二进制编译,go build, mvn package, npm build,
- docker 容器镜像制作
- 发布二进制文件到制品库,例如 mvn deploy
- 发布docker 容器镜像到镜像仓库,例如 harbor 、 quay、 nexus
- 将 容器tag 更新到另一个仓库中,此仓库专门只保存 helm 或 kubectl 的 yaml 文件。(这一步不一定要通过自动实现,下文详述)
细节
- 每个项目的 git commit-id 对应唯一的 镜像tag,格式为 gittag-YYYYMMDD-commit,这样可以让提交排序,便于后续操作
- 在镜像制作的时候,尽可能最大化的利用多层的结构,针对每个开发语言都有相应的方法
基于 GitOps 的持续发布
采用 ArgoCD 、 Fluxcd、 Jenkins-X 等工具,自动或手动检测目标 git 发布仓库的代码,如果发现有变更,则自动进行发布。
如何进行多环境的发布
常见的环境有开发环境、测试环境、预发布环境、正式环境等,每个环境有不同的用途,发布的版本、分支一般也不尽相同。
如果按照上文的描述,kubectl yaml文件里面的镜像版本tag信息,需要思考与现有的流程如何整合。
可选的方式: 每个环境创建一个用来发布的git仓库,一个git仓库里面可以分目录来保存多个应用的发布信息。(或者一个git发布仓库只有一个应用,个人更倾向于前者,这样不至于管理太多的发布仓库)
自动化 CD 流程
开发环境,通过自动(gitlab custom hook)或手动触发,开发环境的jenkins 自动拉取项目的 dev 分支,获取 git commit-id,根据算法得到 容器 tag,再修改 yaml 文件中的 tag 名,通过 kubectl 或 helm 进行发布。
测试环境,通过自动(gitlab custom hook)或手动触发,测试环境的jenkins 自动拉取项目的 test 分支,获取 git commit-id,根据算法得到 容器 tag,再修改yaml文件中的 tag 名,通过 kubectl 或 helm 进行发布。
手动 CD 流程:
- jenkins 发布时,通过 registry v2 的接口,获取该容器镜像最新的20个 tag 列表,用户选择相应的 tag 后,修改yaml文件中的 tag 名,通过 kubectl 或 helm 进行发布。
- jenkins 发布时,用户选择该项目的 git tag 列表(或分支),或是填写commit-id,根据算法得到 容器 tag,再修改yaml文件中的 tag 名,通过 kubectl 或 helm 进行发布。
更优雅的 GitOPS 流程
以上步骤中,修改好 yaml 的 tag 等相关信息后,提交到每个环境相应的发布仓库,再由 GitOps 系统进行自动或手动进行发布。
缺个流程图,画好了再放上来。