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

2020 年 10 月 10 日

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

云计算的普及,不仅改变了目前的 IT 基础设施与企业系统架构,同时也改变了技术团队的组织架构和企业内部的研发流程。而持续集成(CI)和持续交付(CD)就是企业内部研发流程提升交付效率的关键。

CI/CD 的核心价值是效能与质量。效能提升的关键在于自动化,它包含了两个方面:一是整个软件研发流程自动化,降低人力成本;二是 CI/CD 平台在业务接入、资源管理、线上支持、问题排查等诸多方面实现自动化,从而减少技术支撑方面的成本。而质量保障,一方面是研发质量,需要提供相应的质量检查与测试工具;另一方面是过程质量,CI/CD 平台需要能够持续采集研发流程中的指标数据(如交付频率、交付周期、交付成功率),建立起一个完善的质量度量体系。

目前各大公司的 CI/CD 平台,在工具选型、落地实现等方面各有不同,此次 InfoQ 采访到了网易杭州研究院高级产品开发工程师汪灿丰和高级服务端开发工程师梅光辉,他们分享了网易轻舟在 CI/CD 方面的实践。由于干货内容太多,我们将这次实践分为了上中下三篇内容,分别介绍网易的 CI 实践、CD 实践、测试自动化及 API 版本管理。

网易 CI/CD 实践的背景

据了解,网易的大部分互联网产品业务团队都是使用统一的平台来进行 CI/CD 实践,目前平台上运行着数万个仓库,活跃仓库近万个,同时平台内还有大量副本数超过数千个的服务,这些服务每天承载着业务方大量的访问。

为了适应业务发展的节奏,网易内部广泛推行了敏捷开发,每天通过平台发布应用的次数达到数万次,产品迭代节奏快,交付周期短。所有业务使用统一的平台进行 CI/CD,无需各自搭建,降低成本,使用统一的规范,避免了相同问题的多次采坑。

网易公司内部的 CI/CD 实践主要是轻舟 CI/CD 平台,该平台提供了可视化的流水线编排界面,一次配置,多次运行,支持团队成员共享配置。每次提交或者合并代码都会自动触发流水线的执行,自动将代码发布到环境上。数据显示 CI/CD 流水线相比传统的手工或脚本方式平均效率提升了 5 倍以上,发布效率提升了 8 倍以上。另外通过整合多种自动化测试工具帮助业务方实现高质量的集成。通过可视化度量平台从多个维度了解构建,部署的相关指标数据,帮助产品提高发布效率。

之前,网易内部有一套从主机部署时代发展过来的自动化部署平台,但是其对容器部署的支持不友好,部署之前需要先在服务器上部署 agent,注册到内部 CMDB,再下发指令执行。这样的执行操作注定了这个平台在大批量部署场景下会存在性能瓶颈。

基于原平台存在的性能问题,以及对业务容器化、微服务化演进的判断,网易研发了新的轻舟 CI/CD 平台,成为了网易云原生技术栈的重要组成部分,满足云原生环境下企业在能效、团队协作效率、产品迭代速度等多方面的需求。

在使用体验上,轻舟 CI/CD 是一体的,但是在系统架构设计方面,其实是分开的。下面,我们就分别来讲讲 CI 和 CD 的系统设计。

网易 CI 实践的整体架构及工具选型

与绝大多数互联网公司一样,网易内部各业务方的持续集成也大都是由研发团队的 QA 负责的,CI 工具选择了比较常用的 Jenkins,同时在流水线的上下游整合了其它的主流 CI 工具。  整个流水线平台依托于 Kubernetes,基于 K8s 的 CRD(自定义资源)重新设计了流水线上层模型,并通过 Operator 驱动流水线执行过程。

当流水线触发一次执行时,将会产生一个 PipelineRun 对象,Operator 将会根据对应的流水线预先定义好的阶段生成对应的 Job,然后通过 Jenkins 的 API 触发 Job 执行。Job 执行完成后,将会通过 Webhook 回调上层服务接口,将状态回写到 PipelineRun 中,然后触发下一个阶段的执行。

网易 CI 系统整体架构

CI 工具选型

