用例——构建系统的系统——为遗留应用程序创建通用的CI/CD管道

文摘:

Mark Maxey / Raytheon, 2016年5月:许多持续集成和交付(CI/CD)文献都是针对具有类似配置文件的项目,即小型项目发布一些高度模块化的服务,针对互联网,使用Git、Jenkins和Chef或Puppet等自动化配置工具,它们之间很少或没有耦合。这可能对CI/CD独角兽来说是真的,但如果你不是一个很酷的孩子,你会怎么做?

讨论转录:

好吧。嗯,欢迎。我很感激你能在午饭前过来。我很高兴不是在午饭后。我想再过一个小时我就会有不同的听众了。你们都准备好了,饥肠辘辘。渴望学习。我希望。或者可能不是这样。

我叫马克·马克西。我在雷神公司工作。我的电子邮件地址在这里。在Raytheon。com标记下划线R下划线Maxey。你可以通过这个联系我,或者之后我们可以聊天。当我讲到这里的时候,我会停下来,一定要问问题或发表评论。请不要吃烂番茄或其他类似的东西。

所以我们将讨论我们在雷神公司的一个用例。感谢我们所做的以及我们如何使用Artifactory。

让你们了解一下雷神公司。雷神公司有一大堆我们做的东西。我们有大约10万名员工。我们在美国各地有许多不同的校区。我们制造了爱国者导弹,微波,地面控制系统,GPS和气象卫星,还有几天前阿德里安讲过的头盔上的头戴式显示器和其他类似的东西。但我们经常做的一件事,也是我参与最多的一件事就是建立一个系统的系统。

所以通常的情况是,我们聚在一起,我们有一个系统,我们想要加强或一个系统,我们想要与其他系统相结合,所以我们需要把这些东西聚集在一起。大多数情况下,这些系统不是从零开始创建的。我们几乎没有绿屏创业公司,至少在我的行业里是这样。我们总是从其他事物中创造一些东西。所以我们总是把东西放在一起,把两种不同的东西提取出来,让一些新的东西结合在一起。因此,每当我们这样做时,我们通常会面临处理遗留应用程序带来的许多挑战。很多时候,你把不同的技术、不同的流程和不同的管道结合在一起,这些技术、流程和管道可能以前不存在,也可能以前不存在。

所以我们今天要做的是我们将要讨论一个这样的用例,我最近一直在研究它。

所以我只是个普通人。我去做一个项目,他们说,嘿,马克,你能帮我做这个小部件吗。我想,好吧,我来创建这个小部件。但是,你知道,你希望这个小部件是什么样子的?所以,对我来说,我开始谈论非功能需求。你知道,可用性,可靠性,是最常见的非功能需求。但是我认为速度,生产力,可靠性,效率,所有这些——成本——我认为这些也是非常重要的非功能要求。至少这些是我感兴趣解决的问题。但至少当我们进入项目时,至少在我的行业中,我们经常面临固定的需求、进度和预算,这显然有点问题。

所以你开始的时候会有很多限制。你不能彻底检查遗留架构,你有很长的交付,你有很多人不真正理解持续集成,持续交付。很多时候,当我进入一个项目时,我只是一个有一堆想法的人。我唯一的能力就是说服别人。那么当你遇到这种情况时,你会怎么做呢?这就是我今天要讲的内容。

这是我们要看的内容的概要。它会涵盖我们目前所做的很多事情。我们现在正在做的和将来要做的。在这个过程中,我将会提出一些我认为围绕Artifactory的有趣改进,以及Artifactory可能会考虑在未来与我们合作的事情。

首先,像很多人一样,我们没有一个单一的版本控制系统。我们在这个项目中使用了多个版本控制系统。不仅仅是一家公司,我们经常有多家公司合作来创造我们创造的产品。第一个想法是,好吧,当你有这么多不同的vcse,这么多不同的管道,你如何让所有这些家伙在一个故事中一起玩。Artifactory是我们所看到的整合基地。所以,我们不一定关心你在版本控制系统中做了什么,只要它是可重复的,可靠的,有标记的等等。我们真正关心的是说,好吧,无论何时你完成了你的东西,你将把它倾倒到Artifactory中,这将是我们开始执行一些政策和约束之类的地方。

