一文了解CI/CD的常见问题

2020-12-14 10:07:07 浏览数 (1)

VOL 177

27

2020-11

今天距2021年34天

这是ITester软件测试小栈第177次推文

本文6519字,阅读约需17分钟

一千个人心目中,有一千种DevOps。DevOps最核心的特点,是持续化。CI/CD时代,提倡持续集成和持续交付;而在DevOps时代,软件生命周期的每个阶段都被持续化,因此有了持续计划,持续开发,持续集成,持续测试,持续部署,持续交付和持续监控。

本文主要从持续交集成是什么,为什么要做持续集成,怎么实现持续集成以及什么是持续交付,什么是持续部署,原有的持续集成是怎么样的,持续集成如何优雅落地等方面进行介绍。

持续集成是什么?

持续集成(Continuous Integration)是一种软件开发的实践,即团队开发成员经常集成他们的工作,通常每个成员每天至少集成一次,也就意味着每天可能会发生多次集成。每次集成都通过自动化的构建(包括编译,发布,自动化测试)来验证,从而尽快地发现集成错误。许多团队发现这个过程可以大大减少集成的问题,让团队能够更快的开发内聚的软件。

持续集成的目的,就是让产品可以快速迭代,同时还能保持高质量。它的核心措施是,代码集成到主干之前,必须通过自动化测试。只要有一个测试用例失败,就不能集成。

为什么要做持续集成?

实现持续集成的好处如下:

1.降低风险,由于持续集成不断去构建,编译和测试,可以很早期发现问题,所以修复的代价就少;

2.对系统健康持续检查,减少发布风险带来的问题;

3.减少重复性工作;

4.持续部署,提供可部署单元包;

5.持续交付可供使用的版本;

6.增强团队信心;

怎么实现持续集成?

持续集成一般的做法:

  • 通过svn或其他工具拉取代码;
  • 自动化构建;
  • 自动化编译;
  • 自动化测试;
  • 自动化部署;
  • 自动化发布;
  • 邮件发送通知;

Martin Fowler说过,"持续集成并不能消除Bug,而是让它们非常容易发现和改正。

与持续集成相关的,还有两个概念,分别是持续交付和持续部署。

什么是持续交付?

持续交付(Continuous delivery)指的是,频繁地将软件的新版本,交付给质量团队或者用户,以供评审。如果评审通过,代码就进入生产阶段。

持续交付可以看作持续集成的下一步。它强调的是,不管怎么更新,软件是随时随地可以交付。

持续交付的好处:

  • 快速发布,能够应对业务需求,并更快地实现软件价值;
  • 编码->测试->上线->交付,迭代周期缩短,同时获得迅速反馈;
  • 高质量的软件发布标准,整个交付过程标准化、可重复、可靠;
  • 整个交付过程进度可视化,方便团队人员了解项目成熟度;
  • 更先进的团队协作方式,从需求分析、产品的用户体验到设计、开发、测试、运维等角色密切协作,相比于传统的瀑布式软件团队,更少浪费;

什么是持续部署?

持续部署(continuous deployment)是持续交付的下一步,指的是代码通过评审以后,自动部署到生产环境。

“You build it, you run it”。这是 Amazon 一年可以完成 5000 万次部署,平均每个工程师每天部署超过 50 次的核心秘籍。

持续部署的前提是能自动化完成测试、构建、部署等步骤。持续部署的目标是,代码在任何时刻都是可部署的,可以进入生产阶段。

测试是持续集成流程中重要的一环,也是区别传统的软件开发流程中的一个重要的标志。

为什么要有持续集成测试呢?

  • 可以早点发现bug,这时fix bug代价比较小;
  • 可以平滑产品,提高产品质量;
  • 可以让团队的每个人了解产品的质量状态;
  • 每天都有持续集成测试的报告发布;
  • 开发者对自己提交的代码测试情况有比较清晰的了解;
  • 可以有效地解决QA人手不足的情况;
  • 尽可能地把测试自动化,让持续集成测试系统去执行这些自动化测试的case。

持续集成原有模式如何?

1

工作模式

以前团队工作方式:

  • 打包,等待maven编译打包;
  • 发布测试环境,手动重启服务;
  • 通知测试组测试(发邮件、连环夺命Call等等方式...);
  • 一顿grep查Exception,修复BUG,然后重复上述步骤;
  • 到达特殊的日子时,配合运维部署团队到测试环境手动copy最新版WAR包到生产环境,23点的一瞬间执行一个脚本,时刻盯住脚本运行结果,最后验证;

2

存在的问题

我们可以发现很多问题: 1.编译打包的过程浪费开发资源,一次测试部署正常10到20分钟,那出现问题的情况不计其数;

2.测试长时间怠工,资源利用不充分,处于一人干活多人旁观低绩效状态;

3.研发与测试的沟通方式高成本低效率;

4.BUG反馈方式低效;

5.生产环境得不到有效的管控以及安全保障,人工浪费如果产品或者销售想要给客户演示测试环境,得到的结果可能是测试暂时不可用或者稍微等15到20分钟,是否能计算出他们的心理阴影面积?

