她提升了她的舵图……你不会相信接下来发生了什么!——西蒙·沃尔顿,anplan

anplan聘请了Artifactory进行大力支持JFrog全新的CI/CD管道。这个管道可以通过一系列“信任级别”来提升基于helm的微服务,直到它们被认为可以投入生产。这个管道的组成部分是一个Artifactory推广插件的内部开发,它允许Anaplan团队自动推广所有Docker映像与赫尔姆图相关联当只提升图表时,还要为他们提供重要的闸门,以防止不合适的提交被提升。在这次演讲中,Simon Walton概述了Anaplan的CI/CD管道,包括开发支持它的Artifactory插件的动机。Simon还深入研究了复杂的集成测试套件,使Anaplan团队对提升机制的正确性充满信心,并提供了关于最佳实践的观察和指导——所有这些都基于Anaplan团队在Artifactory插件内部开发方面的经验。人工插件开发可以很有趣!

视频记录

西蒙·沃尔顿:对。你好每一个人。谢谢你的到来。我叫西蒙。我是anplan工程生产力团队的一员。从本质上讲,我们是一个团队,负责所有的构建基础设施和所有围绕Slack集成之类的工具。我们也会关注我们内部的GitHub企业实例和Artifactory。我有点像公司的JFrog大使。我很高兴,至少我可以让一些人在午餐后讨论Artifactory插件,这个标题很有针对性的点击诱饵。我也考虑过这个,“为什么这个家伙写了一个人工插件:答案会震惊你和一个奇怪的技巧来促进你的Docker形象”,我认为这是相当不错的。 But in the end I decided upon, “She Promoted Her Helm Chart And You Won’t Believe It Happened Next!”

所以,我们开始吧!这是一个关于人工插件的演讲。我们要做的是,我们首先要讨论,为什么要写一个插件,我们要讨论,我们是如何写这个插件的。好吧?我们在anplan有一个问题需要解决,我们为你的插件写了一个请求(1.06)。在此过程中,我们在如何编写插件方面进行了探索,我想我应该和大家分享一下。当我第一次向swampUP提出这个演讲时,它有点像,“嘿,我们有一个非常酷的插件,让我们展示一下这个插件。”但后来我意识到,“你知道吗,这个插件很简单,插件也应该很简单。所以,“不如我来谈谈,如何编写一个插件。”在此过程中,我将向您展示我们如何编写这个特殊的插件,它是如何工作的,以及您如何编写插件。”所以我们为Artifactory写了一个插件,叫做Atomic-Promote。 And it was designed to solve a set of problems that we had at Anaplan and problems all around CI/CD. So, we’re a Jenkins house, we use Jenkins for pretty much everything to do with bill tooling in the company, and we didn’t see a reason to change that. However, we did have a move towards more CI/CD ways of working.

所以我们去年有了一个全新的项目,叫做“新用户体验”,我们想把它交付给客户,我们意识到我们不能像现在这样经历这种冗长的发布周期。所以我们决定,“你知道吗,这是部署Kubernetes集群的理想用例。”我正在把我们的基础设施至少一部分放到Kubernetes上。这是一个很好的用例。我们所做的是,我们配置了一个Kubernetes集群或一组Kubernetes集群我们决定从Jenkins开始,对吧?所以我们在Jenkins中建立了这个共享管道库。之前在这个房间里的演讲,实际上,我们在做同样的事情。你在顶部有一个Jenkins,你说在port共享库这个共享库允许你做很多事情。我们想要做的是,我们希望这个共享的管道库能够部署到一组不受信任的存储库中。是的,您将您的Helm图表和Docker映像部署到这种不稳定状态,然后您要求Artifactory,“请将所有内容提升到链上,直至测试和生产。” Finally. So this was all, well and good.

我们的想法是,当你开始推广一些东西时,很明显,每个集群只能与每个范围或级别进行对话。换句话说,在Kubernetes生产集群的顶部,它不应该能够从Helm测试和Docker测试中提取Helm图表或Docker映像。因为这个原因,我们用人工许可来锁定东西。简单地说,这就是管道的工作原理。你有一个Jenkins文件,你部署到你的开发集群,你发布你的Helm shot和你的Docker映像到Artifactory,这些都与Artifactory构建相关联,然后你问Artifactory,“请在最后推广我的构建,”Artifactory适时地推广构建。此时你可能会想,为什么这些家伙要写一个插件?因为Artifactory完全可以做促销。这是个好问题。

