基于 Kubernetes 的发布系统设计
背景介绍
在我们之前将服务迁移部署到 Kubernetes 集群的工作中,主要是通过描述 .gitlab-ci.yml 文件来实现 CI/CD 的流程。通过这个流程,我们可以完成代码更新之后的单元测试、lint、编译、镜像打包以及发布等工作。
但是,当服务部署到 Kubernetes 集群之后,每个服务都需要在 GitLab 仓库维护一份 deployment 模板来进行服务新版本的发布上线,每次的 deploy 过程是将一些发布参数结合 deployment 模板生成发布所需的deployment.yml 文件,然后通过 kubectl 命令发布到 Kubernetes 集群中。但是该种方案存在以下缺点:
- 每个服务各自维护一份 deployment 模板,具有一定的管理复杂度
- 缺少统一的发布历史记录管理,不利于问题排查和回溯
- 缺少有效的权限控制,存在一定风险
为了解决以上问题,我们将 CI/CD 的流程发布工作抽取出来,设计了一套基于 Kubernetes 的发布系统来完成服务发布发布工作。
发布系统基本功能
我们设计的发布系统具有一下基本功能:
- 以服务为粒度完成发布功能
- 发布记录展示
- 每条发布记录可以查询发布的详细过程
- 针对每条发布记录可以进行快速回滚操作
- 发布结果通知,支持邮件和钉钉进行通知
- 部分服务支持灰度发布
发布流程总览
发布系统在进行发布操作之前,需要完成前置的 CI 流程,具体操作为:
- 在 GitLab 中有代码更新时,我们可以设置一定的 CI 规则触发流水线
- Gitlab-ci 会进行代码的拉取,并完成单元测试、lint、代码编译和镜像构建等操作
- 完成镜像构建后,将带有版本信息的 Docker 镜像上传到 Docker Harbor 中
- 在发布系统进行 Docker 镜像版本信息的录入
在上述工作准备就绪之后,发布系统可以基于每个服务选择对应的版本,生成每一次发布需要的 deployment 文件,然后调用 Kubernetes API server 实现服务的滚动升级。
发布过程详解
基本发布操作
在发布系统中,每一次发布操作都视为一个发布任务,所以需要对某个服务进行升级就需要对这个服务新建一次发布任务,具体需要进行如下操作:
- 选择需要发布的环境(测试环境或正式环境)
- 根据服务名获取镜像列表,并进行版本选取
- 确认发布参数,并填写发布描述
- 提交信息,开始版本的发布任务
在完成发布任务新建之后,每次的发布任务的信息就可以展示出来,除以上填入的信息之外,还包括发布任务的开始时间,发布时长,操作用户,发布描述,发布状态等信息,这样完成每次发布操作的记录,用助于故障的排除和问题回溯。
此外,每个发布任务还支持回滚操作,可以在新版本发布存在问题时,进行版本的快速回滚。对于最近一次的发布任务,可以进行重发操作,该功能主要有以下两个实用场景:
由于外部因素导致发布失败,在外部因素问题解决后需要重新发布
代码的配置信息更新后,需要让 Kubernetes 中的 Pod 更新此配置信息回滚和重发操作本质上还是新建发布任务,是基于每次的发布任务的信息自动地进行了发布参数选择,更加地快速便捷。
发布 deployment 文件生成
deployment 模板中的参数分为以下两类:
基础参数
发布的基础参数包括 Pod 副本数、健康检查路径、组织信息等,可以根据实际情况进行调整,但是调整频率很低。这些参数通过发布配置进行管理,每一个服务都维护了一份发布配置,存储在数据库中,我们可以通过在页面编辑发布配置进行基础参数的修改。此外,发布配置里维护了该服务所采用的发布模板信息。
对于基础参数的调整,相比于新建发布任务具有更高的权限
发布参数
包括服务名、版本号、发布环境、发布方式等。每次发布根据需求进行填写。这些参数在新建发布任务的时候均会确定。
发布系统每次发布时结合基础模板和以上参数值生成一份本次发布任务所需要的 deployment 文件,然后通过 kubectl apply 调用 Kubernetes 的 API server 进行对应服务的滚动升级。
deployment 模板管理
在我们的实践中,服务是具有共性的,针对一类服务抽象出 deployment 发布模板,然后多个服务可以共用一个发布模板,大大减小了管理成本。目前发布采用的 deployment 模板存储在 GitLab 中,模板的管理与使用方式如下:
- 模板新增通过提交 Merge Request 完成
- GitLab 中的模板文件有新增时,GitLab Pipeline 会被触发向发布系统中同步 deployment 模板信息
- 模板在发布系统中有记录,模板 ID 作为唯一标识
- 每个服务在发布配置中对应一个发布模板 ID
- 新建发布任务时,发布系统会根据发布配置中的模板 ID 获取存对应模板文件的 url,并将内容下载下来
Kubernetes 发布过程跟踪与结果记录
由于 Kubernetes 在进行版本更新时,是通过定义声明式 deployment 文件并进行异步调用的方式实现的。在调用 kubectl apply 之后并无法确定对应的 Pod 是否可以正确地完成滚动更新。所以我们采用命令 kubectl rollout status deployment $deployment_name 来进行发布过程的跟踪,此处变量 deployment_name 与我们的服务为一一对应的关系。
发布过程跟踪的信息可以在每条发布任务的详情中进行查看,此处记录了 Pod 滚动更新的详细过程。
发布的 Pod 成功更新时,kubectl rollout status deployment $deployment_name 会成功退出,发布系统会判定发布任务成功。如果,新版本的 Pod 由于某些原因在滚动更新的过程中一直被阻塞住,在超过发布系统中所设置的超时时间后即判定发布任务失败。
对于发布失败的任务,目前支持简单的 Pod 日志查看,主要原理是对发布过程中 status 不为 Running 和 Terminating 的 Pod 进行日志查询,这样就可以对发布任务失败进行问题定位。效果如下: