网易CI/CD实践(中):CD系统的部署架构与发布流程

2020 年 10 月 16 日

网易CI/CD实践(中):CD系统的部署架构与发布流程

上一篇文章中,我们主要介绍了网易轻舟的 CI 建设实践,在本文中,我们将主要来讲解网易轻舟的 CD 建设实践。

云原生时代,容器技术是实现云原生架构的基础,而 Kubernetes 是容器编排的事实标准。网易轻舟 CI/CD 容器部署系统的架构设计参考了 CNCF 应用兴趣小组提出的云原生应用交付模型,以 Kubernetes 作为底层基础设施平台,将应用的交付分为应用定义、应用发布与应用工作负载管理、自动化运维三个主题。

网易轻舟 CI/CD 容器部署系统是完全基于云原生技术实现的,通过 Kubernetes 的声明式特性,保证系统极强的容错性;使用部署模板的方式来简化应用的定义,在应用发布环节,支持多种发布策略,包括蓝绿发布、灰度发布、自定义分组等;利用 Kubernetes 控制器来控制发布流程,这不仅是 Kubernetes 实现“容器编排”的核心机制,同时也是一种编程范式。在 Kubernetes 中,通过自定义资源(CRD)可以定义满足用户需求的资源对象,并且通过控制器模式来驱动系统状态逐步向 CRD 中定义的期望状态逼近,这样能很好的保证应用交付的效率和准确性。

网易轻舟的 CD 建设实践

众所周知,“CD”其实是包含两层意思,持续交付及持续部署。持续交付指的是所有变更可以部署到生产环境中,但是出于业务安全考虑,部署操作仍需由运维人员手工部署到生产环境。持续部署则是在持续交付的基础上,将新版本直接自动化部署到生产环境的过程。持续交付和持续部署的区别在于部署操作自动化。

如果想实现持续部署,将代码版本直接生效到生产环境,主要依赖的是测试自动化以及自动化发布流程。网易轻舟团队实现了一个渐进式的发布流程,在整个流程执行过程中,通过扩展机制在容器发布过程中运行自动化测试来完成新版本的验证操作,并通过结果反馈来决定是否可以继续。在新版本还未完全生效到线上的时候就进行自动化验证,一旦新版本验证出现问题,可以快速回滚,不至于大面积影响线上用户。通过这个渐进式的发布流程模型,将测试自动化和自动化发布流程结合在一起,从而实现了持续集成。

接下来,我们介绍一下网易轻舟 CI/CD 容器部署系统的部署架构、应用定义、发布流程、发布策略等。

部署架构

网易轻舟 CI/CD 容器部署系统的整体部署架构主要分为管控集群和业务集群,这两个集群可以是同一个 Kubernetes 集群,也可以是部署在不同的 Kubernetes 集群中,并且可以支持多个不同的业务集群的容器部署。

网易轻舟 CI/CD 容器部署系统支持多云多集群的容器部署。管控集群与业务集群之间采用 Agent 进行安全可靠的双向通信。在管控集群,数据存储主要以 Kubernetes 自定义资源存储在 etcd 中,同时使用 Kubernetes 中广为流传的控制器模式,根据自定义资源中声明的容器规格,服务暴露方式等配置信息,通过一个发布流程生效到到相对应的业务集群。

上图为网易轻舟 CI/CD 容器部署系统,其中比较重要的组件是 API 层、管控集群 Operator、业务集群 Operator。

  • API 层:用户通过界面创建的应用工作负载配置、服务访问方式、发布策略、发布环境等信息,通过 API 层将数据以自定义资源的形式存放在 etcd 中。
  • 管控集群 Operator:主要包含了多个控制器。这些控制器主要负责监听各自关心的资源(CR)的创建或者修改,并由此判断是否需要进行发布操作,以及发布流程的启动和继续等。
  • 业务集群 Operator:主要包含了执行控制器(execution_controller),execution_controller 中会根据 ExecutionCRD 的定义来完成在本集群中需要执行的工作负载创建与更新操作。ExecutionCRD 的设计是为了实现对一个发布操作的抽象,可以定义工作负载的创建更新、副本数更新、流量切换等操作。

应用定义

在应用交付过程中,我们常会提到“应用”,但是你真的清楚一个应用到底都包含哪些内容吗?

在 K8s 中,Deployment 用于声明工作负载,Service、Ingress 用于统一访问入口,ConfigMap、Secret 可能用于声明程序配置项或者环境变量。一个应用的部署可能会包含上述多种 K8s 资源,但是在 K8s 中并没有“应用”这一层抽象。所以,在这里,我们认为“应用”的定义应该是希望能够把一个完整应用程序要部署的所有资源聚合起来,统一管理,统一部署。同时还提出了"应用模板"的概念,部署模板用于声明应用整体部署框架,具体的镜像、副本数、端口等参数,根据部署环境而决定的。