所以在Artifactory的促销方式上我们有一些需要解决的问题。我们想要自动推广Helm图表和Docker图像,对吧?所以我的意思是,如果你促进一件事,另一件事也会随之发生,或者什么都不会发生。我们要么两个都提拔,要么两个都不提拔。如果你还记得我们之前的图表,我们有Helm存储库和Docker存储库,它们一起上升。这正是我们想要的。要么整个事情都失败了,用户得到一个箭头,无法推广,要么两个都上升。我们还想要做的是,我们想要对晋升进行各种资格检查。由于Jenkins共享管道库的特性,用户最终有能力调用那里的东西……也许他们不应该这样做。

我们想要做的是确保我们可以验证这个提升是正确的,它是重要的,遵守和审计规定。所以我们确实有很多东西当你最初提交到你的仓库时,它会告诉你这不会通过合规性。然而,我们也希望在管道中加强这一点。所以我们和法国JFrog公司的人打了个电话,我们问他们:“这是我们想要做的一个垃圾想法吗?”他们说:“不。这实际上是一个相当不错的想法,我们鼓励你开发一个插件,并将其反馈给希腊社区。你会遇到一些问题。首先,没有办法使用公共API进行Docker提升,稍后我会向您展示如何做到这一点。他们还说,“从根本上说,你在Docker促销和Artifactory上建立促销的方式,是两个不同的终点。”是的。 They are two different ways of promoting things.

另外,当你在Artifactory中推广产品时,你是在推广构建如果你是在推广你是在向链条上移动或复制一些东西,那么通常你所做的就是说,我有一个源存储库和一个目标存储库假设我有一个Maven构建,我正在移动我的Maven输出,比如一组jar,等等,我正在将它们从一个存储库移动到另一个存储库。它并不是真正围绕着把东西放在一起并在一个集合中移动的想法。因此,考虑到这一点,我将带您了解Artifactory插件是如何工作的。我可以得到一个举手,谁写过Artifactory插件之前?很好,很多人。谁想写一个,但不知道从哪里开始。好的,很好。我这里有很多人可以选择。这将带你了解我们是如何编写插件的我也将带你了解如何开始编写插件。

再举一次手,谁真的喜欢Groovy?好吧。人工插件是用Groovy编写的。不幸的是,我应该小心点。我这么说是因为我知道创意Groovy现在为JFrog工作了。我个人对此有意见。我是说,GString,拜托,GString!在我的工作场所,有多少次我被要求大声说出GString,这太疯狂了。我很惊讶,我被派去人力资源部了。Artifactory插件的工作方式是这样的,你有一个Groovy文件来表达你的插件逻辑,明白吗? And you’ll deploy this into Artifactory. So you’ll have, MyCoolNewPlugin.groovy. It’ll sit in Artifactory, you’ll deploy to, etc plugins directory. If you’re in a HA configuration, they’ll be synchronized straight over to the other node. You’ll also need to call an end point called reload plugins. And that tells Artifactory, “Can you take a look at the plugins and just make sure that you’ve loaded them into the Artifactory, the JVM context.” You can tell Artifactory to automatically look for plugins on a polling basis. But JFrog explicitly say, “Do not do this in production.” It’s okay for development purposes, but if you do in production, you can end up in a weird case where you may reload a plugin halfway through and it’s kind of undefined behavior that results from that.

当你为Artifactory编写插件时,你会使用公共API而公共API,不管名字如何,有点像私有API。我不知道为什么叫这个名字。它位于Artifactory的核心,允许您与内部进行交互。当您编写插件时,您将打开一个DSL块,我将向您展示一个示例。在DSL内部,您将打开一个闭包,并编写一些Groovy来表达如何与Artifactory交互。你会做的一些事情是,你会说,build。get build, repositories。get repository它还可以帮助您查看安全信息,您可以注销和类似的事情。它们是为了方便,所以你不需要调用公共REST端点或类似的东西,那应该是非常冗长和困难的。

人工插件…大概有10种不同类型的插件。如果您查看JFrog的文档,您将看到有10种不同的类型,每种类型都提供了不同的DSL。这是启动或触发插件的三种主要方式。有些是基于Cron的,有些是调度的,有些是基于事件的。换句话说,例如,Jason的建筑即将被保存或已经被保存,或者我们的用户已经启动了下载,而您想要覆盖某些行为。你想要改变一些行为。任何时候你想扩展他们Artifactory的工作方式,你就需要一个插件。推广插件的工作方式是,你有一个来自外部的专用REST端点。好吧。我也会向你们展示它是如何工作的。 So they are user initiated from outside via the REST API.