我们做的一件事是使用Jenkins来构建。Jenkins工作得很好,因为它可以跨多个版本控制系统工作。每当我们在不同的版本控制系统中构建时,我们所做的一件事是,我们将单个基线的所有输出转储到单个存储库中。所以这和你可能从不同的人那里听到的有点不同。在过去,几年前,我和许多人一样,有一个存储库,里面有各种版本,各种分支,各种基线我个人发现,跟踪它是相当具有挑战性的,因为你必须开始依赖IV状态或标签等类似的东西来描述它,最终你的版本号变得很不稳定,对我们来说,我们在任何时候都有20到30个不同的分支在运行。把所有这些都放在一个存储库中会让人很困惑。

所以很快,我们决定一个仓库代表一个基线代表一个分支。所以不管你的版本控制系统来自哪里。无论你的分支名称是什么,或者Git或其他等效的版本控制系统是什么,我们都会触发Jenkins构建输出到逻辑上一起的所有内容,这些内容在逻辑上属于同一分支的一部分。我们把这些都放到了一个仓库里。

这碰巧有一些很好的副作用。你可以在一个存储库中查看一个基线的所有内容然后你可以在不同的存储库中使用不同的基线。然后每当你看着部署时,这是超级简单的因为我们可以部署在一个URL和一个URL代表了一个存储库,我们不需要任何复杂的逻辑来找出哪些分支或者使用哪个版本或其他东西,我们只是去最新的从一个存储库,我们知道最新的,是我们所关心的基线。

因此,为了建立所有这些,第一个挑战是回答我们如何将我们的东西放入Artifactory的问题。这很有挑战性,因为并不是每个人都使用支持发布和解析依赖关系的构建技术。所以我认为这个问题在今天早上的主题演讲中就已经出现了,你如何利用传统技术来实现这个目标。好吧,我要举手说,我认为我们已经找到了一个相当不错的答案它围绕着Gradle的使用。

因此,每当我们谈论短期解决方案时,我们都在谈论我们可以轻松地将自己注入遗留应用程序的方法,而不必让它们改变它们的世界。我们想要一个温和的介绍,我们可以说,好吧,这是一个很容易实现的目标。简单的第一步,您可以使用现有的构建。我们可不想把它弄得太乱。我们只是想把你现在发布的东西放到Artifactory里。

有几种方法可以做到这一点。Gradle的第一种方法是一种非常粗糙的方法。这不是你通常用Gradle做的。但我们使用它作为下载和上传存储库。在你看到的第一个用例中,在右上角,你会看到我们使用Gradle作为下载管理器,并在其中表达依赖关系。我们下载它们,把它们放到一个特定的目录中,然后当[…]构建启动时,它可以是perl脚本、makefiles、Ant等等,我们并不真正关心[…]构建方式是什么。这对我们来说很好,因为我们根本不会碰你。我们把你的依赖放到你期望的地方,然后在外面,一旦你完成了构建,我们就会意识到构建完成了,我们会去发现那些构建的输出是什么。也许我们用rpm或zip或其他方式包装它。然后我们可以把它推到Artifactory中,这样它就可以把它变成一个设置,一个执行,一个拆卸或一个发布阶段。

所以这适用于[…]不太好的构建。我也有同感。但是对于传统上用Ant编写的构建来说,它们是稍微更好的解决方案,因为Gradle handle中集成了非常好的Ant。因此,对于我们的一些构建,我们只是在Gradle中逐步构建Ant。所以我们直接使用Gradle来执行Ant构建。将Ant目标转换为Gradle任务,我们使用相同的依赖解析,将这些依赖注入到Ant属性中。然后在外部,我们发布Ant输出,有时以不同的形式打包它,并将其发布到Artifactory。

