从 CI/CD 持续集成部署到 DevOps 研发运维一体化
今天整理下从传统的 CI/CD 到 DevOps 研发运维一体化的整个演进过程。类似于每日构建和冒烟测试,实际上在 10 多年前就已经在实践,比如当前用的笔记多的 Ant+CruiseControl 方式来实现自动化的编译构建和持续集成能力。
包括当前 DevOps 过程实践中的持续集成,实际和原来在思想上并没有太大的变化,对于 DevOps 我原来也给出过一个总结。
DevOps 过程概述
首先还是回顾下 DevOps 的简单定义如下:
DevOps(英文 Development 和 Operations 的组合)是一组过程、方法与系统的统称,用于促进开发(应用程序/软件工程)、技术运营和质量保障(QA)部门之间的沟通、协作与整合。它的出现是由于软件行业日益清晰地认识到:为了按时交付软件产品和服务,开发和运营工作必须紧密合作。
对于 DevOps 的提出已经很多年,其主要的推动仍来自两个方面:
1. 业务和需求驱动下,推动敏捷方法论,敏捷下需要更加短周期,更快地发布和交付。
2. 技术和运维部门需要衔接,在 PaaS 和容器技术发展下,进一步推动这部分陷阱的自动化。
虽然是三方交融地方为 DevOps 的内容,但是可以看到 DevOps 本身更多的是要解决两大类协同和自动化的问题,其一是开发部门和 QA 协同,其二是开发部门和运维的协同。
对于第一个问题重点解决思路即常说的 CI/CD 持续集成和持续部署方法论,而对于第二个问题则涉及到当前由云平台,微服务架构,容器技术发展推动的自动化发布和监控运维,基于敏捷研发的过程改进等。
因此对于 DevOps 已经不是简单的 CI/CD,而是更多最佳实践的融合。
持续集成和持续部署 CI/CD
敏捷研发和过程协同
微服务化
基于容器云的自动部署和动态资源扩展
自动化测试技术解决 QA 和开发协同
虽然当前对于微服务化,容器云等并不是实施推进 DevOps 过程的必要选项,但是对于当前大部分组织研发过程改进和开发选项中,微服务和容器化也成为了一种默认的标准规范。
因此今天这篇文章重点整理从 CI/CD 开始是如何叠加上各种过程能力和技术,然后逐步发展到当前完整的 DevOps 过程体系。
CI/CD 持续集成和持续部署
最早的团队软件开发中,往往会专门安排一个开发人员或配置管理人员来人工完成编译和部署工作。简单来说核心要做的就是就是:
从配置或源代码库 update 到最新代码
进行代码编译和构建
将编译完成的部署包部署到测试环境
而这个过程本身可以进行自动化处理,即人工完成的工作转为程序自动化来完成。可以看到里面会涉及到配置代码库,编译构建环境,测试环境三个典型资源。
其次编译过程需要进行自动化,将如何进行编译的过程,编译需要依赖的包,编译构建顺序等通过 xml 配置文件进行配置,后续基于该配置内容进行自动化编译。从最早的 Ant 到 Maven 基本均是该思路。
因此,最简的自动化编译和自动部署,冒烟测试过程如下:
为何需要持续集成类工具?
从上图可以看到,即使最简单的编译构建和部署往往也涉及到多个步骤的联动。如上图需要首先连接到配置管理库,拉群和更新到最新的源代码;需要调用自动化编译脚本进行编译,需要触发自动化部署脚本进行部署,部署后还需要调用外部自动化测试脚本进行测试,整体完成后还需要生成报告或发送邮件。
而整个过程需要工具来进行自动化组合和编排,即 CI/CD 类工具来完成。
每日构建和冒烟测试
每日构建和每日编译的最大区别就在于是否进行了冒烟测试,系统必须通过了冒烟测试才能够算每日构建成功。而测试人员人工介入的测试是基于冒烟测试通过的基础上面的。
冒烟测试由于要验证整个编译的正确性,因此冒烟测试必须是针对整个系统进行冒烟测试。但冒烟测试只需要关注系统的主体功能即可,通过冒烟测试并不是说系统没有 BUG,只是说通过了冒烟测试后可以说系统是一个稳定的版本,说系统的每日构建是成功了,代表系统可以转交专门的测试人员进行测试了。
冒烟测试工作一般需要提前准备好自动化测试代码或脚本,CI 工具仅仅是对自动化测试脚本进行集成,在测试完成后输出相应的测试结果报告。
基于二进制的环境迁移
对于 CI/CD 工具将二进制的部署包部署到测试环境,通知开发人员进行测试。如果开发人员在 SIT 测试环境测试通过,可能就需要将版本部署到 UAT 验收测试环境通知最终的用户进行验收测试。
那么这个时候是否重新再进行编译构建操作,然后朝 UAT 环境部署?如果这样的话显然不合适,即无法保证测试人员在 SIT 测试通过的版本就是最终推送给用户在 UAT 环境测试的版本。
持续集成应该是一次构建,形成二进制部署包多处运行。
因此部署版本不应该反复构建,而是直接用测试通过的部署版本进行 UAT 环境的部署,但是这个时候往往不同环境存在的不同的配置信息,典型的即类似接口访问地址,数据库连接串信息等,这些信息都和环境相关。
那么就需要将这些环境相关配置从 WAR 包中剥离出来,在进行环境迁移或新环境部署的时候,仅仅需要动态修改这些配置文件即可。
整个过程如下:
可以看到,整个持续集成和持续部署实际要完成多个环境之间的集成和协同工作,那么支撑集成整个过程设计最好是从上面这些环境中剥离出来,应该是单个一个 Server 服务器来执行整个持续集成流水线设计和编排,调度和运行。
进一步解耦,持续集成节点和制品库
在前面已经谈到,持续集成需要调度和编排多个环境和工具,这个已经不再适合放在类似构建环境上来完成,因此需要独立出来。
其次,对于自动化编译完成的结果,也不适合放在构建环境,编译和构建环境本身是一个临时的环境,不适合对对构建完成的二进制包进行完整的管理,版本追溯,配置等各种操作。因此制品库也需要从构建环境中移出,形成独立的制品库。
基于以上两点,整体过程如下:
到了这步,基本一个完整的持续集成和持续部署就完成了。比如当前主流的 Jekins 进行持续集成和持续交付核心思路仍然如上,包括在最早版本的集成上增加了更加灵活的流水线设计,增加了和容器云能力的集成,增加了和自动化测试工具集成等。
在传统的持续集成里面,一般很少形成独立的制品库 Server,而到了 DevOps 和容器云集成后,一般更加强调独立的制品库和镜像仓库,这个是进行各个环境部署,资源动态扩展的基础。
同时持续集成 Server 是整个核心,通过 Server 来设计和编排,来统一调度各个能力单元,同时实现编译构建过程,和最早的测试,生产环境间的协同。
持续集成类:源代码库,构建环境,制品库,CI/CD 环境
资源类:开发环境,测试环境,正式生产环境
持续集成最终就是实现整个开发到交付过程的完全自动化管理。
和容器云集成
对于容器云相关内容,可以参考网上的其它文章。当持续集成和持续交付和容器云集成的时候可以看到,如下几个变化点。
其一是二进制部署包转变为镜像交付
其二是新增加一个制作镜像的过程,我们一般叫打包
原来整体只有两个动作,编译构建-》部署
在和容器云集成后,整体过程会变化为三个关键动作,即编译构建-》打包-》部署。其中打包即是镜像制作过程,在镜像制作完成后将镜像推送到镜像仓库。同时发起部署任务的时候,是从镜像仓库里找到特定的版本,将版本部署到测试环境上。
整体过程如下:
可以看到整体持续集成和交付过程并没有明显的变化,仅仅在于交付的单位变成镜像,同时增加了镜像制作的过程。
有用底层的环境资源已经变成容器资源池,这些资源需要进行统一的管理,资源需要分配,需要基于资源使用负荷进行动态调度等。因此在 Docker 容器集群上需要有一个统一的管理和编排工具,这个即当前主流的 Kurbernetes 来实现容器集群管理,容器编排。
如上图通过 Maven 来实现代码的构建,同时在 Jenkins 中本身集成 Maven,对于构建完成的部署包会进入到 Jenkins 本身的部署包仓库管理。这个完成后进一步启用 Jenkins 来调用底层的 Docker 命令生成 Docker 镜像文件,这个镜像则是我们后续做自动部署和持续集成的关键镜像文件。
在这个步骤完成后即对接到 Kubernetes 来实现 Docker 镜像文件的自动化部署和动态调度。
在持续集成中有一个重点就是环境迁移,注意每次迁移的都应该是相同的镜像文件,而对于和环境相关的配置则单独进行配置或放置到 OS 的环境变量中。只有这样才能够保证最终上线的部署包就是我们最终开发和测试完成的部署包而没有任何变动。
如果在动态部署的时候启用了多个节点,那么还需要提供负载均衡能力。要注意的是 Kubernetes 本身也提供负载均衡和虚拟 IP 路由能力。我们最终访问的是域名,而域名最终会解析到实际的计算节点。
和敏捷开发过程协同
在 DevOps 最佳实践里面分为了研发管理,持续交付和技术运营几个关键的过程域。
但是在实践的过程中,最容易出现问题的不是单个技术点,而是跨域的协同问题,或者说研发过程管理和持续集成交付本身就是密不可分的两个部分,我们只是为了容易理解和学习将其划分为了不同的过程域而已。
因此流水线设计需要理清研发过程管理和自动化持续集成间的协同关系。具体两者的协同关系我们用下图来进行说明。
要明白任何一次新的编译构建部署完成后都涉及到测试人员测试,测试人员测试出问题后又会提交 Bug,开发人员修改 Bug 后 Check in 代码,等待下一次打包部署以形成多次迭代。整个过程最好方式就是要尽量减少大量的人工沟通协同,而是应该通过工具链协同来完成。
对于传统的持续集成,一般最佳实践为每天晚上进行自动化构建和冒烟测试,而对于当期的 DevOps 过程,在设计完流水线后,可以手工去启动流水线作业,也可以自动去执行流水线,流水线执行时间频度也可以进一步缩短。
假设我们每 2 个小时自动化的执行一次流水线作业,我们以此场景来做进一步梳理。因为对于大部分企业来说再高频的构建集成也不需要代码有变动就马上触发构建打包的程度。
流水线增加启动检查节点
虽然 2 小时执行一次流水线,但是在执行前先进行启动前检查,如果在最近 2 个小时内没有新代码 check in,那么不执行流水线。其次,如果上一次流水线执行实例还处于待处理或未关闭状态的时候,同样也不执行流水线作业而直接跳过。
是否需要人工验证
流水线打包部署包括两个方面,一个是新功能提交或新 bug 解决,只有这种情况才需要人工验证。因此一次流水线执行如果没有新需求或 Bug 状态变化,那么应该直接跳过人工验证节点并关闭。反之,则应该跳转到待人工验证环节。
需求和缺陷的管理
要注意到新需求和新缺陷都应该提交,而且都有状态,需求细分到具体的需求功能点,同时测试人员提交的缺陷应该对应到具体的需求功能点上面。一个需求开发完成后,需求本身也到待验证状态,但是一个待验证的需求是否能够关闭则必须是该需求下面所有的 bug 都解决完成后才能够关闭。
需求和缺陷状态的变化
开发人员首先是将需求或缺陷完成,并在本机进行自测通过,然后将代码 check in 到配置管理库。同时手工将需求或缺陷状态处理到待部署状态。在流水线启动后,如果整个构建打包和部署成功,则在成功完成应用部署后,将待部署状态的需求或 bug 转到待验证状态。在部署完成后测试人员可以看到待验证的 bug 或需求,那么他进入当前的测试环境一定是最新的可以进行缺陷验证的环境。
变更驱动的版本开发和流水线设计
对于一个变更,如果只涉及到一个微服务模块的变动,那么相当来说整个持续集成过程是很简单的,我们也很容易在 DevOps 上完成这个流水线设计并执行。但是如果涉及多个整个过程就复杂了很多。
我们举例来说,现在接收到一个或多个用户变更需求,经过需求分析后发现实际影响三个微服务模块都需要进行配套变更才能够完成。那么我们可以规划一个研发小版本来解决,即首先该需求就会拆分,并对应到三个微服务模块变更的任务。
在这种场景下变更驱动场景下,我们可以保留原来的大而全的顶层流水线,但是对应没有代码变化版本不再执行编译构建操作。
一个大应用涉及多个微服务,务必要执行无变更不重新编译构建原则。但是我们实际看到在很多 DevOps 实践中,一个变更版本开发,往往也会对没有变动的微服务重新构建打包。
即大流水线执行到子流水线的时候自动跳过一些子流水线的执行。当然我们也可以重新规划一个新的顶层流水线,只选择有变更的三个微服务模块进行编排设计,同时根据依赖关系定义好三个模块本身的编译构建顺序。
整个顶层流水线执行的时候就会将三个变更模块全部编译构建并打包部署,然后驱动后面的自动化测试,人工测试和验证。整个需求的实现,缺陷的修改过程应该是完整可视的。简单来说,基于这个变更小版本,提交的几个需求变更点当前已经实现了几个,究竟还有多少缺陷在处理,我们应该一清二楚地了解到。
和测试管理集成
对于测试管理也是整个 DevOps 过程实践中的一个关键内容。其中主要包括三类。
静态代码合规性,安全性检测
自动化测试(接口,UI)
自动化性能测试
自动化测试是把以人为驱动的测试行为转化为机器执行的一种过程,在预设条件下运行系统或应用程序,执行测试并评估测试结果,以达到节省资源和人力,提高测试效率和准确性,主要包括了自动化设计,自动化开发,自动化执行和自动化分析。
对于自动化测试可以看到,对于服务接口和代码级的自动化测试相对来说比较容易实现,但是对于前端和 UI 级的自动化测试相对来说就比较困难些。因此对于前期实践,我们也是建议先实现接口服务和代码级的自动化测试,再来靠前端 UI 的自动化测试。
对于性能测试由于可以提前录制脚本,相对来说自动化测试实现起来比较容易。
测试任务和流水线设计
一般来讲,在进行编译构建前,当从配置库 update 到最新代码后就可以进行代码静态检查,安全类检查任务执行。
在编译构建完成后,如果构建成功,可以执行后续的自动化测试任务脚本。其中本身又建议优先执行类似 Junit 等单元测试脚本和接口类自动化测试脚本。而对于性能测试实际并不需要每次持续集成都执行,因此一般涉及到性能测试的场景需要单独设计独立的流水线执行。
从持续集成到完整 DevOps 支撑
在整个 DevOps 最佳实践里面持续集成/持续部署仍然是最基础的,为了实现整个研发生命周期的过程管理和持续交付,那么需要实现和敏捷研发过程管理的集成协同,需要实现和后端容器云平台的集成和协同。
当构建一个完整的 DevOps 能力支撑平台的时候,更多的是对上面谈到的各种能力进行整合和集成,实现一个完整的端到端过程能力支撑。
DevOps 平台本身是一个诸多开源工具链的一个整合和协同平台,其核心不在于提供独立的类似编译构建,部署等能力,而是对这些能力进行整合和协同。同时在整合这些能力的时候需要考虑多租户,资源的管理,配置管理,任务调度等一系列工作。
一个 DevOps 支撑平台在搭建总体架构的时候可以看到,其核心更多的是围绕持续交付进行的各种能力的集成和自动化,而不是说其本身新创作了什么能力。对于这种集成本身包括几个关键部分。
其一是和 Docker 容器化平台的集成,以实现自动化部署和环境间的动态迁移,包括灰度发布,资源动态调度,集群等关键能力。其二是和微服务平台的集成,类似开源的 SpringCloud 平台中的注册中心,微服务网关的集成。其三包括和前面提到的 PaaS 平台各技术组件和服务的集成。其四则是对持续交付过程中的涉及到的各类工具链的集成,包括了配置和代码管理,代码静态检查,自动化编译构建,自动化测试,自动化运维,自动化监控,日志管理等各种工具的集成。
一个 DevOps 平台需要提供对源代码管理,开发,编译构建,打包,部署,测试,运维完整的能力支撑,同时通过流水线设计将这些任务过程进行自动化串联。一个流水线既可以是完全的自动化流水线,也可以包括人工处理和检查节点。流水线可以对上述动作和任务进行可视化的设计和编排。
评论