如果你想开始写一个插件,这就是你开始的地方。你去JFrog的GitHub,输入用户插件,你会根据你真正关心的存储库进行过滤。所以有两个你会关心的。有一个Dev环境,它非常好,因为它为您提供了一个很好的griddle项目,并且这个griddle项目允许您启动一个真正的Artifactory,您将针对它编写测试。它为你提供了很多,方便的函数。还有Artifactory用户插件,这是你在编写Artifactory插件时可以利用的最重要的资源,因为它为你提供了一组精心策划的Artifactory插件列表,这些插件是由JFrog自己设计的,也由社区贡献。JFrog非常欢迎人们贡献插件。

Artifactory公共API的文档有些稀疏,所以我发现这是迄今为止最好的资源。所以如果你要写一个插件,你要做的是,在开发环境中使用Cron并在那里创建新的插件文件夹。而你的新插件文件夹,它将包含两个文件。它将包含插件本身。所以MyCoolNewPlugin。Groovy会坐在那里。然后你也会有这个测试文件,这个测试表达了一组针对插件的集成测试,针对正在运行插件的Artifactory。因此,您将以某种方式对插件进行压力测试。我也会向你们展示它们是如何工作的。开发环境实际上是一个网格项目,网格项目中有一组特定于开发Artifactory插件的网格任务。

所以当你开始下载的时候,你点击“准备美术-专业版”然后它们就会转到JFrog的网站然后它就会卷曲成你想要的任何版本的艺术品。因此,很明显,您试图匹配生产版本或即将升级到生产版本。所以你可能会尝试匹配你的DR环境或类似的东西。然后你说" Start Art-Pro "它会做的是,这是一个griddle任务,它会在后台启动Artifactory,真正的Artifactory,它会等待它完成,然后把控制权交还给你,在后台为你运行。它知道Artifactory已经启动的方式是,它会监控特定消息的日志。这很聪明。我要说的是,它需要执照。

是的,你需要一个真正的企业执照。JFrog对你使用真正的许可证、集成测试和类似的东西没有问题。印章上有说明,请阅读我如何正确授权。然后你要说" Work on plugin "因为你会说" Griddle Work on plugin "然后输入你的插件的名字然后Griddle任务就会启动它会尝试找到你的插件。默认情况下,它将查找一个目录。所以在这种情况下,你说,griddle work on plugin my-cool-new-plugin,它会找到这个目录,它会符号链接你的插件,它会符号链接测试文件直接到Artifactory plugins目录。然后你就可以出发了。你可以运行griddle test然后griddle test会运行MyCoolNewPluginTest中所有的测试。groovy文件反对真正的Artifactory。这真的很好,这是一个真正的Artifactory。所以当你打开这个开发环境时,你会看到我喜欢JFrog的加载动画,它太棒了。 And you’ll see… It’s a real Artifactory that you can play around with via the UI. It’s available, the port is there. The one thing you will want to do when you start is enable logging. So in a production use case, you would have a log level of info or something like that. For development purposes, you’d probably want something a bit more… You’d want to go with debug or trace or something like that, but yeah, you just need to add a new log entry into the log back to XML file to get logging up, took us a long time to figure out.

那么,atom - promote是如何编写的呢?我在前面提到,JFrog提供了一组dsl,您可以使用这些dsl编写人工插件。这是一个推广插件看起来像什么。所以你有这个开始的促销块,告诉Artifactory,“我要定义一个促销插件”,你给促销插件命名。在我们的例子中,我们称之为atomicPromote。然后我们给它四个参数,在我们的例子中,这些参数没有真正的文档,除了github中的例子。如果你正在寻找文档,寻找其中一个示例推广插件的示例,你会在那里找到它。第一个参数告诉Artifactory,“这是组。”所以从权限系统的角度来看,这里是允许执行这个插件的组,其他任何组都将被拒绝。

我们还可以对插件进行版本化,这非常好,因为如果我们试图诊断Artifactory的问题,并且您有多个Artifactory,那么知道您正在运行的插件的版本非常好,这样您就可以在查看日志之类的东西时诊断问题。这也意味着,举个例子,如果你在管道中构建这个,你可以在每次构建的时候碰撞那个版本。我们还有参数,这是我们强制用户传递的强制参数。在我们的例子中,我们说,他们必须传入一个目标分数参数,我们默认为已测试。你们还记得我们在推广过程中的水平,我们有一些不稳定,我们测试过,然后我们生产。它默认假设你从第一层提升到第二层,然后我们打开这个闭包。