这是一个很好的即时步骤,但我们发现,当人们开始了解Gradle能为你做什么时,当他们开始看到那里的dsl时。当他们开始看到来自Gradle的约定以及Gradle转换是多么容易时,越来越多的人开始想要转换到Gradle。所以对于我们和我们的项目来说,我们长期战略的一部分是转换到Gradle,并且只使用纯Gradle构建。所以我们所做的其中一件事就是我们编写了一些插件,为我们介绍企业或项目特定的标准,这对Java来说真的很好。但是我们也支持一些非常不标准的东西。例如,我们的构建支持,使用Gradle在Windows和Linux上使用c++进行本地构建。我们还支持Java代码生成,例如使用Jax B或Sequal J、Jax WS或任何不同的Java代码生成工具。

这样做的好处之一就是我们的构建端我们最终得到的Gradle构建脚本里面除了依赖声明几乎什么都没有。因为我们的Gradle构建脚本最终会完全依赖于你声明你的依赖项是什么,然后我们的企业插件会为我们照顾所有其他的构建逻辑。不仅仅是构建逻辑,还有打包、发布、依赖项解析,所有这些都是为您完成的。所以你最终得到的是5行构建脚本,而不是20到30个不同的项目,每个项目都有自己的一套构建技术,每个项目背后都有数百或数千行构建内容。一个相当不错的过渡。

有多少人熟悉常青藤构型?甜的。好吧。除了你,大家都可以上一分钟艾薇的课。Ivy是一种非常好的依赖声明技术。它与Ant的集成很好,与Artifactory和Pom文件的集成也很好。我当然,我更喜欢艾薇因为艾薇有一种叫构型的东西。Ivy配置基本上是一个存放文件的桶。所以当你发布文件时,你会说,好吧,我想要存储某些文件这些文件以某种方式相互关联。因此,例如,常见的桶是诸如数据、编译时间、运行时、配置工件、文档或源文件之类的东西。 So whenever you create packages, zips, rpms, whatever that aggregates these things into nice packages, you want to take those different files and put them into buckets and so for example all of your, you know, HTML documentation of your Java docs, all of your user guides and all that kind of stuff, you may want to put into a documentation configuration and that helps you be able to aggregate things together that go together well.

另一方面,在Ivy中,你实际上依赖于配置,所以当我表达对别人的依赖时,我想表达我对他们的配置的依赖,所以每当我表达依赖时,我都是在你的运行时声明或API上表达它。例如,如果你有一个公共API,那么你把所有的jar或共享库或其他东西放到你的API配置中,这让我依赖于你,但让我依赖于一个抽象。我不依赖于特定的文件名,我是特定的——我依赖于一个概念,API。无论何时你改变文件名,或者你改变基数,你决定从1到2或者从3到1或者其他什么,这都不会让我崩溃因为我唯一依赖的是我依赖于你的API的概念你要定义那个API是什么。

所以我们用它。不只是在构建时,这真的很好,但我们在部署时也使用它。每当我们部署东西时,我们不会在Artifactory中寻找特定的文件,我们会寻找特定的模块,然后说我们想要部署那个模块的运行时配置。所以当你找到定义运行时配置的团队时它可以是jar,共享库,配置文件,你知道,任何他们想要的东西。但是他们可以选择那是什么,但是那将我们从部署时间系统中抽象出来因为部署时间系统变得有点愚蠢。它们不在乎,它们与组件本身没有紧密耦合,它们只与运行时本身的抽象耦合。因此,我们发现这是一种隔离构建和部署系统的好方法,并赋予各个团队决定构建和部署系统的权力。具有讽刺意味的是,他们通过简单地配置他们的build。Gradle来弄清楚这是什么。

(观众)

我们所做的。所以Gradle的配置工作得很好,我们目前没有在部署时使用Gradle,这是其中的一个选择,而且Artifactory不支持Gradle原生语言,所以每当我们进行构建时,我们的构建都会从Gradle配置本身生成一个Ivy xml。所以Ivy xml和Gradle构建脚本在逻辑上是等价的。就像常青藤和pomms通常是等同的。所以Ivy是Artifactory的母语,就像我说的,它是构建端和部署端之间的一个很好的桥梁。

所以我们要解决的下一个问题是系统的重用。我们发现,我们有相当多的单片系统存在于那里,你知道,我们有一些东西可以构建和部署一些东西,这是非常好的,但我们发现,一些系统喜欢发布35g的zip文件,然后说,嘿,部署这个。我们说,什么?我们对这个庞大的整体有点困惑。更不用说还有很多补丁之类的问题。或者表示依赖关系。