3

解决措施

DevOps的中心思想在于提高产品各个阶段的产出效率,减少或者避开团队间的沟通障碍,推动产品的快速迭代,“快速失败”,从而实现持续交付、持续部署。而持续集成只是DevOps中的一个环节,下图清晰描述了CI各个周期活动。

我们可以发现较多优点:

  • 流程全自动化,减少重复性的手工操作;
  • 持续发布测试,时刻保持可发布的产品;
  • 团队、高层对项目、产品的进展清晰可见,把控风险;
  • 资源效率有效利用,流动效率更快;

持续集成如何优化?

1

基本原则

我们要做到持续集成,我们需要:

1.一套持续集成工具,大体可分为云集成与本地化集成系统,云集成比如Travis CI、cloudbees的云集成等,本地化集成主要是开源Jenkins的搭建,如果需要大规模部署Jenkins且有预算可使用Jenkins商业版;

2.自动化测试工具、良好的测试用例编写;

3.版本控制系统,git、gerrit推荐;

4.构建、测试失败反馈机制,邮件、自动化运维(AI...)、日志收集分析系统;

5.一套需求、产品、开发、测试、部署、运维共同使用的敏捷研发管理系统,市场上有阿里云效、腾讯的TAPD等。

2

流程A

根据持续集成的设计,代码从提交到生产,整个过程有以下六步。

①提交

流程的第一步,是开发者向代码仓库提交代码。所有后面的步骤都始于本地代码的一次提交(commit)。

②第一轮测试

代码仓库对 commit 操作配置了钩子(hook),只要提交代码或者合并进主干,就会跑自动化测试。测试有以下几种:

  • 单元测试:针对函数或模块的测试;
  • 集成测试:针对整体产品的某个功能的测试,又称功能测试;
  • 端对端测试:从用户界面直达数据库的全链路测试;

第一轮至少要跑单元测试。

③构建

通过第一轮测试,代码就可以合并进主干,就算可以交付。交付后,就先进行构建(build),再进入第二轮测试。所谓构建,指的是将源码转换为可以运行的实际代码,比如安装依赖,配置各种资源(样式表、JS 脚本、图片)等等。常用的构建工具如下:

  • Jenkins;
  • Travis;
  • Codeship;
  • Strider;

Jenkins 和 Strider 是开源软件,Travis 和 Codeship 对于开源项目可以免费使用。它们都会将构建和测试,在一次运行中执行完成。

④第二轮测试

构建完成,就要进行第二轮测试。如果第一轮已经涵盖了所有测试内容,第二轮可以省略,当然,这时构建步骤也要移到第一轮测试前面。第二轮是全面测试,单元测试和集成测试都会跑,有条件的话,也要做端对端测试。所有测试以自动化为主,少数无法自动化的测试用例,就要人工跑。需要强调的是,新版本的每一个更新点都必须测试到。如果测试的覆盖率不高,进入后面的部署阶段后,很可能会出现严重的问题。

⑤部署

通过了第二轮测试,当前代码就是一个可以直接部署的版本(artifact)。将这个版本的所有文件打包( tar filename.tar * )存档,发到生产服务器。生产服务器将打包文件,解包成本地的一个目录,再将运行路径的符号链接(symlink)指向这个目录,然后重新启动应用。这方面的部署工具有 Ansible,Chef,Puppet等。

⑥回滚

一旦当前版本发生问题,就要回滚到上一个版本的构建结果。最简单的做法就是修改一下符号链接,指向上一个版本的目录。

3

流程B

实现持续集成,一般需要以下四方面的内容:

①具有版本控制的代码库

例如:SVN, Git。相信现在的项目没有不对代码进行版本管理的,这里不再详述。

②构建工具

在持续集成的过程中,需要对已存在的或者新提交的代码进行编译、打包等操作。这样,就需要构建工具帮助构建一个编译环境,并对代码进行编译、集成、打包等操作。而构建的方式越简单越好,最好是一句命令就可以启动构建。现在,各种语言都有自己的构建工具,例如Java中的Maven、Gradle、Ant,前端中的Grunt、Gulp等等,好好利用这些工具,就能帮你完成这部分工作。

③测试

测试是持续集成中重要的一环。代码提交前,需要在本地运行单元测试,通过测试后再提交代码。构建完成后,需要运行全部测试(单元测试,功能测试,端到端测试)以确保产品质量。如果有一个测试没有通过,那么这次提交的代码不能进入主干;或者这次构建的产物是一个失败的构建品,不能用于发布。另外,由于持续集成依赖于这些测试去保证产品质量,所以测试的覆盖率要尽可能高。测试覆盖率不够高(包含代码覆盖率和功能覆盖率),就无法充分反映代码的变动是否对系统带来影响。而低覆盖率的测试,压根就无法保证产品质量。当上线的时候才发现问题就太迟了。

④CI工具