闭包是最后一个参数闭包是当用户调用这个提升时执行的东西。是的。因此,作为标准,当您执行构建提升Artifactory时,您有buildName和buildNumber。这就是你给Artifactory的和一组参数。这就是我们通过REST端点调用它的方式。作为一个经过认证的用户,你通常调用build promotion Artifactory的方式是你会调用,这里有很多,所以你的/ Artifactory /api/plugins/build/promote/ except到它的末尾,你会放这个推广插件的名字。你会放置atomicPromote,它匹配我们在那里的促销块中的功能。

接下来,你给它buildName和buildNumber,你想要提升,这些链接到buildName和buildNumber,你看到那里,在闭包参数。然后我们打开一个查询字符串。现在查询字符串在Artifactories中工作的方式有点尴尬,因为我们有一个查询字符串,它是参数,但是我们也可能想要把一些参数链接到我们在闭包中看到的parameters属性中。我们这样做的方式是,我们用UNIX管道参数来描述。在这个例子中,我说,ciUser=Jenkins|targetScope=production,这就是我传递参数的方式。这只是对我们要做的事情的回顾。所以插件尝试做的是,你给它一个构建,你说,“去那里找Helm图表。去找那些和赫尔姆图一起推送的Docker图像。我想让你同时给他们升职。好吧。 If you can’t do that, then I want you to just collapse in on yourself and just do nothing and just return an error.”

考虑到这一点,我将向您展示这个推广插件的一些代码,以便您可以对插件的代码有一个感觉,因为有些人可能以前没有见过这些代码。你们也可以看看我是怎么写的。让我们转到vs代码,然后全屏。大家都能看到吗?这很清楚。为了这次演讲,我确保我的线条宽度很窄。这是一个很好的练习,行宽应该是80个字符。这是切入点,你可以看到,我们已经讨论过了。这是我们打开DSL的地方。我们正在注销一些信息。 We’re assuming that everything is okay. HTTP(18.27) status is 200. And the functionality for this plugin is, kind of, broken into three parts. The first is some sanity checks.

我们获取用户传递进来的参数我们对它们进行一些完整性检查以确保,从我们的角度来看,这是用户想要做的。然后我们要做的是,在那之后,我们要问Artifactory,“给我构建元数据。给我代表账单的公共API中的对象,给我Docker图像。”我要去问Artifactory,“给我所有Docker的图像。”最后,第三步,我们将获取所有信息,然后我们会说,“请同时推广Helm图表和Docker图像。”然后退出。很简单。getString属性是我们写的一个方法,用于进入这个传入的Params HashMap,你在闭包中获取它并尝试从中获取目标作用域。我们用true表示强制性。这个getString属性在你在GitHub上看到的许多示例插件中都有。 It’s, kind of, a standard method that they tend to drop in there.

然后我们要做的是从目标范围计算源范围。所以作用域,记住我们说的,例如,对于Sap(19.40),将其提升到已测试,因此,具有以下级别的源作用域。然后我们要做的是,找出存储库的名称。我们在Docker图像上找到了头盔的源和目标范围。我们只是计算这些是什么,我们对它们做一些完整性检查,以确保它们确实存在,并且它是一个有效的作用域。或者你会注意到我们的Helm图表在它的末尾有-local,这是因为我们使用了后台Helm存储库。对于那些在Artifactory中创建过Helm存储库的人来说,您将知道为了让Artifactory充当Helm存储库,您需要一个本地存储库和一个虚拟存储库。虚拟存储库是人们实际访问的存储库,然后由本地存储库提供支持。

然后我们做的是尝试填充这个sourceBuild和detailedSourceBuild。这是一个如何使用公共API获取build信息的例子。这是我们真正开始使用这个公共API的地方。getBuild是一个我们已经有了的功能,它基本上没什么意思,它只说构建。getBuild在后台执行一系列的完整性检查。然后我们把它转换成detailedBuilds。你能思考这些的方式是一个buildobject。它实际上叫做一个BuildRun对象它在公共API中。BuildRun对象本质上就是您在Artifactory UI中浏览到构建时所得到的。BuildRun有点像,你在顶部看到的那个面板。然后detailedBuild运行是你在下面看到的所有标签,比如模块列表,那个build的发布历史等等。如果出了什么差错,我们就离开。

