持续集成(11.27)

注:图片来源于网络

在谈DevOps持续交付这个过程域之前,准备把原来敏捷开发或软件工程里面的持续集成最佳实践再做下回顾,要知道早在10多年前我们就已经在实践持续集成,每日构建,自动化测试和冒烟测试,因此对于持续集成并不是新鲜事物。

唯一我们看到的是在DevOps最佳实践里面将持续集成过程变得更加灵活,自动化和可编排了。

对于持续集成的过程,我们以每天进行一次持续集成为例来进行说明

1. 所有开发人员,每天在下班前检入自己开发完成并单元测试通过的代码文件

2. 统一的配置库环境服务器(CI服务器),Update到最新的源代码文件

3. 基于自动化编译配置文件,执行自动化的代码编译,并输出编译完成二进制包到指定目录

4. 将相关部署文件根据自动化执行脚本安装和部署到我们的测试服务器

5. 安装部署成功后,执行自动化测试脚本,输出自动化测试报告

6. 测试人员介入进行功能点的黑盒测试,并反馈测试缺陷和跟踪缺陷在下次集成版本中解决

以上是我们最早使用的持续集成过,也没有和Docker容器相结合,对于自动部署过程也是通过自定义脚本来完成部署。而现在我们可以看到在DevOps里面的持续集成更加强调了容器化技术的结合和整个持续集成过程的可配置熟悉。

简单理解,就是上面提到的6个步骤,你是可以自己灵活组合和可视化编排的。

在传统的单体应用架构下,我们最终是打包成一个大的部署包,而实际在编译构建中存在诸多的依赖关系和构建顺序,而这些内容都是我在构建脚本中通过配置文件或代码进行控制的。而在新的微服务架构模式下,各个微服务模块相互独立开来,都可以独立构建打包,但是模块之间的关联关系依然是存在的。也就是说从一个包含了多个微服务模块的大的应用来说,我们在大构建过程中仍然有依赖和先后关系。

也就是说,我们在构建过程中,从单个模块的流水线编排后,还有一个更加上层的主体大流程编排。也就是说流水线编排本身也是分层的,才能够更好的满足大应用集成的需要。

在整个持续集成的过程中一定会涉及到环境的迁移问题,比如SIT测试完成后需要迁移到UAT环境,而UAT环境测试完成后需要迁移到生产环境。不论是最早的持续集成最佳实践,还是当前的结合容器镜像的DevOps过程实践, 我们始终在强调一次构建多地部署,即最终的环境迁移是基于二进制部署包或容器镜像进行的。在后续的多个测试环境和生产环境,不能再执行打包动作。

这也是我一直在思考的另外一个点,就是环境迁移是否要体现在完整流水线上。

在我考虑清楚流水线设计的本身分层后,这个问题也就想清楚了, 即在最上层的大应用集成或顶层的流水线设计上一定是可以体现环境迁移过程的。只有这样才能够更好的可视化监控从测试到生产交付的完整过程。

一般考虑在配置库update到最新代码后,就可以进行代码静态检查,检查完成后再进行编译和打包,代码静态检查问题不用影响到后续的直接构建过程。在部署完成后再进行自动化的单元测试操作,按道理自动化单元测试或冒烟测试不通过应该影响到后续的人工介入测试。

在多个微服务模块有强依赖关系的情况下,按道理在前置模块编译构建失败的情况下整个大流水线应该完全终止掉,不再进行后续的编译构建操作。

持续集成实际上全新的产品开发和交付只是其一,更加重要的是用于后续的变更管理和变更版本,补丁版本的开发和交付上线。这个过程本身的效率和自动化程度真正体现了开发,质量和运维人员的协同度。

变更驱动的版本开发和流水线设计

对于一个变更,如果只涉及到一个微服务模块的变动,那么相当来说整个持续集成过程是很简单的,我们也很容易在DevOps上完成这个流水线设计并执行。但是如果涉及多个整个过程就复杂了很多。

我们举例来说,现在接收到一个或多个用户变更需求,经过需求分析后发现实际影响三个微服务模块都需要进行配套变更才能够完成。那么我们可以规划一个研发小版本来解决,即首先该需求就会拆分,并对应到三个微服务模块变更的任务。

我们可以保留原来的大而全的顶层流水线,但是对应没有代码变化版本不再执行编译构建操作。即大流水线执行到子流水线的时候自动跳过一些子流水线的执行。当然我们也可以重新规划一个新的顶层流水线,只选择有变更的三个微服务模块进行编排设计,同时根据依赖关系定义好三个模块本身的编译构建顺序。

那我们整个顶层流水线执行的时候就会将三个变更模块全部编译构建并打包部署,然后驱动后面的自动化测试,人工测试和验证。整个需求的实现,缺陷的修改过程应该是完整可视的。简单来说, 基于这个变更小版本,提交的几个需求变更点当前已经实现了几个,究竟还有多少缺陷在处理,我们应该一清二楚的了解到

持续集成的周期和频度

对于持续集成的频率,如前面所说原来的最佳实践就是每天完成进行一次构建和集成,当然这个周期可以更短,比如每天两次持续集成和构建,实际上做到每天2个小时自动化执行一次持续集成和构建已经能够满足业务和交付的需要。

如果是定时执行,我在前面也谈到过,对于没有代码check in的模块和分支,不应该再去执行后续的自动化编译构建操作。这个是需要我们在流水线设计的时候进行判断。

另外一种思路就是在开发人员进行代码提交后自动触发持续集成,也就是我们说的按需进行集成。但是暂时还不清楚比如一次提交10个代码文件修改,如果判断10个文件都提交完成后并触发集成。感觉整体里面还是需要研发人员手工去触发一次集成操作。如果是需要研发人员手工去触发流水线,可以看到反而不如前面谈到的定时自动化的去触发持续集成操作。

测试分层策略和探索性测试

我们来谈下有哪些测试分类的方法,在持续集成里面我们当然更加会强调自动化测试,因此可以理解为人工测试和自动化测试两类;也可以离开为代码级测试,接口测试和前端测试分离。也可以理解为功能测试和非功能测试两类。

当然也可以看到,在微服务架构下,我们希望我们本身的开发也是分层的,即中台模块+服务接口+前台功能,即我们通常说的前后端分离,在这种前后端分离的情况下,可以更加方便我们进行测试分层设计和自动化测试。 只要是厚中台+薄前台模式,那么就越容易实现测试过程的自动化。

越是持续集成自动化承担越高,那么自动化测试的比重就会越大。

探索性测试可以说是一种测试思维技术。它没有很多实际的测试方法、技术和工具,但是却是所有测试人员都应该掌握的一种测试思维方式。探索性强调测试人员的主观能动性,抛弃繁杂的测试计划和测试用例设计过程,强调在碰到问题时及时改变测试策略。

对探索性测试最直白的定义是:同时设计测试和执行测试。探索性测试有时候会与即兴测试(ad hoc testing)混淆。即兴测试通常是指临时准备的、即兴的Bug搜索测试过程。从定义可以看出,谁都可以做即兴测试。由Cem Kaner提出的探索性测试,相比即兴测试是一种精致的、有思想的过程。