所以我们开始做的一件事是说,嘿,我们需要了解你发布了什么服务,我们需要了解你的子系统是什么。所以我们看了一下Michael Feathers的书,有效地处理遗留代码它说,嘿,我们需要确定接缝是什么,并开始将这些接缝独立发布给Artifactory。现在的挑战之一是我们经常发现子系统里面有很多意大利面条式的代码,有很多遗留的东西你不想弄乱。我们面临的挑战是,如何解决暴露依赖关系。我如何在不需要解决过去15年历史的情况下解决颗粒级别的补丁问题。我们发现这样做的方法是,再次使用Ivy配置和构建技巧。

那么,让我来谈谈常春藤的结构。举个例子,如果你有一个构建,创建了一个大的压缩文件我们鼓励人们做的是,嘿,你知道,用你的构建,做你之前做的,但不是创建一个大的jar文件或其他什么,而是创建几个不同的。开始将其组件化成不同的部分。我们并不是要求您更改您的源代码,我们只是要求您更改您的构建以创建构建-更好地为我们构建工件。然后在这些构建工件中,我们开始根据它们的目的将它们弯曲成不同的配置,这样我们就可以增加部署时间,然后我们可以根据我们的需要,选择在不同的地方部署它的不同部分。

所以没关系,这不是很棒。这样做的部分挑战是,无论何时在组件级别或配置级别执行此操作,所有配置的版本号都保持不变。所以它们不能独立变化。一个稍微好一点的方法是简单地改变你的构建系统,使用相同的源代码,但是为它创建完全不同的构建。所以有时候我们拿一个大的整体组件,我们说,好吧,我们要做的不是创建一个大的,你知道的,所有构建之母,我们要有两个稍微小一点的构建,或者10个更小的构建,它们会产生相同的单独输出,但每个都是独立的版本,可以变化,你不必-构建时间增加了因为你不必等待其他的东西。你有独立性。当其他人成功时,它的一部分可能会失败。你不需要等到整个世界都运转起来。把你的一点点改变带到宇宙中去。

所以我们使用这些策略来确保我们不需要改变源代码,我们不需要重构世界,只是为了能够让模块化进入我们的Artifactory,这样我们就可以让其他东西表达对它的依赖,以及独立的模块化部署。

所以这是我认为我们在Artifactory周围投入了一些非常有趣的工作的第一个领域。我们目前这个项目面临的挑战之一是我们要在25到30个不同的地方部署一些东西,大约四个不同的云。我们有多个州多个地点,涉及到地理位置。有很多不同的用户。每个子系统都独立地贡献给我们的基线。我们以一种松散的方式合作,但我们每个人都按照不同的时间表和不同的节奏运作。

所以我们面临的挑战之一就是跟踪到底发生了什么。除了电子表格和人类英雄之外,我们没有很好的机制来做到这一点。我们所做的是引入了一个API,一个用于Artifactory部署的API。实际上,技术上讲它是两个api。

第一个API是通知API。我们的部署系统,无论何时它要部署一个模块,它要做的第一件事之一,当然是它会从Artifactory解析它。一旦它从Artifactory中解析出来,我们就会在Artifactory中编写的用户插件上调用通知API。那个通知API会告诉Artifactory谁,什么,何时,何地,为什么。它会讲到具体的文件名,版本。它将讨论部署的上下文。它会给Artifactory提供很多不同的上下文信息。然后Artifactory用户插件就会理解主机做了什么,哪里没有,它有多统一,它是哪个子集。所有这些信息都给了它。它会在文件名或与之相关的版本上创建一大堆Artifactory属性。

这对我们来说是一个非常强大的概念因为我们为此编写了一个API,一个查询API。现在我们可以回到Artifactory,我们可以问它,对于模块Y的X版本,它部署在哪里。或者对于这样或那样的环境,在其中部署了什么。或者在X天内没有部署的东西。还是这件藏物,还在被使用。由此产生了很多问题我们发现这些问题很有用。我将在几分钟内多讲一点。