接下来我们要做的是……我记得我之前说过我们想要在这个插件中加入资格检查。所以我们想说,“嘿,如果用户没有资格推广这个构建,或者如果构建中的工件有问题,比如它没有通过我们的遵从性测试,那么我们想立即退出。”这个应该被我们推广的功能,我们将会开放这个插件的源代码目前,这只是一个功能,它说,目前返回真。所以本质上,这个是要填上的。在我们的anplan示例中,我们在那里提取了REST调用。我不认为在插件中调用是明智的,但我们就是这么做的。我们称它为服务,它只是验证提交之类的东西,以确保它们通过那些标准。希望你能得到一个真实的结果。就是这样。如果用户是管理员,这很好,很直接,对吧? We’ve got the user above by asking the security system, we’re saying if the user is, and I’ve been, then they can override that because you’ve always got to have an override mechanism in place in case things go wrong because things do go wrong.

下一个函数很有趣。这被称为getDockerdigestsForArtifacts。有很多方法可以将Docker映像与Helm图表关联起来,对吗?您可以将该图表放入Helm图表中。你可以告诉Helm,“这就是我要去的仓库,等等。”所以有可能我们能做的是下载赫尔姆图表我们可以进去,我们可以找出我们应该寻找的东西。但我们认为,从长远来看,这可能不是一个好策略。我们决定做的是,我们决定在Artifactory中用属性标记Helm图表。我会展示它在UI中的样子。你们中的一些人可能不知道什么时候…你可以在Artifactory中用属性标记东西,你实际上可以有列表和单个属性。 So in our case, what we do is we tag the Helm chart with a list of Docker digests. So we get the Docker digest strings and we tag them into the Helm chart attributes. All this method does… I’ll show you what it does.

看(23.31),它所做的就是说构建,这是我之前提到的公共可用对象,你得到所有这些构建和存储库等等。所以我们说构建。getArtifactsfiles,你给它构建然后它会给你那个构建中的所有文件。然后我们遍历它们,寻找一个属性,叫atomic。docker。digest,然后我们把它平展,然后我们。因为如果你告诉Artifactory在一个属性上存储一个列表,它会返回一个字符串,用逗号分隔。我们只需要分割它,把它弄平然后返回所有不为空的值。这很简单。然后我们做的是我们把那一组摘要转换成一组repoPath对象repoPath就像它暗示的那样,是一个对象表示Artifactory中某个东西的精确路径。这就是它的作用。然后我们只需要做一个健康检查,然后说,“嘿。我们想要获得的摘要列表是否与我们返回的实际Docker图像列表相同?” If we didn’t get them all, then there’s some problem. And in that case we would cancel the promotion with a 404. We’d say we didn’t find some of the Docker images.

正确的。下一部分。接下来我们要做的是,我们已经准备好了所有的信息,接下来我们要做的是我们想对Artifactory说,“请尝试一下Helm图表推广的试运行,然后是Docker推广的试运行。”如果一切顺利,那么我们知道我们可能就可以进行真正的促销了。所以你可以看到这下面发生了什么。我们先排练Docker和Helm,然后再演真正的。它们所做的就是我们这里的闭包。这是Helm。Helm所做的就是创建这个在公共API中可用的提升对象。我在getPromotionInstance功能中有这个提升它为我填充提升对象因为它有很多进入提升的参数。 I don’t know if anybody’s called the promotion that implies a lot of things you can customize. And it passes this dryRun parameter that is also passed into the closure which means that we can run a dryRun first and then we promote the build by giving it this promotion object.

我们还会说,如果你不做dryRun,那么在release status和release status下,我会在这个之后的UI中显示它是什么样子。但是Release Status是免费的当你做一个普通的构建推广Artifactory但如果你做自定义推广,你是负责添加Release Status的人。从可审计性的角度来看,这显然非常重要。你想说,你想让我点击构建,然后看到,“好的。该用户在某个时候将其提升到测试范围。”在我们的例子中,詹金斯会作为推动它的人出现,老詹金斯。

正确的。现在是Docker的晋升。现在这有点困难,因为正如我之前提到的,你没有得到,公共API提供的一流Docker提升支持。你必须调用REST API,也就是大家都在使用的那个。这就是我们在这里所做的。所以我们说dockerImages。每个,promoteDockerImage为每个。是的。如果他们中的任何一个失败了,我们会立即救助,记住我们也可以先做一次演练。现在不幸的是,当您试图要求Artifactory执行Docker升级时,您不能像使用正常构建升级那样执行dryRun。 It’s basically, you do it or you don’t do it. So in our case, what we do is we do a bunch of sanity checks. We say, “If dryRun, then do some sanity checks.” Like does the repository exist and so on. We could be doing a lot better here and we have improved this since, but that’s how it is right now.

