不要让Maven部署插件绊倒你

Apache Maven是一个常用的构建工具。它有许多很酷的特性,比如开箱即用的默认处理步骤,特别适合编译和打包Java代码。但是这篇博文并不是Maven的介绍。有很多很棒的书都提供了这些,你也可以找到有经验的同事来学习。我也不打算讨论Maven的优缺点。有很多成功的项目喜欢它的优点,也有一些项目喜欢其他工具,因为它的缺点。我想要探索的是Maven的部署插件(主要在Maven部署阶段使用),它的缺点以及如何解决它们。这是我经常被问到的问题,所以这里总结一下答案。
Maven部署插件及其缺点
使用Maven通常包括使用部署插件将构建工件上传到远程存储库,以便与其他团队共享。这很方便,你只需要加一个< distributionManagement / >节到您的Maven POM以引用远程存储库,如JFrog Artifactory,你就差不多完成了。有时,这确实是一个充分的解决办法,但现在,往往有一些要求和基本条件促使我们寻求更先进的解决办法,原因如下:
项目聚合可能导致部署不一致
Maven支持项目聚合的概念,在这个概念中,一批模块被一起处理。这尤其在将模块部署到组件存储库时使用。问题是,所有Maven模块都是依次处理和部署的,一个接一个。如果部署任何模块失败,则远程存储库将使用新版本的模块更新,但保留部署失败的模块的旧版本,从而使其处于不一致的状态。“质量就是没有错误”(杰拉尔德·温伯格,《质量软件管理》卷1《系统思考》(Dorset House, 1992),第9页)。

环境很重要
如今,当上下文越来越重要时,仅仅分发二进制文件往往是不够的。二进制的真实值是从它的上下文和元信息中产生的。例如,在大型和复杂的项目设置中,质量检验关被注射,并且二进制文件根据当前的处理状态进行标记/认证,或者只是由构建引擎使用构建信息(包括依赖项)进行充实。用例包括想要找到并处理带有特定属性注释的工件,或者检查构建依赖关系的影响路径。构建管理中更高级的工具提供了物料清单报告,依赖性和可追溯性检查,有助于完整性和审计(Mario E. Moreira, Agile团队的适应性配置管理(Wiley, 2010),第231页)。.
您需要部署灵活性
在运行一系列构建时,您通常需要配置应该将哪些构件部署到目标存储库。例如,您可能会跳过正在构建的一些构件,并从其他来源添加不同的构件。默认情况下,Maven采用更严格的方法,并期望为构建的每个工件部署一个模块。虽然有一些方法可以解决这个问题,但是临时解决方案可能很快就会变得不可维护,因此最好是提供细粒度部署灵活性的更标准、更灵活的解决方案。
您应该保持您的POM文件整洁
添加< distributionManagement / >到Maven POM,即使它只是一个父POM,也会污染POM文件。POM应该只包含关于如何编译和打包代码的信息,保持整洁通常是明智的做法。
不要向开发人员公开Maven远程存储库
在敏捷设置中,不应该允许开发人员直接部署到Maven远程存储库。那么,为什么要费心打开大门并添加关于远程存储库的部署目标的信息呢?它是构建服务器,如詹金斯,这部署工件,并且在Jenkins的情况下,它可以被配置为集中完成。