Artifactory的下一个我们稍微增强的领域是元数据。所以Artifactory在构建输出方面做得很好。它还集成了Jira和其他敏捷生命周期管理工具。但我们发现需要增强的一件事是Artifactory跟踪元数据的能力。

就像我之前的幻灯片,我们讨论了部署跟踪。我们当然发明了一大堆属性来跟踪所有这些东西,但如果我们有一个叫做部署的第一级概念对象就像第一级构建对象那样肯定会更好。build in Jenkins和所有CI服务器都有一个很好的build info对象它有一组定义良好的信息。它有与之相关联的层次结构。它有一个很好的数据图。我们当然可以在部署方面使用它。

当我们谈论ALM工具或版本控制集成时,在元数据跟踪方面也是类似的。我们当然发明了自己的元数据来跟踪所有这些。但事实证明,所有这些东西彼此之间都有相当紧密的关系。例如,进来的变更集很大程度上依赖于正在开发的功能。在我们的世界里,我们决定我们不想部署功能,抱歉,我们不想部署版本号,我们想部署功能。因此,当我们向运营商或实际部署系统的人员展示时,我们不想向他们展示一个版本号,我们不想向他们展示一个链集ID,我们想用他们的自然语言向他们展示一些他们理解的东西,他们可以部署,他们理解的东西可以追溯到我们的敏捷生命周期管理工具。所以我们选择部署特性,而不是版本号,也不是更改集id。

所以有一个图表关系描述了事物是如何相互关联的实际上我们使用人工元数据来跟踪我们拥有的各种系统中的外键。如果你在使用Jira,我们有一个键,外键,允许我们去使用Jira的REST API。因为,当我们需要从它那里找到信息时,我们使用rational[…]concert,我们使用它的REST API或它的公共API来查询它。所以我们不会试图在人工元数据中重塑世界。我们尝试将足够的元数据放入Artifactory,这样我们就可以跳转到其他系统中去寻找它的精彩内容。

然后我们有仪表板把所有这些都呈现给宇宙。你当然可以去Artifactory,去到发布标签在那里你可以找到构建信息标签。你可以找到这样的东西,当然build info选项卡你可以跳转到Jenkins或Bamboo去找到那个build,这很好。但我们发现,我们需要一个全面的世界观,我们的部署如何,我们的特性如何,我们的链集如何,部署如何协调,所有这些如何结合在一起?外面有什么?什么没有被使用?使用的是什么?我怎么知道什么时候发现了一个bug,应该针对什么写一个差异报告?因此,我们使用这类信息作为上下文线索,并能够以用户的语言为他们提供信息,这样他们就不必在不同的生态系统工具之间跳转。它们都是很棒的,但我们需要一些更高层次的表达,能说它们的语言。

在过去的几天里,我听到了很多关于净化的挑战。所以,我们也发现这种净化是具有挑战性的。我们的数据存储,我们的存储会像其他人一样被填满。我们有一个存储库,里面装满了各种各样的东西,有些很棒,有些不好。那么我们如何区分什么是了不起的,什么不是了不起的呢,我个人发现,选择宣布一些东西不是了不起的,你知道,根据它的日期,或者它已经10天了,或者它在X天内没有被下载。我觉得这些政策还可以,但不一定是最好的政策。因为你决定清洗什么是很随意的。

你知道,当然有Jenkins,在Jenkins清洗中配置策略。Artifactory插件。那真是太好了。Artifactory的内容真的很不错。但我们发现,一旦我们引入了部署跟踪,它就为我们打开了一种全新的策略,这是以前不存在的。我们想要使用并且正在开始使用的策略是清除那些不再使用的东西。而不是等待X天,希望它是不对的,或者设置净化策略,你知道,等待一个月,知道名义上的东西在三天后不会使用,然后有27天,你知道,事情处于这种不确定的状态。

我们根据不再使用的内容清除内容,这样我们就可以查询我们的REST API,以便能够找出一个工件是否已经被使用,它最后一次被使用是什么时候,然后基于它最后一次实际使用的位置,我所说的使用是指在部署时使用。所以最后一次它被实际部署并在一个真实的环境中被一个真实的人使用,无论是开发还是开发,或者两者之间的任何东西,我们都会跟踪所有这些,所以一旦一些东西在30天,60天之后没有使用,不管是什么,我们会把它移到垃圾桶里然后我们让垃圾桶照顾它的自然净化政策。