然后我们要做的是获取执行插件的当前用户的用户名和密码然后在内部调用REST API。对吧?我们在Artifactory中运行,我们从Artifactory内部调用它的公共REST API。8081是Tomcat端口。我们只调用Artifactory的REST API。当我写它的时候,我并没有期望这一切都能起作用,但它确实起作用了,这太神奇了。然后我们寻找这个HTTP responseCode 200来确保最后一切都成功了。是的,这没有我想的那么健壮。如果可能的话,我希望JFrog推出一个Docker的dryRun促销活动。我不知道这是否可能,真的很好,因为现在这是,有点,它没有我想要的那么强大。 So at the very end then all we do is we just say, “Okay, if we got to this point, everything’s okay.” We log out, the plugin is ended because that’s where… You’re looking for those blocks. When you’ve written a plugin, you’re looking for, if anything goes wrong, you want to know when did the plugin start, when did it end, did it end successfully? We make sure the status is 200 and we write that, “OK”. And if you say, “OK”… When you call this endpoint, that’ll come back to you in the response body as well. Yeah. So it’s nice. You can see that in Jenkins. You can see, “OK”. We should probably be more descriptive than “OK”.

测试。所以Artifactory插件开发中的测试是非常非常有趣的。如果只是因为你能把它们做得出人意料地优雅。我们来看看。这是我的目录结构,是一堆不相关的东西,但你会注意到,正如我之前提到的,你有这个AtomicPromote。groovy,但我们还有AtomicPromoteTest。也很棒。我们的测试就在这里。关闭。这些集成测试看起来,嗯,它们看起来,有点像你所期望的集成测试。我们有每个测试的设置和每个测试的拆除。每个测试的设置告诉Artifactory,“创建一堆我想要的存储库。” So it’ll create the Helm repositories, the Docker repositories. It’ll create this PromoteGroup that is eligible to perform the promotions that we can have a test whereby we removed that group and then we try running it and we should get a 403 in response.

测试本身,你可以看到它很简单。我试着通过尽可能多的抽象,让它们变得简单明了。这个测试是您可以针对这个插件运行的最基本的测试。它验证了插件的本质。我们说,当我将三个Alpine图像和一个Helm图表部署到不稳定状态时,我执行一个升级到测试状态,所以在上面一个级别,然后我期望Helm图表存在于测试状态,在上面一个级别。我还期望Docker映像存在于被测试的一个级别之上。这很不错,对吧?因为如果你…这是你编写测试的标准方式,对吧?你是否在一开始就尽可能多地把它抽象出来,这样当下一个人来写测试时,他们就会意识到,“哦,这太……不要重复了。”

我有很多障碍物,我可以用它们来验证我的直觉。我有一些新的功能,你可以正确地红绿人工测试。我们还有另一个测试…如果服务不存在和测试,升级到生产就会失败。所以我们可以说部署一些阿尔卑斯镜像来测试,但我们没有在那里部署Docker镜像。我们要做的是,我们要执行提升,我们应该得到的响应是404,因为它找不到Docker映像。然后我们验证这两件事都不会发生。舵图(确实存在)和Docker图像(甚至都不存在)都没有得到提升。这就是插件的本质。我们在验证,如果出了问题,什么也不会发生。

这就是人工测试的原理。如果有人想在我们一起看完代码后来看我,我很乐意。我真的只擅长推广类型的插件。在JFrogs GitHub上的用户插件存储库中有大量可用的插件。我真的鼓励你们去看看那里因为在Artifactory中有很多东西可以扩展。它真的非常非常强大。你们也可以看一些很好的测试例子。我认为这是我见过的最全面的测试套件。当然,我们已经开始进行这些测试了。我要回到演讲上了。 Okay. Yeah.

正如我提到的,这就是Docker摘要属性的样子。你会看到atomic.Docker.digest是列表中的第一个属性。你会看到值,它说" see list "。你可以在Artifactory UI中点击它它会打开一个模型框它会在那里显示列表。我警告你,如果你通过其他端点自动设置这些值,会有点尴尬。字符编码会欺骗你,你会使用的描绘字符会时不时地欺骗你。如果你想看看我是怎么做的例子,如果你也有这个问题,来找我。但你可以在属性中存储列表,这非常非常好。这是发布历史记录。当我们进行推广时,通常是构建推广,我们希望看到这一点,我们希望看到我们也编写了自己的推广机制。 Right? It’s important for auditing purposes. We want to see who performed the promotion let me say, and when it happened and we want to see why as well. You can add comments as well. Ours is just commenting promoted to target scope.