实际上,应用的定义可以对标 CNCF 云原生应用交付模型的 Topic1,当配置发生变化的时候,就会生成一个新的版本,每当有新版本生成,都会根据发布策略产生一个新的发布流程。这个自动化发布流程对应了 CNCF 的 Topic2。目前 Topic3 工作负载实际上还是利用了 K8s 原生的 Deployment、StatefulSet、Deamonset,可能后面也会存在对这些资源进行扩展的需求。

发布流程

网易轻舟 CI/CD 容器部署系统的发布流程是一条多阶段串行执行的工作流。根据 DeploymentCRD 定义变化(比如 Deployment 的镜像改变了),会根据发布策略产生一个 Upgrade 自定义资源(发布流程的资源抽象)。只有当一个阶段的任务全部全部完成之后,才能够进行下一个阶段。并且用户可以自定义在阶段结束之后,是直接自动继续下一个阶段,还是需要手动点击「继续」才能进行下一个阶段。在每一个阶段中,可以定义多个并行的指令,只有当所有指令都完成了,就表示阶段完成。

为了更好地支持流程的扩展,网易轻舟团队在阶段前后增加了钩子功能,在阶段开始执行之前和阶段执行完成执行钩子所定义的内容,可以是一个外部调用,也可以执行一些具体的命令。

这个钩子功能的主要使用场景:

  • 与自动化测试平台的集成:在一个阶段执行完成之后,通过接口调用触发自动化测试平台的验证,然后在下一个阶段开始之前轮询调用验证结果,如果验证通过便可以进入下一个阶段的流程,这就是实现持续部署的方式;
  • 金丝雀发布:定义指标阈值,每个阶段发布完成之后,查询指标是否处于健康状态,如果处于健康状态,可以通过并自动继续下一阶段;
  • 与服务网格(ServiceMesh)对接,实现灰度发布流量的精准控制:可以通过修改服务网格的相关流量配置,实现在发布流程不同版本之间精准的流量控制;

发布策略

目前,轻舟 CI/CD 容器部署系统已经集成了多种发布策略,包括 Kubernetes 原生的滚动更新,蓝绿发布,灰度发布以及自定义分组发布。轻舟 CI/CD 容器部署系统设计发布流程的初衷就是为了支持多种不同的发布策略,使用统一的发布流程来控制版本升级。

K8s 原生滚动更新

如果选择了 K8s 原生滚动更新的模式,整个发布流程只有一个阶段,这个阶段就是将用户定义的 PodSpec 以及滚动更新的策略更新到业务集群的 Deployment。之前其它的事情都可以全部交给 K8s 的 DeploymentController 完成,直到 Deployment 更新完成之后,流程结束。

灰度发布,自定义分组发布

在 K8s 原生的滚动更新策略的实现逻辑中,通过 MaxSurge 和 MaxUnavailable 来控制每次更新的比例或者数量,但是整个更新的过程是无法暂停的,而在真实的使用场景下,用户往往会选择对线上升级采用灰度发布的方式。

灰度发布是为了保证新版本应用能够平滑过渡的一种方式,让一部分的用户优先使用新版本应用,另外一部分的用户仍旧使用老版本的应用。但这样的场景,使用原生的 Deployment 滚动更新是无法完成的。

而 Upgrade 就是用来满足上面的场景,将不同版本对应到不同的 Deployment,通过新版本 Deployment 的扩容以及老版本 Deployment 的缩容,逐步地将新版本 Deployment 的副本数扩容到指定副本数,老版本 Deployment 的副本数缩容到 0。同时,在这整个发布过程中,Service 上的 SelectorLabel 会同时选中两个 Deployment 的 Pod。

假设有一个 10 的副本数的 Deployment,它的自定义分组的策略定义为:

复制代码
strategy:
type: Custom
custom: # 可选的,type=Custom 的时候生效
betaStageEnabled: false # 不开启 beta 阶段
percentageList: [50, 100] # 每个元素对应每个阶段的副本更新比例

那么对应的整个发布流程的副本数变化如下所示(min 表示最小的可用副本数,max 表示最大的可用副本数):

Deployment Init Stage1 Stage2
v1 10 max: 5 max:0
v2 0 min:5 min:10

蓝绿发布

在 Kubernetes 中实现蓝绿发布的主要方式是通过修改 Service 的 SelectorLabel,让 Service 选到新版本的 Pod。因此蓝绿发布的整个流程实际上可以分为三步骤:

  1. 部署新版本的工作负载,在 Pod 上打上新版本的标签(比如 cicd.skiff.netese.com/revision: v2);
  2. 更新 Service 的 SelectorLabel,使用新版本的标签 cicd.skiff.netese.com/revision: v2;
  3. 回归新版本,如果没有问题,将 v1 版本的 Deployment 缩为 0;