一旦它最终从Artifactory被删除我们会拦截那个调用并删除与它关联的Jenkins作业。所以我们要确保的一件事是Jenkins和Artifactory总是同步的,我们总是跟踪实际使用的东西。任何我们不再需要的东西都要处理掉。我们不想保留一年的快照构建,因为没有人再引用它了。能够在我们拥有的不同子系统之间保持跟踪是清除策略的挑战,有时一个子系统可能一天发布五个内容,有时他们可能一周不发布一些内容,这取决于他们的构建和签入策略是什么样的等等。因此,能够根据使用的东西来跟踪东西对我们来说实际上是一个相当强大的概念。

所以我们开始研究的一件事是如何促进不同的子系统。所以如果你能想象,有25 30 40 50 60个不同的子系统在那里,有些是巨大的,有些是中等大小的,很少有实际上是很小的,你知道。所以把100 K的代码当做中等大小的系统考虑一下,也许有几百万行代码,为一个模块创建一个35g的zip文件。所以我们的挑战是,好吧,我们每个人都在独立运作,我们如何把一个真正有效的系统整合在一起。所以,我们不是在创造,60个单独的产品,最终我们是向一个客户,一个系统,提供一大堆与之相关的功能hth华体会最新官方网站所以我怎么知道这个子系统实际上与这个子系统集成在一起。

我们用几种不同的方法来解决这个问题。第一种方法是使用语义版本控制。语义版本控制有一些挑战,但我们目前认为它的优点值得投资。因此,语义版本控制解决了确保物理接口绑定在一起的问题。这样我就知道不兼容的变化不会在相同的构建中得到解决,它们不会在相同的部署中得到解决。所以我们保证使用语义版本控制,这很好。但是,我们面临的挑战之一是,有很多非物理的方式让事情无法工作,所以,你知道,仅仅因为你有一个Java API,你把它们连接在一起不一定不是我们的接口连接在一起的唯一方式。我们的许多接口都是通过JMS、消息键、web服务、任意数量的文件系统、ftp或任意数量的其他类型的接口实现的,而语义版本控制并不完全适合这些接口。因此,我们面临的挑战之一是,我们如何识别当你实现并测试了一个特定的接口我需要去利用它。

这就是多阶段推广开始发挥作用的地方。所以在我们目前的系统中,我们实际上有五种不同类型的释放。第一种类型的发布是当每一个单独的20到60个不同的子系统做他们的测试。这就是传统意义上的CI。所以你经历了一个单独的组件测试阶段,他们从另一边出来,竖起大拇指,我们在其中做一个传统的人工产品推广。

所以我们的每一种其他类型的脸-阶段都涉及到某种类型的推广,我们将这些不同的组成部分聚集在一起。所以,你知道,这里的这五个已经完成了他们的测试,这里的三个已经完成了他们的测试,现在我想在一个单独的测试中一起测试这八个。我们怎么知道它是多少呢?我们使用Artifactory元数据来识别哪些东西经过了测试,哪些没有,然后我们运行基于AQL查询的推广来找出哪些东西值得放在一起,这样我们就知道,嘿,这些东西一起被推广到一个存储库中,我们要测试这些,我们要给它们,一旦它们通过了推广,通过了测试,我们就会推广它们。然后把这8个和这里的15个放在一起,然后我们把它们按层聚集在一起,直到我们到达顶层,60个都玩得很好。

好了,这是第三个我们觉得很有趣的概念,我们要进行实验。这实际上是弗雷德提出的一个想法但我们将在这里迈出一步看看它是否可行。因此,无论何时我们向Artifactory发布,Artifactory都会创建并跟踪校验和、sha等。所有这些都很棒。但是,如果你去查看构建磁盘,你会发现,在你推上去的很多工件和包中,磁盘总是会出现不同,即使它们在逻辑上是相同的。为什么它们不同?时间戳,校验和,用户名等等,这些都不会影响现实世界的执行。它不会影响界面,但它会对你的校验和产生影响,使两件事没有正确的区别。这就产生了很多困惑,带来了很多挑战。

