基于Jenkins的持续集成自动部署研究*
2016-03-15欧中红
周 莹 欧中红 李 俊
(武汉数字工程研究所 武汉 430205)
基于Jenkins的持续集成自动部署研究*
周莹欧中红李俊
(武汉数字工程研究所武汉430205)
摘要在基于Jenkins的持续集成系统中,应用程序的组件管理和依赖管理是至管重要的。论文提出了一种方案,通过引入依赖管理工具Ivy和制品管理工具Artifactory,以及设计相应的脚本程序,获取正确版本的制品组成部署安装包。确保在集成过程中,组成应用程序的模块的所有版本保持一致,避免依赖地狱的产生,为自动化部署提供基础。
关键词持续集成; 依赖关系; Jenkins; 自动部署
Automated Deployment of Continuous Integration Based on Jenkins
ZHOU YingOU ZhonghongLI Jun
(Wuhan Digital Engineering Institute, Wuhan430205)
AbstractIn the continuous integration system based on Jenkins, it is very important to manage the components of application and the dependencies between components. A scheme is given in this paper, in which the correct version of artifacts for deployment package is gotten by enhancing Ivy the dependency management tool and Artifactory artifacts management tool, as well as constructing related script. This is the basis for automated deployment, ensuring all versions of the modules in the application be consistent and dependence hell be avoided in the process of integration.
Key Wordscontinuous integration, dependency relationship, Jenkins, automated deployment
Class NumberTP311.1
1引言
持续集成是软件开发的一个重要实践。持续集成的引入,降低了软件开发的风险,提高软件开发效率,提高代码质量,使项目管理人员更好地了解项目的开发进度[1~2]。每次集成过程包括编译,构件、部署、测试、发布,并且这个过程是自动化实现的[3]。实现自动化部署是实现自动化测试的基础[4]。
在软件开发过程中,不同的功能模块一般由不同的开发团队负责,相同模块也由团队程序员共同实现。在这种情况下,代码的集成显得尤为重要。当各模块通过单元测试后,需要将模块组合在一起,进行集成测试,测试模块之间的接口。当模块与第三方库或模块与模块之间存在依赖关系时,为集成测试提供正确版本的模块及第三方库是集成测试成功的基础。模块之间的依赖是二进制文件的依赖,在为应用程序组装部署安装包时,必须保证各个模块在构建过程中依赖的二进制文件版本与其在部署安装包中的版本保持一致,并且不同模块不能对同一模块的不同版本存在依赖关系,防止形成依赖地狱(dependence hell)。
在基于Jenkins[5]的持续集成系统中,使用已有的插件只能部署当前job生成的war/ear文件到远程Web容器中,如Tomcat,不能实现C++应用的多个且有依赖关系的文件地部署。本文通过在持续集成系统中,引入依赖管理工具Ivy和制品管理工具Artifactory,旨在对C++项目的模块间依赖关系和模块的制品进行有效的管理。当所有模块通过单元测试并将制品上传到制品库中后,可通过执行脚本文件获取指定版本、指定平台的部署安装包,并保证各模块为正确版本,为自动化部署提供基础。
本文通过一个多模块应用程序的实例,说明如何根据模块之间的关系在持续集成服务器中配置模块的工程,如何通过Ivy管理组件之间的依赖关系,同时说明如何从制品库中获取指定版本的应用程序的模块。
2持续集成的实现过程
在对软件实施持续集成之前,需要在持续集成服务器上为每个模块创建一个构建流水线。在每个模块的job配置中,需指定该模块源代码在svn中的存放地址,使系统能够检测到svn上代码的更新,并立即触发新的构建过程;指定构建过程执行的脚本,以及指定上传制品的制品库地址;根据组件之间的依赖关系,配置需要触发的下游项目,以此达到持续集成的目的。
持续集成的实现可分为提交阶段和测试阶段。图1为持续集成系统的基本实现过程[6~7]。
图1 持续集成系统基本实现过程
提交阶段主要包含以下过程:
1) 开发人员向版本控制库提交A模块的代码;
2) 持续集成服务器A模块的job检测到代码变更,触发A模块构建过程,编译代码、运行单元测试、执行代码分析,创建模块的二进制包。当构建通过单元测试并且代码符合编码标准,便将生成的二进制文件存放在制品库中;
3) 若B模块依赖与A模块,当A模块通过构建之后会触发B模块流水线的构建过程;
4) 当由代码更新触发的所有模块的构建过程完成之后,将该软件所有模块的制品组装成部署安装包,触发自动化验收测试阶段。
测试阶段主要是将部署安装包部署到相应的测试环境进行测试,通过自动化测试来验证集成是否成功[8],验证模块接口及软件是否符合用户的需求。
从提交阶段进入测试阶段,最主要的就是组装部署安装包。部署安装包是由所有组件的二进制文件及其依赖文件组成,设计组件依赖关系的管理。
3获取部署安装包
3.1持续集成系统基本组成
本文主要采用Jenkins+svn+ant[9]+Ivy+Artifactory组成基本的持续集成系统。其中Jenkins为持续集成服务器,svn为版本控制工具,ant为脚本构建工具,Ivy是一个用来管理(记录、跟踪、解决和报告)项目依赖项的工具,Artifactory是一个制品库管理工具,用于存放第三方库文件和系统构建产生的制品。Ivy具有灵活性和可配置性,适应广泛的依赖管理和构建过程,支持通过查找Ivy文件中的元数据来解决传递依赖这一普遍问题。Ivy与maven[10]比较而言,在冲突管理及灵活性方面做的更好。使用专业的制品管理工具,是为了确保构件的可重复性,通过在整个组件范围内控制应用程序对应的库的版本来避免依赖地狱。
本文实例应用程序的模块包括Console、Find、Sizewhere、List、Size、Version以及第三方依赖库Commons-coli、Common-logging、Commons-lang、和Commons-collections。它们之间的依赖关系如下图2所示。图中箭头终点处模块对箭头起点处组件依赖。
图2 模块依赖关系图
3.2模块的相关配置
根据模块依赖关系图可知,模块间有直接依赖和间接依赖的关系。在Jenkins中对模块进行配置时,需对模块之间的上下游关系进行分析。图3模块间触发关系图。
图3 模块间触发关系图
从图3可以看出模块Size对模块Version直接依赖,同时模块Size因为依赖模块List而对模块Version间接依赖。当模块Version代码更新时,若同时触发模块List和模块Size,可能导致模块Size依赖的是新版本的模块Version和对旧版本模块Version依赖的模块List。这样就导致了模块Size同时对Version的新版本和旧版本同时依赖,这种情况在持续集成过程中是应该避免的。为了防止Size对不同版本的Version有依赖关系,模块Version不能直接触发模块Size。同理分析,对各模块上下游触发关系进行如下配置:
1) Version模块触发下游List模块;
2) List模块触发下游模块Find模块和Size模块,并且使用Join插件实现在Find和Size都构件完成之后再触发下游模块Sizewhere;
3) Find模块触发下游组模块Sizewhere;
4) Size模块触发下游模块Sizewhere;
5) Sizewhere模块触发下游模块Console;
6) Console模块不触发下游模块。
3.3Ivy管理模块的依赖关系
在软件中常见的依赖关系有模块依赖和第三方库文件依赖。根据图中模块的依赖关系,可为每个模块定义Ivy文件,用于在模块构建时从制品库中下载依赖文件。如模块List对Version、和第三房库Commons-cli有依赖关系,模块List的ivy.xml为
〈ivy-module version="1.0"〉
〈info status="integration" module="list"
organisation="org.apache.ivy.example"/〉
〈configurations〉
〈conf name="core"/〉
〈conf name="standalone" extends="core"/〉
〈/configurations〉
〈publications〉
〈artifact name="list" conf="core"
type="jar"/〉
〈/publications〉
〈dependencies〉
〈dependency name="version"
rev="latest.integration"
conf="core->default"/〉
〈dependency org="commons-cli"
name="commons-cli" rev="1.0"
conf="standalone->default"/〉
〈/dependencies〉
〈/ivy-module〉
其中〈configurations〉定义了组件List发布制品的集合core和standalone。〈publications〉定义了将该组件生成的制品list.jar发布到core配置项中。若开发多平台的应用程序,可指定不同平台的配置项,并指定发布到该配置项中的制品实现制品与平台的映射关系。〈dependencies〉中配置的是List与其他组件的依赖关系。指定依赖于组件Version的版本为最新版本latest.integration。在Ivy中有三种默认的状态release、milestone和integration,此外还可以通过statues来定义更多可用的状态,状态定义的顺序即为解析依赖时匹配的优先级。Conf为配置依赖项之间的映射关系,如List对Version的依赖映射关系core->default表明模块List的core配置项依赖Version的默认配置项。由于第三方库文件也是以二进制文件的格式存储在制品管理库中,并且版本不会经常更新,因此可以指定rev为固定版本。
对于存在传递依赖关系的模块,在Ivy文件中只需要定义模块的直接依赖项,在解析依赖过程中Ivy会同时解析间接依赖项。为了在某版本的应用程序中保持模块版本的一致性,Ivy通过在解析过程中创建一个文件,使在同一个resolveId和同一个解析缓冲区中不能对同一个模块有不同的解析版本。
通过在Ivy文件中指定依赖项的版本号和配置映射关系,在模块构建的过程中便可以正确解析模块的依赖项。同时对模块之间的依赖关系进行分析,对模块进行正确的配置,当模块代码更新时,可以触发相关模块的构建以及测试过程。
3.4组装部署安装包
对所有模块的ivy.xml进行正确配置是模块进行正确构建的基础。所有模块通过单元测试,将生成的二进制制品上传到制品库后,就需要将所有模块组装在一起。当当前流水线组装安装包或组装指定版本的应用程序安装包时,本文也通过采取解析Ivy文件的方式获得相关模块的正确版本。该Ivy文件是在每个模块上传制品的同时上传的构建过程的产生的依赖解析报告ivy.xml。依赖解析报告ivy.xml内容为
〈ivy-module version="1.0"〉
〈info organisation="org.apache.ivy.example"
module="console" revision="1.0-dev-b1"
status="release" publication="20150705"/〉
〈dependencies〉
〈dependency name="version"
rev="1.0-dev-b1"
revConstraint="latest.integration"
conf="default"/〉
〈dependency name="find" rev="1.0-dev-b1"
revConstraint="latest.integration"
conf="default->standalone"/〉
〈dependency name="sizewhere"
rev="1.0-dev-b1"
revConstraint="latest.integration"
conf="default->standalone"/〉
〈/dependencies〉
〈/ivy-module〉
该ivy.xml文件描述的是模块Console版本为1.0-dev-b1的依赖解析报告。与之前定义的Ivy文件的区别是,依赖项的版本是准确版本,依赖模块Version的1.0-dev-b1版本,模块Find的1.0-dev-b1版本,及模块Sizewhere的1.0-dev-b1版本。若指定获取Console的1.0-dev-b1版本,可通过解析该Ivy文件及迭代解析模块Version、Find、Sizewhere的Ivy文件,获取相关模块的版本。根据制品在Artifactory中存放的规律,通过在脚本中使用Artifactory REST API便可从制品库中获取与指定版本相关的所有二进制文件,这些制品文件便组成了部署安装包。
过程的实现依赖于对模块Ivy文件定义的正确性,通过Ivy的使用,通过执行脚本可以从制品库中获取组成该版本应用程序的模块及依赖库的二进制制品,并组装成部署安装包,用于后续的测试过程。
4结语
通过在持续集成服务器中对应用程序的模块的配置,正确指定模块的上下游触发关系,并结合ivy文件对模块之间依赖关系的管理,能够避免应用程序产生对统一模块的不同版本的依赖。同时根据产生的依赖解析报告,可以从制品库中下载制定版本应用程序的部署安装包,为集成测试提供基础。
参 考 文 献
[1] 陈刚,羌玲玲.软件项目开发中的持续集成研究[J].项目管理技术,2011,12(12):1.
CHENG Gang, QIANG Lingling. Research on Continuous Integration in Software Development[J]. Project Management Technology,2011,12(12):1.
[2] 王英.持续集成在软件项目管理中的作用[J].福建电脑,2009,12:66-67.
WANG Ying. The Role of Continuous Integration in Software Project Management[J]. Fujian Computer,2009,12:66-67.
[3] 刘巧玲,范冰冰,黄兴平.基于Husdon的持续集成研究和应用[J].计算机系统应用,2010,12:1.
LIU Qiaoling, FAN Bingbing, HUANG Xingping. Research and Application of Continuous Integration Based on Hudson[J]. The Computer System Application,2010,12:1.
[4] 李进.某公司软件持续集成改进的分析设计及实施[D].北京:北京邮电大学,2012,5.
LI Jin. Analysis, Design And Implementation of Software Continuous Integration Improvement in a Company[D]. Beijing: Beijing University of Posts and Telecommunications,2012,5.
[5] JenkinsM.[2015-6-2]. http://wiki.jenkins-ci.org/display/JENKINS/Meet+Jenkins.
[6] 林新党,穆加艳.基于Jenkins的持续集成系统研究[J].雷达与对抗,2014,3(34):58-61.
LIN Xindang, MU Jiauan. Continuous integration system based on Jenkins[J]. Radar & ECM,2014,3(34):58-61.
[7] Jez Humble, David Farley,乔梁.持续交付发布可靠软件的系统方法[M].北京:人民邮电出版社,2011,10:89.
Jez Humble, David Farley, QIANG Liang. Continuous Delivery Reliable Software Releases Through Build, Test, and Development Automation[M]. Beijing: Posts and Telecom Press,2011,10:89.
[8] 马建辉.持续集成的概念与应用分析[J].福建电脑,2010(5):58-59.
MA Jianhui. The Concept and Application Analysis of Continuous Integration[J]. Fujian Computer,2010(5):58-59.
[9] 徐仕成,杨邦荣.基于Cruise Control的持续集成实现方案[J].计算机与数字工程,2007,35(4):169-175.
XU Shicheng, YANG Bangrong. Continuous Integration Realization Scheme Based on Cruise Control[J]. Computer and Digital Engineering,2007,35(4):169-175.
[10] 李俊杰.Maven在企业Java软件产品中的应用[J].电脑知识与技术,2011(7):1562-1563.
LI Junjie. Applying Maven Developing EnterpriseJava Application[J]. Computer Knowedge and Technology,2011(7):1562-1563.
中图分类号TP311.1
DOI:10.3969/j.issn.1672-9722.2016.02.021
作者简介:周莹,女,硕士研究生,研究方向:计算机系统结构。欧中红,男,研究员,研究方向:计算机系统结构。李俊,女,博士,高级工程师,研究方向:计算机软件与理论。
*收稿日期:2015年8月12日,修回日期:2015年9月25日