根据ActiveState的CI/CD 2020状态调查结果,Jenkins是市场上最常用的CI/CD工具。作为市场上最早的工作运行者之一,它有足够的时间来获得普及,并且是推进构建和交付软件的DevOps方法的一个重要组成部分。
由于有1800多个插件,Jenkins非常容易扩展--有了正确的插件集,你几乎可以做任何事情。插件库允许每个Jenkins用户最终获得个性化的体验,这在很大程度上取决于他们安装的插件。
插件可能是Jenkins的核心,但它们也很快成为使用Jenkins的团队的负担。为成长中的团队和公司管理Jenkins平台很快就会成为一个瓶颈,拖慢你的速度而不是提高你的敏捷性。
在本指南中,你将进一步了解Jenkins的一些缺点,以及了解一些替代方案。
什么是Jenkins插件?
插件是使用Jenkins的核心,它们在安装过程中首次出现,在那里你被要求选择一个插件来开始使用。默认安装有大约20个插件,加上你在安装时选择的任何插件。这些插件负责将你的CI/CD与外部工具(如GitHub或Bitbucket的版本控制)集成。插件还扩展了Jenkins的能力和工作方式。甚至协调构建的管道系统也是一个插件,可以使用其他插件进行修改。
你可以通过市场向Jenkins添加新的插件。市场上的所有插件都是基于社区的,并且是开源的,这意味着任何人都可以创建一个符合他们需求的自定义插件,并将其列在市场上。通常,在选择一个插件时,有三件重要的事情需要关注。
插件的受欢迎程度可以通过安装的数量来评估
它的维护情况如何,这可以通过查看最近一次更新的时间来估计
需要的依赖性,例如你需要安装的其他插件
为什么Jenkins的插件可能是坏的
虽然大量的插件曾经被看作是平台的优势,但现在它经常被看作是一个缺点,或者至少是一个挫折的来源,这助长了许多人对Jenkins的爱恨情仇。
当它第一次发布时,Jenkins感觉像是一个美妙的自助服务环境,一个可靠的开发者或团队可以通过Jenkins管道和正确的插件集做几乎任何事情。然而,今天,你需要真正的Jenkins专业知识来维护Jenkins服务器,这是一个缺点,特别是与市场上较新的SaaS CI/CD选项相比。
有许多与Jenkins插件生态系统相关的反复出现的问题。第一个是无休止的升级和依赖性的循环。一个简单的项目可能需要超过25个不同的插件,因为你安装的每一个插件都可以安装其他插件,而这些插件是第一个插件工作所需要的。这就导致了这样一种情况:你可以安装两个插件,每个都需要相同的第三个插件来工作,而每个都依赖于第三个插件的不同版本,导致安装问题或错误。
当你发现一个插件有安全漏洞时,更大的问题就出现了。如果你发现一个插件不安全或有漏洞,你可以在GitHub上打开一个问题,等待插件被修补,但如果补丁永远不会来呢?你可以忍受安全漏洞,找到一个替代的插件,并修改你所有的管道以适应新的插件,或者分叉该插件,打上补丁,并成为该插件的新维护者。鉴于每天都有新的安全漏洞被发现,而且插件需要经常打补丁,这很快就会成为一个很大的工作。
这也导致了Jenkins插件的另一个问题。即使是非常受欢迎的插件,也经常被维护得很糟糕,或者被原始维护者完全放弃。从维护者的角度来看,这是完全可以理解的。插件的创建是为了解决一个问题,而大多数维护者并不打算在工作之余成为专业的插件维护者。但是,从用户的角度来看,这导致了插件的支持率很低,因为维护者是社区成员,没有义务无限期地维护插件。
Jenkins插件的最后一个问题是缺乏透明度。如果不仔细检查代码,你就无法知道一个插件的范围,而且你限制插件在你的服务器上的访问和行动的能力有限。因此,在选择插件时,信任因素非常重要,你需要注意减少潜在的攻击面。
Jenkins插件如何影响你的组织
当你考虑到与单个团队一起使用Jenkins时,这些问题可能看起来不是一个大问题。他们可以用自己喜欢的一套插件建立他们的管道基础,假设没有安全问题,一切都很好。
但是,当公司发展壮大,更多的开发人员加入进来,新的团队成立,并且有多个应用程序和服务,Jenkins插件就不能很好地扩展。如果你让每个人使用他们想要的任何插件,你会很快遇到依赖性和升级问题。另一方面,如果你限制开发人员可以使用的插件,你最终会得到一个沮丧的团队和开发人员,他们觉得你在阻止他们将工作流程中乏味的方面自动化。
Jenkins只允许有一个主节点,因此,在设计时根本没有考虑到高可用性。由于这些设计选择,不得不重新启动服务器来改变配置或安装新的插件会导致停机,并打断你的组织中每个依赖Jenkins的人的工作。这个难题没有简单的解决方案。为每个团队创建一个Jenkins服务器将是非常不划算的,而且会在团队之间形成孤岛。拥有独立Jenkins服务器的团队会根据不同的插件集建立不兼容的管道,为你的团队不能相互分享他们的自动化工作的情况做准备。
你不能让Jenkins成为一个真正的自助服务平台,因为这在操作上会很复杂,并减少团队之间的合作。但反对Jenkins插件的最大论点是,插件是一种安全隐患。如前所述,几乎所有的插件都是由社区创建和支持的。你需要相信维护者使用了安全的最佳实践,并保持插件对新发现的漏洞进行修补,如果做得正确,这可能是每周的工作。CI/CD平台通常可以访问许多系统,并拥有修改你的基础设施和与你的生产环境互动所需的凭证。这使得任何CI/CD平台成为你的基础设施中非常敏感的一部分,安全应该是这些工具的首要任务。
如何才能不再依赖Jenkins的插件?
现在,你已经对Jenkins插件的一些问题有了很好的了解。如果你正在考虑摆脱它们,转向一个更安全的基础设施,这里有一些步骤要做。
精心策划插件
创建一个精心挑选的插件的短名单,并坚持使用这些插件。这个名单应该考虑到安全和可维护性问题。一般来说,最好坚持使用那些提供与云供应商(如GitHub或Amazon Web Services)集成的插件,因为它们通常得到这些云供应商的社区和开发人员的大力支持。例如,GitHub插件是一个维护良好的插件,你可以信赖。在主服务器上运行新的插件和升级之前,先在第二台Jenkins服务器上测试这些插件。
避免使用那些改变Jenkins管道工作方式的插件,因为如果这些插件出现故障,不再被维护,或者出现安全漏洞,你就需要重做整个管道。
主动关注你的插件的健康状况,检查它们的GitHub仓库,看看它们是否被积极维护;如果它们没有,你应该寻找一个替代品。这可以防止将来在升级Jenkins服务器或发现安全漏洞时出现停机。插件是独立的软件,具有潜在的可利用的漏洞,攻击者可以利用这些漏洞进入你的构建系统--以及Jenkins出于需要被授予读/写权限的系统的所有其他部分,例如你的代码库、云提供商和网络连接。正如SolarWinds通过构建管道注入恶意软件事件所表明的那样,CI/CD管道是构建过程中受信任的部分,只需要一段恶意代码,不仅使你的公司,而且使你的所有客户都受到攻击。这一领域的极端敏感性使得插件的监控和管理变得绝对重要。
依靠基于容器的步骤
容器技术使你可以将环境与所有的依赖性打包。多亏了Docker插件,你可以在Docker容器内运行Jenkins构建。Docker容器可以使用为任务创建的镜像,并作为Jenkins代理,为你的构建提供所有必要的依赖,消除了在服务器上安装插件的需要。
使用更少的插件
解决Jenkins插件问题最简单的方法之一就是少用插件。你使用的插件越少,你遇到的问题就越少。为了达到这个目的,你可以偏爱脚本而不是插件。例如,发送Slack通知就像向API发送HTTP请求一样简单,而且可以让你避免依赖第三方插件。脚本可以比插件更可靠,因为你可以在本地使用它们来执行相同的动作。虽然这看起来比使用插件更费事,但你可以在整个公司内分享你的自动化脚本,并在任何管道中使用它们,而不影响Jenkins服务器。
第二种方法是尽可能地使用Jenkins模板。模板让你定义可重复使用的管道(作业)片段,并增加一层抽象,使开发人员更容易配置和使用Jenkins。使用模板为你提供了一个简单的方法来确定所需的插件,因为你需要的插件就是模板中引用的插件。这为你提供了一个协作建立管道的地方,并减少你在整个组织中使用的插件数量。
总结
Jenkins和它的插件生态系统对于为他们的项目寻找CI/CD解决方案的人来说是非常有吸引力的。然而,维护不善的插件、多种不同的依赖关系和安全风险使许多人对这个工具感到失望。
Jenkins的插件管理会影响你的组织,管理不善的插件会使你的组织处于风险之中。实施缓解策略很重要,比如通过定义标准作业或管道来尽量减少插件的数量,仔细策划你的插件,在一个单独的实例上测试插件和升级,使用基于容器的作业来减少你对Jenkins插件的依赖。
如果你厌倦了管理你的CI/CD生态系统,包括你的Jenkins服务器,你可能会对一个无代码的DevOps平台感兴趣,该平台提供集成以取代许多Jenkins插件。像这样的平台还可以与你现有的工具连接,使你的团队更加敏捷,反应更加迅速,让你专注于创造伟大的软件,而不是管理你的管道。
如有想了解更多软件设计与架构, 系统IT,企业信息化, 团队管理 资讯,请关注我的微信订阅号:
作者:Petter Liu
出处:http://www.cnblogs.com/wintersun/
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
该文章也同时发布在我的独立博客中-Petter Liu Blog。
类classAprivatedeffooputs:fooendpublicdefbarputs:barendprivatedefzimputs:zimendprotecteddefdibputs:dibendendA的实例a=A.new测试a.foorescueputs:faila.barrescueputs:faila.zimrescueputs:faila.dibrescueputs:faila.gazrescueputs:fail测试输出failbarfailfailfail.发送测试[:foo,:bar,:zim,:dib,:gaz].each{|m|a.send(m)resc
我有一个模型:classItem项目有一个属性“商店”基于存储的值,我希望Item对象对特定方法具有不同的行为。Rails中是否有针对此的通用设计模式?如果方法中没有大的if-else语句,这是如何干净利落地完成的? 最佳答案 通常通过Single-TableInheritance. 关于ruby-on-rails-Rails-子类化模型的设计模式是什么?,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.co
我正在使用的第三方API的文档状态:"[O]urAPIonlyacceptspaddedBase64encodedstrings."什么是“填充的Base64编码字符串”以及如何在Ruby中生成它们。下面的代码是我第一次尝试创建转换为Base64的JSON格式数据。xa=Base64.encode64(a.to_json) 最佳答案 他们说的padding其实就是Base64本身的一部分。它是末尾的“=”和“==”。Base64将3个字节的数据包编码为4个编码字符。所以如果你的输入数据有长度n和n%3=1=>"=="末尾用于填充n%
我主要使用Ruby来执行此操作,但到目前为止我的攻击计划如下:使用gemsrdf、rdf-rdfa和rdf-microdata或mida来解析给定任何URI的数据。我认为最好映射到像schema.org这样的统一模式,例如使用这个yaml文件,它试图描述数据词汇表和opengraph到schema.org之间的转换:#SchemaXtoschema.orgconversion#data-vocabularyDV:name:namestreet-address:streetAddressregion:addressRegionlocality:addressLocalityphoto:i
在选择我想要运行操作的频率时,唯一的选项是“每天”、“每小时”和“每10分钟”。谢谢!我想为我的Rails3.1应用程序运行调度程序。 最佳答案 这不是一个优雅的解决方案,但您可以安排它每天运行,并在实际开始工作之前检查日期是否为当月的第一天。 关于ruby-如何每月在Heroku运行一次Scheduler插件?,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.com/questions/8692687/
为什么4.1%2返回0.0999999999999996?但是4.2%2==0.2。 最佳答案 参见此处:WhatEveryProgrammerShouldKnowAboutFloating-PointArithmetic实数是无限的。计算机使用的位数有限(今天是32位、64位)。因此计算机进行的浮点运算不能代表所有的实数。0.1是这些数字之一。请注意,这不是与Ruby相关的问题,而是与所有编程语言相关的问题,因为它来自计算机表示实数的方式。 关于ruby-为什么4.1%2使用Ruby返
为了将Cucumber用于命令行脚本,我按照提供的说明安装了arubagem。它在我的Gemfile中,我可以验证是否安装了正确的版本并且我已经包含了require'aruba/cucumber'在'features/env.rb'中为了确保它能正常工作,我写了以下场景:@announceScenario:Testingcucumber/arubaGivenablankslateThentheoutputfrom"ls-la"shouldcontain"drw"假设事情应该失败。它确实失败了,但失败的原因是错误的:@announceScenario:Testingcucumber/ar
我对最新版本的Rails有疑问。我创建了一个新应用程序(railsnewMyProject),但我没有脚本/生成,只有脚本/rails,当我输入ruby./script/railsgeneratepluginmy_plugin"Couldnotfindgeneratorplugin.".你知道如何生成插件模板吗?没有这个命令可以创建插件吗?PS:我正在使用Rails3.2.1和ruby1.8.7[universal-darwin11.0] 最佳答案 随着Rails3.2.0的发布,插件生成器已经被移除。查看变更日志here.现在
它不等于主线程的binding,这个toplevel作用域是什么?此作用域与主线程中的binding有何不同?>ruby-e'putsTOPLEVEL_BINDING===binding'false 最佳答案 事实是,TOPLEVEL_BINDING始终引用Binding的预定义全局实例,而Kernel#binding创建的新实例>Binding每次封装当前执行上下文。在顶层,它们都包含相同的绑定(bind),但它们不是同一个对象,您无法使用==或===测试它们的绑定(bind)相等性。putsTOPLEVEL_BINDINGput
我可以得到Infinity和NaNn=9.0/0#=>Infinityn.class#=>Floatm=0/0.0#=>NaNm.class#=>Float但是当我想直接访问Infinity或NaN时:Infinity#=>uninitializedconstantInfinity(NameError)NaN#=>uninitializedconstantNaN(NameError)什么是Infinity和NaN?它们是对象、关键字还是其他东西? 最佳答案 您看到打印为Infinity和NaN的只是Float类的两个特殊实例的字符串