上面三个步骤实际上就直接对应了 Upgrade 中的三个阶段,并且每个阶段结束后,系统默认都会暂停,便于用户进行回归验证,验证通过之后再进入到下个阶段。通过上述流程,可以实现蓝绿发布的自动化。

流程监控

流程监控的主要工作是负责监控所有正在进行的流程状态,主要用于通知和告警。一般情况下,运维人员在操作上线流程的时候,希望收到告警通知:

  • 当发布流程暂停时;
  • 当流程暂停超过一定的时间时;
  • 发布流程中出现错误事件(资源不足,镜像拉取失败);
  • 发布完成,可以作为 webhook 对接其他系统;

发布流程监控同样是采用了 CRD+ 控制器的模式,当采集到符合条件的流程状态的时候,以标准的 HTTP 方式和统一的请求格式调用预先定义好的服务。目前,流程监控已经被用于对接告警和指标度量平台。

相关阅读:

网易 CI/CD 实践(上):CI 系统的技术选型与部署流程

采访嘉宾简介:

汪灿丰,网易杭州研究院高级产品开发工程师,专注于云原生以及 DevOps 领域,目前主要负责网易轻舟 CICD 的研发工作。

梅光辉,网易杭研究院高级服务端开发工程师,目前主要负责网易轻舟 CICD 研发工作,在云原生以及容器 DevOps 领域有过深入的研究和实践。

2020 年 10 月 16 日 11:09 2
用户头像
田晓旭 InfoQ 编辑

发布了 356 篇内容, 共 174.0 次阅读, 收获喜欢 995 次。

关注

评论

发布
暂无评论
发现更多内容

重学JavaScript01:就从面向对象说起吧

张理查rootv

JVM详解之:类的加载链接和初始化

程序那些事

Java JVM GC 加载

敏捷教练和Scrum Master - 敏捷转型中的两个重要角色的对比

Bob Jiang

Scrum 敏捷教练 ScrumMaster

Python 多进程之间共享变量

AlwaysBeta

Python 进程

基于 opentracing + Jaeger 实现全链路追踪 ----理论部分

是老郭啊

golang 全链路监控 OpenTracing Jaeger

极客时间 - 架构师培训 - 9 期作业

Damon

第九章作业

武鹏

ARTS Week10

时之虫

ARTS 打卡计划

F5G+X:给5G一个伙伴,给千行百业一个拥抱

脑极体

LeetCode题解:70. 爬楼梯,递归+哈希表,JavaScript,详细注释

Lee Chen

LeetCode 前端进阶训练营

RRedis系列(八):缓存到底该如何做到高可用?

z小赵

redis 分布式系统 高并发系统设计

速览国内主要银行区块链技术应用现状

CECBC区块链专委会

应用落地 区块链+金融 信任 部署与维护

nginx配置文件

张明森

无意中参加了infoQ的一期活动,获得了所有奖项,哈哈哈。。。

诸葛小猿

InfoQ 奖品

Docker 网络

北漂码农有话说

Docker

你该知道的Docker-compose

北漂码农有话说

图解+代码|常见限流算法以及限流在单机分布式场景下的思考

yes的练级攻略

分布式限流 单体限流 限流算法

第九周作业

赵龙

架构师训练营第九周作业

张明森

谈谈敏捷中的那些模式

Bob Jiang

敏捷 敏捷开发 敏捷教练

复杂事件处理简介

星际行者

分布式 流计算 CEP 复杂事件处理

LeetCode题解:70. 爬楼梯,DP遍历数组,JavaScript,详细注释

Lee Chen

LeetCode 前端进阶训练营

Dockerfile你值得拥有

北漂码农有话说

Docker

Scrum Master是否需要懂技术

Bob Jiang

敏捷 敏捷开发 敏捷教练 ScrumMaster

入门WebGL,看这一篇就够了

一颗大橄榄

前端 WebGL

区块链行业发展月度新动态

CECBC区块链专委会

产业落地 政策扶持 差混高新技术 应用场景广泛

JVM垃圾回收

羽球

刘华:事实证明,假敏捷都比瀑布优秀

刘华Kenneth

DevOps 敏捷 软件开发

稳定匹配:幸福不靠等,脱单要主动

KAMI

生活 算法 方法论

这是我迄今为止读过的最有价值的技术书,却一行代码都没有

双儿么么哒

第九周学习总结

赵龙

网易CI/CD实践(中):CD系统的部署架构与发布流程-InfoQ