当我们开始写这个插件的时候,最初只有我一个人在写。我有了一个想法,我想试着把它代入。我继续写,写得很开心,很开心。到了创建一个PolarQuest的时候了,我把它交给了团队的另一个成员来审查。我做了一个公关,我说:“山姆,你能帮我检查一下吗?”他说:“当然。”他查看了GitHub企业版的早午餐,他说:“哦,我看到你做了一个关于如何运行测试的Read Me。”我说:“没错。我已经做得很彻底了。”我记得大概6个小时后,他说:“如果我还不能让测试运行……”结果证明他在这个“读我”的过程中遗漏了一个小步骤,因为你要做的是把所有东西都按正确的目录顺序排列好。 Then you’ve got to crawl all the Griddle commands in the correct order, and you’ve got to make a minor configuration change to Tomcat to match what’s in production so that the tests are pointing in the right place. You don’t have to change those and so on. You’ve got to make some change to the Docker. Remember that in our tests we are really using Docker. Those tests are literally using Docker, they’re Docker-pushing into the development Artifactory which is really cool. However, Docker will not push to a localhost repository. If you say, “Push to localhost repository,” Docker will say, “Nope, not doing it.” What you can do is you can say, “Okay, I’ll add something to my UTC hosts and I’ll say Artifactory is at 127.0.0.1.”

然后Docker会说,“这是一个不安全的注册表。我不会逼你的,你疯了吗?然后您说,“好吧,我将把HTTP Artifactory添加到不安全注册表列表中。”Docker很高兴,它会推送到那个存储库。我意识到我在阅读中也错过了这一点。我完全忘记了我曾经做过,因为我花了几周的时间做这件事,我意识到这不好。因为如果测试很难运行,那么它不仅会花费我们大量的开发时间,而且人们可能最终不会运行它们。所以我可能会给某人一个pull请求,他们可能会说,“哦,是的,完全运行测试,太棒了。为什么不直接应用呢?”因为他们碰巧认为Groovy代码很好因为在现实世界中,对吧? Ideally integration test, they should be one click. Although integration testing is hard, it should still be one click. If you can possibly automate it, you should automate everything. I realized this wasn’t good enough, so I set out to automate these tests and I realized we had three concerns. But the plug in itself, we have Artifactory, sits in the middle. And then we have Docker, which we also want to control in some way.

所以我们能做的是Docker合成这个,对吧?所以我们可以说,“docker-compose up”,我们可以有一个在其中运行Artifactory的容器。我们会说:“准备Artifactory Pro,下载并启动它。”然后我们可以让我们的插件定期轮询Artifactory的ping和点数,最终返回200,其中包含“OK”。所以我们可以让插件不停地问Artifactory:“你还活着吗,你还活着吗,你还活着吗?”然后我们可以让插件执行这些griddle命令来测试插件。我们还会做很多其他的事情来配置这些测试,就像我们想要的那样。所有的事情,有人会手动忘记做,我将以某种方式搞砸了打字错误和事情。因为人们很难相处,人们有时不读书,人们很累,所以最好把事情自动化。这个Artifactory正在从公共Docker中心推送和拉出,或者实际上它是从镜像出来的Artifactory中拉出,并将其推回Artifactory。 It’s using this Docker that we control.

这是Docker镜像中真正的官方Docker。是的。在这里,我们在Docker文件中所做的就是我们说" From Docker And Docker "然后我们自定义说HTTP Artifactory是一个不安全的注册表,这很好。然后Docker非常高兴,这意味着我们可以对这个插件进行一键测试设置。如果我们说从插件中退出代码,这意味着我们有一个环境,我们可以运行docker-compose up -exit-code-from plugin, docker-compose将运行完整的测试套件。当插件退出时,换句话说,当我所有的测试都通过了,或者其中一些测试失败了,整个环境将被关闭,控制权将返回给用户,这真的很好。然后我们可以将测试结果从人工容器中取出。如果你是人类,你就会把HTML版本删掉。如果你是一个机器人或者你是一个Jenkins,那么你就会得到XML版本。