周期时间太长
的周期时间是衡量你的产品上市时间是否最优的常用指标(米ichael Huttermann, DevOps for Developers (Apress, 2012), 38ff)。为了保持低成本和优化,流程和工具必须以高质量快速完成它们的工作。Maven部署任务通常花费的时间比必要的要长,因为它们包含不必要的处理步骤,例如编译和打包已经打包的工件的代码,或者它们只是低效地部署工件。
二进制文件和它们的构建管道应该解耦
随着DevOps的不断发展,输送管道变得越来越异质。管道基于单一技术(如Java)的日子已经一去不复返了。受特定技术的约束可能是不必要的,甚至会适得其反。最好将二进制管理与本地构建基础结构解耦,这样就可以轻松地部署二进制文件,并且操作等下游功能可以完全独立于构建工具和技术获取并使用它们。虽然Maven是一种广泛传播的标准,但为什么要坚持其专有的部署流程呢?“成功的秘诀不在于预见未来,而在于建立一个能够在任何不可预见的未来中繁荣发展的组织。(Mary和Tom Poppendieck, Leading Lean Software Development-Results are not the Point (Addison-Wesley, 2010), 236ff)。
让打包和部署再次变得有趣
“协调复杂系统的打包和部署是一项无聊的任务,几乎比看起来要困难得多”(Eric Evans,领域驱动设计(Addison-Wesley, 2014),第387页)。事实并非如此。打包和部署是整个过程的重要组成部分,它太重要了,不能仅仅坚持一些可能不适合您的个人需求和基本条件的假定标准。
如何做得更好
JFrog Artifactory,通用工件存储库管理器,以及它的生态系统,支持解决上述开箱即用的所有缺点的解决方案。它为您提供了不同的方法来实现与您的需求一致的解决方案。在下面的段落中,我将提供示例,展示使用原子事务部署工件的不同方法,以及如何使用与构建工具无关的细粒度处理来标记/认证它们,同时支持诸如关注点分离通过保持POM文件干净(参见弗兰克Buschmann等人,面向模式的软件架构(Wiley, 1996),第241页)。让我们从最明显的方法开始,即与构建引擎的集成。
使用构建引擎集成
集成Jenkins和Artifactory,通过Jenkins Artifactory插件,有许多吸引人的好处(参见米ichael Huttermann, Agile ALM (Manning, 2011),第229页),包括解决上面提到的标准Maven方法的缺点。安装Jenkins Artifactory插件后,只需创建一个新的构建作业(例如Jenkins Freestyle构建),并在其配置页面中启用Maven3-Artifactory集成。的调用Artifactory Maven 3构建步骤只需要调用Maven的安装阶段,其余的由Jenkins Artifactory插件完成。
你也可以使用Jenkins 2的原生交付管道特性。以下阶段向工件添加一个属性(即一个键/值对),并将二进制文件以及一个示例属性部署到Artifactory。
stage ('Maven build') {rtMaven.deployer.addProperty(“地位”,“在qa阶段”)buildInfo = rtmwen .run pom: 'all/pom.xml',目标:'clean install'服务器。publishBuildInfo buildInfo}
下一个例子展示了如何:
- 通过使用上传规范,以JSON格式定义要部署到Artifactory的二进制文件集
- 上传带有示例元信息注释的工件
- 并且还发布上下文信息,即插件生成的详尽构建信息
”“”{“文件”:[{“模式”:“所有/目标/ - (*). war”,“目标”:“libs-snapshot-local / com/huettermann/web/{1} /”,“道具”:“= swampUP;所有者= huettermann”}]}”“”buildInfo = Artifactory.newBuildInfo()buildInfo.env.capture = truebuildInfo = server.upload (uploadSpec)server.publishBuildInfo (buildInfo)}
这可以集成到整体的交付管道中,并允许实现质量检验关(也可以应用于其他工件类型,如Docker映像或厨师烹饪书)。
但是有一种更灵活的方法可以将二进制文件传输到JFrog Artifactory;通过使用REST API。
使用REST API
人工暴露了一个富人REST API这使您可以自动执行工件上的许多不同操作,包括上传二进制文件.使用以下命令上传二进制文件旋度看起来像这样:
curl -u admin:$artifactory_key -X PUT "https://localhost:8071/artifactory/simple/libs-qa/com/huettermann/all/1.0.0/all-1.0.0.war;status=in-qa" -T all-1.0.0.war
我们传递凭据,并定义目标存储库和要上传的本地文件。配置调用有几种不同的方法。例如,您可以使用访问密钥或访问令牌.现在,我们可以搜索所有标有财产“状态”和“质量”的价值。在UI中,它看起来像这样:

作为脚本化解决方案的一部分,我们现在可以使用人工查询语言(AQL)来查找具有给定属性的工件。
venus:剪贴簿michaelh$ curl -H "X-JFrog-Art-Api:$artifactory_key" -X POST https://localhost:8071/artifactory/api/search/aql -T search.aql{"results": [{"repo": "lib -release-local";"path": "com/huettermann/all/1.0.0","name": "all-1.0.0.war"},{"repo": "lib -qa";"path": "com/huettermann/all/1.0.0","name": "all-1.0.0.war"}),"range": {"start_pos": 0,"end_pos": 2,total: 2}}
在哪里search.aql脚本看起来像这样:
items.find ({"名称":{" $匹配”:“* . war”},“@status”:{" $ eq”:“在qa阶段”},“created_by”:“部署”})其中包括(“名称”、“回购”、“路径”).sort({“asc美元”:["名称"]})
最后,我想介绍的最后一个选项是JFrog CLI。
使用JFrog命令行
JFrog命令行接口是一个封装REST API的小型辅助可执行文件。可以是很容易下载而且非常。使用直观.再一次,让我们考虑一个简单的例子,将名为“hello.txt”的二进制文件上传到Artifactory中名为“generic-local”的通用存储库(即,类型为“generic”的存储库)。这很简单:
Jfrog rt u——url=https://localhost:8071/artifactory——apikey=$artifactory_key你好。战争generic-local
另一个常见的用例是在工件通过某些质量关口后,将其提升到Artifactory中的另一个存储库触发促销基于前一个构建的构建信息。请注意,这个示例将工件复制(而不是移动)到staging存储库,而不复制其依赖项:
Jfrog rt BPR——include-dependencies=false——apikey=$artifactory_key——url = https://localhost: 8071 / artifactory——copy=true $JOB_NAME $BUILD_NUMBER lib -qa
在这里,您也可以对指定的构件做更多的事情,比如包括Java部署单元、向其中添加元信息等等。阅读所有的可能性JFrog CLI用户指南.
因此,您不必让Maven的缺点部署让你下来。这篇文章展示了不同的使用方法JFrog Artifactory和它的生态系统去克服它们。我所举的例子都非常具体,但都说明了一点。由你来探索神器,它的REST API和JFrog CLI了解如何使用Maven部署解决您自己的问题。
