她提升了自己的头盔排行榜,你不会相信接下来发生了什么!- Anaplan的西蒙·沃尔顿
Anaplan已聘请Artifactory大力支持JFrog全新的CI/CD管道.该管道可以通过一系列“信任级别”来推广基于helm的微服务,直到它们被认为可以投入生产。这个管道中不可或缺的是Artifactory推广插件的内部开发,该插件允许Anaplan团队原子地推广所有Docker映像与舵图有关当只提升图表时,也为他们提供重要的门控,以防止不合适的提交被提升。在这次演讲中,Simon Walton概述了Anaplan的CI/CD管道,包括支持它的Artifactory插件的开发动机。Simon还深入研究了复杂的集成测试套件,使Anaplan团队对推广机制的正确性有信心,并提供了关于最佳实践的观察和指导——所有这些都基于Anaplan团队在Artifactory插件的内部开发中的经验。Artifactory插件开发可以很有趣!
视频记录
西蒙·沃尔顿:对。你好每一个人。谢谢你能来。我叫西蒙。我是Anaplan工程生产力团队的一员。我们基本上是一个团队,负责所有的构建基础设施和围绕它的所有工具,有点像Slack集成之类的东西。我们也会照看我们内部的GitHub企业实例和Artifactory。我有点像公司的JFrog大使。我很高兴,至少我可以让一些人在午餐后讨论Artifactory插件,用这个很有针对性的标题。我也考虑过这个,“为什么这个家伙写了一个Artifactory插件:答案会震惊你和一个奇怪的技巧来推广你的Docker图像”,我认为这是相当好的。 But in the end I decided upon, “She Promoted Her Helm Chart And You Won’t Believe It Happened Next!”
所以,我们开始吧!这是一个关于Artifactory插件的演讲。我们要讲的是,为什么要写一个插件我们要讲的是,如何写这个插件。好吧?我们在Anaplan上有一个问题需要解决,我们为你的插件写了一个ask(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,你说在端口共享库中共享库允许你做各种事情。我们想要做的是,我们希望这个共享的管道库能够部署到一组,不受信任的存储库中。是的,你把你的Helm图表和Docker映像部署到这种不稳定的状态,然后你问Artifactory,“请提升链条上的所有东西,直到测试和生产。” Finally. So this was all, well and good.
这个想法是,当你开始推广东西时,很明显,每个集群只能与每种范围或级别对话。换句话说,在生产Kubernetes集群的顶部,它应该不能从Helm测试和Docker测试中提取Helm图表或Docker图像。出于这个原因,我们用Artifactory的权限来锁定事情。简单地说,这就是管道的工作方式。你有一个Jenkins文件,你部署到你的开发集群,你发布你的Helm照片和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,等等,还有一些构建firs,我正在将它们从一个存储库移动到另一个存储库。它并不是真正围绕着把东西放在一起并在一个集合中移动的想法。因此,考虑到这一点,我将带您了解Artifactory插件的工作原理。请举手,谁以前写过Artifactory插件?很好,很多人。谁想写一个,但不知道从哪里开始。好的,很好。我这里有很多人可以选择。这将会告诉你我们是如何写这个插件的,我也会告诉你如何开始写这个插件。
再举一下手,谁喜欢Groovy?好的。Artifactory插件是用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交互。你会做的一些事情是,你会说,“构建。得到构建,存储库得到。得到存储库。”它还能帮助你查看安全信息,你可以注销等等。所以它们真的是为了方便,这样你就不必调用公共REST端点或类似的东西,这应该是非常冗长和困难的。
Artifactory插件…大概有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插件时可以利用的最重要的资源,因为它为你提供了一组由JFrog自己设计和社区贡献的Artifactory插件的列表。JFrog非常欢迎人们为其贡献插件。
Artifactory公共API的文档有些稀少,所以我发现这是目前为止最好的资源。如果你要写一个插件,你要做的就是,在开发环境中找到Cron然后在那里创建新的插件文件夹。而你的新插件文件夹,它将包含两个文件。它将包含插件本身。所以MyCoolNewPlugin。帅呆了。然后你也会有这个测试文件,这个测试表达了一组针对你的插件的集成测试,针对正在运行你的插件的Artifactory。所以你需要以某种方式对你的插件进行压力测试。我也会向你们展示它们是如何工作的。开发环境实际上是一个griddle项目,griddle项目中有一组特定于开发Artifactory插件的griddle任务。
当你最初下载它的时候,你会说"准备艺术专业版"它会转到JFrog的网站上它会卷进你想要的任何版本的Artifactory。因此,很明显,您正在尝试匹配生产环境或即将升级到生产环境的版本。你可以尝试匹配你的DR环境之类的。然后你会说,Start Art-Pro它会做的是,这是一个griddle task,它会在后台启动Artifactory,真正的Artifactory它会等待它完成,然后把控件交还给你并在后台运行。它可以告诉Artifactory已经启动,它将监视特定消息的日志。这很聪明。我想说的是它需要许可证。
是的,你需要一个真正的企业执照。JFrog没有问题,你使用一个真正的许可证,集成测试和类似的东西。印章上有说明,请阅读我关于如何正确授权的说明。然后你会说,Work on plugin因为你会说,Griddle Work on plugin你会给它一个插件的名字然后Griddle task就会启动,它会尝试找到你的插件。默认情况下,它将查找一个目录。在这个例子中,你说,griddle work在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.
所以,Atomic-Promote是如何编写的。我在前面提到JFrog提供了一组dsl,您可以使用这些dsl编写Artifactory插件。下面是推广插件的样子。你有这个打开促销块,它告诉Artifactory,“我要定义一个促销插件”,然后你给这些促销插件命名。在本例中,我们将其命名为atomicPromote。然后我们给它四个参数,在我们的例子中,这些参数没有真正的文档,除了在GitHubs的例子中。如果你正在寻找文档,寻找一个推广插件的例子,你会在那里找到它。第一个参数告诉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图表。去找那些和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.”
考虑到这一点,我将向你展示这个推广插件的一些代码,这样你就可以对插件的代码有一个感觉,因为有些人可能之前没有见过这些代码。而且,你可能会看到我是怎么写的。切换到V S码,全屏显示。大家都能看出来吗?这是相当清楚的。为了这次演讲,我确保我的线宽很紧。这是一个很好的练习,行宽应该是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,你在闭包中得到它并从中获取目标作用域。我们说强制性为真。这个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。你可以这样想,它实际上叫做BuildRun对象,它在公共API中。BuildRun对象本质上是在Artifactory UI中浏览构建时得到的对象。BuildRun是,有点像,你在顶部看到的面板。然后detailedBuild运行是你在下面看到的所有选项卡,比如模块列表,那个构建的发布历史等等。如果出了什么岔子,我们就逃。
接下来我们可以做的是,我记得我之前说过,我们想要在这个插件中加入资格检查。所以我们想说,“嘿,如果用户没有资格推广这个构建,或者构建中的工件有什么问题,比如它没有通过我们的遵从性测试,那么我们希望立即放弃。”我们应该推广这个方法,我们会开源这个插件,这个方法说,现在返回true。本质上,这是要填进去的。在我们在Anaplan的例子中,我们有一些东西,我们提取了我们的REST调用。我不认为在插件中调用out是明智的,但我们就是这么做的。我们称之为服务,它只是验证提交和类似的东西,以确保它们通过这些标准。希望你能得到一个真值。就是这样。如果用户是管理员,这很简单,对吧? 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,“这就是我要去的仓库,等等。”所以我们有可能做的是下载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在属性上存储一个列表,它会以逗号分隔的字符串形式返回。所以我们只是把它分开,把它压平,然后返回所有不为null的。这很简单。然后我们要做的是将这组摘要转换为一组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所做的就是创建这个在公共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,那么在发布状态下,还有一个发布状态,我会在UI中展示它的样子。但是发布状态,在你做一个普通的构建推广Artifactory时是免费的,但如果你做自定义推广,你是负责添加发布状态的人。从我们可审计性的角度来看,这显然是非常重要的。你想说,你想让我点击构建,然后看到,“好的。这个用户在某个时候将其提升到测试范围。”在我们的例子中,詹金斯将作为推广者出现,善良的老詹金斯。
正确的。现在是Docker的促销活动。现在这有点困难,因为正如我之前提到的,你没有得到,公共API提供的一流Docker提升支持。你必须调用REST API,也就是其他人都在使用的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 responseccode为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 chart部署到不稳定状态时,我执行了一个升级到测试状态,所以在上面一级,那么我期望Helm chart存在于测试状态,在上面一级。我还希望Docker映像在测试中存在,比测试高一级。这很不错,对吧?因为如果你…这是你应该写测试的标准方式,对吧?你是否在一开始就尽可能地把它抽象出来,这样当下一个人来编写测试时,他们就会意识到,“哦,这非常……不要重复你自己。”
我有很好的障碍物,我可以用它来验证我的直觉。我有一些新的功能,你可以正确地红绿Artifactory测试。我们还有另一个测试……如果服务不存在并没有测试,那么升级到生产就失败了。我们可以说部署一些Alpine镜像到测试中,但我们没有在那里部署Docker镜像。我们要做的是执行促销,我们得到的响应是404因为它找不到Docker图像。然后我们就能证明这两件事都不会发生。舵舵图(确实存在)和Docker图片(甚至根本不存在)都没有得到推广。这就是插件的本质。我们在验证,如果出了问题,什么都不会发生。
这就是Artifactory测试的工作方式。如果有人想在我们一起看完代码后来看我,我很乐意。我真的只擅长推广类型的插件。在JFrogs GitHub上的用户插件库中有大量的插件可用。我真的鼓励你去看看那里,因为在Artifactory中有很多东西可以扩展。它真的非常非常强大。还有一些很好的测试例子可供参考。我认为这是我见过的最全面的测试套件。当然,我们真的在这些测试中转向了。我要回到我的演讲。 Okay. Yeah.
正如我提到的,这是Docker文摘属性的样子。你会看到atom。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,并把它交给团队的另一个成员来审查。我创建了一个PR,我说,“山姆,你能帮我检查一下这个吗?”他说:“当然。”他查看了GitHub企业版的早午餐,他说:“哦,我看到你已经做了一个关于如何运行测试的Read Me。”我说:“没错。我做得非常彻底。”我记得大约6个小时后他说,“如果我仍然不能运行测试……”原来他错过了这个Read Me here中的一个小步骤,因为你要做的是你必须把所有东西都按正确的顺序排列。 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 request他们可能会说,哦,完全运行测试,太棒了。为什么不直接应用呢?”因为他们认为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和points,最终将返回你的200个“OK”。所以我们可以让插件一直问Artifactory:“你还活着吗?你还活着吗?”然后我们可以让插件执行这些griddle命令,说在插件测试中工作。我们还需要做很多其他的事情来完全按照我们的要求配置这些测试。所有那些别人会手动忘记做的事情,我也会因为打字错误和其他事情而搞砸。因为人们很难相处,人们有时不阅读,人们很累,最好是把事情自动化。这个Artifactory正在从一个公共Docker中心进行拉取或者实际上它正在从一个Artifactory进行拉取,这个Artifactory镜像出来并将它推回Artifactory。 It’s using this Docker that we control.
这是Docker图片中真正的官方Docker。是的。在Docker文件中,我们所做的只是说,From Docker And Docker然后我们自定义说HTTP Artifactory是一个不安全的注册中心,这很好。Docker非常高兴,这意味着我们可以对这个插件进行一键测试设置。如果我们说exit code from plugin,这意味着我们有一个环境,我们可以运行docker-compose up -exit-code-from plugin, docker-compose将运行完整的测试套件。当插件退出时,换句话说,当我的所有测试都通过或其中一些测试失败时,整个环境将被关闭,控制权将返回给用户,这真的很好。然后我们可以将Docker CP的测试结果输出到Artifactory容器中。如果你是一个人,那么你会CP HTML版本。如果你是一个机器人,或者你是一个Jenkins,那么你会得到XML版本。
本着为坐在教室后面的人设计的精神,这是一个小型文本终端,我将向你们展示它正在运行我们的集成测试。我们说runtests。sh,它有点像一个篮子,它运行docker-compose,然后复制测试。你可以在底部看到,Artifactory仍然处于不可用状态,处于休眠状态。Artifactory正在尝试启动,插件一直在问Artifactory,“你醒了吗?”你醒了吗?”最后,Artifactory启动了,我们的插件说:“Artifactory启动了,太可怕了!执行命令。”插件的作用是插件容器会设置Gradle并运行所有的测试。顺便说一下,这是大幅度加速的,因为我不认为我们都想坐在这里看这个。它正在执行针对Artifactory的所有测试。 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挂钩上运行。当你提交的时候,当你提出一个pull request的时候,一个网络钩子就会去找Jenkins,对Jenkins说,“运行所有的测试?所以运行Gradle测试吧。”在我们的例子中,我们说,我们有一个Jenkins文件,它将运行所有这些集成测试。我们可以有一个Jenkins文件这个Jenkins文件创建了一个pod。在那个吊舱里,有一个Docker吊舱和一个build吊舱。build pod说:“docker-compose up -exit-code-from plugin。”然后它做的最后一件事是Docker从Artifactory容器中CPs J unit兼容XML并将它交给Jenkins中的J unit插件,这意味着你可以在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到JFrogs的官方插件集,因为这会使他们的Jenkins文件失败,因为它会期望Docker在我们的控制之下,等等。这并不理想。如果可能的话,我想改进一下。你可以玩得开心。所以如果你有好的自动化,我们会TDD这个插件的一部分,这对于像Artifactory插件这样深奥的东西来说是很神奇的。你可以用TDD。我们让一个人坐下来,写一个失败的测试,表达你想要的插件功能,把笔记本电脑交给另一个人,他们会实现功能。然后运行测试套件,希望它再次通过,然后我们交换角色。你可以做和其他事情一样的开发,这真的非常非常好。
重要的是,因为你有集成测试,所以当你把这个插件部署到生产环境中时,你也可以有信心,你注意到我没有涉及到部署,因为这是一个独立的问题。但是当您将其投入生产时,您可以相信它会像您所说的那样工作。显然,为了完全自信,您应该将其放入登台环境中。特别是,如果你正在升级Artifactory,你会想知道,这个插件在Artifactory的下一个版本中是否正常运行?所以你仍然想要执行所有这些测量,但至少你知道插件的行为是你想要的,逻辑上。如果你确实写了一个插件,我鼓励你开源它,因为这是我们互相学习的方式。
我们今天早上开了一个关于社区的座谈会。这是非常非常重要的,我们都要互相学习,改进文档,并给出很多很多的例子,如何用插件做很酷的事情,并注意原子推广。我现在正在跟阿纳潘谈。我想要的是,我是开源的,应该很快就能得到。我要把它放在哪里?我还不知道。但要小心。如果你访问github.com/Anaplaninc,它应该很快就会出现。我想可能没有时间提问了。然而,我想我会被带到一个人们可以问我问题的地方,所以我们就这样做吧。 Thanks very much everyone.