CI工具的作用是将整个CI过程管理起来并自动化,结果可视化。部分工具还结合了CD(持续交付)的功能。现在已经有很多CI工具去满足你不同的需求,例如Jenkins,专为Github开源项目提供的Travis,.Net用的CruiseControl.Net。他们各有特色,根据自己的需求选择适合自己的工具即可。

4

小结

以上两种流程A,B都是一些公司常用的模式,大同小异,供自行参考。

持续集成如何优雅落地?

1

背景描述

假设现在有一个产品P,以war包形式发布,由三个模块module A, module B, module C构建而成。三个模块的关系为:A和B为独立模块提供不同功能。C依赖A和B,然后构成产品P。我们使用了Git作为我们代码库的版本管理工具,用Java进行开发,maven作为我们的构建工具。在每个模块里,有我们基于JUnit写的单元测试代码。独立于三个模块外,有一块代码,也是基于JUnit写的,作为我们的功能测试代码(集成测试)。

2

实现步骤

①集成代码

当我们完成开发工作,需要提交代码到代码库前,我们至少需要在本地跑一次单元测试,在保证全部测试通过后,才可以将代码提交至我们的代码库Git上面去。例如,在我们上面描述的项目中,我对module A的代码进行了修改,那我最起码得在本地运行一次mvn test(执行Maven命令,test代表将会执行到maven default生命周期中从validate到test阶段), 执行成功后,我才会将代码commit and push到远程Git库上去。要做到这样效果的话,就需要保证单元测试代码也同步完成。而在极限编程中(XP),人们比较倾向于测试驱动开发(TDD, Test-driven Development)的实践,通过提前写好自动化的单元测试,保证好每一步功能开发的质量。

②自动构建

通过CI工具,可以设置一个勾子,当代码提交后触发相应构建。例如,我们提交了module A的代码时,Jenkins会扫描到我们这次提交,勾子触发module A的构建。这个过程会做如下操作:

1.Jenkins调用Git插件,从Git库上下载最新代码;

2.Jenkins调用Maven插件,执行Maven命令(一般为mvn install,如果需要上传至远端Maven库,也可以执行mvn deploy)对该模块进行构建。经过编译、通过单元测试后,便可以打包并安装到本地Maven库,以供其它依赖所用。这次构建成功,意味module A在模块自身的单元测试范围内是正常的。

3.因为module A是包含在产品P里面,所以,也需要进行产品功能的回归测试。由于module C依赖A,并构建成产品。所以在CI工具里面,我们需要配置好在module A构建成功后,自动触发module C的构建,经过类似步骤1、2这样的构建后,最终会生成产品P的war包。而C的构建成功,只代表着通过了module C自身的单元测试,还不能对生成的war包进行功能测试。然后就要看我们下一步的工作-自动部署。

③自动部署

在功能测试之前,我们需要在CI工具里配置一项任务,用于将最新构建出来的产品包部署到测试环境中去。这个任务由产品构建任务成功而被触发,而部署方式根据不同使用方式及不同的实际情况而多种多样。例如通过脚本将新构建的war包上传至指定位置,等待web容器自动扫描及部署。或者产品有自己的安装脚本,我们在任务中配置好运行安装脚本,就可以自动将产品部署到指定的测试环境中去。

④功能测试/集成测试

当部署成功后,真正的功能测试就可以开始了。一般情况下,我们可以独立出一块代码,基于JUnit编写好我们的功能测试代码(JUnit是作为测试的入口以及基本测试框架。如果你的需求比较复杂,那你完全可以将其它三方框架与JUnit集成使用)。功能测试过程和构建过程非常相似,均是依赖Git和Maven去完成:

1.Jenkins调用Git插件,从Git库上下载最新代码;

2.Jenkins调用Maven插件,执行Maven命令:mvn clean test。

区别在于功能测试阶段,Maven只执行到default生成周期的test阶段,不会执行后面的package和install。因为它只需要Maven帮忙运行测试代码即可,它本身没有什么可以构建的。

如果还需要更复杂的端到端测试的话,可能就需要准备更复杂的部署脚本,或者预先准备好整套端到端测试环境,之后只需要部署好war包即可。但无论怎样,最终原理还是相同。

⑤交付

当新提交代码构建出来的产品包,通过了各种各样残酷的测试后,就说明这个包是稳定的,能达到基本交付条件的(前提是自动化测试的覆盖率足够高,当然,有一些极端的情况需要人工测试的另说)。那么,我们就可以将这个包放到指定目录作为交付品,供其它测试团队获取并进行进一步的测试,甚至供生产环境部署使用。

4

总结

持续集成(Continuous Integration)、持续交付(Continuous Delivery)和持续部署(Continuous Deployment)提供了一个优秀的 DevOps 环境,对于整个团队来说,好处与挑战并行。

持续集成作为极限编程中的一个实践,是敏捷开发中快速迭代的重要保证,现在已被很多公司使用。但是使用持续集成并不是说要接受极限编程的全部东西,相反,它可以独立开来,与其它实践结合使用。

自动化测试是持续集成中重要一环,要真正用好持续集成,就要尽量提高自动化测试的覆盖率。

以上

That‘s all

0 人点赞