一、时刻保持Jenkins的安全
在默认配置情况下,Jenkins是不执行任何安全检查的。也就是说,除一些简单基本的Jenkins配置、作业和构建,网站的访问者几乎可以在Jenkins的主数据库中执行任何随机代码。同时,Jenkins还允许在所有连接的代理上,执行包括用户密码、证书、以及其他隐私数据之类的代码操作。
具体实践
为了保护Jenkins的安全,我们需要通过如下两个方面,来“配置全局安全性(Configure Global Security)”选项。
安全领域: 通常也被称为“身份验证”。它会告知Jenkins的基本环境,以及从何处提取用户信息。
如上图所示,从Jenkins V2.214和Jenkins LTS V2.222.1开始,“Jenkins自己的用户数据库”被用作了默认的安全选项。而对于两者之前的版本,我们应当选中“启用安全”复选框,以方便用户使用其凭据登录,进而避免任何侵入。
在配置有诸如LDAP之类外部身份提供者的组织中,我们需要为Jenkins实例安装并启用LDAP插件,以实现将所有身份验证(包括用户和组),都委派给已配置的LDAP服务器。
授权:告知Jenkins环境中有关哪些用户和(或)组,可以访问Jenkins的哪些方面,以及他们的权限。如上图所示,我们有五种授权的选择方式:
任何人都可以做任何事:除了本地测试的Jenkins控制器,我们应避免启用该设置。毕竟所有人、包括匿名用户都可以完全控制Jenkins,是极其危险的。
旧版模式:我们同样应当避免选用该设置。只有具有“管理员”角色的用户才能被授予对系统具有完全控制权;否则,他们将只有读取权限。
已登录的用户可以执行任何操作:此模式会强制每个用户在使用Jenkins之前,必须登录。据此,匿名用户只能获得对于Jenkins的读取访问权限,或者根本就没有访问权限。同时,用户的任何操作也会得到审核。
基于矩阵的安全性:该方案可以准确控制在Jenkins环境中,哪些用户和组可以执行哪些操作。
基于项目的矩阵授权策略:该插件提供了基于矩阵的安全性,和基于项目的矩阵授权策略,因此它们需要在Jenkins上被单独安装。同时,该授权方案是对基于矩阵的安全性的扩展,它允许在“项目配置”的界面中,为每个项目、以及特定的用户或组,分别定义访问控制列表(ACL)。总的说来,此类策略为许多Jenkins环境提供了极好的安全性和灵活性,因此是一种不错的实践。
为了保护Jenkins用户免受其他威胁,我们还可以按需开启如下功能(它们默认处于关闭状态):
跨站点请求伪造(CSRF)保护:防止针对运行在防火墙内部的Jenkins进行远程攻击。CSRF设置的路径为:“管理Jenkins”>“配置全局安全性”>“部分:CSRF保护”。具体说明请参见--https://www.jenkins.io/doc/book/managing/security/#cross-site-request-forgery。当然,从Jenkins 2.0开始,CSRF保护是默认已启用的。
在主节点上运行构建的安全隐患:在主节点上运行的构建,是可以读取或修改JENKINS_HOME中任何文件的。由于可以读取凭据,创建管道与作业,安装插件,因此会影响Jenkins的整个构建过程。通常,为了配置主节点为不具备执行权限,我们既可以只在构建代理上运行构建,又可以在构建代理中,将管理Jenkins的人员与配置人员,以及提交项目的人员角色区分开来;或者直接使用“作业限制插件(Jobs Restrictions Plugin)”,来对哪些作业可以在主节点上运行进行过滤。
二、始终备份JENKINS_HOME目录
Jenkins的主目录包含了:作业配置、构建日志、插件配置等各种重要的数据。我们可以通过Jenkins提供的插件,来配置需要备份的作业。
具体实践
1.精简备份(Thin Backup)插件
这是所有提供自动化定期备份的工具中,最方便的插件之一。它的启用过程为:
· 通过“管理Jenkins”>“管理插件”>“单击‘可用’选项卡”>“搜索‘精简备份’”以安装插件。
· 完成安装后,请转到“管理Jenkins”>“精简备份”>“设置”。
· 单击“立即备份”以测试备份的效果。
2.定期备份插件
如下图所示,一旦配置完成,该插件将会定期运行备份作业。具体内容,请参阅--https://plugins.jenkins.io/periodicbackup/。
该插件定义了如下三个方面:
· 文件管理器:定义在备份中需要包括哪些文件,以及文件的还原策略。例如,ConfigOnly将仅选择配置类XML文件。
· 存储:指定存档和取消存档备份的方法。例如,“ZipStorage”会将备份文件压缩为ZIP档案。
· 位置:指定备份的位置。例如,“LocalDirectory”是将备份文件存储到指定的路径上。
3.配置常规备份作业
· 在创建新的Jenkins任务时选择“自由式项目”。
· 将SCM标记为“无”。
· 在“构建触发器”中选择“定期构建”,然后在“计划”中配置频率。
· 根据配置文件,添加执行壳(Execute Shell),以构建作业。
4.将Jenkins配置备份到Google Cloud存储空间
如果您在Google Cloud的Kubernetes集群上部署了Jenkins的服务器配置,则可以将上述精简备份插件与Google Cloud Storage插件一起使用,以便连接到云端。具体实现说明,请参照--https://medium.com/faun/backing-up-jenkins-to-google-cloud-storage-4ba12e69ded2。
三、为每个维护或开发分支,设置不同的作业/项目
众所周知,利用持续集成工具的优势之一便是:在开发生命周期的早期阶段,能够检测出问题。而Jenkins恰好提供了并行构建管道的方法。因此,为每个分支设置不同的作业/项目,可以让我们在开展并行开发的同时,尽早发现问题,降低风险,并提高开发人员的生产率。
具体实践
最新的Parallel Test Executor插件(请参见--https://plugins.jenkins.io/parallel-test-executor/),可帮助我们执行并行测试。
四、防止并行运行的作业产生资源冲突
当然,值得注意的是,多个同时运行的作业在创建服务或需要排他式的访问时,可能由于冲突的产生,而导致Jenkins管道失效。
具体实践
我们可以为并行的各个项目构建,分配不同的端口,以避免冲突。例如,对于数据库之类需要锁定某个持久资源的需求场景,我们可以通过采用Throttle Concurrent Builds 插件(请参见--https://wiki.jenkins.io/display/JENKINS/Throttle+Concurrent+Builds+Plugin),来根据全局配置或某个项目启用的节点数,调节并行构建的数量。
如上图所示,我们可以使用0,将并发构建设置为无限。
五、使用“文件指纹”管理依赖项
我们在Jenkins上创建依赖项时,往往容易引发相互之间版本的混淆问题。而Jenkins支持的“文件指纹(File fingerprinting)”功能正好可以简化该过程。
具体实践
我们需要将所有相关项目,都配置为记录下由项目产生的jar文件,以及项目所有依赖项的jar文件指纹。在具体配置上,您可以依次进入:“项目”>“配置”>“构建后操作”>“记录指纹”。同时,您可以参考文档--https://wiki.jenkins.io/display/JENKINS//Fingerprint。
六、避免在管道中使用复杂的Groovy代码
对于Jenkins管道,Groovy代码往往会在主服务器上调用大量的主资源(如:内存和CPU)来执行。因此,我们需要减少在管道中执行的Groovy代码量。
具体实践
1. JsonSlurper
此功能函数与XmlSlurper或readFile类似,可被用于从磁盘上读取文件,将文件中的数据解析为JSON对象,然后使用JsonSlurper().parseText(readFile(“$LOCAL_FILE”))命令,将该对象注入管道中。由于该命令会两次将本地文件加载到主服务器上的内存中,因此如果文件过大、或该命令被反复执行的话,则将消耗大量的内存。
解决方案:为了代替JsonSlurper,我们可以使用shell step的如下命令。
def JsonReturn = sh label: ”, returnStdout: true, script: ‘echo “$LOCAL_FILE”| jq “$PARSING_QUERY”‘
它将使用代理资源来读取文件,其中的$PARSING_QUERY将有助于将文件解析成小块。
2. HttpRequest
通常,此命令可用于从外部资源获取数据,并将其存储在变量中。在此过程中,由于请求直接来自主服务器,而如果主服务器未加载证书,则可能造成HTTPS请求的结果不一致。另外,该请求的响应也会被重复性地存储了两次。
解决方案:使用shell step来执行代理的HTTP请求。例如,我们可以适当地使用诸如curl或wget等工具。同时,如果结果必须是在Jenkins管道的后端,那么我们则必须在代理端过滤掉尽可能多地结果,以便只把必要的信息传送到Jenkins的主数据库中。
七、建立可扩展的Jenkins管道
相比一般的程序库,共享库(Shared Libraries)提供了版本控制的管道代码。我们可以从源代码管理(SCM)处进行存储和访问。
具体实践
我们需要在SCM中存储具有一致性结构的源文件,然后使用SCM的插件,将该库连接到Jenkins实例上。具体的操作步骤为:依次在“管理Jenkins”>“配置系统”>“全局管道库”下启用全局共享库。当然,我们也可以在Jenkinsfile中使用库名称,以允许管道访问共享库。
八、管理声明式语法和声明式管道
当涉及到企业级Jenkins的实施和管道资源的管理时,我们可以通过声明式管道配置,告知系统该如何运作,以便将复杂性转移到系统上。同时,您可以参考通用的声明性步骤(请参见--https://jenkins.io/doc/book/pipeline/getting-started/#directive-generator),来创建未开发的管道;或使用代码段生成器(请参见--https://www.jenkins.io/doc/book/pipeline/getting-started/#snippet-generator),将现有的构建步骤转换为管道语法。此外,《管道入门指南》和《管道示例》都是两个不错的社区参考资源。
九、保持较高的测试代码覆盖率,并将单元测试作为管道的一部分
显然,代码测试的覆盖率越高,产品的缺陷就会越少,用户验收测试(UAT)的通过率也就越高。因此,我们需要依靠更详细的单元测试,以及更高的测试覆盖范围,来确保开发人员在开发生命周期的早期阶段,提高代码的质量。
具体实践
1. Jenkins Cobertura插件
为了捕获代码覆盖率的相关报告,我们需要完成Cobertura插件的如下配置步骤:
· 通过“管理Jenkins”>“管理插件”来安装Cobertura插件。
· 配置项目的构建脚本,以生成Cobertura XML报告。
· 启用“发布Cobertura覆盖率报告”。
· 指定生成coverage.xml报告的目录。
· (可选)配置覆盖率的相关指标。
您可以通过链接,来获悉如何配置单个项目、项目的层次结构、以及Maven。
2.代码覆盖率API插件
作为统一的API插件,它能够支持Cobertura等其他插件。其主要功能包括:
· 根据用户的配置,查找覆盖率的相关报告。
· 使用适配器将报告转换为标准格式。
· 汇总已解析的标准格式化报告,并在图表中显示已解析的结果。
3.LambdaTest Selenium Grid Cloud
由于提供了广泛的浏览器及其版本库,因此您可以在使用Selenium测试套件,在执行自动化测试时,获得更高的测试覆盖率。通常,LambdaTest Jenkins插件可以提供:
· 为Jenkins作业配置LambdaTest凭据。
· 设置Lambda隧道并删除二进制文件,以方便在本地托管的Web应用上,进行自动化跨浏览器测试。
· 将包括视频日志、网络日志、以及LambdaTest执行步骤的相关截图等所有测试结果,嵌入Jenkins的作业结果。
在完成LambdaTest Jenkins插件的安装后,我们通过将Jenkins CI实例连接到LambdaTest grid上,来自动化Selenium自动化测试脚本。您也可以通过链接,参考Jenkins集成的支持文档。
十、监控CI/CD管道
我们需要通过监控,来获悉诸如云服务、网络、测试服务等外部依赖项是如何影响CI/CD管道的,以便及时采取行动。在此,我们可以使用Jenkins Slack插件,将错误通知发送到由值守工程师监控的频道中。该插件不但可以提供诸如:构建合格率、平均构建时间、以及特定阶段的错误计数等信息;还能够协助我们识别出在构建中,效率低下、需要改进的潜在区域。
小结
总的说来,Jenkins的优秀实践包括:让Jenkins运行在自己的用户数据库上,采用基于权限和用户矩阵的访问控制方式,自动运行相关配置的备份,鼓励应用团队采用Shell step,以避免复杂的Groovy脚本,拥有共享库和Jenkinsfiles的所有权,通过使用自动化状态插件来监控管道,并定义声明性的管道,提高代码测试的覆盖率,以及让代码覆盖率API与LambdaTest Selenium Grid相集成,以实现无缺陷的交付。
- END -
本文分享自微信公众号 - 互联网后端架构(fullstack888)。
如有侵权,请联系 [email protected] 删除。
本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一起分享。