所以我们感兴趣的是看看这个叫做真校验和的东西。所以我们要做的是在构建时,我们要看一个包,一个zip,一个jar,一个共享库,或者别的什么东西,我们要让构建时技术来声明什么是真正的校验和。现在,真正的校验和基本上可以是一个排除列表。你知道,不要看jar文件中的元NSF,也许忽略其中的rpm头。我不知道这到底是什么样子,但是我们会给人们,也许我们会给他们正则表达式来忽略清单的某些部分。但是我们要给他们一些能力来声明在创建的包中什么是重要的,什么是不重要的。

作为构建的一部分,我们将创建真正的校验和,我们将在它发布到Artifactory时标记它。嗯,这实际上是有趣的部分,这就是人工方面的作用。我们要在Artifactory端尝试做的事情之一是有一个我们要查询的用户插件它会说,这个校验和是否为真,它是否已经存在于Artifactory中。因为如果它已经存在于Artifactory中,那么我们就不会在那里发布这个东西,因为我们只是要重用先前存在的工件,因为真正的校验和表示逻辑上等价的两个东西。现实世界的行为是相同的,即使它们的部分元数据可能由于构建输出而不完全相同。

所以如果一些东西已经存在于Artifactory中,我们不会将它部署到Artifactory,我们只是在那里重用它。然后在构建时间结束时,如果构建没有任何变化,那么我们根本不会将构建发布到Artifactory。我们只是要重用之前存在的一些现有构建。这将解决很多问题至少我们希望它能解决我们的一些问题因为我们的构建往往会生成一大堆东西。我们的下游依赖关系倾向于构建一大堆东西,并将一大堆并不真正需要的东西发布到Artifactory,因为它在逻辑上已经存在了。我们并没有引入变更集,我们只是重建一些东西来验证上游的行为。所以我们希望这能够解决这个问题,同时减少我们后端数据库的负载,因为我们需要更新一些不必要的东西。

我们还面临的一个问题是跟踪需求,所以我谈到了逻辑上联系在一起的事情,至少在我们的世界里,我不知道你们的情况,但在我们的世界里,我们处理成百上千的需求文档。所有从指定接口指定的东西,客户给我们的东西,内部生成的,外部生成的,各种各样的东西,所以我们必须声明遵从性。

所以我们要探索的一件事是如何同时发布软件和文档,其中包括用户指南,需求和接口规范。我们如何以同样的方式CM控制这两者呢?因为对我来说,我们发布软件,我们有一些非常复杂的方法来处理它。但是我们的文档管理和需求管理,至少落后了几十年。他们的待遇也截然不同。因此,试图在它们之间画出可追溯性线是非常具有挑战性的,我认为发布和配置管理控制文档,构建它们,发布它们,用软件推广它们是一个非常有趣的概念,我们将探索这个概念。

最后,我们来听析,快结束了。一旦你在Artifactory中完成了所有这些,就能够创建版本描述文档,并且能够说,在哪里部署了什么,谁做了这些,诸如此类的事情都非常简单。

我就讲到这里,给大家留几分钟时间提问,我想留给大家的两点是,我们生活在一个不完美的世界。我们不是在绿色屏幕的土地上工作,在那里每个人都是一些,你知道,超级善意的人,总是想要克服,想要持续整合,持续交付。我们面临着各种遗留的挑战,但是我们有一个管道。我们正在采取一些步骤,向人们介绍一个持续集成、持续交付的管道。这是一种比以前更好的东西。

它并不完美,但也许在5年、10年的时间里,我们可以把这些分解成微服务,提供细粒度的服务,拥有自动化测试和所有这类东西,这些都是先决条件——作为在一个定义良好的管道中实际拥有东西的下一步。

我们的方法很简单,我们只是去看看着火的是什么,我们去解决实际可行的问题,然后我们转过身来,再问同样的问题,着火的是什么,我们如何解决它。我们就这样不断迭代,直到我退休。

就是这样。

要么释放,要么死亡