传统的持续集成实践本身就很占资源,编译构建对磁盘、CPU,甚至是网络都有一定的要求,如果在高峰期想要保证持续集成任务能够及时运行,通常需要预留大量的构建机资源,这不仅会导致资源浪费,同时也需要更多人力来维护管理,成本会很高。

所以,网易技术团队在进行 CI 工具选型时,就直接圈定了 4 个当前主流的工具,分别是 Travis CI、Circle CI、GitLab CI 和 Jenkins,并详细对比了 4 个工具。

项目名称 开发语言 配置语言 公有云服务 私有部署
Travis CI Ruby YAML 不支持
CircleCI Clojure YAML 不支持
Gitlab CI Ruby YAML 支持
Jenkins Java Groovy 支持

其中,Travis CI、CircleCI 在 Github 开源项目中使用较多,但不支持私有化部署,不适合公司实践;GitLab CI 可以与代码仓库无缝集成,且天然支持 GitOps,但整体生态目前并不成熟,需要自己制作 builder 的镜像,并与 Gitlab 深度绑定;Jenkins 作为传统的 CI 工具,社区和生态都比较完善,Jenkins 2.0 版本提供了 Pipeline as code 的特性,可以将 CI 过程纳入版本管理,支持 GitOps。此外,Jenkins 社区也诞生了 kubernetes-plugin 这样的插件,可以将流水线的执行从传统的物理机转移到容器中,再依托 Kubernetes 强大的调度能力,就可以实现资源的动态调度和编排。

基于以上原因,网易轻舟最终选择了 Jenkins,但是传统的 Jenkins 在系统运维、资源管理、使用方式等方面,存在很多问题。例如,Jenkins 的 master-slave 架构比较经典,但由于诞生时间较早,所有配置和数据都是基于文件存储的(存储在 Jenkins master 节点 home 目录下),修改时,会先更新内存,然后异步写入磁盘,而当底层文件被更新时,Jenkins 并不会自动 reload 更新后的数据,因此,很难做到高可用;Jenkins master 实例对文件目录是独占的,不同 Jenkins 实例也无法共享底层存储…因此,网易技术团队希望能够在传统 Jenkins 版本中做出以下改进:

  • 结合 Docker/Kubernetes 云原生技术栈,解决传统 Jenkins 使用中的痛点;
  • 通过将业内最佳实践固化到产品中,解决易用性的问题,降低用户使用门槛,提高接入效率;
  • 重新设计上层流水线模型,提供更加强大的流水线编排调度能力;
  • 自研流水线底层组件,替代 Jenkins 插件,提供更加灵活的扩展能力,方便与公司内部系统进行集成;
  • 提供丰富的企业级特性(如认证、鉴权、审计、告警、通知等),满足企业客户需求;

除了 Jenkins,网易轻舟在整个流水线的上下游也整合了其它的主流 CI 工具,例如:

  • 代码仓库:支持 Git/SVN,可以适配绝大多数代码托管平台,并且对 Gitlab 做了深度适配,例如,支持从 Gitlab Webhookpayload 中提取各类参数;
  • 代码扫描:集成了 SonarQube,支持了所有主流的编程语言;
  • 单元测试:整合了 Java 中常用的 Jacoco 工具,方便用户在运行单元测试时,生成对应的 UT 和覆盖率报告;
  • 代码编译:Java 支持了 Maven/Gradle,并且内置了 Nexus 私服,方便做内网代理;Node.js 支持了 Npm;Golang 支持了 go mod 缓存加速;
  • 镜像构建:支持 Docker out of Docker、Kaniko 两种构建方式,用户可以根据自身需求选择使用;
  • 镜像仓库:整合了 Harbor,支持 Harbor webhook,并且集成了 Harbor 的镜像扫描和镜像复制功能;
  • 容器部署:支持 kubectl 原生部署、升级,以及轻舟 CI/CD 应用部署等多种部署方式;
  • 自动化测试:支持 Java 语言常用的 TestNG,同时整合了网易内部的 GoAPI 测试平台,支持在流水线中运行指定的接口测试集,并在执行时输出测试报告;
  • 告警通知:集成了邮件发送、短信告警、网易 POPO 等多种通知方式;