本着为坐在房间后面的人设计的精神,这是一个小的文本终端,我将向你们展示它正在运行我们的集成测试。我们说的是runtests.SH,它有点像一个篮子,它运行docker-compose,然后复制测试。你可以在底部看到,Artifactory仍然处于不可用状态,处于睡眠状态。Artifactory试图启动,插件一直在问Artifactory,“你醒着吗?”你醒了吗?”最后,Artifactory启动了,我们的插件说:“Artifactory启动了,万岁!执行命令。”所以知道插件的作用是插件容器会设置Gradle并运行所有的测试。顺便说一下,这是大幅加速的因为我不认为我们都想坐在这里看这个。它正在执行所有针对人工工厂的测试。 The full theme takes about three minutes or so. It’s not, actually not too bad from start to finish. And then the plugging container is exited called zero. That’s good. And then the bass script opens up our test HTML and we can browse to see which tests passed and which ones failed. In this case, everything was good. Fantastic. So I realized once we had this, is that what I could do as well was, I could make Jenkins run these tests.

我们团队的一个标准是,如果你有测试,它们应该在PR挂钩上运行。所以当你提交时,当你提出拉取请求时,一个web hook会跑到Jenkins那里,对Jenkins说:“运行所有的测试?所以运行Gradle测试。”在我们的例子中,我们说,我们有一个Jenkins文件它会运行所有这些集成测试。我们可以有一个Jenkins文件那个Jenkins文件创建了一个pod。在这个舱里,有一个Docker舱和一个build舱。构建pod说,“docker-compose up -exit-code-from plugin”。然后它做的最后一件事是Docker从Artifactory容器中取出J单元兼容的XML并将其提供给Jenkins中的J单元插件,这意味着你可以在Jenkins中看到最新的测试结果,用于可审计性,也意味着,当你触发PR钩子并查看Jenkins时,你会看到这个旋转的圆圈。最终你会看到Jenkins对你的构建没有问题,所有的测试都通过了。

从本质上讲,这是因为我们有一个Kubenetes驱动的Jenkins,这里的抽象层次有点疯狂,因为我们有一个Kubenetes驱动的Jenkins,它给你一个代理,它在Docker容器中。然后你有一个pod,它定义了两个Docker容器,其中一个是Docker容器中的Docker,另一个是一个Docker容器,它旋转Docker -compose,其中需要Docker。在这三个使用Docker -compose的容器中,其中一个是Docker容器中的Docker。总而言之,我认为它达到了Docker的五个层次。所以,我想我们知道我们已经达到了Docker的顶峰,当我们走到这一步时,有些事情可能会有点错,但它实际上对我们来说很好。

总而言之,你可以编写Artifactory插件,如果你有良好的自动化,你可以作为一个团队来编写它们,并一起协作。这是有限制的,特别是对于我们的用例来说,因为我们需要Docker,这使得事情变得非常困难,因为这意味着,例如,我不能轻易地将它PR到jfrog的官方插件集中,因为这会使他们的Jenkins文件失败,因为它会期望Docker在我们的控制之下,等等。所以这并不理想。如果可能的话,我想改进一下。你可以玩得开心。所以如果你有很好的自动化,我们TDD这个插件的一部分,这对于像Artifactory插件这样深奥的东西来说是惊人的。你可以TDD它。我们会让一个人坐下来,写一个失败的测试,表达你想要的插件功能,把笔记本电脑交给另一个人,他们会实现这个功能。然后你会运行测试套件,你会希望它再次通过,然后我们交换角色。你可以像做其他任何事情一样做同样的开发,这真的非常非常好。

重要的是,因为你有集成测试,你也可以有信心,当你把这个插件部署到生产中,你注意到我没有涉及部署,因为那是一个单独的问题。但是当你把它投入生产时,你可以有信心,它会像你说的那样工作。显然,为了确保完全可靠,您可能希望将其放入staging环境中。特别是,如果你正在升级Artifactory,你会想知道,这个插件在Artifactory的下一个版本中表现良好吗?因此,您仍然希望执行所有这些措施,但至少您知道插件的行为是您希望它在逻辑上。如果你写了一个插件,我鼓励你开源它,因为这是我们互相学习的方式。

今天早上我们有一个关于社区的小组讨论。我们应该互相学习,改进文档,提供很多关于如何用插件做一些很酷的事情的例子,并注意原子提升,这是非常非常重要的。我现在正在接受anplan的治疗。我想要得到的是,我是开源的……它应该很快就可以用了。我该把它放在哪里?我还不知道。但是要小心。如果你去github.com/Anaplaninc,它应该很快就会出现。我想可能没有时间提问了。然而,我想我会被带到一个人们可以问我问题的地方,所以我们就这样做。 Thanks very much everyone.

免费试用JFrog !