24岁秃头程序员教你微服务交付下如何持续集成交付,学不会砍我
wptr33 2024-11-17 02:41 21 浏览
微服务如何持续集成交付
在微服务架构下,每一个微服务都是职责单一的,可独立部署单元,但是众多分散的微服务也带来了代码共享、微服务功能依赖、版本管理等复杂问题,微服务需要解决配置管理、服务持续集成、持续部署、快速交付过程中的一系列软件挑战。下面我们将讲解如何通过配置管理、持续集成、持续交付为微服务保驾护航。
配置管理概述
微服务架构下,应用被拆分为众多细粒度服务,对统一的配置管理的需求也随之增加。软件配置管理(Software ConfigurationManagement,SCM)指通过执行版本控制、变更控制的规程,以及使用合适的配置管理软件,来保证所有配置项的完整性和可跟踪性。软件配置管理在整个软件生命周期中建立和维护项目产品的完整性,它的目标如下。
● 目标1:对软件配置的各项工作进行计划。
● 目标2:被选择的项目产品得到识别、控制并且可以被相关人员获取。
● 目标3:已识别出的项目产品的更改得到控制。
● 目标4:使相关组别和个人及时了解软件基准的状态和内容。
软件配置项在配置管理流程中,IT组件及运用这些IT组件所提供的服务被称为软件配置项(SCI)。软件配置项包含了软件代码、代码的版本描述、文档数据(开发人员、用户)、软件所属组织等所有软件生产过程中产生的数据。这些配置项可以作为元数据信息对外暴露数据接口,其他第三方平台可以根据这些配置项的元数据信息调整系统中的相关配置。
配置管理数据库(CMDB)
配 置 管 理 数 据 库 ( Configuration Management Data Base ,CMDB)的官方解释是,它用来存储与管理企业IT架构中设备的各种配置信息,包含了配置项全生命周期的信息及配置项之间的关系。CMDB开放的数据服务供各个业务系统调用,从而让业务系统具备统一的视图和配置信息。
其实微服务在自动化运维、标准化运维、DevOps中都离不开CMDB,可以说CMDB是运维体系的基石。有了配置信息数据库,后面各种标准、流程都可以建立在CMDB基础之上,实现真正的标准化、自动化、智能化运维,在节约运维成本的同时,降低运维流程混乱带来的操作风险。
基线
在开始软件项目开发前,我们需要一个稳定的代码版本。我们将这个稳定的代码版本称为代码基线,基线是软件进一步开发的基础,同时基线的确立是软件项目中的一个里程碑。当基线形成后,项目负责SCM的人需要通知相关人员,并且告知在什么位置可以找到基线的代码版本,这个过程可被认为是内部发布。至于对外的正式发布,更是应当从基线的版本中发布。下面总结一下基线配置的优势。
● 制定基线可以让所有开发人员的工作在基础代码层面保持一致和同步,为开发工作制定一个基点和快照。
● 制定基线可以让项目之间建立前后继承关系,而不会因为各自代码的基线不一致,导致无法追溯变更。
● 当代码变更有问题或者不可靠时,基线为分支代码提供了一个取消变更或者回退版本的操作。
在微服务架构中,基线模式通常把框架下的某个版本作为代码基线。以Spring Boot代码为例,Spring Boot的快速迭代,出现了众多版本。从Spring Boot 1.x到Spring Boot 2.x,不同的版本配置,让Spring Boot对依赖配套的底层组件和类库都有很大的差异。如果我们在开发过程中,没有统一的代码基线,在后续微服务的开发集成过程中,将出现代码版本冲突的风险及类定义缺失等底层代码不兼容问题。对于Spring Boot的版本兼容问题,我们可以参考官方网站发布的Release说明。
持续集成概述
持续集成(Continues Integration,CI)最早在1991年由GradyBooch命名并提出。XP极限编程中采用了CI的概念,并提倡每天不止一次集成。当时持续集成的目的就是能够通过采用自动化的手段和工具,来代替手动处理事务,实现项目的持续集成。而提出微服务概念的软件大师Martin Fowler对持续集成的定义则更加准确。
持续集成是一种软件开发实践,即团队开发成员经常集成他们的工作,通常每个成员每天至少集成一次,也就意味着每天可能会发生多次集成。每次集成都通过自动化构建(包括编译、发布、自动化测试)来验证,从而尽快地发现集成错误。
在微服务架构下,我们关注更多的是如何将一个大的单体拆分成多个微服务。分而治之虽然解决了系统的耦合问题,但是就像汽车的零部件被拆解后,如何再组装成一个完整的汽车一样,微服务同样需要通过相关调用、相互依赖、系统集成,最终完成整体对外功能。而持续集成正是将各个微服务的功能集成在一起来整体对外提供服务的。
同时,持续集成必须考虑针对这些独立部署的微服务,如何建立起代码仓库中的代码版本与CI构建和交付物版本之间的对应关系。在代码被更新后,保证每一次迭代和构建都可以经过质量验证,回归测试用例如何自动化执行,代码的频繁更新需要有一个良好的持续集成
方案来高效地验证,并控制变更代码的副作用(Side-Effect)。
持续集成Pipeline
下图是持续集成的一个Pipeline(管道)方案,里面包含了我们通常会使用的代码集成工具和最佳实践。下面我们对持续集成使用的工具一一进行介绍。
Git代码构建
在微服务架构下,我们通过代码集成到主干分支完成一次CI构建,代码分支管理有多种不同的构建模式,具体如下:
● 单独代码库,一个CI构建:在这种方式下,微服务使用相同的代码库,并且使用一个单独的CI构建,这种模式容易产生代码冲突,一般不建议采用。
● 单独代码库,多个CI构建:这种模式通过创建多个子目录,每个子目录由单独的CI构建,这种模式在实际开发场景中使用较多。这种方式的问题是所有微服务代码都在相同的代码库,存在服务代码耦合隐患。
● 多个代码库,多个CI构建:每个微服务都有自己独立对应的代码库,这使微服务更加独立,代码管理更加独立。但缺点是跨服务的共享代码修改变得复杂,需要将共享代码上传到私服,通过版本工具进行代码升级更新。
对于使用传统SVN或者CVS的代码库构建的项目,使用第二种模式比较常见;而把Git作为代码库,划分为多个代码库则更适合管理,相比传统单一代码库,集成过程中产生代码冲突的可能性会大大降低,也降低了集成代码过程中处理冲突花费的精力和成本。
如果你的微服务使用了单一代码库和多个CI构建的模式,为了降低集成的风险,建议提高本地代码提交到主干分支的频率,减少由于代码变化过大引起的集成风险。
Maven构建&Nexus私服
在Spring Boot项目中,大部分公司目前还是以Maven作为主要的代码编译工具。Maven工具的安装十分简单,IDEA和Eclipse工具对Maven都有相应插件的支持。这里我们主要介绍Maven中的pom.xml文件。
最基本的pom.xml文件包含工程信息、Spring Boot父工程、属性配置、依赖包、构建插件。下面是pom.xml文件的一个简单模板。
下面是微服务Spring Boot应用依赖关系管理的示意图。
● 最上层Spring Boot Parent:只有pom.xml文件,无代码。
● 中间层继承Parent依赖:包含pom.xml文件和一些具有通用性的代码,如工具类等。
● 最下层应用:Spring Boot应用工程,含有启动类,与单体应用类似。
Nexus私服管理
为避免在微服务下滥用包,应该统一管理第三方依赖的版本,同时为了方便mvn deploy操作,可以加上公司内部Maven私服的信息。
首先,执行代码上传私服命令。Maven私服常用的操作是将代码库安装到本地,并推送到Maven私服,代码如下:
其次,在项目pom.xml中设置的版本号添加Snapshot标识的都会发布为Snapshot版本(快照版),没有Snapshot标识的都会发布为Release版本。Snapshot版本会自动增加一个时间戳作为标识。如1.0.0-SNAPSHOT 发 布 后 变 成 1.0.0-SNAPSHOT-20180522.123456-1.jar,需要注意的是,Snapshot作为开发过程中使用的快照版是最为方便的,它可以随时更改代码,并重新被上传到Nexus。而Release发行版不能更改代码,如有修改提交失败,或因为版本冲突,则需要为Release指定新的版本号。下面我们对比下Snapshot与Release的区别。
● nexus-releases:用于发布Release版本。
● nexus-snapshots:用于发布Snapshot版本。
Release版本与Snapshot版本的定义如下。
● Release:1.0.0/1.0.0-RELEASE.
● Snapshot:1.0.0-SNAPSHOT.
在分发到远程Maven仓库之后,所有能访问该仓库的用户都能使用你的组件,然后我们需要配置pom.xml的distributionManagement来指定Maven分发构件的位置,在pom.xml中添加如下代码实现远程仓库的配置功能。
注意:虽然目前Maven仍然是Java代码构建的事实标准,但是Groovy的Gradle构建工具相比Maven摒弃了冗长的XML语法格式,同时在集成Maven诸多优点的前提下,Gradle在并行编译和编译效率方面都有更好的体验。在Spring Boot 2.3.0中,Spring Boot开始使用Gradle而非Maven进行构建。而Spring Boot团队给出的切换到Gradle的主要原因是减少构建所需要的时间。对于Spring Boot构建的复杂性,Gradle的构建缓存能力,以及增量和并行构建都是模块化CI构建中加快构建速度的重要因素。
测试验证
在持续集成中,当代码提交到主干分支后,需要单元测试、集成测试、功能测试。对于微服务而言,频繁的代码发布和快速迭代需要一个自动化回归测试方案,帮助验证增加的代码改动是否有副作用。
在系统集成测试中,对于一些依赖上下游服务的测试验证工作,还要模拟对端服务的API,这种方式就是俗称的“挡板测试”,其实就是Mock程序,用于客观条件限制下,在无法搭建整体测试环境的情况下,使用软件系统模拟依赖的服务功能。常见的使用场景是,当真实的调用可能产生资费时,就需要挡板技术解决系统集成时的代码验证问题。
下面我们使用JUnit实现Spring Boot程序的单元测试功能,从Spring Boot 2.2.0开始引入JUnit 5作为单元测试默认库。
Spring Boot 2.2.0 之 前 , spring-boot-starter-test 包 含 了JUnit 4的依赖,Spring Boot 2.2.0之后替换成了JUnit Jupiter。下面的实例用来演示使用Spring Boot整合JUnit的单元测试。
1.创建项目,添加Maven依赖
2.Dao层实例代码
3.Service层实例代码
4.编写启动类
5.编写测试文件,运行testSaveUser方法即可
6.执行mvn clean install会自动触发JUnit测试工作,测试结果会输出到Console
代码静态检查
SonarQube是一个用于代码质量检测管理的开放平台,SonarQube可以通过不同的插件对这些结果进行再加工处理,通过量化方式度量代码质量的变化。SonarQube不仅提供了对IDE的支持,可以在Eclipse和IntelliJ IDEA这些工具里联机查看结果;同时对大量的持续集成工具提供了接口支持,可以很方便地在持续集成中使用。另外,SonarQube的插件还可以对Java以外的其他编程语言提供支持。
● 编码规范:是否遵守了编码规范,遵循了最佳实践。
● 潜在的BUG:可能在最坏情况下出现问题的代码,以及存在安全漏洞的代码。
● 文档和注释:过少(缺少必要信息)、过多(没有信息量)、过时的文档或注释。● 重复代码:违反了Don't Repeat Yourself原则。
● 复杂度:代码结构太复杂(如圈复杂度高),难以理解、测试和维护。
● 测试覆盖率:编写单元测试,特别是针对复杂代码的测试覆盖是否足够。
● 设计与架构:是否高内聚、低耦合,依赖最少。
在Jenkins中下载SonarQube插件,安装完成后,在系统管理->系统设置中,找到SonarQube servers模块,填写需要扫描的工程代码路径,构建成功后即可在SonarQube地址中登录访问,查看代码扫描情况。
Jenkins实现自动化集成
Jenkins是一个持续集成工具,也是我们持续集成整个流程的主角,从Git源码库中的代码拉取、单元测试验证到代码扫描报告的一系列流程,都可以通过Jenkins实现自动化执行。它可以根据设定持续定期编译,运行相应代码;运行UT或集成测试;将运行结果发送至邮件或展示结构。
目前,在现有的持续集成工具中,Jenkins已经成为持续集成事实上的标准,Jenkins的Pipeline插件已经定义了这些标准过程。
Jenkins用Java编写,可在Tomcat等流行的Servlet容器中运行,也可独立运行。通常与版本管理工具、构建工具结合使用;常用的版本管理工具有SVN、Git,构建工具有Maven、Ant、Gradle。Jenkins的安装和初始化启动过程可以参考Jenkins官网。
下面是使用Docker构建Jenkins的CI Server的过程。
首先,制作Jenkins的DockerFile配置文件。
其次,构建Jenkins Docker Image。
然后,启动Jenkins CI容器服务。
使用Docker部署Jenkins的好处是应用程序可以发布并直接部署Docker镜像,省去大量环境配置。我们在后面的Docker交付中,将对基于Docker的交付模式做进一步讲解。
下面,我们总结一下使用Jenkins实现持续集成的流程。
(1)开发者将自己分支的最新代码推到主干分支。
(2)从Git Master分支收到新的代码提交后,会触发Webhook启动相应的Jenkins job,启动Jenkins的整个CI流程。
(3)Jenkins从对应项目设置的代码仓库拉取相应编译环境的代码,完成代码的编译。
(4)Jenkins根据Pipeline插件功能增加集成测试任务,用于自动化回归测试。
(5)Jenkins根据事先设置的脚本任务和集成的SonarQube插件,完成对指定项目的代码扫描和代码分析报告,并将结果发送到指定邮箱。
下面是利用Jenkins的Pipeline DSL代码描述持续集成的示例流程。
总结一下,上述过程原本需要开发人员手动切换到不同环境进行例行工作,现在通过Jenkins实现了常规化、自动化的持续集成工作,有效避免了开发人员集成代码的重复工作。上述工作完成后,就实现了从代码提交到代码集成编译、单元测试、代码检查相关的集成工作。利用其Pipeline式的管理方式,Jenkins不仅可以进行持续集成,还可以进一步实现后续的代码部署和交付任务。
持续交付概述
持续交付(Continuous Delivery,CD)是一种软件工程方法,开发者可以用快速、自动化和可重复的方式从源码库部署交付软件,确保交付过程的标准化和自动化。它更加注重随时随地提供可靠发布的能力。
如果说持续集成是让我们的团队通过快速迭代提交代码到共享代码库中,提前发现模块集成中的问题,那么持续交付就是通过构建自动化的交付平台,允许团队更加频繁地交付可工作的软件产品,从而能够更快地得到用户对产品的反馈和对产品价值的体验。
持续交付最早由Jez Humble和David Farley提出,并在《持续交付:发布可靠软件的系统方法》一书中对其实现进行系统说明。而本书未对持续交付做明确定义,目前对持续交付比较认同的定义来自DevOps Handbook上的定义。
持续交付指的是,所有开发人员都在主干上进行小批量工作,或者在短时间存在的特性分支上工作,并且定期向主干合并,同时始终让主干保持可发布状态,并能做到在正常工作时段里按需进行一键式发布。开发人员在引入任何回归错误时(包括缺陷、性能问题、安全问题、可用性问题等),都能快速得到反馈。一旦发现这类问题,就立即加以解决,从而保持主干始终处于可部署状态。
首先,微服务的流行本身就是在持续交付方法论下发展起来的。
在单体架构下,所有模块集成在一个代码库下,往往一个小的改动会牵一发而动全局,代码的耦合影响产品对外的发布交付速度,如果不进行微服务的拆分,则系统的持续交付将面临一系列问题,而将单体分解成独立、自治、可部署的微服务,单独交付部署,就可以减少代码之间的耦合及相互影响。同时,微服务的交付周期短、功能单一、扩展性好、技术多样性等特征,都是持续交付所需要的。
同时,微服务的发展需要持续交付的支撑,微服务在拆分后面临服务众多、版本众多的问题,如果没有一套自动化的代码构建、测试、部署打包工具,则很难应付微服务在规模化部署下的持续交付。
另外,持续交付的价值不仅仅在于提升服务交付的效率,它还通过指定统一的标准、规范的流程、自动化平台,影响着软件研发到运维的整个生命周期。而持续交付最终将软件的研发流程进化为DevOps软件开发模式,实现端到端的软件价值交付。
持续交付Pipeline
下面是持续交付Pipeline的流程图。可以看出,持续交付的前提是持续集成,也可以说持续交付包含持续集成过程。
持续交付的核心是构建一个自动化的流水线,而这个持续交付工作平台可能贯穿了软件项目的整个生命周期。它不仅要串联起软件工程代码的提交集成、测试验证、打包管理、镜像交付,同时将影响整个公司组织端到端的业务,从开发测试到部署交付的整个流程过程。
下面我们总结一下实现持续交付的核心工作流程。
● 准备工作
○ 集成工具的技术选型,在持续集成一节中,源码的管理、持续集成工具的选择、自动化测试等软件工具的选择都将是后续完成自动化流程的关键步骤。
○ 部署载体的选择,目前容器已经成为微服务部署实施的标准运行时环境,而对于有状态服务或者存储相关服务,我们需要提前规划好交付方式的步骤。
○ 软件工程和组件结构可以帮助更频繁地发布服务,而不会对用户产生影响。
○ 软件监控和服务治理是持续交付的重要机制,在构建持续交付平台前,就应该为服务运维中需要的日志管理、应用及容器状态、指标性能等需求做配套设计开发。
○ 组织结构、业务流程的变化,需要支持持续交付。
● 自动化一切
○ 自动化的代码构建和打包。
○ 自动化的测试集成。
○ 自动化的发布机制。
○ 测试环境下服务的自动化部署。
○ 生产环境下服务的自动化部署。
● 构建持续交付流水线
我们在持续集成中,说过利用Jenkins的Pipeline可以实现自动化的流水线流程。如果你所在公司的人力不是很充足,则可以使用开源版本的Jenkins构建流水线平台。对于定制化的流水线,我们可以把软件生命周期中从代码到生产环境的所有过程全部可视化地展示出来,实现端到端的持续交付,实现持续交付过程中的增强功能。
○ 实现环境定制化配置管理。
○ 实现版本的回滚。
○ 实现灰度发布和版本切换。
○ 记录操作日志审计。
○ 可以实现网络的监控和拓扑管理。
本文给大家讲解的内容是微服务交付:微服务如何持续集成交付?
- 下篇文章给大家讲解的内容是微服务交付:基于容器的交付-Docker概述
- 觉得文章不错的朋友可以转发此文关注小编;
- 感谢大家的支持!
相关推荐
- Linux高性能服务器设计
-
C10K和C10M计算机领域的很多技术都是需求推动的,上世纪90年代,由于互联网的飞速发展,网络服务器无法支撑快速增长的用户规模。1999年,DanKegel提出了著名的C10问题:一台服务器上同时...
- 独立游戏开发者常犯的十大错误
-
...
- 学C了一头雾水该咋办?
-
学C了一头雾水该怎么办?最简单的方法就是你再学一遍呗。俗话说熟能生巧,铁杵也能磨成针。但是一味的为学而学,这个好像没什么卵用。为什么学了还是一头雾水,重点就在这,找出为什么会这个样子?1、概念理解不深...
- C++基础语法梳理:inline 内联函数!虚函数可以是内联函数吗?
-
上节我们分析了C++基础语法的const,static以及this指针,那么这节内容我们来看一下inline内联函数吧!inline内联函数...
- C语言实战小游戏:井字棋(三子棋)大战!文内含有源码
-
井字棋是黑白棋的一种。井字棋是一种民间传统游戏,又叫九宫棋、圈圈叉叉、一条龙、三子旗等。将正方形对角线连起来,相对两边依次摆上三个双方棋子,只要将自己的三个棋子走成一条线,对方就算输了。但是,有很多时...
- C++语言到底是不是C语言的超集之一
-
C与C++两个关系亲密的编程语言,它们本质上是两中语言,只是C++语言设计时要求尽可能的兼容C语言特性,因此C语言中99%以上的功能都可以使用C++完成。本文探讨那些存在于C语言中的特性,但是在C++...
- 在C++中,如何避免出现Bug?
-
C++中的主要问题之一是存在大量行为未定义或对程序员来说意外的构造。我们在使用静态分析器检查各种项目时经常会遇到这些问题。但正如我们所知,最佳做法是在编译阶段尽早检测错误。让我们来看看现代C++中的一...
- ESL-通过事件控制FreeSWITCH
-
通过事件提供的最底层控制机制,允许我们有效地利用工具箱,适时选择使用其中的单个工具。FreeSWITCH是一个核心交换与混合矩阵,它周围有几十个模块提供各种功能特性。我们完全控制了所有的即时信息,这些...
- 物理老师教你学C++语言(中篇)
-
一、条件语句与实验判断...
- C语言入门指南
-
当然!以下是关于C语言入门编程的基础介绍和入门建议,希望能帮你顺利起步:C语言入门指南...
- C++选择结构,让程序自动进行决策
-
什么是选择结构?正常的程序都是从上至下顺序执行,这就是顺序结构...
- C++特性使用建议
-
1.引用参数使用引用替代指针且所有不变的引用参数必须加上const。在C语言中,如果函数需要修改变量的值,参数必须为指针,如...
- C++程序员学习Zig指南(中篇)
-
1.复合数据类型结构体与方法的对比C++类:...
- 研一自学C++啃得动吗?
-
研一自学C++啃得动吗?在开始前我有一些资料,是我根据网友给的问题精心整理了一份「C++的资料从专业入门到高级教程」,点个关注在评论区回复“888”之后私信回复“888”,全部无偿共享给大家!!!个人...
- C++关键字介绍
-
下表列出了C++中的常用关键字,这些关键字不能作为变量名或其他标识符名称。1、autoC++11的auto用于表示变量的自动类型推断。即在声明变量的时候,根据变量初始值的类型自动为此变量选择匹配的...
- 一周热门
-
-
C# 13 和 .NET 9 全知道 :13 使用 ASP.NET Core 构建网站 (1)
-
因果推断Matching方式实现代码 因果推断模型
-
git pull命令使用实例 git pull--rebase
-
git pull 和git fetch 命令分别有什么作用?二者有什么区别?
-
面试官:git pull是哪两个指令的组合?
-
git 执行pull错误如何撤销 git pull fail
-
git fetch 和git pull 的异同 git中fetch和pull的区别
-
git pull 之后本地代码被覆盖 解决方案
-
还可以这样玩?Git基本原理及各种骚操作,涨知识了
-
git命令之pull git.pull
-
- 最近发表
- 标签列表
-
- git pull (33)
- git fetch (35)
- mysql insert (35)
- mysql distinct (37)
- concat_ws (36)
- java continue (36)
- jenkins官网 (37)
- mysql 子查询 (37)
- python元组 (33)
- mysql max (33)
- vba instr (33)
- mybatis 分页 (35)
- vba split (37)
- redis watch (34)
- python list sort (37)
- nvarchar2 (34)
- mysql not null (36)
- hmset (35)
- python telnet (35)
- python readlines() 方法 (36)
- munmap (35)
- docker network create (35)
- redis 集合 (37)
- python sftp (37)
- setpriority (34)