据了解,目前国内大部分公司对 Jenkins 的使用方式依然停留在 1.0 的时代,很多人都还在使用 Jenkins 的 UI 配置方式,并没有使用到 Jenkins 2.0 提供的 Pipeline as code 功能,并且在使用场景上,大量依赖一些自定义脚本,这些脚本通常由 QA 同学事先预置在机器上,一旦机器出现宕机或故障,迁移起来成本也很高。相较之下,选择更新版本的 Jenkins,使用更前沿的功能,并适时辅以其它 CI 工具,往往会有更好的效果。

网易 CI 实践的分支管理与协作流程

所有 CI 实践的源头一定是代码变更,好的代码分支管理和版本变更规范是做好 CI 实践的前提。网易轻舟是基于 GitFlow 进行代码管理和协作流程的,主要的阶段包括预发验证、测试验证和代码审查、集成、验证。

网易轻舟 CI 实践中的主要分支有 devlop 和 master,辅助分支包括 feature/*、release/v1.x.0、hotfix/v1.x.1。

  • develop: 集成分支, 不允许 commit/push, 仅允许来自   feature/*  或  hotfix/v*  分支的合并
  • master: 版本分支, 不允许 commit/push, 仅允许来自  release/v*  或  hotfix/v*  分支的合并, 每次接受合并后必须在其上创建 TAG
  • feature/*: 功能分支, 从 develop 派生, 不允许来自 develop 的合并, 合并到 develop 后删除
  • release/v1.x.0: 发版更新验证分支, 从 master 派生, 派生时根据 master 分支 TAG 标记并递第二位版本号命名。不允许 commit/push, 只允许来自 develop 的合并, 合并到 master 之后删除。
  • hotfix/v1.x.1: 补丁更新验证分支, 从   master 派生, 派生时根据 master 分支 TAG 标记并递增第三位版本号命名。允许 commit/push, 不允许 来自 develop 的合并, 合并到 master 后必须再合并到 develop , 合并后删除。

除此之外,关于 TAG,网易轻舟也有一些特定要求:

  • v1.x.0: 发版更新, release/v*  分支合入  master  后, 在  master  分支上创建。
  • v1.x.1: 补丁更新, hotfix/v*  分支合入   master  后, 在  master  分支上创建。
  • 此外,为了保证代码合入的质量,我们也制定了对应的代码 review 原则:
  • 任何代码变更都必须提 mr,不允许直接 push 到 dev/master 等保护分支;
  • 任何变更至少必须有两名团队其他成员 review 过,才能合入 develop、hotfix 分支,只有被团队接受的代码才是团队的代码;

网易 CI 流程的具体步骤

通常,一个持续集成流程会包括以下步骤:代码检出、单元测试、静态扫描、编译、构建、镜像扫描和测试部署。好的持续集成流程一定是面向质量的,所以,在实践过程中除了工具和流程,还需要做好代码质量相关的工作。

对于大部分团队来说,CI 可能是由 QA 维护的,因此在实际使用过程中,会将线下环境的 CI 和线上分离开,线上通常更加注重持续部署,主要由 QA、PE 等角色负责,流程上会简化一些,更加注重运维规范、上线审核。

代码检出:通常需要在流水线中配置代码源、ssh 秘钥以及代码分支等信息,为了优化代码检出性能,CI/CD 流水线会采用的 git 浅拷贝的方式来加速整个过程。

静态扫描:这是流水线至关重要的一环,运行时会将扫描的数据上传至用户预先配置好的 SonarQube 平台,并且通过 SonarQube 的 QualityGate 进行质量卡点,除了 QualityGate,用户还可以自定义一些流水线特有的卡点规则,并且配置通过邮件、网易 popo 等通知执行结果。

单元测试:这是 CI 过程中必不可少的一环,CI/CD 流水线整合了常用的 Jacoco 工具,方便用户在运行单元测试时生成对应的 UT 和覆盖率报告,报告的内容可以在流水线执行详情页查看,同时支持用户设置单元测试通过率、UT 覆盖率卡点,并发送相应的邮件通知。

代码编译:支持大部分主流的编程语言,比如 Java、Node.js、C++、Golang 等,并且针对各类语言做了相应的编译加速方案,支持 Maven、Gradle、C++、Go mod 构建缓存。

镜像构建:支持 Docker out of Docker、Kaniko 等多种构建方式,同时整合了网易轻舟 Harbor,集成了 Harbor 的镜像扫描功能,支持在流水线运行过程中执行镜像扫描、查看镜像安全报告,同时支持安全项卡点以及邮件通知等功能。

集成测试:CI/CD 流水线与网易内部自动化测试平台 GoAPI 做了集成,用户可以预先在平台侧配置好相应的接口执行集,然后在流水线中选择对应的执行集执行,并在流水线详情页中查看执行集的通过率,同时支持卡点以及邮件通知。

流水线触发器:多种触发器,比如定时触发、PollSCM、Webhook 以及流水线串联触发,其中 Webhook 还额外提供了对 Gitlab、Harbor 的支持,支持从 Gtilab、Harbor 的 payload 中提取相关参数,并在流水线阶段中使用。

采访嘉宾简介:

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

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

2020 年 10 月 10 日 10:02 4979
用户头像
田晓旭 InfoQ 编辑

发布了 364 篇内容, 共 176.2 次阅读, 收获喜欢 1020 次。

关注

评论 1 条评论

发布
用户头像
Jenkins multibranch pipeline 😁
2020 年 10 月 18 日 22:08
回复
没有更多评论了
发现更多内容

阿里花500万年薪招天才黑客?官方回应:这种人得交给警察

程序员生活志

黑客 阿里

如何编写可怕的 Java 代码?

武培轩

Java 编程 程序员 后端

架构师训练营第六周学习总结

张明森

百万级别数据Excel导出优化

Throwable

架构设计 springboot

看动画学算法之:排序-冒泡排序

程序那些事

算法 动画 排序算法 轻松学

SpringBoot 入门:02 - 实现 MVC

封不羁

Java spring springboot

如何不写一行代码就做出一款游戏来

Lawliet

Vue 游戏开发 游戏制作 游戏开源 前端进阶训练营

U盘+grub2安装centos8实战

昌安古城

要不要做一个gif动态图玩一下?

诸葛小猿

GIF ScreenToGif 动态图

修炼我们的智慧之眼

Jeff.Spring

认知提升

创业使人成长系列 (3)- 如何取个好名字

石云升

创业 成长 取名

并行流ParallelStream中隐藏的陷阱

Throwable

JAVA stream

ARST Week7

时之虫

ARTS 打卡计划

关于架构的几件小事:架构概述(1)

北风

架构 架构设计 架构师 架构设计原则

工程规约 - maven统一管理

Man

maven DevOps 工程规约

帮助小团队实现大梦想 | Atlassian 云产品免费使用

Atlassian速递

谈谈对分布式事务的一点理解和解决方案

Throwable

分布式 分布式事务 架构设计

如何搭建Hive 环境

Rayjun

大数据 hive

玛雅密码社区不忘初心 共筑未来通证新经济

Geek_116789

大话设计模式 | 4. 装饰模式

Puran

C# 设计模式

如何使用预测性指标衡量敏捷转型的成功?

Atlassian速递

敏捷开发 开发工具 Atlassian Jira

如何在 Go 中写出高效的单元测试

_why先生

go testing slideshare

使用 Generic Webhook Trigger 触发 Jenkins 多分支流水线自动化构建

jerry.mei

DevOps 持续集成 jenkins CI/CD 持续交付

架构师训练营第六周作业

talen

3W字干货深入分析基于Micrometer和Prometheus实现度量和监控的方案

Throwable

Java 监控 Grafana Prometheus springboot

了不起的 Webpack Scope Hoisting 学习指南

pingan8787

JavaScript 前端 webpack

iOS - CollectionViewCell对应不同flow layout的实例

teoking

ios

SpringBoot2.x入门:应用打包与启动

Throwable

springboot

list vs tupple

Leetao

Python 数据结构 Python基础知识

AOP有几种实现方式?

八苦-瞿昙

技术 随笔杂谈 aop 代理 框架

[译] 图说前端-图解 React

梦见君笑

前端 前端框架 React 框架 前端训练

易观A10数据智能峰会

易观A10数据智能峰会

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