网站首页 > java教程 正文
持续集成、部署与交付
◎ 持续集成(CI)
◎ 持续交付(CD)
◎ 持续部署(CD)
◎ CI/CD工具
讲到持续集成、部署与交付(CI、CD与CD),我们不妨回想一下微服务的概念,围绕着业务建立了一组小的服务,这些服务都可以独立运行和部署,轻量级的交互,可以使用不同的语言和数据存储技术,拥有最小化的集中管理机制,可以自动化部署。
除了自动化部署,所有的点都介绍到了,虽然第8章提到了使用容器化技术的部署方式,但并没有实现自动化。本章就给大家介绍自动化部署的相关概念和方法,也思考一下,为什么微服务项目中需要自动化部署机制?
持续集成(CI)
持续集成(Continuous Integration,CI)是一种软件开发中的工作流程,或者是一种工程实践方式。我们知道,在软件开发过程中,有各式各样的集成,需要集成数据库、客户端,有的项目还需要集成第三方的系统或服务。在微服务项目中集成则更多见,我们需要集成BFF、API Gateway、后端不同的基础服务、各种数据存储等。
那么,持续集成又是什么意思?它与传统的软件集成方式相比有哪些不同?
传统的系统集成
在软件工程中,系统集成以满足用户需求为根本目的,将各类资源整合在一起,形成一个完整的系统,其中包括设备、网络、数据、应用系统等集成。通常,我们在项目开发过程中所说的系统集成多指应用系统集成,就是将系统的各组件或子系统集成到一个系统中的过程,在这个过程中我们将各个应用系统连接在一起,并确保它们可以在一起运行,如图9.1所示。
在微服务项目中,由于服务数量相对较多,系统集成的工作就显得尤为重要,很多时候各组件在独立的运行环境中可以良好地运行,但集成在一起时就会出现各种各样的问题。当然,我们通过之前的章节已经掌握了很多微服务的实践,如使用容器化技术来减少不同环境的差异性影响,使用契约测试来保证各个服务的交互正确性,使用BFF来为不同的客户端定制不同的数据处理策略,通过这些软性的手段,降低系统在集成时的困难程度和出错率,但绝不是百分之百地避免出错,再健壮的系统架构也需要测试,尤其是集成测试。
为了保证系统能够正确的运行,我们需要把系统集成在一起进行测试,然后上线部署,再测试,最后发布到生产环境,这也是为什么需要那么多集成测试的环境,如SIT、UAT、Staging等。
传统的系统集成是如何做的?我们设想一个场景。例如,一个完整的电商平台,需要商品子系统、库存子系统、订单子系统、用户子系统、物流子系统等集成在一起运行,当我们需要在商品子系统中开发一些新的功能时,如在商品子系统中丰富商品的检索功能,可以根据商品的库存和销量等信息对商品进行检索。
正常的流程是我们需要和订单子系统、库存子系统等有关联的系统约定好接口定义,然后开始开发工作,等到该版本开发完成后,再将系统部署到集成环境进行测试,首先这一步是人工手动完成,人工的过程就有可能出错,其次一个大的版本开发完成后,由本地环境部署到集成环境的过程中会遇到各种各样的问题,如数据库集成、接口兼容、配置项的问题,甚至是第三方子系统接口调用问题等,这时又需要把版本打回,然后对相关问题进行修复,再继续集成,传统系统集成流程如图9.2所示。
无论是从开发效率方面,还是从敏捷方法论的角度,传统的系统集成方式并不能适应如今软件开发的需求,尤其是在微服务架构下,服务的职责范围都不大,各服务数目众多,迭代频繁,传统的系统集成速度甚至赶不上微服务版本的开发速度,各系统无法提前验证集成运行时的正确性,集成的问题频繁暴露,开发者也只能一边开发新功能,一边修复之前版本的集成BUG,所以聪明的程序员又在想出路。
基于微服务的特性和敏捷的工程思想,希望我们开发的功能能够更快更早地被集成和验证,最好是自动化,这样只要代码有变化,新的代码就会自动部署到集成环境中,问题在第一时间暴露,于是持续集成的概念就被提出来了。
持续集成的概念
持续集成(CI)是指在软件开发过程中每天持续不断地将开发者的工作产物合并到共享主线的做法。也就是说,在开发人员提交代码之后,自动将新的代码进行构建,新的代码最后附有单元测试,然后将新的构建产物集成到集成环境中,以便于快速地发现新的代码和原有的环境是否能正常地集成在一起运行,持续集成流程如图9.3所示。
通常要做到持续集成,除了使用一些集成工具,还需要团队在开发过程中达成共识并共同使用良好的开发实践,从而确保项目的CI可被顺利执行。那么,要做到持续集成,需要哪些实践呢?
1. 代码管理
首先,持续集成需要获取最新的交付物,也就是我们的项目代码,它需要维护一个公共的代码仓库来存储代码和管理代码版本的变更。例如,我们经常在项目中使用的SVN、Git等代码管理工具来管理代码版本,搭建或购买私有代码仓库来存储代码,这是实践持续集成的第一步。
有人认为这就是版本控制,我们几乎每个项目都在用,一旦去做持续集成,就会发现总不顺畅,不是系统有问题,就是代码合并冲突。其实代码管理除了选择合适的工具,更加重要的是团队在提交时代码的质量和提交意识。首先是质量,最好新代码带有单元测试,也就是说,最好我们的每个commit都有测试覆盖,并且测试通过,至少在构建和运行层面,提交的代码可正常运行,不会破坏集成环境。
其次是意识,笔者在带新人时经常会教给他们一个习惯:保持你的工作区是干净的,这里的工作区当然不是指工作桌面,而是指本地代码工作区,主要是我们需要尽早地提交代码,尽早地去做代码合并,这样做的好处是可以快速地暴露代码的问题,也可以大大减少最后合并代码时解决冲突的痛苦,有些项目团队还会定时去做提交,甚至规定每天至少要提交的次数。在极限编程(XP)思想中也十分提倡这种做法。
关于代码提交的另一个重要意识就是保证提交的原子性,又称为原子提交。例如,将一组不同的更改视为单个操作应用的原子操作,如果应用了更改,就说明原子提交已成功,如果在原子提交完成之前发生故障,那么原子提交中完成的所有更改都将被撤销。这样可确保系统始终处于一致的状态。例如,编写一个新的方法需要操作两次数据,在一次提交中最好是包括两次数据的操作代码,因为提交完成了一半代码对于构建或集成来讲都没有意义,也不方便进行代码的版本管理,所以代码的测试最好一起提交。
2. 自动构建
有了有效的代码管理策略,自动构建相对简单,首先我们要选择合适的构建工具或框架,如在Java项目中的Maven和Gradle就是很好的构建工具,能够帮助我们快速地进行依赖管理和编译构建,接下来只需选择合适的自动构建工具来自动获取最新的主线代码进行构建即可。常用的工具有Jenkins、GoCD等,而拉取最新的代码一般有两种策略:一种是通过配置定时任务,如每5分钟定时任务会去拉取最新的代码,然后和本地的版本进行比较,若有新的提交,则开始执行构建;另一种是由代码仓库主动触发构建,当有新代码提交时,代码仓库会主动地触发持续集成工具的自动构建接口,当然第二种方式需要代码仓库的功能支持。
3. 自动测试
在自动构建的过程中,测试代码是否能够正常执行,除了测试新提交的代码,还需要回归地测试原有的代码是否会受到影响。通常我们会要求每个提交都有单元测试覆盖,这样在集成时,都会先过一遍所有的单元测试,以确保新老代码都可以正常运行,有时还要单独编写一些接口的集成测试,以确保在集成环境中端到端的测试通过,确认系统的逻辑运行正常。
微服务的CI
在微服务架构中我们会有更多的服务,大部分项目还会有API网关、BFF等服务,也就是会有更多的集成点,如果每个服务都各自为政,等待版本开发完成后再去集成,那么在集成时所有的问题都集中爆发,哪怕是一些小的问题,都有可能影响整个系统的集成进展,这时就需要花费相当大的精力去解决问题。
既然微服务架构下的集成点更多,就需要系统能够更加敏捷地去集成,更加快速地去验证代码的正确性。所以,在采用微服务架构的项目中,几乎都使用或自建CI环境来确保各个服务能够做到持续集成。笔者所参与的项目中通常还会专门申请一台大电视,用来展示项目的CI墙(CI Monitor),如图9.4所示。
这样可以及时地展示各服务的集成进度和状态,一旦持续集成过程中构建或测试失败,CI Monitor就会变红,告警团队有问题需要处理,所以在敏捷团队中经常会有“流水线红不过夜”的说法。
持续交付(CD)
除了CI,还有一个更高级的自动化部署方式,那就是持续交付(Continuous Delivery,CD)。持续交付就是持续不断地自动化交付我们的软件工件。那么,它和CI有什么不同呢?我们又该如何做到持续交付呢?
CD的概念
在我们提起CI时,往往会和CD一起说,那么CD是指什么?和CI有什么区别?
CD就是持续交付,如果说CI是将新的交付产物集成起来并且可以执行相关的测试,那么CD实际上就是比CI又往前一步,我们新的代码不仅可以持续构建和测试,还可以自动部署。例如,完成了一个新的接口的开发,这时CD工具不仅可以拉取最新的代码进行构建和测试,还可以将构建好的服务部署到系统的开发环境、测试环境或集成环境中,持续交付流程如图9.5所示。
持续交付将集成做得更加彻底,它确保了团队在每次提交后所产生的增量的可交付物,可以随时发布部署,一旦各环节都验证通过,就可以在最后手动地将产品增量发布到生产环境中,从而有助于降低成本、时间和交付变更的风险。这个过程对业务人员同样重要,意味着一旦开发人员开发完成了某一个小功能,甚至是小部件,业务人员可以随时验证这些改动,并提供相应的反馈。
而对于持续交付的实施,配置简单且可重复的部署过程非常重要,这里所说的部署主要是将测试通过的构建产物部署到相应的集成环境中,通过一些流程配置,还可以中断整个问题代码的部署,保证集成环境的稳定,我们一般都会为项目建立整个的持续集成流程,而这个流程通常称为流水线(Pipeline)。图9.6所示为Jenkins的CI流水线示例。
图9.6所示的流水线配置了5个步骤:代码下载→测试→构建打包→构建镜像→部署。其中任何一个步骤失败都会导致流水线中断,保护了集成环境的文档,也可以提前暴露集成的问题。
DevOps与持续交付
DevOps是近几年出现的新词,目前还很流行,常常与CI/CD一起提起,其实CD就是CI的进化版,在持续集成的基础上,将持续集成的流程扩展到交付现实的产物。那DevOps又是什么?从字面上理解,DevOps似乎是Dev(开发)加Ops(运维),是一种新的项目角色,同时拥有开发和运维的能力,很多时候大家可能理解DevOps就是来搭建CI/CD的,但实际上DevOps的范围比CI/CD更广阔。
DevOps往往是以文化变革为中心,特别是参与软件交付的各个团队的协作,以及软件交付的流程自动化,是一种将软件开发和信息运维相结合的方法,目的与持续交付类似,都是缩短软件开发的生命周期。而持续交付(CD)是一种自动交付的方法,侧重于将不同的流程汇集在一起更快、更频繁地执行。
因此,DevOps与持续交付经常结合使用,持续交付的重点是自动化软件交付流程,DevOps更专注于组织变更,以及所涉及的众多功能之间的良好协作。其最终的目的都是加快软件的变更速率,缩短反馈环,为最终客户提供重要价值。
软件质量门
在持续交付的过程中还有一个很重要的概念,那就是质量门(Quality Gate)。简单来说,质量门就是一个质量标准,如通过全部的单元测试,代码测试覆盖率大于85%,重复代码小于10%等对交付产物质量的标准,只有通过了这些标准才能成功发布。
那么,质量门有什么作用?最直接的就是可以通过设定质量门提高项目的质量,如果用过SonarQube等代码扫描工具,就可以看到有关质量门的设置项,可以通过组合各种条件或运算符来配置一个项目的质量门,如图9.7所示。
然后在CI/CD流水线中加入SonarQube扫描的步骤,如果没有通过质量门就中断流水线的进程。除了基础的代码质量扫描,质量门也是一种测试和部署的策略,其实CI/CD除了能够减少人工集成的工作量,最大的目的是快速检验新交付工件、新的代码是否能够集成到对应的环境中。所以,可以把它理解成一种测试,在软件项目过程中,往往会存在多种环境,如开发环境、测试环境、集成测试环境、准生产环境和生产环境等,通常我们的代码会按照顺序逐步通过这些环境直到最终的生成环境。那么,我们的质量门应该设立在哪里?
其实每个环境的测试,无论是代码扫描还是单元测试,或者是人工测试,都是对质量的一种把关,所以每个环境都会有自己的质量门,只不过这些质量门的侧重点可能各不相同,每个质量门的输入都是上一个质量门的输出,我们的代码就像“闯关者”一样,通过重重考验,最终发布到生产环境中,如图9.8所示。
在图9.8中,每个步骤只需关注自己的质量标准,这样既可以保证最终的交付质量,又减少重复的质量检测工作,在风险管理或测试管理中称为瑞士奶酪模型(Swiss Cheese Model),这个模型在很多航空安全、工程、医疗卫生和应急服务机构中也作为基础的安全分层原则,如图9.9所示。
该模型由曼彻斯特大学的Dante Orlandella和James T.Reason联合提出,从图9.9中可以看出,在软件开发过程中存在很多风险,需要通过层层的质量门来帮助开发者对软件漏洞进行把关。例如,开发环境可能关注于单元测试,测试环境可能关注于功能的测试,集成测试环境可能关注于端到端的集成测试,而准生产环境可能关注于性能和各种配置项的测试,每个质量门就像一片奶酪一样,可能存在很多漏洞,但是每片奶酪的漏洞都不重叠,通过层层的筛选,最终可以保证风险不会穿透所有的分层,这种结果也被称为累积行为效应。
本文给大家讲解的内容是持续集成、部署与交付;
- 下篇文章给大家讲解的是持续部署(CD);
- 觉得文章不错的朋友可以转发此文关注小编;
- 感谢大家的支持!
猜你喜欢
- 2025-03-11 实践一下,用IDEA自动化部署Docker镜像,并没有你想象中的那么难
- 2025-03-11 Java本地搭建宝塔部署实战Springboot酒店宾馆管理系统源码
- 2025-03-11 运维小白---centOS系统下部署基础项目
- 2025-03-11 使用arthas实时追踪docker容器上部署的Java程序的方法出入参
- 2025-03-11 Java项目本地部署宝塔搭建实战java中小医院管理系统源码
- 2025-03-11 Java项目本地部署宝塔搭建实战java外卖小程序源码
- 2025-03-11 Java本地搭建宝塔部署实战SSM房屋租赁系统源码
- 2025-03-11 Java本地搭建宝塔部署实战springboot仓库管理系统源码
- 2025-03-11 Tomcat热部署与热加载
- 2025-03-11 Kafka单机部署
你 发表评论:
欢迎- 最近发表
-
- Java常量定义防暴指南:从"杀马特"到"高富帅"的华丽转身
- Java接口设计原则与实践:优雅编程的艺术
- java 包管理、访问修饰符、static/final关键字
- Java工程师的代码规范与最佳实践:优雅代码的艺术
- 编写一个java程序(编写一个Java程序计算并输出1到n的阶乘)
- Mycat的搭建以及配置与启动(mycat部署)
- Weblogic 安装 -“不是有效的 JDK Java 主目录”解决办法
- SpringBoot打包部署解析:jar包的生成和结构
- 《Servlet》第05节:创建第一个Servlet程序(HelloSevlet)
- 你认为最简单的单例模式,东西还挺多
- 标签列表
-
- java反编译工具 (77)
- java反射 (57)
- java接口 (61)
- java随机数 (63)
- java7下载 (59)
- java数据结构 (61)
- java 三目运算符 (65)
- java对象转map (63)
- Java继承 (69)
- java字符串替换 (60)
- 快速排序java (59)
- java并发编程 (58)
- java api文档 (60)
- centos安装java (57)
- java调用webservice接口 (61)
- java深拷贝 (61)
- 工厂模式java (59)
- java代理模式 (59)
- java.lang (57)
- java连接mysql数据库 (67)
- java重载 (68)
- java 循环语句 (66)
- java反序列化 (58)
- java时间函数 (60)
- java是值传递还是引用传递 (62)
本文暂时没有评论,来添加一个吧(●'◡'●)