Jenkins 2.x实践指南(txt+pdf+epub+mobi电子书下载)


发布时间:2020-06-19 00:21:54

点击下载

作者:翟志军

出版社:电子工业出版社

格式: AZW3, DOCX, EPUB, MOBI, PDF, TXT

Jenkins 2.x实践指南

Jenkins 2.x实践指南试读:

前言

2016年4月Jenkins发布了2.0版本(https://jenkins.io/blog/2016/04/26/jenkins-20-is-here/),开始支持pipeline as code。同年11月,pipeline as code作为“采用”项出现在ThoughtWorks技术雷达(https://www.infoq.cn/article/2016%2F11%2Fthoughtworks-radar-forecast)的采用环中。

2019年1月,笔者见同行在微信群里吐槽Jenkins的老旧,比如Jenkins不支持手动stage。经过了解,笔者大概猜到这位朋友还在使用Jenkins 1.x,或者知识还停留在Jenkins 1.x上。因为他说的问题,在Jenkins 2.x中已经不存在了。

这里并不是想说这位朋友不了解Jenkins 2.x,而是想说Jenkins 1.x已经成为过去式。长期以来,在中文网站上能搜到的关于Jenkins的文章大多停留在Jenkins 1.x时代。这样想来,也就能理解为什么这位朋友会有这样的误解了。

自Jenkins 2.0发布已有三个年头,据笔者所知,目前市面上还没有pipeline as code实践方面的书籍。中文的Jenkins书籍,只有《Jenkins权威指南》一本,其中也并没有pipeline as code方面的介绍。本书弥补了这一空白,系统地介绍了Jenkins 2.x的pipeline as code。

本书第1章介绍笔者对软件工程生产力的独到见解;第2章通过一个Hello world示例带领初学者入门Jenkins pipeline;第3章详细介绍Jenkins pipeline的语法;第4∼14章介绍在Jenkins pipeline中如何实现持续集成、持续交付的各个阶段,包括构建、测试、制品管理、部署等;第15章介绍扩展Jenkins pipeline的多种方式,本章对希望通过Jenkins实现持续集成、持续交付平台的读者非常有帮助;第16章介绍Jenkins运维相关知识;第17章介绍笔者整合Jenkins与多个第三方系统,实现ChatOps及自动化运维的经验;为避免读者出现“不知从哪里下手”的情况,第18章通过一个简单的案例介绍如何设计pipeline。

笔者建议所有读者都要阅读第1章和第3章,它们是本书的核心;已经入门了Jenkins pipeline的读者可以跳过第2章;而第4∼14章可以作为参考手册使用。

本书适合对Jenkins有初步认识,希望通过Jenkins实现持续集成、持续交付、DevOps的技术人员,以及希望了解pipeline as code技术在实际工作中如何应用的读者。

最后,感谢策划编辑郑柳洁女士为本书付出的努力;感谢刘杜康和黄献华在百忙之中对部分章节的审校;感谢黄峰达在出版方面的帮助;感谢王晓峰在部署目录命名方面的建议;感谢志平帮助处理我的个人照片;感谢妻子的理解与支持。1 关于软件工程生产力1.1 从另一个角度看“提高软件工程生产力”

所谓另一个角度,是指从社会学的理论中找到提高软件工程生产力的理论基础。

如果将软件工程看成软件的生产过程,软件工程师是这个生产过程中的一种劳动者,知识是这个生产过程中的劳动对象,我们就会发现,这就是马克思的生产力理论三要素。

生产力三要素是劳动力、劳动资料、劳动对象,其中劳动资料和劳动对象构成生产资料。

我们根据这三要素来思考如何提高软件工程生产力。

生产力三要素分别指的是什么呢?

劳动力:一般意义,指工作人群,通常指在一家公司、各个产业乃至某个社会工作的人,多指体力劳动者,但通常不包括雇佣者(老板)和管理层。

劳动资料:也称劳动手段,是在劳动过程中所运用的物质资料或物质条件。

劳动对象:是指劳动本身所作用的客体,比如耕作的土地、纺织的棉花等。

在软件工程领域,生产力三要素又分别指的是什么呢?

劳动力:通常将软件开发工程师、测试工程师认为是劳动力。然而,当他们不在工作状态时,就不能称其为劳动力,只能称为劳动者。

劳动资料:严格意义来说,办公场所、座椅、生产工具等都被称为劳动资料。本书主要讨论的是生产工具。笔者从硬件、软件的角度对生产工具进行了分类。

· 硬件:开发时使用的电脑、机械键盘、灵敏的鼠标、网络速度等。

· 软件:IDE(如Eclipse、IntelliJ IDEA)、构建工具(如Webpack、Maven)、协作工具(如Jira)、部署工具(如Ansible、Puppet)等。

劳动对象:不像制造汽车,在开发软件时,劳动对象则是看不见、摸不着的知识。笔者将软件工程中的知识分为业务知识和技术知识。

在理解了生产力三要素后,如何根据此理论来提高软件工程生产力呢?我们分别讨论。1.1.1 从劳动力要素考虑提高软件工程生产力

如果能招到比一般程序员生产力高10倍的程序员,并好好利用,就可以提高生产力。如果这个程序员的生产力比一般程序员高10倍,那么通常意味着其工资也高10倍。

另外,不论招到什么样的程序员,管理者都要关心的是,如何帮助劳动者达到最佳工作状态,以产出更多的劳动力。不在工作状态,就不能称之为劳动力,只能称为劳动者。也许,那些经常随意打断程序员的管理者需要反思一下了。

另外,注重培养员工的公司,不仅可以提升员工生产力,还可以提升公司的整体生产力。1.1.2 从劳动对象要素考虑提高软件工程生产力

如果将软件生产过程看成是无形的知识具化成有形软件的过程,那么产品经理需要将想法(一种知识)具化成原型,美工和交互设计师理解产品经理的想法后,将自己的想法具化成设计稿,然后再将自己的理解及想法(又是一种知识)传达给前端开发人员。接着,前端开发人员和后端开发人员又沟通接口的设计(还是一种知识)······ 可以看出,要提高软件工程生产力,知识的流通效率起着很关键的作用。所谓知识的流通效率,指的是让知识从一个人的大脑流动到另一个(群)人的大脑的准确性和速度。

所以说,沟通能力在软件工程领域十分重要。

我们甚至可以将一些需要重复操作的知识,具化成一个个工具或者模块。这无疑也是提高生产力的方法。这也就等于告诉我们,在管理软件生产过程时,要主动去识别那些需要重复操作的知识。

如果更深入地思考,你会发现,对于工厂里的生产流水线,如果工人辞职了并不会带走什么。而知识存在于人的大脑里,人辞职了,就意味着把公司的劳动对象带走了。这对团队、公司是一大损失。想想公司通过发放工资生产出来的劳动成果,就这样被轻而易举地带走了。

那怎么解决这个问题呢?根据劳动力要素,应该尽可能留住这些带有“关键”知识的人;根据劳动对象要素,应该尽可能提高同一知识在团队中的携带人数。

那怎么做呢?敏捷实践中的站会、结对编程以及看板的应用,都是增加知识流通效率的手段,从劳动对象要素考虑提高软件工程生产力。1.1.3 从生产工具要素考虑提高软件工程生产力

程序员笑话一则:程序员在椅子上打斗,经理叫他们回去,其中一位说:正在编译呢!

经理回答:哦,那你们继续。

从生产工具要素考虑提高软件工程生产力。这似乎不需要多谈。大家都知道挖土机比铁铲更具有生产力。然而,很多管理者还给程序员使用低配置的电脑。

低配置的电脑会导致程序员无用的等待,比如打开IntelliJ IDEA需要等2分钟、多打开两个窗口就卡顿等。

我们算算账。假如一个20 000元/月工资的程序员,工作22天,每天8小时,那么每小时就是113.6元。假如程序员每天因为打开程序慢、网络慢、编译慢等而等待的时间总和为0.5小时,那么这0.5小时就属于浪费的,总共约57元。这意味着一个月会浪费1254元。

这只是一个程序员一个月的浪费,还没有算其他人的。虽然计算有些粗糙,但是能反映问题。相对程序员的工资成本,电脑的成本真的不算什么。

说句题外话,这样计算并不是在压榨员工,而是在8小时范围内计算着如何提高公司整体生产力。

从另一个角度来看,作为软件开发团队的负责人,需要深入“开发现场”去了解,当前的生产工具是否变成提高生产力的阻力。生产工具除了电脑,还包括网络、构建工具、IDE等。1.1.4 生产力三要素的意义

总而言之,比起管理成功学的“心灵鸡汤”,从生产力三要素的角度来看软件工程的意义,在于为我们提供了更多的可操作性。管理者可以将生产力三要素作为理论基础,有据可依地来提高生产力。

话说回来,如果你是那位看到“程序员在椅子上打斗”的经理,你会怎么办?

从生产力三要素的角度看,你要问平均编译时间是多久、为什么这么久,进而从三个要素发问:

• 生产工具:是电脑太慢了?是编译工具本身太慢了?

• 劳动力(程序员的能力):是构建逻辑写得不合理?是编译过程中的某个阶段的问题影响了整体编译速度?

• 劳动对象:是不是缺少对当前构建工具(技术知识)的了解?1.2 Jenkins介绍

买这本书的大多数读者,可能对Jenkins都已经有了一定的了解,至少知道它大概是做什么的。所以,本书像网络上的大多数文章那样介绍Jenkins是什么显得有些多余。

笔者根据自己对Jenkins的理解,给出另一种介绍:

Jenkins是一款使用Java语言开发的开源的自动化服务器。我们通过界面或Jenkinsfile告诉它执行什么任务,何时执行。理论上,我们可以让它执行任何任务,但是通常只应用于持续集成和持续交付。

从生产力三要素来看,Jenkins属于劳动资料要素下的生产工具。

使用Jenkins能提升软件工程生产力的根本原因就在于它提供的是一个自动化平台。一个团队引入了Jenkins就像原来手工作坊式的工厂引入了生产流水线。由于知识的特殊性,它还能帮助我们将知识固化到自动化流水线中,在一定程度上解决了知识被人带走的问题。

我们使用Jenkins的过程,有如设计软件生产流水线的过程。1.3 Jenkins与DevOps

在行业内,DevOps的标杆Amazon Web Services(AWS)这样定义DevOps(https://aws.amazon.com/cn/devops/what-is-devops/):

DevOps集文化理念、实践和工具于一身,可以提高组织高速交付应用程序和服务的能力,与使用传统软件开发和基础设施管理流程相比,能够帮助组织更快地发展和改进产品。这种速度使组织能够更好地服务于客户,并在市场上更高效地参与竞争。

是不是可以理解为能帮助组织更快地发展和改进产品,可以提高组织高速交付应用程序和服务能力的都可以称自己为DevOps?

AWS给出的定义似乎没有可操作性。而维基百科(https://zh.wikipedia.org/wiki/DevOps)给出的定义,可操作性或许多一些:

DevOps(Development和Operations的组合)是一种重视软件开发人员(Dev)和IT运维技术人员(Ops)之间沟通合作的文化、运动或惯例。通过自动化软件交付和架构变更的流程,使得构建、测试、发布软件能够更加快捷、频繁和可靠。

看到这里,恐怕又有人站出来说:这个定义不够全面啊!正因为DevOps的定义没有标准,所以就DevOps的定义到底是什么,大家吵得不可开交。但是可以注意到,这些定义都是在给我们一个承诺:能更快、更好地交付软件。大家争吵的只是如何兑现这个承诺。那问题来了,假如最后兑现不了这个承诺呢?留给读者思考。

对于如何兑现DevOps的承诺,大家可能又有很多话说了。但是在谈到真正要落地DevOps时,基本上都会谈到Jenkins。这说明Jenkins能帮助我们很好地兑现DevOps的承诺。1.4 本章小结

如何提高软件工程生产力,软件行为从来不缺少新概念,但是按它们所言进行实践,真的能提高生产力吗?我们需要思考它们的理论基础是什么,这才是关键。

本章的内容过于个人化,笔者没有创造新概念,而是以原来就已经存在的生产力三要素作为理论基础,思考如何提高软件工程生产力的。同时简单介绍了Jenkins,以及它与DevOps之间的关系。

总之,希望能给读者带来一些新的思考。2 pipeline入门2.1 pipeline是什么

从某种抽象层次上讲,部署流水线(Deployment pipeline)是指从软件版本控制库到用户手中这一过程的自动化表现形式。——[1]《持续交付——发布可靠软件的系统方法》(下称《持续交付》)

按《持续交付》中的定义,Jenkins本来就支持pipeline(通常会把部署流水线简称为pipeline,本书会交替使用这两个术语),只是一开始不叫pipeline,而叫任务。

Jenkins 1.x只能通过界面手动操作来“描述”部署流水线。Jenkins 2.x终于支持pipeline as code了,可以通过“代码”来描述部署流水线。

使用“代码”而不是UI的意义在于:

• 更好地版本化:将pipeline提交到软件版本库中进行版本控制。

• 更好地协作:pipeline的每次修改对所有人都是可见的。除此之外,还可以对pipeline进行代码审查。

• 更好的重用性:手动操作没法重用,但是代码可以重用。

本书全面拥抱pipeline as code,放弃依赖手动操作的自由风格的项目(FreeStyle project)。2.2 Jenkinsfile又是什么

Jenkinsfile就是一个文本文件,也就是部署流水线概念在Jenkins中的表现形式。像Dockerfile之于Docker。所有部署流水线的逻辑都写在Jenkinsfile中。

Jenkins默认是不支持Jenkinsfile的。我们需要安装pipeline插件,本书使用的插件版本为2.27,其安装方式和普通插件的安装方式无异。安装完成后,就可以创建pipeline项目了,如图2-1所示。图2-1 创建pipeline项目2.3 pipeline语法的选择

Jenkins团队在一开始实现Jenkins pipeline时,Groovy语言被选择作为基础来实现pipeline。所以,在写脚本式pipeline时,很像是(其实就是)在写Groovy代码。这样的确为用户提供了巨大的灵活性和可扩展性,我们还可以在脚本式pipeline中写try-catch。示例如下:

以上写法被称为脚本式(Scripted)语法。Jenkins pipeline还支持另一种语法:声明式(Declar-ative)语法。pipeline插件从2.5版本开始,才同时支持两种格式的语法。

脚本式语法的确灵活、可扩展,但是也意味着更复杂。再者,Groovy语言的学习成本对于(不使用Groovy的)开发团队来说通常是不必要的。所以才有了声明式语法,一种提供更简单、更结构化(more opinionated)的语法。示例如下:

本书所有的示例都将使用声明式语法。因为声明式语法更符合人类的阅读习惯、更简单。声明式语法也是Jenkins社区推荐的语法。2.4 创建第一个pipeline

如前文所述,要创建pipeline,首先要安装pipeline插件(也许将来会默认安装)。本书默认读者已经安装了pipeline插件。下面我们一起创建本书第一个pipeline。

首先在Jenkins中新建一个pipeline项目,如图2-2所示。图2-2 新建pipeline项目

在pipeline-hello-world项目的设置页面中,在Pipeline节点下填入pipeline的内容,如图2-3所示。图2-3 填入pipeline的内容

执行后,结果如图2-4所示。图2-4 pipeline执行结果

和大多数Hello world示例一样,以上示例只是为了让大家对pipeline有一个感性的认识。2.5 从版本控制库拉取pipeline

在Hello world示例中,我们是直接在Jenkins界面上填入pipeline内容的。在试验时可以这么做,但是不推荐,因为这样无法做到pipeline的版本化。

接下来,我们让Jenkins从Git仓库拉取pipeline并执行。

首先需要安装Git插件,然后使用SSH的clone方式拉取代码。所以,需要将Git私钥放到Jenkins上,这样Jenkins才有权限从Git仓库拉取代码。

将Git私钥放到Jenkins上的方法是:进入Jenkins→Credentials→System→Global credentials页,然后选择Kind为“SSH Username with private key”,接下来按照提示设置就好了,如图2-5所示。关于Credential的更多内容,我们会在第9章中进行详细介绍。目前只需要理解:Jenkins从Git仓库拉取代码时,需要SSH key就可以了,然后Jenkins本身提供了这种方式让我们设置。图2-5 增加SSH key

另外,需要注意的是,我们需要提前将SSH的公钥放到Git仓库中。关于这方面内容网络上有很多教程,本书不再赘述。

现在,我们来看看项目结构,只有一个Jenkinsfile文件。

Jenkinsfile文件中的内容就是Hello world示例的内容。接下来,我们将项目推送到GitLab。

在Hello world示例中,在Pipeline节点下,在“Definition”中选择“Pipeline script from SCM”,并在“SCM”中选择“Git”,然后根据选项填入信息内容就可以了,如图2-6所示。图2-6 从SCM下载pipeline

这里有两点需要注意:

• 在“Credentials”中选择我们刚刚创建的用于拉取代码的凭证。

•“Script Path”就是pipeline的文件名,默认是Jenkinsfile。

保存并创建成功后,执行,在日志中除了Hello world被打印出来,git clone过程的日志也被打印出来。2.6 使用Maven构建Java应用

Maven是非常流行的一个Java应用构建工具。下面我们再来看一个使用Maven构建Java应用的例子。Jenkins默认支持Maven。

首先在本地创建一个Maven项目,目录结构如下:

接下来,需要在Jenkins上安装JDK和Maven。我们可以登录Jenkins服务器手动安装,也可以让Jenkins自动安装。这里选择后者。方法如下:(1)进入Manage Jenkins→Global Tool Configuration→Maven页,设置如图2-7所示。图2-7 自动安装Maven

留意Name输入框中的值,这里填的是mvn-3.5.4。在后面的pipeline中会使用到。(2)进入Manage Jenkins→Global Tool Configuration→JDK页,设置如图2-8所示。图2-8 自动安装JDK

Jenkinsfile内容如下:

当Jenkins执行到tools时,就会根据Maven的设置自动下载指定版本的Maven,并安装。tools是pipeline中的一个指令,用于自动安装工具,同时将其路径放到PATH变量中。通过命令sh "printenv",可以看到tools将MAVEN_HOME放到了当前任务的环境变量中。

关于tools的更多信息,我们会在第4章中进行详细介绍。

单击构建后,通过Jenkins执行日志,我们看到指定版本的Maven被下载和安装,mvn执行打包。

至此,又一个完整的pipeline入门示例完成了。2.7 本章小结

本章通过两个简单的pipeline入门示例,让读者对Jenkins pipeline有了一个感性的认识。通常Jenkins pipeline被简称为pipeline。只有安装了pipeline插件,Jenkins才支持pipeline as code。这个“code”被写在一个被命名为Jenkinsfile的文本文件中。在同一个代码项目下可以按需创建多个不同名的Jenkinsfile。

由于历史原因,Jenkins pipeline支持两种语法。node为根节点的是脚本式语法,而pipeline为根节点的是声明式语法。本书使用的是Jenkins社区推荐的声明式语法。

在下一章中,我们将详细介绍pipeline的声明式语法。[1] 《持续交付——发布可靠软件的系统方法》讲述的是如何实现更快、更可靠、低成本的自动化软件交付。该书介绍了多种pipeline相关实践,比如第5章介绍的只生成一次二进制包、对不同环境采用同一种部署方式等。本书介绍的pipeline设计基本符合这些实践。笔者在这里推荐此书,因为Jenkins pipeline毕竟只是工具,我们需要原则与实践的指导。同时,在本书写成之际,《持续交付2.0》(乔梁著)也出版了。3 pipeline语法讲解3.1 必要的Groovy知识

虽然学习Jenkins pipeline可以不需要任何Groovy知识,但是学习以下Groovy知识,对于我们写pipeline如虎添翼。

• 虽然Groovy同时支持静态类型和动态类型,但是在定义变量时,在Groovy中我们习惯使用def关键字,比如def x="abc"、def y=1。

• 不像Java,Groovy语句最后的分号不是必需的。

• Groovy中的方法调用可以省略括号,比如System.out.println "Hello world"。

• 支持命名参数,比如:

• 支持默认参数值,比如:

• 支持单引号、双引号。双引号支持插值,单引号不支持。比如:

• 支持三引号。三引号分为三单引号和三双引号。它们都支持换行,区别在于只有三双引号支持插值。比如:

• 支持闭包。闭包的定义方法如下:

还可以将闭包看作一个参数传递给另一个方法。

• 闭包的另类用法。我们定义一个stage函数:

这些知识点没有连贯性,读者浏览一遍后,大概有个印象就可以。等学习完本章后,再回头看就理解Jenkins pipeline的语法了。3.2 pipeline的组成

Jenkins pipeline其实就是基于Groovy语言实现的一种DSL(领域特定语言),用于描述整条流水线是如何进行的。流水线的内容包括执行编译、打包、测试、输出测试报告等步骤。

本章对Jenkins pipeline的结构、语法进行详细介绍。3.2.1 pipeline最简结构

前文中,我们已经了解到:从软件版本控制库到用户手中这一过程可以分成很多阶段,每个阶段只专注处理一件事情,而这件事情又是通过多个步骤来完成的,这就是软件工程的pipeline。Jenkins对这个过程进行抽象,设计出一个基本的pipeline结构。

• pipeline:代表整条流水线,包含整条流水线的逻辑。

• stage部分:阶段,代表流水线的阶段。每个阶段都必须有名称。本例中,build就是此阶段的名称。

• stages部分:流水线中多个stage的容器。stages部分至少包含一个stage。

• steps部分:代表阶段中的一个或多个具体步骤(step)的容器。steps部分至少包含一个步骤,本例中,echo就是一个步骤。在一个stage中有且只有一个steps。

• agent部分:指定流水线的执行位置(Jenkins agent)。流水线中的每个阶段都必须在某个地方(物理机、虚拟机或Docker容器)执行,agent部分即指定具体在哪里执行。我们会在第14章中进行详细介绍。

以上每一个部分(section)都是必需的,少一个,Jenkins都会报错。3.2.2 步骤

pipeline基本结构决定的是pipeline整体流程,但是真正“做事”的还是pipeline中的每一个步骤。步骤是pipeline中已经不能再拆分的最小操作。前文中,我们只看到两个步骤:sh和echo。sh是指执行一条shell命令;echo是指执行echo命令。这两个步骤只是Jenkins pipeline内置的大量步骤中的两个。

那是不是说,Jenkins pipeline内置了所有可能需要用到的步骤呢?显然没有必要。因为有些步骤我们可能一辈子也不会用到。

更好的设计是:步骤是可插拔的,就像Jenkins的插件一样。如果现有的插件不用修改或者只需要简单修改,就能在Jenkins pipeline中当成一个步骤来使用,该多好?这样就不用重新实现一遍已经存在的插件了。

Jenkins就是这样做的,只需要对现有的插件进行一些修改,就可以在pipeline中被当成一个步骤使用。这样大大降低了从现有依赖于界面的插件过渡到pipeline中步骤的成本。

已经有哪些插件适配了Jenkins pipeline呢?pipeline plugin的GitHub仓库给出了一个列表(https://github.com/jenkinsci/pipeline-plugin/blob/master/COMPATIBILITY.md)方便大家检索,如图3-1所示(只截取了一部分)。

只要安装了这些适配了Jenkins pipeline的插件,就可以使用其提供的pipeline步骤。

Jenkins官方还提供了pipeline步骤参考文档(https://jenkins.io/doc/pipeline/steps/)。图3-1 适配了Jenkins pipeline的部分插件列表3.3 post部分

在上一章中,我们已经见过post部分,在pipeline执行失败后,发送邮件到指定邮箱中。

post部分包含的是在整个pipeline或阶段完成后一些附加的步骤。post部分是可选的,所以并不包含在pipeline最简结构中。但这并不代表它作用不大。

根据pipeline或阶段的完成状态,post部分分成多种条件块,包括:

• always:不论当前完成状态是什么,都执行。

• changed:只要当前完成状态与上一次完成状态不同就执行。

• fixed:上一次完成状态为失败或不稳定(unstable),当前完成状态为成功时执行。

• regression:上一次完成状态为成功,当前完成状态为失败、不稳定或中止(aborted)时执行。

• aborted:当前执行结果是中止状态时(一般为人为中止)执行。

• failure:当前完成状态为失败时执行。

• success:当前完成状态为成功时执行。

• unstable:当前完成状态为不稳定时执行。

• cleanup:清理条件块。不论当前完成状态是什么,在其他所有条件块执行完成后都执行。post部分可以同时包含多种条件块。以下是post部分的完整示例。3.4 pipeline支持的指令

显然,基本结构满足不了现实多变的需求。所以,Jenkins pipeline通过各种指令(directive)来丰富自己。指令可以被理解为对Jenkins pipeline基本结构的补充。

Jenkins pipeline支持的指令有:

• environment:用于设置环境变量,可定义在stage或pipeline部分。

• tools:可定义在pipeline或stage部分。它会自动下载并安装我们指定的工具,并将其加入PATH变量中。

• input:定义在stage部分,会暂停pipeline,提示你输入内容。

• options:用于配置Jenkins pipeline本身的选项,比如options {retry(3)}指当pipeline失败时再重试2次。options指令可定义在

试读结束[说明:试读内容隐藏了图片]

下载完整电子书


相关推荐

最新文章


© 2020 txtepub下载