Jenkins-持续集成学习手册-全-

Jenkins 持续集成学习手册(全)

原文:zh.annas-archive.org/md5/AC536FD629984AF68C1E5ED6CC796F17

译者:飞龙

协议:CC BY-NC-SA 4.0

前言

在过去的几年里,敏捷软件开发模式在全球范围内得到了相当大的增长。特别是在电子商务领域,对于一种快速灵活应对频繁修改的软件交付解决方案的需求非常巨大。因此,持续集成和持续交付方法越来越受欢迎。

无论是小项目还是大项目,都会获得诸如早期问题检测、避免糟糕的代码进入生产以及更快的交付等好处,这导致了生产力的增加。

本书,使用 Jenkins 学习持续集成第二版,作为一个逐步指南,通过实际示例来设置持续集成、持续交付和持续部署系统。这本书是 20% 的理论和 80% 的实践。它首先解释了持续集成的概念及其在敏捷世界中的重要性,并专门有一整章介绍这个概念。用户随后学习如何配置和设置 Jenkins,然后实现使用 Jenkins 的持续集成和持续交付。还有一个关于持续部署的小章节,主要讨论持续交付和持续部署之间的区别。

本书内容

第一章,持续集成的概念,介绍了一些最流行和广泛使用的软件开发方法如何催生了持续集成。接着详细解释了实现持续集成所需的各种要求和最佳实践。

第二章,安装 Jenkins,是一份关于在各种平台上安装 Jenkins 的分步指南,包括 Docker。

第三章,新 Jenkins,提供了新 Jenkins 2.x 的外观和感觉概述,并深入解释了其重要组成部分。它还向读者介绍了 Jenkins 2.x 中新增的功能。

第四章,配置 Jenkins,专注于完成一些基本的 Jenkins 管理任务。

第五章,分布式构建,探讨了如何使用 Docker 实现构建农场,并讨论了将独立机器添加为 Jenkins 从属节点的方法。

第六章,安装 SonarQube 和 Artifactory,涵盖了为持续集成安装和配置 SonarQube 和 Artifactory 的步骤。

第七章,使用 Jenkins 进行持续集成,带领你设计持续集成并使用 Jenkins 以及其他一些 DevOps 工具来实现它的步骤。

第八章,使用 Jenkins 进行持续交付,概述了持续交付的设计以及使用 Jenkins 与其他一些 DevOps 工具实现它的方法。

第九章,使用 Jenkins 进行持续部署,解释了持续交付与持续部署之间的区别。它还提供了使用 Jenkins 实现持续部署的逐步指南。

附录,支持工具和安装指南,介绍了使您的 Jenkins 服务器在互联网上可访问所需的步骤以及 Git 的安装指南。

本书所需的内容

要能够理解本书中描述的所有内容,您需要一台具有以下配置的计算机:

  • 操作系统

    • Windows 7/8/10

    • Ubuntu 14 及更高版本

  • 硬件要求

    • 至少拥有 4 GB 内存和多核处理器的计算机
  • 其他要求

    • GitHub 账户(公共或私人)

本书面向的读者

本书旨在读者具有较少或没有敏捷或持续集成和持续交付方面的经验。对于任何新手想要利用持续集成和持续交付的好处以提高生产力并缩短交付时间的人来说,它都是一个很好的起点。

构建和发布工程师、DevOps 工程师、(软件配置管理)SCM 工程师、开发人员、测试人员和项目经理都可以从本书中受益。

已经在使用 Jenkins 进行持续集成的读者可以学习如何将他们的项目提升到下一个级别,即持续交付。

本书的当前版本是其前任的完全重启。第一版读者可以利用当前版本讨论的一些新内容,例如 Pipeline as Code、Multibranch Pipelines、Jenkins Blue Ocean、使用 Docker 的分布式构建农场等。

约定

在本书中,您将找到许多用于区分不同类型信息的文本样式。以下是其中一些样式的示例及其含义的解释。文本中的代码词、数据库表名、文件夹名、文件名、文件扩展名、路径名、虚拟 URL、用户输入和 Twitter 句柄显示如下:“这将在您的系统上下载一个.hpi文件。”

代码块设置如下:

stage ('Performance Testing'){
    sh '''cd /opt/jmeter/bin/
    ./jmeter.sh -n -t $WORKSPACE/src/pt/Hello_World_Test_Plan.jmx -l
    $WORKSPACE/test_report.jtl''';
    step([$class: 'ArtifactArchiver', artifacts: '**/*.jtl'])
}

当我们希望引起您对代码块的特定部分的注意时,相关行或项将加粗显示:

stage ('Performance Testing'){
    sh '''cd /opt/jmeter/bin/
    ./jmeter.sh -n -t $WORKSPACE/src/pt/Hello_World_Test_Plan.jmx -l
    $WORKSPACE/test_report.jtl''';
    step([$class: 'ArtifactArchiver', artifacts: '**/*.jtl'])
}

在一些命令中使用的额外的“****”仅用于指示命令在下一行继续。任何命令行输入或输出都按以下方式编写:

 cd /tmp
   wget https://archive.apache.org/dist/tomcat/tomcat-8/ \
   v8.5.16/bin/apache-tomcat-8.5.16.tar.gz

新术语重要单词 以粗体显示。屏幕上看到的单词,例如在菜单或对话框中,会以如下方式出现在文本中:“从 Jenkins 仪表板上,点击 “Manage Jenkins”|“Plugin Manager”|“Available” 选项卡。”

警告或重要提示呈现如下。

提示和技巧呈现如下。

读者反馈

我们始终欢迎读者的反馈。请告诉我们您对本书的看法-您喜欢或不喜欢的地方。读者反馈对我们很重要,因为它帮助我们开发让您真正受益的标题。要向我们发送一般反馈,只需发送电子邮件至feedback@packtpub.com,并在消息主题中提到书的标题。如果您对某个专题有专业知识,并有兴趣参与撰写或投稿书籍,请查看我们的作者指南,网址为www.packtpub.com/authors

客户支持

既然您是 Packt 书籍的自豪所有者,我们有许多措施可帮助您充分利用您的购买。

下载示例代码

您可以从您在 www.packtpub.com 的账户下载本书的示例代码文件。如果您在其他地方购买了这本书,您可以访问www.packtpub.com/support,注册后文件将直接发送到您的邮箱。按照以下步骤下载代码文件:

  1. 使用您的电子邮件地址和密码登录或注册到我们的网站。

  2. 将鼠标指针悬停在顶部的“支持”标签上。

  3. 点击“代码下载 & 勘误”。

  4. 在搜索框中输入书名。

  5. 选择您想要下载代码文件的书籍。

  6. 从下拉菜单中选择您购买本书的位置。

  7. 点击“代码下载”。

下载文件后,请确保使用最新版本的解压软件解压文件夹:

  • Windows 下的 WinRAR / 7-Zip

  • Mac 下的 Zipeg / iZip / UnRarX

  • Linux 下的 7-Zip / PeaZip

本书的代码包也托管在 GitHub 上,链接为github.com/PacktPublishing/Learning-Continuous-Integration-with-Jenkins-Second-Edition。我们还有其他丰富的图书和视频代码包可供下载,地址为github.com/PacktPublishing/。赶紧去看看吧!

下载本书的彩色图片

我们还为您提供了一个 PDF 文件,其中包含本书中使用的截图/图表的彩色图片。彩色图片将帮助您更好地理解输出中的变化。您可以从www.packtpub.com/sites/default/files/downloads/LearningContinuousIntegrationwithJenkinsSecondEdition_ColorImages.pdf下载此文件。

勘误

尽管我们已经尽一切努力确保内容的准确性,但错误还是会发生。如果你在我们的书中发现了错误——也许是文本或代码中的错误——我们将不胜感激地接受您的报告。通过这样做,你可以帮助其他读者避免困扰,也可以帮助我们改进后续版本的这本书。如果你发现任何勘误,请访问 www.packtpub.com/submit-errata,选择你的书,点击勘误提交表格链接,并输入勘误的详细信息。一旦你的勘误被核实,你的提交将被接受,并将勘误上传到我们的网站,或者添加到该标题的现有勘误列表的勘误部分。要查看以前提交的勘误,请访问 www.packtpub.com/books/content/support,并在搜索字段中输入书名。所需信息将出现在勘误部分下。

盗版

互联网上对受版权保护的材料的盗版是所有媒体持续存在的问题。在 Packt,我们非常重视对我们的版权和许可的保护。如果你在互联网上发现我们作品的任何形式的非法副本,请立即向我们提供位置地址或网站名称,以便我们采取措施。请通过 copyright@packtpub.com 联系我们,并附上可疑盗版材料的链接。感谢你帮助我们保护我们的作者和我们提供有价值内容的能力。

问题

如果你在阅读本书的过程中遇到任何问题,可以通过 questions@packtpub.com 联系我们,我们将尽力解决问题。

持续集成的概念

我们将从介绍当今两种主要软件开发方法论开始:瀑布模型和敏捷开发。理解它们的概念和影响将帮助我们回答持续集成CI)是如何产生的。

接下来,我们将尝试理解 CI 背后的概念及构成要素。通过阅读这些内容,您将了解到 CI 如何帮助项目实现敏捷。完成本章后,您应该能够:

  • 描述 CI 是如何产生的。

  • 定义什么是 CI。

  • 描述 CI 的要素。

软件开发生命周期

对于那些对术语“软件开发生命周期”不太熟悉的人,让我们尝试理解一下。

软件开发生命周期,有时简称为SDLC,是规划、开发、测试和部署软件的过程。

团队按照一系列阶段进行工作,每个阶段都利用了其前一个阶段的结果,如下图所示:

软件开发生命周期

让我们详细了解 SDLC 的各个阶段。

需求分析

这是循环的第一个阶段。在这里,业务团队(主要由业务分析师组成)对其项目的业务需求进行需求分析。需求可能是组织内部的,也可能是来自客户的外部需求。这项研究涉及发现需求的性质和范围。根据收集到的信息,提出了改进系统或创建新系统的建议。项目成本得到确定,并列出了利益。然后确定项目目标。

设计

第二阶段是设计阶段。在这里,系统架构师和系统设计师制定软件解决方案的期望功能,并创建项目计划。该计划可能包括流程图、整体接口和布局设计,以及大量的文档。

实现

第三阶段是实现阶段。在这里,项目经理创建并分配工作给开发人员。开发人员根据设计阶段定义的任务和目标开发代码。这个阶段可能会持续几个月到一年,这取决于项目的规模。

测试

第四阶段是测试阶段。当所有确定的功能都开发完成后,测试团队接管。在接下来的几个月里,所有功能都会经过彻底的测试。软件的每个模块都会被收集和测试。如果在测试过程中出现任何错误或 bug,就会提出缺陷。在出现故障时,开发团队会迅速采取措施解决故障。经过彻底测试的代码随后会被部署到生产环境中。

演进

最后阶段是演进阶段或维护阶段。用户/客户的反馈被分析,整个开发、测试和发布新功能和修复的循环以补丁或升级的形式重复。

软件开发的瀑布模型

最著名且广泛使用的软件开发过程之一是瀑布模型。瀑布模型是一个顺序软件开发过程,源自制造业。人们可以看到高度结构化的流程在一个方向上运行。在其创立时期,没有其他软件开发方法论,开发人员唯一能够想象的就是简单适用于软件开发的生产线流程。

下图展示了软件开发的瀑布模型:

瀑布模型

瀑布方法简单易懂,因为所涉及的步骤类似于 SDLC。

首先是需求分析阶段,然后是设计阶段。在分析和设计部分花费了相当多的时间。一旦完成,就不再进行添加或删除。简而言之,在开发开始后,设计中不允许修改。

然后是实施阶段,实际的开发将在此阶段进行。开发周期可以长达三个月至六个月。这段时间,测试团队通常是空闲的。开发周期结束后,计划整合源代码需要一整周时间。在此期间,会出现许多集成问题,并立即进行修复。这个阶段后是测试阶段。

当测试开始时,会持续三个月甚至更长时间,取决于软件解决方案。测试成功后,源代码将部署在生产环境中。为此,会再次计划一天左右来进行生产部署。可能会出现一些部署问题。软件解决方案上线后,团队会收到反馈,也可能预料到问题。

最后阶段是维护阶段。用户/客户的反馈被分析,整个开发、测试和发布新功能和修复的循环以补丁或升级的形式重复。

毫无疑问,瀑布模型在数十年间运行良好。然而,存在缺陷,但长时间以来被忽视。因为在那个时代,软件项目有足够的时间和资源来完成工作。

然而,看着过去几年软件技术的变化,我们可以说瀑布模型无法满足当前世界的需求。

瀑布模型的缺点

以下是瀑布模型的一些缺点:

  • 可工作的软件仅在大多数情况下持续一年左右的 SDLC 结束时产生。

  • 存在大量不确定性。

  • 不适用于对新功能需求过于频繁的项目。例如,电子商务项目。

  • 仅在整个开发阶段完成后执行集成。因此,集成问题会在更晚的阶段和大量发现。

  • 不存在向后追溯。

  • 在各个阶段内很难衡量进度。

瀑布模型的优点

通过查看瀑布模型的缺点,我们可以说它主要适用于以下项目:

  • 需求已经很好地记录并且是固定的。

  • 有足够的资金可供维护管理团队、测试团队、开发团队、构建和发布团队、部署团队等。

  • 技术是固定的,而不是动态的。

  • 没有模棱两可的要求。最重要的是,它们不会在除了需求分析阶段之外的任何其他阶段中出现。

敏捷来拯救

名称敏捷恰如其分地暗示了快速且简单。敏捷是一种通过自组织团队之间的协作开发软件的方法集。敏捷背后的原则是增量、快速、灵活的软件开发,并促进自适应规划。

敏捷软件开发过程是传统软件开发过程的替代方案。

敏捷十二原则

以下是敏捷模型的十二原则:

  • 通过尽早和持续地交付有用的软件来实现客户满意度。

  • 欢迎在开发的后期接受变更的需求。

  • 经常交付可工作的软件(以周为单位,而不是月)。

  • 业务、人员和开发者之间的密切日常合作。

  • 项目围绕着应该受到信任的积极主动的个人构建。

  • 面对面的交流是最好的沟通方式(共同位置)。

  • 可工作的软件是进度的主要衡量标准。

  • 可持续发展——能够保持稳定的速度。

  • 持续关注技术卓越和良好的设计。

  • 简单——最大化未完成工作量的艺术是必不可少的。

  • 自组织团队。

  • 定期适应变化的环境。

要了解更多关于敏捷原则的内容,请访问链接:www.agilemanifesto.org

敏捷软件开发的十二原则表明了当前软件行业的期望以及其在瀑布模型上的优势。

敏捷软件开发过程是如何工作的?

在敏捷软件开发过程中,整个软件应用被分割成多个特性或模块。这些特性以迭代方式交付。每个迭代持续三周,涉及到跨职能团队同时在各个领域工作,如规划、需求分析、设计、编码、单元测试和验收测试。

因此,在任何给定时间点,没有人处于空闲状态。这与瀑布模型大不相同,在瀑布模型中,尽管开发团队正在忙于开发软件,但测试团队、生产团队和其他所有人都是空闲或利用率不高的。以下图示了软件开发的敏捷模型:

敏捷方法论

从上图中我们可以看到,没有时间花费在需求分析或设计上。相反,准备了一个非常高层次的计划,仅足以勾勒项目的范围。

然后团队经历一系列迭代。迭代可以分类为时间框架,每个时间框架持续一个月,甚至在一些成熟项目中持续一周。在此期间,项目团队开发和测试特性。目标是在单个迭代中开发、测试和发布一个特性。在迭代结束时,该特性进行演示。如果客户喜欢它,那么该特性就上线了。但是,如果被拒绝,该特性将作为待办事项,重新排优先级,并在后续迭代中再次进行处理。

也存在并行开发和测试的可能性。在单个迭代中,可以并行开发和测试多个特性。

敏捷软件开发过程的优势

让我们看一下敏捷软件开发过程的一些优势:

  • 功能可以迅速开发和演示:在敏捷过程中,软件项目被划分为特性,并且每个特性被称为一个待办事项。其想法是从概念化到部署,一周或一个月内开发单个或一组特性。这至少让客户有一个或两个特性可以使用。

  • 资源需求较少:在敏捷中,没有单独的开发和测试团队。也没有构建或发布团队,或者部署团队。在敏捷中,一个项目团队包含约八名成员。团队的每个成员都能做所有事情。

  • 促进团队合作和交叉培训:由于团队规模小约为八名成员,团队成员轮流担任角色,并从彼此的经验中学习。

  • 适用于需求经常变化的项目:在软件开发的敏捷模型中,整个软件被分割成特性,每个特性在短时间内开发和交付。因此,更改特性,甚至完全放弃它,都不会影响整个项目。

  • 极简主义文档:这种方法主要专注于快速交付可工作的软件,而不是创建庞大的文档。文档存在,但仅限于整体功能。

  • 几乎不需要计划:由于功能在短时间内依次开发,因此无需进行广泛的规划。

  • 并行开发:迭代由一个或多个功能依次开发,甚至是并行开发。

Scrum 框架

Scrum 是一个基于敏捷软件开发流程的开发和维护复杂产品的框架。它不仅仅是一个过程;它是一个具有特定角色、任务和团队的框架。Scrum 由肯·施瓦伯杰夫·萨瑟兰编写;他们一起创作了Scrum 指南

在 Scrum 框架中,开发团队决定如何开发一个功能。这是因为团队最了解他们所面临的问题。我假设大多数读者在阅读完这篇文章后都会感到满意。

Scrum 依赖于一个自组织和跨职能的团队。Scrum 团队是自组织的;因此,没有总体团队领导者决定哪个人将做哪个任务,或者如何解决问题。

Scrum 框架中使用的重要术语

以下是 Scrum 框架中使用的重要术语:

  • 冲刺:冲刺是在其中创建一个可用且可能可发布的产品的时间段。一个新的冲刺在上一个冲刺结束后立即开始。冲刺的持续时间可能介于两周到一个月之间,具体取决于对 Scrum 的命令。

  • 产品待办列表:产品待办列表是软件解决方案中所有必需功能的列表。该列表是动态的。也就是说,客户或团队成员时不时地向产品待办列表中添加或删除项目。

  • 冲刺待办列表:冲刺待办列表是为冲刺选择的产品待办列表项目集合。

  • 增量:增量是在冲刺期间完成的所有产品待办列表项目以及所有先前冲刺的增量价值的总和。

  • 开发团队:开发团队负责在每个冲刺结束时交付一个可发布的功能集合,称为增量。只有开发团队的成员创建增量。开发团队由组织授权组织和管理他们的工作。由此产生的协同作用优化了开发团队的整体效率和效果。

  • 产品负责人:产品负责人是 Scrum 团队与所有其他人之间的中介。他是 Scrum 团队的前台,并与客户、基础架构团队、管理团队以及所有参与 Scrum 的人等进行交互。

  • Scrum 主管:Scrum 主管负责确保人们了解并执行 Scrum。Scrum 主管通过确保 Scrum 团队遵循 Scrum 理论、实践和规则来做到这一点。

Scrum 如何工作?

产品负责人,Scrum Master 和 Scrum 团队共同遵循一套严格的程序来交付软件功能。以下图表解释了 Scrum 开发过程:

Scrum 方法论

让我们看看团队经历的 Scrum 软件开发过程的一些重要方面。

冲刺计划

冲刺计划是 Scrum 团队规划当前冲刺周期功能的机会。计划主要由开发人员创建。一旦计划创建完成,它会向 Scrum Master 和 Product Owner 解释。冲刺计划是一个时间框定的活动,通常在一个月的冲刺周期中总共约八小时。确保每个人都参与冲刺计划活动是 Scrum Master 的责任。

在会议中,开发团队考虑以下项目:

  • 要处理的产品待办事项数量(包括上一个冲刺的新事项和旧事项)。

  • 上一个冲刺中的团队表现。

  • 开发团队的预期容量。

冲刺周期

在冲刺周期内,开发人员只需完成冲刺计划中决定的待办事项。冲刺的持续时间可能会从两周到一个月不等,这取决于待办事项的数量。

每日 Scrum 会议

这是每天发生的事情。在 Scrum 会议期间,开发团队讨论昨天完成的工作,以及今天将要完成的工作。他们还讨论阻止他们实现目标的事情。开发团队除了 Scrum 会议外,不参加任何其他会议或讨论。

监控冲刺进展

每日 Scrum 是团队测量进展的好机会。Scrum 团队可以跟踪剩余的总工作量,通过这样做,他们可以估计实现冲刺目标的可能性。

冲刺计划

在冲刺回顾中,开发团队展示已完成的功能。Product Owner 更新到目前为止的产品待办事项状态。产品待办事项列表根据产品在市场上的表现或使用情况进行更新。冲刺回顾对于一个月的冲刺来说是一个总共四小时的活动。

冲刺回顾

在这次会议上,团队讨论了做得好的事情和需要改进的事情。然后,团队决定了要在即将到来的冲刺中改进的要点。这次会议通常在冲刺回顾之后,冲刺计划之前进行。

持续集成

持续集成(CI)是一种软件开发实践,开发人员经常将他们的工作与项目的集成分支相结合,并创建一个构建。

集成是将您的个人工作(修改后的代码)提交到公共工作区(潜在的软件解决方案)的行为。这在技术上通过将您的个人工作(个人分支)与公共工作区(集成分支)合并来完成。或者我们可以说,将您的个人分支推送到远程分支。

持续集成是为了尽早发现集成过程中遇到的问题。可以从下图中理解这一点,该图描述了单个持续集成周期中遇到的各种问题。

构建失败可能是由于不正确的代码或在构建过程中出现人为错误(假设任务是手动完成的)而导致的。如果开发人员不经常将他们的本地代码副本与集成分支上的代码重新基准,则可能会出现集成问题。如果代码未通过任何单元测试或集成测试用例,则可能会出现测试问题。

在出现问题时,开发人员必须修改代码以修复它:

图片

持续集成过程

敏捷运行在持续集成上

敏捷软件开发过程主要关注快速交付,持续集成帮助敏捷实现了这一速度。但是持续集成是如何做到的呢?让我们通过一个简单的案例来理解。

开发一个功能涉及到许多代码更改,在每次代码更改之间,有一系列任务要执行,比如检入代码,轮询版本控制系统以查看更改,构建代码,单元测试,集成,基于集成代码构建,集成测试和打包。在持续集成环境中,使用诸如Jenkins之类的持续集成工具可以使所有这些步骤变得快速且无错误。

添加通知可以使事情变得更快。团队成员越早意识到构建、集成或部署失败,他们就能越快采取行动。下图描述了持续集成过程中涉及的所有步骤:

图片

带通知的持续集成过程

团队通过这种方式快速从一个功能转移到另一个功能。简单地说,敏捷软件开发的敏捷性很大程度上是由持续集成所致。

从持续集成中受益的项目类型

汽车内嵌系统中编写的代码量比战斗机内嵌系统中的代码量更多。在今天的世界中,嵌入式软件存在于每一种产品中,无论是现代产品还是传统产品。无论是汽车、电视、冰箱、手表还是自行车,所有产品都有多少与软件相关的功能。消费品每天都在变得更加智能。如今,我们可以看到一个产品更多地通过其智能和智能功能来进行市场推广,而不是其硬件功能。例如,空调通过其无线控制功能进行市场推广,电视则通过其智能功能(如嵌入式网页浏览器等)进行市场推广,等等。

推广新产品的需求增加了产品的复杂性。软件复杂性的增加使得敏捷软件开发和 CI 方法学备受关注,尽管过去有时敏捷软件开发仅被 30-40 人的小团队用于简单项目。几乎所有类型的项目都受益于 CI:主要是基于 Web 的项目,例如电子商务网站和手机应用程序。

CI 和敏捷方法论在基于 Java、.NET、Ruby on Rails 和今天存在的每一种编程语言的项目中都被使用。唯一不使用它的地方是在传统系统中。然而,它们甚至也在转向敏捷。基于 SAS、主机的项目;都在尝试从 CI 中受益。

CI 的元素

让我们看看 CI 过程的重要元素。

版本控制系统

这是实现 CI 的最基本和最重要的要求。版本控制系统,有时也称为修订控制系统,是管理代码历史记录的工具。它可以是集中式的或分布式的。一些著名的集中式版本控制系统包括 SVN 和 IBM Rational ClearCase。在分布式部分,我们有像 Git 和 Mercurial 这样的工具。

理想情况下,构建软件所需的一切都必须进行版本控制。版本控制工具提供许多功能,如标记、分支等。

分支策略

使用版本控制系统时,应将分支保持在最低限度。一些公司只有一个主分支,所有的开发活动都在这个分支上进行。然而,大多数公司都遵循一些分支策略。这是因为总会有一部分团队可能在一个发布版上工作,而另一部分团队可能在另一个发布版上工作。有时,需要支持旧版本的发布。这些情况总是导致公司使用多个分支。

GitFlow 是另一种使用多个分支管理代码的方式。在以下方法中,Master/Production 分支保持清洁,仅包含可发布、准备好发货的代码。所有的开发都在 Feature 分支上进行,Integration 分支作为一个公共集成所有功能的地方。以下图示是 GitFlow 的一个中等版本:

分支策略

GitFlow 分支模型

以下图示说明了完整版本的 GitFlow。我们有一个包含仅生产就绪代码的 Master/Production 分支。功能分支是所有开发都发生的地方。集成分支是代码集成和测试质量的地方。除此之外,我们还有从集成分支拉出的发布分支,只要有稳定版本发布,就会有与发布相关的所有错误修复。还有一个热修复分支,只要有必要进行热修复,就会从 Master/Production 分支拉出来:

GitFlow 分支策略

CI 工具

什么是 CI 工具?嗯,它不过是一个协调者。CI 工具位于 CI 系统的中心,连接到版本控制系统、构建工具、二进制存储库管理工具、测试和生产环境、质量分析工具、测试自动化工具等等。有许多 CI 工具:Build Forge、Bamboo 和 TeamCity 等等。但我们书中的重点是 Jenkins:

集中式 CI 服务器

CI 工具提供了创建流水线的选项。每个流水线都有其自身的目的。有一些流水线负责 CI。有些负责测试;有些负责部署等等。技术上,流水线是作业的流动。每个作业是一组按顺序运行的任务。脚本编写是 CI 工具的一个组成部分,它执行各种类型的任务。这些任务可能是简单的,比如从一个位置复制文件/文件夹到另一个位置,或者它们可能是复杂的 Perl 脚本,用于监视文件修改的机器。尽管如此,随着 Jenkins 中可用插件数量的增加,脚本正在被替换。现在,你不需要脚本来构建 Java 代码;有相应的插件可用。你所需要做的就是安装和配置一个插件来完成工作。技术上,插件只是用 Java 编写的小模块。它们减轻了开发人员的脚本编写负担。我们将在后续章节中更多地了解流水线。

自触发构建

接下来要理解的重要事情是自触发自动化构建。构建自动化只是一系列自动化步骤,用于编译代码和生成可执行文件。构建自动化可以借助构建工具如 Ant 和 Maven。自触发自动化构建是 CI 系统中最重要的部分。有两个主要因素需要自动化构建机制:

  • 速度。

  • 尽早捕获集成或代码问题。

有些项目每天会有 100 到 200 次构建。在这种情况下,速度是一个重要因素。如果构建是自动化的,那么可以节省很多时间。如果构建的触发是自动驱动的,而不需要任何手动干预,事情就变得更有趣了。在每次代码更改时自动触发构建进一步节省时间。

当构建频繁且快速时,SDLC 框架中发现错误(构建错误、编译错误或集成错误)的概率更高且更快:

错误概率与构建图

代码覆盖

代码覆盖是您的测试用例覆盖的代码量(以百分比表示)。您在覆盖报告中看到的度量标准可能更多或更少,如下表所定义:

覆盖类型 描述
Function 被调用的函数数量占定义的函数总数的比例
Statement 程序中实际调用的语句数占总数的比例
Branches 执行的控制结构的分支数
Condition 正在测试的布尔子表达式的数量,测试真值和假值
Line 正在测试的源代码行数占代码总行数的比例

代码覆盖类型

该覆盖率百分比通过将被测试项的数量除以找到的项的数量来计算。以下截图显示了来自 SonarQube 的代码覆盖报告:

SonarQube 上的代码覆盖报告

代码覆盖工具

根据您使用的语言,可能会发现几种创建覆盖报告的选项。以下是一些流行工具:

语言 工具
Java Atlassian Clover, Cobertura, JaCoCo
C#/.NET OpenCover, dotCover
C++ OpenCppCoverage, gcov
Python Coverage.py
Ruby SimpleCov

静态代码分析

静态代码分析,通常也称为白盒测试,是一种查找代码结构质量的软件测试形式。例如,它回答了代码的健壮性或可维护性如何。静态代码分析是在实际执行程序之前执行的。它与功能测试不同,功能测试着眼于软件的功能方面,并且是动态的。

静态代码分析是对软件内部结构的评估。例如,是否有一段重复使用的代码?代码中是否包含大量的注释行?代码有多复杂?使用用户定义的度量标准,生成了一个分析报告,显示了代码在可维护性方面的质量。它不质疑代码的功能。

一些静态代码分析工具,如 SonarQube,配备了仪表板,显示每次运行的各种指标和统计数据。通常作为 CI 的一部分,每次运行构建时都会触发静态代码分析。如前几节讨论的,静态代码分析也可以在开发人员尝试提交代码之前包含。因此,低质量的代码可以在最初阶段就被阻止。

他们支持许多语言,如 Java、C/C++、Objective-C、C#、PHP、Flex、Groovy、JavaScript、Python、PL/SQL、COBOL 等等。以下截图展示了使用 SonarQube 进行静态代码分析报告:

静态代码分析报告

静态代码分析报告

自动化测试

测试是 SDLC 的重要组成部分。为了保持软件质量,必须让软件解决方案通过各种测试场景。对测试的重视不足可能导致客户不满意和产品延迟。

由于测试是一项手动、耗时且重复的任务,自动化测试流程可以显着提高软件交付速度。然而,自动化测试流程要比自动化构建、发布和部署流程困难得多。通常需要大量工作来自动化项目中几乎所有使用的测试用例。这是一个随着时间逐渐成熟的活动。

因此,在开始自动化测试时,我们需要考虑一些因素。首先考虑那些价值高且易于自动化的测试用例。例如,在步骤相同的情况下自动化测试,尽管每次都使用不同的数据。此外,自动化测试涉及在各种平台上测试软件功能的测试。还要自动化测试涉及使用不同配置运行软件应用程序的测试。

以前,世界主要由桌面应用程序主导。自动化 GUI 系统的测试相当困难。这就需要脚本语言,其中手动鼠标和键盘输入被脚本化并执行以测试 GUI 应用程序。然而,如今,软件世界完全被基于 Web 和移动的应用程序主导,可以通过使用测试自动化工具的自动化方法轻松测试。

一旦代码构建、打包和部署完成,就应该自动运行测试来验证软件。传统上,遵循的流程是为 SIT、UAT、PT 和预生产环境准备环境。首先,发布通过 SIT,即系统集成测试。在这里,对集成代码进行测试,以检查其功能是否完全。如果集成测试通过,则代码将部署到下一个环境,即 UAT,在那里经过用户验收测试,最后可以部署到 PT,在那里经过性能测试。通过这种方式,测试得到了优先考虑。

并不总是可能自动化所有的测试。但是,思想是尽可能自动化所有可能的测试。前述的方法需要许多环境,以及在各种环境中进行更高数量的自动化部署。为了避免这种情况,我们可以采用另一种方法,在这种方法中,只有一个环境部署了构建,然后运行基本测试,然后手动触发长时间

二进制存储库工具

作为 SDLC 的一部分,源代码被持续地使用 CI 构建成二进制产物。因此,应该有一个地方来存储这些构建包以供以后使用。答案是,使用一个二进制存储库工具。但是什么是二进制存储库工具?

二进制存储库工具是用于二进制文件的版本控制系统。不要将其与前面讨论的版本控制系统混淆。前者负责对源代码进行版本控制,而后者负责二进制文件,例如.rar.war.exe.msi等文件。除了管理构建产物外,二进制存储库工具还可以管理构建所需的第三方二进制文件。例如,Maven 插件始终会下载构建代码所需的插件到一个文件夹中。与其一遍又一遍地下载插件,不如使用存储库工具管理:

存储库工具

从上面的说明中,您可以看到,一旦创建了一个构建并通过了所有的检查,构建产物就会被上传到二进制存储库工具中。从这里,开发人员和测试人员可以手动选择、部署和测试它们。或者,如果自动部署已经就位,那么构建产物将自动部署到相应的测试环境。那么,使用二进制存储库的优势是什么呢?

二进制存储库工具执行以下操作:

  • 每次生成构建产物时,都会存储在一个二进制存储库工具中。存储构建产物有许多优点。其中一个最重要的优点是,构建产物位于一个集中的位置,可以在需要时访问。

  • 它可以存储构建工具所需的第三方二进制插件、模块。因此,构建工具不需要每次运行构建时都下载插件。存储库工具连接到在线源并不断更新插件存储库。

  • 记录了什么、何时以及谁创建了一个构建包。

  • 它提供了类似于环境的分段,以更好地管理发布。这也有助于加速 CI 流程。

  • 在 CI 环境中,构建的频率太高,每个构建都会生成一个包。由于所有构建的包都在一个地方,开发人员可以自由选择在高级环境中推广什么,而不推广什么。

自动打包

有可能一个构建可能有许多组件。例如,让我们考虑一个具有.rar文件作为输出的构建。除此之外,它还有一些 Unix 配置文件、发布说明、一些可执行文件,以及一些数据库更改。所有这些不同的组件需要在一起。将许多组件创建为单个存档或单个媒体的任务称为打包。同样,这可以使用 CI 工具自动化,并节省大量时间。

使用 CI 的好处

以下是使用 CI 的一些好处。该列表简要概述,不全面。

摆脱长时间的集成

很少进行代码集成,正如在瀑布模型中所见,可能导致合并地狱。这是一个团队花费数周解决合并问题的情况。

与此相反,将特性分支上的每个提交与集成分支进行集成,并对其进行问题测试(CI),允许您尽早发现集成问题。

指标

Jenkins、SonarQube、Artifactory 和 GitHub 等工具可以让您在一段时间内生成趋势。所有这些趋势都可以帮助项目经理和团队确保项目朝着正确的方向和正确的步伐发展。

更快地发现问题

这是仔细实施 CI 系统的最重要优势。任何集成问题或合并问题都会被及早发现。CI 系统有能力在构建失败时立即发送通知。

快速开发

从技术角度来看,CI 有助于团队更高效地工作。使用 CI 的项目在构建、测试和集成其代码时采用自动和持续的方法。这导致开发速度更快。

开发人员花费更多时间开发他们的代码,零时间构建、打包、集成和部署它,因为一切都是自动化的。这也有助于地理上分布的团队共同工作。有了良好的软件配置管理流程,人们可以在广泛分布的团队上工作。

花更多时间添加功能

在过去,构建和发布活动由开发人员负责,与常规开发工作一起进行。随后出现了一个趋势,即有专门的团队负责构建、发布和部署活动。而且事情并没有止步于此;这种新模式遭遇了开发人员、发布工程师和测试人员之间的沟通问题和协调不足。然而,使用 CI,所有构建、发布和部署工作都得到了自动化。因此,开发团队无需担心其他任何事情,只需开发功能即可。在大多数情况下,甚至连完整测试都是自动化的。因此,通过使用 CI 流程,开发团队可以花更多时间开发代码。

摘要

“每个成功的敏捷项目背后都有一个持续集成的过程。”

在本章中,我们粗略地了解了软件工程流程的历史。我们学习了持续集成(CI)及其组成要素。

本章讨论的各种概念和术语构成了后续章节的基础。没有这些,接下来的章节只是技术知识。

在下一章中,我们将学习如何在各种平台上安装 Jenkins。

安装 Jenkins

本章讲述了如何在各种平台上安装 Jenkins 等内容。完成本章后,您应该能够做到以下几点:

  • 在 Servlet 容器(Apache Tomcat)上运行 Jenkins

  • 在 Windows/Ubuntu/Red Hat Linux/Fedora 上以独立应用程序的形式运行 Jenkins

  • 在反向代理服务器(Nginx)后运行 Jenkins

  • 使用 Docker 运行 Jenkins

  • 利用 Docker 数据卷的优势

  • 使用 Docker 运行 Jenkins 的开发、分段和生产实例

在 Servlet 容器内运行 Jenkins

Jenkins 可用于以下 Servlet 容器:

  • Apache Geronimo 3.0

  • GlassFish

  • IBM WebSphere

  • JBoss

  • Jetty

  • Jonas

  • Liberty profile

  • Tomcat

  • WebLogic

在本节中,您将学习如何在 Apache Tomcat 服务器上安装 Jenkins。在 Apache Tomcat 上将 Jenkins 安装为服务相当简单。您可以选择将 Jenkins 与 Apache Tomcat 服务器上已有的其他服务一起运行,或者您可以仅使用 Apache Tomcat 服务器来运行 Jenkins。

先决条件

在开始之前,请确保您准备好以下事项:

  • 您需要一台至少拥有 4GB 内存和多核处理器的系统。

  • 根据团队中的基础设施管理方式,机器可以是云平台的实例(例如 AWS、DigitalOcean 或任何其他云平台)、裸金属机器,或者它可以是一个虚拟机(在 VMware vSphere 或任何其他服务器虚拟化软件上)。

  • 机器应该安装有 Ubuntu 16.04。选择一个 LTS 版本。

  • 检查管理员权限;安装可能会要求管理员用户名和密码。

安装 Java

按照以下步骤在 Ubuntu 上安装 Java:

  1. 更新软件包索引:
 sudo apt-get update
  1. 接下来,安装 Java。执行以下命令将安装Java Runtime EnvironmentJRE):
 sudo apt-get install default-jre 
  1. 要设置JAVA_HOME环境变量,请获取 Java 安装位置。通过执行以下命令来执行此操作:
 update-java-alternatives -l
  1. 上一个命令将打印在您的机器上安装的 Java 应用程序列表以及它们的安装路径。复制在终端上出现的 Java 路径:
 java-1.8.0-openjdk-amd64  1081
        /usr/lib/jvm/java-1.8.0-openjdk-amd64
  1. 使用以下命令编辑/etc/environment文件:
 sudo nano /etc/environment 
  1. /etc/environment文件中以以下格式添加 Java 路径(您之前复制的路径):
        JAVA_HOME="/usr/lib/jvm/java-1.8.0-openjdk-amd64" 
  1. 输入Ctrl + X并选择Y以保存并关闭文件。

  2. 接下来,使用以下命令重新加载文件:

 sudo source /etc/environment

安装 Apache Tomcat

按照以下步骤下载并安装 Apache Tomcat 服务器到您的 Ubuntu 机器上:

  1. 移动到/tmp目录并使用wget命令下载 Tomcat 应用程序,如下所示:
 cd /tmp
       wget https://archive.apache.org/dist/tomcat/tomcat-8/ \
        v8.5.16/bin/apache-tomcat-8.5.16.tar.gz

要获取完整的 Apache Tomcat 版本列表,请访问:archive.apache.org/dist/tomcat/

  1. 使用以下命令创建一个名为/opt/tomcat的目录:
 sudo mkdir /opt/tomcat 
  1. /opt/tomcat内解压存档的内容:
 sudo tar xzvf apache-tomcat-8*tar.gz \
        -C /opt/tomcat --strip-components=1 
  1. 接下来,使用以下命令创建一个 systemd 服务文件:
 sudo nano /etc/systemd/system/tomcat.service
  1. 将以下内容粘贴到文件中:
        [Unit] 
        Description=Apache Tomcat Web Application Container 
        After=network.target 

        [Service] 
        Type=forking 

        Environment=JAVA_HOME=/usr/lib/jvm/java-1.8.0-openjdk-amd64                     
        Environment=CATALINA_PID=/opt/tomcat/temp/tomcat.pid 
        Environment=CATALINA_HOME=/opt/tomcat 
        Environment=CATALINA_BASE=/opt/tomcat 
        Environment='CATALINA_OPTS=-Xms512M -Xmx1024M
        -server -XX:+UseParallelGC' 
        Environment='JAVA_OPTS=-Djava.awt.headless=true
        -Djava.security.egd=file:/dev/./urandom' 

        ExecStart=/opt/tomcat/bin/startup.sh 
        ExecStop=/opt/tomcat/bin/shutdown.sh 

        RestartSec=10 
        Restart=always 

        [Install] 
        WantedBy=multi-user.target 
  1. 输入 Ctrl + X 并选择 Y 保存并关闭文件。

  2. 接下来,使用以下命令重新加载 systemd 守护程序:

 sudo systemctl daemon-reload 
  1. 使用以下命令启动 Tomcat 服务:
 sudo systemctl start tomcat 
  1. 要检查 Tomcat 服务的状态,请运行以下命令:
 sudo systemctl status tomcat 
  1. 您应该看到以下输出:
 ● tomcat.service - Apache Tomcat Web Application Container 
          Loaded: loaded (/etc/systemd/system/tomcat.service; disabled;
          vendor preset: enabled) 
          Active: active (running) since Mon 2017-07-31 21:27:39 UTC;
          5s ago 
          Process: 6438 ExecStart=/opt/tomcat/bin/startup.sh (code=exited,
          status=0/SUCCESS) 
         Main PID: 6448 (java) 
            Tasks: 44 
           Memory: 132.2M 
              CPU: 2.013s 
           CGroup: /system.slice/tomcat.service 
                   └─6448 /usr/lib/jvm/java-1.8.0-openjdk-amd64/bin/java
       -Djava.util.logging.config.file=/opt/tomcat/conf/logging.properties
       -Djava.util.logging.manager=org.apache.juli.ClassLoaderLogMan 

启用防火墙和端口 8080

Apache Tomcat 运行在端口 8080 上。如果防火墙已禁用,请按照以下步骤启用防火墙:

  1. 使用以下命令启用防火墙:
 sudo ufw enable 
  1. 允许端口 8080 上的流量:
 sudo ufw allow 8080 
  1. 使用以下命令启用 OpenSSH 以允许 SSH 连接:
 sudo ufw enable "OpenSSH" 
  1. 使用以下命令检查防火墙状态:
 sudo ufw status 
  1. 您应该看到以下输出:
 Status: active  
        To                         Action      From 
        --                         ------      ---- 
        8080                       ALLOW       Anywhere 
        OpenSSH                    ALLOW       Anywhere 
        8080 (v6)                  ALLOW       Anywhere (v6) 
        OpenSSH (v6)               ALLOW       Anywhere (v6) 
  1. 现在,您应该能够访问 Apache Tomcat 服务器页面:http://<Apache Tomcat 的 IP 地址>:8080

配置 Apache Tomcat 服务器

在本节中,我们将启用对 Tomcat 管理器应用程序和主机管理器的访问:

  1. 打开位于 /opt/tomcat/conf 目录内的 tomcat-users.xml 文件进行编辑:
 sudo nano /opt/tomcat/conf/tomcat-users.xml 
  1. 文件将看起来像下面这样,为简单起见,我忽略了文件内的注释:
        <?xml version="1.0" encoding="UTF-8"?> 
        . . . 
        <tomcat-users  

        xsi:schemaLocation="http://tomcat.apache.org/xml tomcat-users.xsd" 
        version="1.0"> 
        . . . 
          <!-- 
            <role rolename="tomcat"/> 
            <role rolename="role1"/> 
            <user username="tomcat" password="<must-be-changed>"
             roles="tomcat"/> 
            <user username="both" password="<must-be-changed>"
             roles="tomcat,role1"/> 
            <user username="role1" password="<must-be-changed>"
             roles="role1"/> 
          --> 
        </tomcat-users> 
  1. 从前一个文件中,您可以看到 roleuser 字段被注释了。我们需要启用一个角色和一个用户来允许访问 Tomcat 管理器应用程序页面:
        <role rolename="manager-gui"/> 
        <role rolename="admin-gui"/> 
        <user username="admin" password="password"
         roles="manager-gui,admin-gui"/>
  1. 最后,文件应如下所示(已移除注释):
        <?xml version="1.0" encoding="UTF-8"?>  
        <tomcat-users  

        xsi:schemaLocation="http://tomcat.apache.org/xml tomcat-users.xsd" 
        version="1.0"> 
          <role rolename="manager-gui"/> 
          <role rolename="admin-gui"/> 
          <user username="admin" password="password"
           roles="manager-gui,admin-gui"/> 
        </tomcat-users> 
  1. 输入 Ctrl + X 并选择 Y 保存并关闭文件。

  2. 默认情况下,您只能从 Apache Tomcat 服务器内访问 Manager 和 Host Manager 应用程序。由于我们将从远程机器管理在 Apache 上运行的服务,因此需要删除这些限制。

  3. 打开以下两个文件,/opt/tomcat/webapps/manager/META-INF/context.xml/opt/tomcat/webapps/host-manager/META-INF/context.xml

  4. 在这些文件中,取消注释以下部分:

        <Context antiResourceLocking="false" privileged="true" > 
          <!--<Valve className="org.apache.catalina.valves.RemoteAddrValve" 
          allow="127\.\d+\.\d+\.\d+|::1|0:0:0:0:0:0:0:1" />--> 
          <Manager sessionAttributeValueClassNameFilter="java\.lang\
          .(?:Boolean|Integer|Long|Number|String)|org\.apache\.catalina\
          .filters\.CsrfPreventionFilter\$LruCache(?:\$1)?|java\.util\
          .(?:Linked)$ 
        </Context> 
  1. 输入 Ctrl + X 并选择 Y 保存并关闭文件。

  2. 使用以下命令重新启动 Tomcat 服务器:

 sudo systemctl restart tomcat 
  1. 尝试从 Apache Tomcat 服务器主页访问管理器应用程序和主机管理器。

在 Apache Tomcat 服务器上安装 Jenkins

如果您不希望为 Jenkins 主服务器拥有独立的服务器,并希望将其与存在于 Apache Tomcat 服务器上的其他服务一起托管,可以执行以下步骤:

  1. 切换到 /tmp 目录,并使用 wget 命令下载 Jenkins 应用程序,如下所示:
 cd /tmp
        wget http://mirrors.jenkins.io/war-stable/latest/jenkins.war 
  1. 前一个命令将下载最新稳定版本的 jenkins.war 文件。

  2. 将文件从 /tmp 移动到 /opt/tomcat/

 sudo mv jenkins.war /opt/tomcat/webapps/ 
  1. 列出 /opt/tomcat/webapps/ 目录的内容:
 sudo ls -l /opt/tomcat/webapps 

您应该看到以下输出:

 total 68984 
        -rw-rw-r--  1 ubuntu ubuntu 70613578 Jul 19 22:37 jenkins.war 
        drwxr-x---  3 root   root       4096 Jul 31 21:09 ROOT 
        drwxr-x--- 14 root   root       4096 Jul 31 21:09 docs 
        drwxr-x---  6 root   root       4096 Jul 31 21:09 examples 
        drwxr-x---  5 root   root       4096 Jul 31 21:09 manager 
        drwxr-x---  5 root   root       4096 Jul 31 21:09 host-manager 
        drwxr-x--- 10 root   root       4096 Jul 31 22:52 jenkins 

注意,将 jenkins.war 包移动到 webapps 文件夹时,会自动创建一个 jenkins 文件夹。这是因为 .war 文件是一个 Web 应用程序存档文件,一旦部署到 webapps 目录中就会自动解压缩。我们所做的是一个小型的部署活动。

  1. 就是这样了。你可以使用http://<Tomcat 服务器的 IP 地址>:8080/jenkins访问 Jenkins。

仅在 Apache Tomcat 服务器上安装 Jenkins

如果你选择为 Jenkins 使用单独的 Apache Tomcat 服务器,请按照以下步骤操作:

  1. 切换到/tmp目录并使用wget命令下载 Jenkins 应用程序,如下所示:
 cd /tmp 
 wget http://mirrors.jenkins.io/war-stable/latest/jenkins.war 
  1. 将下载的jenkins.war包重命名为ROOT.war
 sudo mv jenkins.war ROOT.war 
  1. 接下来,通过切换到root用户删除/opt/tomcat/webapps目录中的所有内容:
 sudo su - 
 cd /opt/tomcat/webapps 
 sudo rm -r * 
  1. 现在将ROOT.war(重命名)从/tmp目录移动到/opt/tomcat/webapps文件夹:
 sudo mv /tmp/ROOT.war /opt/tomcat/webapps/ 
  1. 列出/opt/tomcat/webapps目录的内容,你会注意到自动创建了一个ROOT文件夹:
 total 68964 
        drwxr-x--- 10 root   root       4096 Jul 31 23:10 ROOT 
        -rw-rw-r--  1 ubuntu ubuntu 70613578 Jul 19 22:37 ROOT.war 

始终建议专门为 Jenkins 配置一个专用的 Web 服务器。

  1. 你可以通过http://<Tomcat 服务器的 IP 地址>:8080/访问 Jenkins,不需要任何额外路径。显然,Apache 服务器现在是一个 Jenkins 服务器。

删除/opt/tomcat/webapps目录下的所有内容(保留ROOT目录和ROOT.war),然后将jenkins.war文件移动到webapps文件夹,这样就足以将 Apache Tomcat 服务器单独用于 Jenkins。

jenkins.war重命名为ROOT.war的步骤仅在你想要使http://<Tomcat 服务器的 IP 地址>:8080/成为 Jenkins 的标准 URL 时才有必要。

设置 Jenkins 主目录路径

在开始使用 Jenkins 之前,有一件重要的事情要配置,即jenkins_home路径。当你在 Tomcat 上安装 Jenkins 作为服务时,jenkins_home路径将自动设置为/root/.jenkins/。这是所有 Jenkins 配置、日志和构建存储的位置。你在 Jenkins 仪表板上创建和配置的所有内容都存储在这里。

我们需要使其更易访问,比如/var/jenkins_home。可以按照以下方式实现:

  1. 使用以下命令停止 Apache Tomcat 服务器:
 sudo systemctl stop tomcat 
  1. 打开/opt/tomcat/conf中的context.xml文件进行编辑:
 sudo nano /opt/tomcat/conf/context.xml 
  1. 文件看起来是这样的(注释已删除):
        <?xml version="1.0" encoding="UTF-8"?> 
        <Context> 
          <WatchedResource>WEB-INF/web.xml</WatchedResource> 
          <WatchedResource>${catalina.base}/conf/web.xml</WatchedResource> 
        </Context>
  1. <Context> </Context>之间添加以下行:
        <Environment name="JENKINS_HOME" value="/var/jenkins_home" 
        type="java.lang.String"/> 
  1. 使用以下命令启动 Tomcat 服务:
 sudo systemctl start tomcat 

在 Windows 上安装独立的 Jenkins 服务器

在 Windows 上安装 Jenkins 非常简单。在执行在 Windows 上安装 Jenkins 的步骤之前,让我们先看看先决条件。

先决条件

在开始之前,请确保您已准备好以下事项:

  • 我们需要一台至少具有 4 GB RAM 和多核处理器的机器。

  • 根据团队中对基础设施的管理方式,该机器可以是云平台上的一个实例(如 AWS、DigitalOcean 或任何其他云平台)、裸金属机器,或者是一个 VM(在 VMware vSphere 或其他服务器虚拟化软件上)。

  • 机器上需要安装最新的任一 Windows 操作系统(Windows 7/8/10,Windows Server 2012/2012 R2/2016)。

  • 检查管理员权限;安装可能会要求管理员用户名和密码。

  • 确保端口8080处于开放状态。

安装 Java

按照以下步骤安装 Java:

  1. java.com/en/download/manual.jsp下载最新版本的 Java JRE(根据您的操作系统选择 x86 或 x64)。

  2. 按照安装步骤操作。

  3. 要检查 Java 是否成功安装,请使用命令提示符运行以下命令:

 java -version 
  1. 您应该获得以下输出:
 java version "1.8.0_121" 
        Java(TM) SE Runtime Environment (build 1.8.0_121-b13) 
        Java HotSpot(TM) 64-Bit Server VM (build 25.121-b13, mixed mode) 
  1. 要设置JAVA_HOME,首先使用以下命令获取 Windows 上的 Java 安装路径:
 where java 
  1. 上一个命令应输出 Java 安装路径,如下所示。复制路径但不包括\bin\java
 C:\Program Files\Java\jdk1.8.0_121\bin\java 
  1. 以管理员身份打开命令提示符,并运行以下命令以设置JAVA_HOME路径。确保使用屏幕上显示的 Java 安装路径:
 setx -m JAVA_HOME "C:\Program Files\Java\jdk1.8.121" 

安装最新稳定版本的 Jenkins

要安装最新稳定版本的 Jenkins,请按照以下步骤顺序执行:

  1. 在 Jenkins 官方网站jenkins.io/download/上下载最新稳定的 Jenkins 软件包。要安装最新稳定版本的 Jenkins,请下载长期支持LTS)版本。如果只想要最新版本的 Jenkins,则选择周更版。

  2. 解压下载的软件包,您将找到一个jenkins.msi文件。

  3. 运行jenkins.msi并按照安装步骤操作。

  4. 在安装过程中,您将有选择 Jenkins 安装目录的选项。默认情况下,它将是C:\Program Files\JenkinsC:\Program Files (x86)\Jenkins。保持默认设置,然后单击下一步按钮。

  5. 单击完成按钮完成安装。

在 Windows 上启动、停止和重启 Jenkins

Jenkins 默认在安装时开始运行。在本节中,显示了启动、停止、重启和检查 Jenkins 服务状态的命令:

  1. 通过以下命令从命令提示符中打开服务窗口:
 services.msc 
  1. 寻找名为 Jenkins 的服务。

  2. 再次右键单击 Jenkins 服务,然后单击属性

  3. 常规选项卡下,您可以看到 Jenkins 服务名称、可执行文件路径、服务状态和启动参数。

  4. 使用启动类型选项,您可以选择 Jenkins 在 Windows 机器上启动的方式。您可以选择自动、手动和自动(延迟启动)中的一种。确保它始终设置为自动。

  5. 在以下服务状态中,有手动启动停止暂停恢复Jenkins 服务的选项:

配置 Jenkins 服务的启动选项

  1. 转到下一个标签,即登录。在这里,我们通过 Jenkins 启动的用户名。

  2. 您可以选择使用本地系统帐户(不推荐),或者您可以创建一个具有特殊权限的特殊 Jenkins 用户(推荐):

对于 Jenkins,始终首选专用帐户。原因是 Local System 帐户 无法受控制;根据组织的政策,它可能会被删除或密码可能会过期,而 Jenkins 用户帐户可以设置为首选策略和特权。

图片

配置 Jenkins 服务的登录选项

  1. 下一个选项卡是 Recovery。在这里,我们可以指定 Jenkins 服务启动失败时的操作项目。

  2. 这里有一个例子。在第一次失败时,尝试重新启动 Jenkins,在第二次失败时,尝试重新启动计算机。最后,在随后的失败中,运行一个程序来调试问题,或者我们可以运行一个脚本,将 Jenkins 失败日志通过电子邮件发送给相应的 Jenkins 管理员进行调查:

图片

配置 Jenkins 服务的恢复选项

在 Ubuntu 上安装独立的 Jenkins 服务器

在 Ubuntu 上安装 Jenkins 服务器相当容易。在执行在 Ubuntu 上安装 Jenkins 的步骤之前,让我们先看看先决条件。

先决条件

在开始之前,请确保您准备好了以下事项:

  • 我们需要一台至少有 4GB RAM 和多核处理器的机器。

  • 根据您团队中如何管理基础设施,该机器可以是云平台上的实例(如 AWS、DigitalOcean 或任何其他云平台)、裸金属机器,或者它可以是一个 VM(在 VMware vSphere 或任何其他服务器虚拟化软件上)。

  • 机器应该安装了 Ubuntu 16.04。选择一个 LTS 发行版本。

  • 检查管理员特权;安装可能会要求输入管理员用户名和密码。

  • 确保端口8080是开放的。

安装 Java

按照以下步骤安装 Java:

  1. 使用以下命令更新软件包索引:
 sudo apt-get update 
  1. 接下来,安装 Java。以下命令将安装 JRE:
 sudo apt-get install default-jre 
  1. 要设置JAVA_HOME环境变量,请首先获取 Java 安装位置。通过执行以下命令来执行此操作:
 update-java-alternatives -l  
  1. 上一个命令将打印出安装在您机器上的 Java 应用程序列表,以及它们的安装路径。复制出现在您的终端上的 Java 路径:
 java-1.8.0-openjdk-amd64 1081
        /usr/lib/jvm/java-1.8.0-openjdk-amd64
  1. 使用以下命令打开/etc/environment文件进行编辑:
 sudo nano /etc/environment 
  1. 将 Java 路径(您之前复制的路径)以以下格式添加到/etc/environment文件中:
        JAVA_HOME="/usr/lib/jvm/java-1.8.0-openjdk-amd64" 
  1. 键入 Ctrl + X 并选择 Y 保存并关闭文件。

  2. 接下来,使用以下命令重新加载文件:

        sudo source /etc/environment

安装 Jenkins 的最新版本

要安装 Jenkins 的最新版本,请按照以下顺序执行以下步骤:

  1. 使用以下命令将存储库密钥添加到系统中:
 wget --no-check-certificate -q -O \
        - https://pkg.jenkins.io/debian/jenkins-ci.org.key | \
 sudo apt-key add - 
  1. 你应该获得一个OK的输出。接下来,使用以下命令添加 Debian 软件包存储库地址:
 echo deb http://pkg.jenkins.io/debian binary/ | \
        sudo tee /etc/apt/sources.list.d/jenkins.list 
  1. 更新软件包索引:
 sudo apt-get update 
  1. 现在,使用以下命令安装 Jenkins:
 sudo apt-get install jenkins 
  1. 如果需要启动 Jenkins,请参阅 在 Ubuntu 上启动、停止和重新启动 Jenkins 部分。

  2. Jenkins 现在已经准备好使用了。默认情况下,Jenkins 服务在端口 8080 上运行。要访问 Jenkins,请在浏览器中使用 http://localhost:8080/http://<Jenkins 服务器 IP 地址>:8080/

安装最新稳定版本的 Jenkins

如果您希望安装 Jenkins 的稳定版本,请按顺序执行以下步骤:

  1. 使用以下命令将存储库密钥添加到系统中:
 wget --no-check-certificate -q -O - \
        https://pkg.jenkins.io/debian-stable/jenkins-ci.org.key | \
        sudo apt-key add - 
  1. 您应该得到一个 OK 的输出。接下来,使用以下命令附加 Debian 软件包存储库地址:
 echo deb http://pkg.jenkins.io/debian-stable binary/ | \
        sudo tee /etc/apt/sources.list.d/jenkins.list 
  1. 更新软件包索引:
 sudo apt-get update
  1. 现在,使用以下命令安装 Jenkins:
 sudo apt-get install jenkins 
  1. 如果需要启动 Jenkins,请参阅 在 Ubuntu 上启动、停止和重新启动 Jenkins 部分。

  2. Jenkins 现在已经准备好使用了。默认情况下,Jenkins 服务在端口 8080 上运行。要访问 Jenkins,请在浏览器中使用 http://localhost:8080/http://<Jenkins 服务器 IP 地址>:8080/

为了排除 Jenkins 故障,访问日志文件 /var/log/jenkins/jenkins.log

Jenkins 服务以用户 Jenkins 运行,该用户在安装时自动创建。

在 Ubuntu 上启动、停止和重新启动 Jenkins

Jenkins 默认在安装时开始运行。以下是启动、停止、重新启动和检查 Jenkins 服务状态的命令:

  1. 要启动 Jenkins,请使用以下命令:
 sudo systemctl start jenkins 
  1. 类似地,要停止 Jenkins,请使用以下命令:
 sudo systemctl stop jenkins 
  1. 要重新启动 Jenkins,请使用以下命令:
 sudo systemctl restart jenkins 
  1. 要检查 Jenkins 服务的状态,请使用以下 systemctl 命令:
 sudo systemctl status jenkins 
  1. 您应该看到以下输出:
 ● jenkins.service - LSB: Start Jenkins at boot time 
        Loaded: loaded (/etc/init.d/jenkins; bad; vendor preset: enabled) 
        Active: active (exited) since Wed 2017-07-19 22:34:39 UTC; 6min ago 
        Docs: man:systemd-sysv-generator(8) 

在 Red Hat Linux 上安装独立的 Jenkins 服务器

在本节中,我们将学习在 Red Hat Linux 上安装 Jenkins。这里讨论的安装过程也适用于 Fedora。

先决条件

在开始之前,请确保您准备好以下事项:

  • 我们需要一台至少拥有 4 GB RAM 和多核处理器的机器。

  • 根据您团队中如何管理基础架构,该机器可能是云平台的实例(例如 AWS、DigitalOcean 或任何其他云平台)、裸机、也可能是 VM(在 VMware vSphere 或任何其他服务器虚拟化软件上)。

  • 机器应该安装了 RHEL 7.3。

  • 检查管理员权限;安装可能会要求输入管理员用户名和密码。

  • 确保端口 8080 是开放的。

安装 Java

按照以下步骤安装 Java:

  1. 移动到 /tmp 目录并下载 Java:
 cd /tmp 
 wget -O java_8.131.rpm \
        http://javadl.oracle.com/webapps/download/AutoDL? \
        BundleId=220304_d54c1d3a095b4ff2b6607d096fa80163 
  1. 接下来,安装 Java。以下命令将安装 JRE:
 sudo rpm -ivh java_8.131.rpm 
  1. 要设置 JAVA_HOME 环境变量,请首先获取 Java 安装位置。通过执行以下命令来执行此操作:
 sudo alternatives --config java 
  1. 上一个命令将打印出在您的机器上安装的 Java 应用程序列表,以及它们的安装路径。复制在您的终端上出现的 Java 路径:
 There is 1 program that provides 'java'. 
        Selection    Command 
        ----------------------------------------------- 
        *+ 1           /usr/java/jre1.8.0_131/bin/java
  1. 使用以下命令将 Java 路径(先前复制的路径)添加到 /etc/environment 文件内:
 sudo sh \
        -c "echo JAVA_HOME=/usr/java/jre1.8.0_131 >>
        /etc/environment" 

安装最新版本的 Jenkins

要安装最新版本的 Jenkins,请按照以下步骤进行:

  1. 使用以下命令将 Jenkins 仓库添加到 yum 仓库内:
 sudo wget -O /etc/yum.repos.d/jenkins.repo \
         http://pkg.jenkins-ci.org/redhat/jenkins.repo 
        sudo rpm --import https://jenkins-ci.org/redhat/jenkins-ci.org.key
  1. 使用以下命令安装 Jenkins:
 sudo yum install jenkins 
  1. 如果需要启动 Jenkins,请查看 在 Red Hat Linux 上启动、停止和重启 Jenkins 部分。

Jenkins 现在已准备就绪。默认情况下,Jenkins 服务运行在端口 8080 上。要访问 Jenkins,请在浏览器中使用  http://localhost:8080/http://<Jenkins 服务器 IP 地址>:8080/ 。

安装最新稳定版本的 Jenkins

如果您更喜欢安装 Jenkins 的稳定版本,请按照以下步骤操作:

  1. 使用以下命令将 Jenkins 仓库添加到 yum 仓库内:
 sudo wget -O /etc/yum.repos.d/jenkins.repo \
         http://pkg.jenkins-ci.org/redhat-stable/jenkins.repo 
 sudo rpm --import https://jenkins-ci.org/redhat/jenkins-ci.org.key 
  1. 使用以下命令安装 Jenkins:
 sudo yum install jenkins
  1. 如果需要启动 Jenkins,请查看 在 Red Hat Linux 上启动、停止和重启 Jenkins 部分。

在 Red Hat Linux 上启动、停止和重启 Jenkins

这些是启动、停止、重启和检查 Jenkins 服务状态的命令:

  1. 要启动 Jenkins,请使用以下命令:
 sudo systemctl start jenkins 
  1. 同样,要停止 Jenkins,请使用以下命令:
 sudo systemctl stop jenkins 
  1. 要重启 Jenkins,请使用以下命令:
 sudo systemctl restart jenkins 
  1. 要检查 Jenkins 服务的状态,请使用以下 systemctl 命令:
 sudo systemctl status jenkins  
  1. 您应该看到以下输出:
        ● jenkins.service - LSB: Jenkins Automation Server 
          Loaded: loaded (/etc/rc.d/init.d/jenkins; bad;
          vendor preset: disabled) 
          Active: active (running) since Wed 2017-07-19 18:45:47 EDT;
           2min 31s ago 
             Docs: man:systemd-sysv-generator(8) 
          Process: 1081 ExecStart=/etc/rc.d/init.d/jenkins start
          (code=exited, status=0/SUCCESS) 
           CGroup: /system.slice/jenkins.service 
                   └─1706 /etc/alternatives/java
           -Dcom.sun.akuma.Daemon=daemonized -Djava.awt.headless=true
           -DJENKINS_HOME=/var/lib/j...

为了排除 Jenkins 问题,请访问 var/log/jenkins/jenkins.log 中的日志。

Jenkins 服务以 Jenkins 用户运行,该用户会在安装时自动创建。

在反向代理后运行 Jenkins

在这个例子中,我们将学习如何将一个 Nginx 服务器(在一个独立的机器上运行)放置在 Jenkins 服务器(在另一个独立的机器上运行)的前面。

先决条件

在开始之前,请确保您已准备好以下事项:

  • 我们需要两台至少配备 4GB 内存和多核处理器的机器。一台将运行 Nginx,另一台将运行 Jenkins。

  • 根据团队如何管理基础设施,该机器可以是云平台上的实例(例如 AWS、DigitalOcean 或任何其他云平台)、裸机服务器,或者它可以是一个 VM(在 VMware vSphere 或任何其他服务器虚拟化软件上)。

  • 机器应该安装了 Ubuntu 16.04 或更高版本。

  • 检查管理员权限;安装可能会要求管理员用户名和密码。

  • 两台机器应该在同一个网络上。以下设置假设您的组织有一个用于所有服务的内部网络。

安装和配置 Nginx

在 Ubuntu 上安装 Nginx 很简单。请按照以下步骤在 Ubuntu 上安装 Nginx 服务器:

  1. 更新本地软件包索引:
 sudo apt-get update
  1. 使用以下命令安装 nginx
 sudo apt-get install nginx 

配置 Nginx 服务器的防火墙

我们需要在我们的 Nginx 服务器上配置防火墙以允许访问 Nginx 服务。请按照以下步骤操作:

  1. 使用 ufw 命令检查防火墙状态:
 sudo ufw status 

应该看到以下输出:

 Status: inactive 
  1. 如果已启用,请转到 第三步。但是,如果发现它被禁用了,则使用以下命令启用防火墙:
 sudo ufw enable  

应该看到以下输出

        Command may disrupt existing ssh connections.
        Proceed with operation (y|n)? y 
        Firewall is active and enabled on system startup 
  1. 使用以下命令列出可用的配置。你应该看到三个 Nginx 配置文件和一个 OpenSSH 配置文件:
 sudo ufw app list  

应该看到以下输出

        Available applications: 
          Nginx Full 
          Nginx HTTP 
          Nginx HTTPS 
          OpenSSH

Nginx Full 配置文件打开 80 端口(未加密)和 443 端口(TLS/SSL)。

Nginx HTTP 配置文件仅打开 80 端口(未加密)。

Nginx HTTPS 配置文件仅打开 443 端口(TLS/SSL)。

OpenSSH 配置文件仅打开 22 端口(SSH)。

始终建议启用最严格的配置文件。

  1. 为了保持简单,我们将启用 Nginx Full 配置文件,如以下命令所示:
 sudo ufw allow 'Nginx Full'  
        Rules updated 
        Rules updated (v6) 
  1. 如果未激活,则启用 OpenSSH 配置文件,如所示。这将允许我们继续通过 SSH 访问我们的 Nginx 机器:
 sudo ufw allow 'OpenSSH' 

如果 OpenSSH 被禁用,你将无法登录到你的 Nginx 机器。

  1. 使用以下命令验证更改。你应该看到 Nginx FullOpenSSH 被允许:
 sudo ufw status  

应该看到以下输出:

        Status: active  
        To                         Action      From 
        --                         ------      ---- 
        OpenSSH                    ALLOW       Anywhere 
        Nginx Full                 ALLOW       Anywhere 
        OpenSSH (v6)               ALLOW       Anywhere (v6) 
        Nginx Full (v6)            ALLOW       Anywhere (v6)
  1. 使用 systemctl 命令检查 Nginx 服务是否正在运行:
 systemctl status nginx  

应该看到以下输出:

        ● nginx.service - A high performance web server and a reverse proxy
        server 
           Loaded: loaded (/lib/systemd/system/nginx.service; enabled;
           vendor preset: enabled) 
           Active: active (running) since Thu 2017-07-20 18:44:33 UTC;
        45min ago 
         Main PID: 2619 (nginx) 
            Tasks: 2 
           Memory: 5.1M 
              CPU: 13ms 
           CGroup: /system.slice/nginx.service 
                   ├─2619 nginx: master process /usr/sbin/nginx
           -g daemon on;                master_process on 
                   └─2622 nginx: worker process
  1. 从前面的输出中,你可以看到我们的 Nginx 服务正常运行。现在尝试使用浏览器访问它。首先,使用 ip route 命令获取你的机器的 IP 地址:
 ip route  

应该看到以下输出:

        default via 10.0.2.2 dev enp0s3
        10.0.2.0/24 dev enp0s3  proto kernel
        scope link src 10.0.2.15
        192.168.56.0/24 dev enp0s8  proto kernel  scope link
        src 192.168.56.104 
  1. 现在使用 http://<IP Address>:80 访问 Nginx 主页。你应该看到类似以下截图的内容:

Nginx 索引页面

启动、停止和重新启动 Nginx 服务器

现在我们的 Nginx 服务器已经启动了,让我们看看一些可以用来管理 Nginx 的命令。就像 Jenkins 一样,我们将使用 systemctl 命令来管理 Nginx:

  1. 要停止 Nginx,请使用以下命令:
 sudo systemctl stop nginx
  1. 要在停止时启动 Nginx,请使用以下命令:
 sudo systemctl start nginx 
  1. 要重新启动 Nginx,请使用以下命令:
 sudo systemctl restart nginx 
  1. 若要在进行配置更改后重新加载 Nginx,请使用以下命令:
 sudo systemctl reload nginx 

使用 OpenSSL 保护 Nginx

在本节中,我们将学习为我们的 Nginx 服务器设置自签名 SSL 证书。

创建 SSL 证书

运行以下命令使用 OpenSSL 创建自签名密钥和证书对:

sudo openssl req -x509 -nodes -days 365 -newkey rsa:2048 \
-keyout /etc/ssl/private/nginx-selfsigned.key -out \
/etc/ssl/certs/nginx-selfsigned.crt 

以下表格解释了前面命令中使用的参数:

参数 描述
req 此参数指示我们要使用 X.509 证书签名请求 (CSR) 管理。
-x509 此参数允许我们创建自签名证书而不是生成证书签名请求。
-nodes 此参数允许 OpenSSL 跳过使用密码短语验证我们的证书的选项。
-days 此参数设置证书有效期。
-newkey rsa: 2048 此参数告诉 OpenSSL 同时生成新证书和新密钥。 rsa:2048 选项使 RSA 密钥长度为 2048 位。
-keyout 此参数允许您将生成的私钥文件存储在您选择的位置。
-out 此参数允许你将生成的证书存储在你选择的位置。

当你执行以下命令生成一个新的私钥和证书时,将提示你提供信息。 提示将如下所示:

Country Name (2 letter code) [AU]:DK 
State or Province Name (full name) [Some-State]:Midtjylland 
Locality Name (eg, city) []:Brande 
Organization Name (eg, company) [Internet Widgits Pty Ltd]: Deviced.Inc 
Organizational Unit Name (eg, section) []:DevOps 
Common Name (e.g. server FQDN or YOUR name) []:<IP address of Nginx> 
Email Address []:admin@organisation.com 

通用名称CN)字段,也称为完全限定域名FQDN)非常重要。 你需要提供你的 Nginx 服务器的 IP 地址或域名。

/etc/ssl/private/ 现在将包含你的 nginx-selfsigned.key 文件,而 /etc/ssl/certs/ 将包含你的 nginx-selfsigned.crt 文件。

接下来,我们将创建一个强大的 Diffie-Hellman 组,用于与客户端协商完全前向安全PFS)。我们将通过使用openssl来执行以下命令:

sudo openssl dhparam -out /etc/ssl/certs/dhparam.pem 2048 

这将需要相当长的时间,但完成后,它将在 /etc/ssl/certs/ 内生成一个 dhparam.pem 文件。

创建强加密设置

在下一节中,我们将设置一个强大的 SSL 密码套件来保护我们的 Nginx 服务器:

  1. 创建一个名为 *s*sl-params.conf 的配置文件在/etc/nginx/snippets/中,如下所示:
 sudo nano /etc/nginx/snippets/ssl-params.conf
  1. 将以下代码复制到文件中:
        # from https://cipherli.st/ 
        # and https://raymii.org/s/tutorials/
          Strong_SSL_Security_On_nginx.html 

        ssl_protocols TLSv1 TLSv1.1 TLSv1.2; 
        ssl_prefer_server_ciphers on; 
        ssl_ciphers "EECDH+AESGCM:EDH+AESGCM:AES256+EECDH:AES256+EDH"; 
        ssl_ecdh_curve secp384r1; 
        ssl_session_cache shared:SSL:10m; 
        ssl_session_tickets off; 
        ssl_stapling on; 
        ssl_stapling_verify on; 
        resolver 8.8.8.8 8.8.4.4 valid=300s; 
        resolver_timeout 5s; 
        # disable HSTS header for now 
        #add_header Strict-Transport-Security "max-age=63072000;
         includeSubDomains; preload"; 
        add_header X-Frame-Options DENY; 
        add_header X-Content-Type-Options nosniff; 

        ssl_dhparam /etc/ssl/certs/dhparam.pem; 
  1. 输入 Ctrl + X,选择 Y 保存并关闭文件。

我们使用了 Remy van Elst 在 cipherli.st/ 中提供的建议。

修改 Nginx 配置

接下来,我们将修改我们的 Nginx 配置以启用 SSL。 按照以下步骤进行:

  1. 首先,备份你现有的位于/etc/nginx/sites-available/中名为default的 Nginx 配置文件:
 sudo cp /etc/nginx/sites-available/default \
        /etc/nginx/sites-available/default.backup
  1. 现在,使用以下命令打开文件进行编辑:
 sudo nano /etc/nginx/sites-available/default 
  1. 你会在文件中找到很多被注释掉的内容。 如果你暂时忽略它们,你可能会看到以下内容:
        server { 
            listen 80 default_server; 
            listen [::]:80 default_server; 

            # SSL configuration 

            # listen 443 ssl default_server; 
            # listen [::]:443 ssl default_server; 

            . . . 

            root /var/www/html; 

            . . . 

            index index.html index.htm index.nginx-debian.html; 
            server_name _; 

            . . . 
  1. 我们将修改配置以便未加密的 HTTP 请求自动重定向到加密的 HTTPS。 我们将通过添加以下三行来执行此操作,如下方代码中所示:
        server { 
            listen 80 default_server; 
            listen [::]:80 default_server; 
            server_name <nginx_server_ip or nginx domain name>; 
            return 301 https://$server_name$request_uri; 
        } 

            # SSL configuration 

            # listen 443 ssl default_server; 
            # listen [::]:443 ssl default_server; 

            . . .
  1. 从前面的代码中,你可以看到我们已关闭了服务器块。

  2. 接下来,我们将启动一个新的服务器块,取消注释使用端口443的两个listen指令,并在这些行中添加http2以启用 HTTP/2,如下代码块所示:

        server { 
            listen 80 default_server; 
            listen [::]:80 default_server; 
            server_name <nginx_server_ip or nginx domain name>; 
            return 301 https://$server_name$request_uri; 
        } 

        server { 

            # SSL configuration 

            listen 443 ssl http2 default_server; 
            listen [::]:443 ssl http2 default_server; 

            . . . 
  1. 接下来,我们将添加我们自签名证书和密钥的位置。 我们只需要包含我们设置的两个片段文件:
        server { 
            listen 80 default_server; 
            listen [::]:80 default_server; 
            server_name <nginx_server_ip or nginx domain name>; 
            return 301 https://$server_name$request_uri; 
        } 
        server { 

            # SSL configuration 

            listen 443 ssl http2 default_server; 
            listen [::]:443 ssl http2 default_server; 
            ssl_certificate /etc/ssl/certs/nginx-selfsigned.crt; 
            ssl_certificate_key /etc/ssl/private/nginx-selfsigned.key; 
            include snippets/ssl-params.conf; 

            . . .
  1. 接下来,我们将在 SSL 服务器块内设置server_name值为我们的 Nginx IP 或域名。默认情况下,server_name 可能被设置为一个下划线(_), 如下代码块所示:
        server { 
            # SSL configuration 

            . . . 

            server_name <nginx_server_ip or nginx domain name>; 

            . . . 
        } 
  1. 输入 Ctrl + X,选择 Y 保存并关闭文件。

启用更改并测试我们的 Nginx 设置

现在我们将重新启动 Nginx 来实施我们的新更改:

  1. 首先,检查我们的文件中是否有任何语法错误。通过输入以下命令来执行此操作:
 sudo nginx -t 
  1. 如果一切顺利,你应该能够看到类似以下命令输出的内容:
 nginx: [warn] "ssl_stapling" ignored, issuer certificate not found 
        nginx: the configuration file /etc/nginx/nginx.conf syntax is ok 
        nginx: configuration file /etc/nginx/nginx.conf test is successful 
  1. 使用以下命令重新启动 Nginx:
 sudo systemctl restart nginx 
  1. 接下来,使用http://<Nginx_IP_Address>:80访问您的 Nginx 服务器。您应该注意到您已被自动重定向到https://<Nginx_IP_Address>:80

  2. 您将看到类似以下截图的警告:

SSL 警告

  1. 这是预期的,因为我们创建的证书未由您浏览器信任的证书颁发机构签名。

  2. 单击高级按钮,然后单击继续访问 192.168.56.104(不安全)

以不安全的方式继续

  1. 您现在应该能够看到 Nginx 默认页面,如以下截图所示:

带有 SSL 加密的 Nginx 索引页面

配置 Jenkins 服务器

在本节中,我们将对我们的 Jenkins 服务器执行一些配置。要首先设置 Jenkins 服务器,请参阅在 Ubuntu 上安装独立的 Jenkins 服务器部分。

一旦您运行起一个 Jenkins 服务器,就按照以下步骤进行操作:

  1. 要使 Jenkins 与 Nginx 配合工作,我们需要更新 Jenkins 配置,以便 Jenkins 服务器仅侦听 Jenkins IP 地址或 Jenkins 域名接口,而不是所有接口(0.0.0.0)。如果 Jenkins 监听所有接口,则可能可以在其原始未加密端口(8080)上访问。

  2. 为此,请修改/etc/default/jenkins配置文件,如下所示:

 sudo nano /etc/default/jenkins
  1. 在文件中,滚动到最后一行或者只查找JENKINS_ARGS行。

  2. 将以下参数追加到现有的JENKINS_ARGS值:

        -httpListenAddress=<IP Address of your Jenkins>  
  1. 最终的JENKINS_ARGS行应该类似于这样(单行):
        JENKINS_ARGS="--webroot=/var/cache/$NAME/war
        --httpPort=$HTTP_PORT
        --httpListenAddress=192.168.56.105" 
  1. 输入Ctrl + X并选择Y以保存并关闭文件。

  2. 为了使新的配置生效,重新启动 Jenkins 服务器:

 sudo systemctl restart jenkins 
  1. 要检查 Jenkins 是否正常运行,请执行以下命令:
 sudo systemctl status jenkins  

你应该能够看到以下截图:

        ● jenkins.service - LSB: Start Jenkins at boot time 
           Loaded: loaded (/etc/init.d/jenkins; bad;
           vendor preset: enabled) 
           Active: active (exited) since Sat 2017-07-22 23:30:36 UTC;
           18h ago 
             Docs: man:systemd-sysv-generator(8) 

将反向代理设置添加到 Nginx 配置中

以下步骤将帮助您向 Nginx 配置中添加反向代理设置:

  1. 打开 Nginx 配置文件进行编辑:
 sudo nano /etc/nginx/sites-available/default
  1. 因为我们将所有请求发送到我们的 Jenkins 服务器,所以请注释掉默认的try_files行,如下面的代码块所示:
        location / { 
          # First attempt to serve request as file, then 
          # as directory, then fall back to displaying a 404\. 
          # try_files $uri $uri/ =404; 
        } 
  1. 接下来,添加如下所示的代理设置:
        location / { 
          # First attempt to serve request as file, then 
          # as directory, then fall back to displaying a 404\. 
          #try_files $uri $uri/ =404; 
          include /etc/nginx/proxy_params; 
          proxy_pass http://<ip address of jenkins>:8080; 
          proxy_read_timeout  90s; 
          # Fix potential "It appears that your reverse proxy set up
 is broken" error. 
          proxy_redirect http://<ip address of jenkins>:8080
 https://your.ssl.domain.name; 
        } 
  1. 输入Ctrl + X并选择Y以保存并关闭文件。

  2. 运行以下命令检查 Nginx 配置文件中是否存在任何语法错误:

 sudo nginx -t  

你应该能够看到以下输出:

        nginx: [warn] "ssl_stapling" ignored, issuer certificate not found 
        nginx: the configuration file /etc/nginx/nginx.conf syntax is ok 
        nginx: configuration file /etc/nginx/nginx.conf test is successful 
  1. 如果输出没有错误,请重新启动 Nginx 以使新配置生效。使用以下命令:
 sudo systemctl restart nginx
  1. 接下来,使用https://<nginx_ip_address>:80访问您的 Nginx 服务器:

Jenkins 入门页面

在同一台机器上运行 Nginx 和 Jenkins

如果要在反向代理服务器(Nginx)后运行 Jenkins,且 Jenkins 服务器和 Nginx 服务器在同一台机器上运行,则按顺序执行以下各部分:

  1. 使用至少 4 GB RAM 和多核处理器设置一台机器。

  2. 根据团队如何管理基础设施,该机器可能是云平台上的实例(如 AWS、DigitalOcean 或任何其他云平台)、裸机,或者可能是 VM(在 VMware vSphere 或任何其他服务器虚拟化软件上)。

  3. 机器应安装 Ubuntu 16.04 或更高版本。

  4. 检查管理员权限;安装可能会要求输入管理员用户名和密码。

  5. 安装 Nginx;参考安装和配置 Nginx部分。

  6. 配置防火墙;参考在 Nginx 服务器上配置防火墙部分。

  7. 使用 OpenSSL 安全地配置 Nginx 服务器;参考使用 OpenSSL 安全地配置 Nginx部分。

  8. 使用以下命令配置防火墙以允许端口8080上的流量:

 sudo ufw allow 8080 
  1. 接下来,使用以下命令检查防火墙状态:
 sudo ufw status  

您应该看到以下输出:

        Status: active  
        To                         Action      From 
        --                         ------      ---- 
        OpenSSH                    ALLOW       Anywhere 
        Nginx Full                 ALLOW       Anywhere 
        8080                       ALLOW       Anywhere 
        OpenSSH (v6)               ALLOW       Anywhere (v6) 
        Nginx Full (v6)            ALLOW       Anywhere (v6) 
        8080 (v6)                  ALLOW       Anywhere (v6) 
  1. 安装 Jenkins,参考在 Ubuntu 上安装独立 Jenkins 服务器部分。

  2. 配置 Jenkins 服务器;参考配置 Jenkins 服务器部分。在执行本节中提到的步骤时,请确保将<IP Address of your Jenkins>替换为127.0.0.1

  3. 在 Nginx 中添加反向代理设置;参考将反向代理设置添加到 Nginx 配置部分。在执行本节中提到的步骤时,您将被要求在 Nginx 配置文件的各处输入 Jenkins 服务器 IP。由于我们的 Jenkins 服务器现在在与 Nginx 相同的机器上运行,因此<IP Address of your Jenkins>的值应为localhost

在 Docker 上运行 Jenkins

在 Docker 上运行 Jenkins 的真正优势在于当您需要快速创建多个开发和分段实例时。它还非常有用,可以在主 Jenkins 服务器上执行维护活动时将流量重定向到次要 Jenkins 服务器。虽然我们稍后将看到这些用例,但让我们首先尝试在 Docker 上运行 Jenkins。

先决条件

在开始之前,请确保准备了以下内容:

  • 我们需要一台至少拥有 4 GB RAM(越多越好)和多核处理器的机器。

  • 根据团队中的基础设施管理方式,机器可能是云平台上的实例(如 AWS、DigitalOcean 或任何其他云平台)、裸机,或者可能是 VM(在 VMware vSphere 或任何其他服务器虚拟化软件上)。

  • 机器应该安装 Ubuntu 16.04 或更高版本。

  • 检查管理员权限;安装可能会要求管理员用户名和密码。

设置 Docker 主机

在本节中,我们将学习如何使用存储库方法和使用 Debian 软件包安装 Docker。按照以下各节中的步骤设置 Docker 主机。

设置存储库

按照以下步骤设置存储库:

  1. 使用以下命令让 apt 使用存储库:
 sudo apt-get install apt-transport-https ca-certificates 
  1. 使用以下命令添加 Docker 的官方 GPG 密钥:
 curl -fsSL https://yum.dockerproject.org/gpg | sudo apt-key add -
  1. 使用以下命令验证密钥 ID 是否确实为 58118E89F3A912897C070ADBF76221572C52609D
 apt-key fingerprint 58118E89F3A912897C070ADBF76221572C52609D

你应该看到以下输出:

        pub  4096R/2C52609D 2015-07-14 
        Key fingerprint = 5811 8E89 F3A9 1289 7C07  0ADB F762 2157 2C52
         609D 
        uid  Docker Release Tool (releasedocker) docker@docker.com 
  1. 使用以下命令设置稳定存储库以下载 Docker:
 sudo add-apt-repository \
       "deb https://apt.dockerproject.org/repo/ubuntu-$(lsb_release \
       -cs) main" 

建议始终使用稳定版本的存储库。

安装 Docker

设置存储库后,请执行以下步骤安装 Docker:

  1. 使用以下命令更新 apt 包索引:
 sudo apt-get update 
  1. 要安装最新版本的 Docker,请运行以下命令:
 sudo apt-get -y install docker-engine 
  1. 要安装特定版本的 Docker,请使用以下命令列出可用版本:
 apt-cache madison docker-engine  

你应该看到以下输出:

        docker-engine | 1.16.0-0~trusty |
        https://apt.dockerproject.org/repo ubuntu-trusty/main amd64
        Packages docker-engine | 1.13.3-0~trusty |
        https://apt.dockerproject.org/repo ubuntu-trusty/main amd64
        Packages  
        ...

上一个命令的输出取决于前一节中配置的存储库类型(设置存储库)。

  1. 接下来,执行以下命令来安装特定版本的 Docker:
 sudo apt-get -y install docker-engine=<VERSION_STRING>  
        sudo apt-get -y install docker-engine=1.16.0-0~trusty 
  1. Docker 服务会自动启动。要验证 Docker 是否已安装并运行,请执行以下命令:
 sudo docker run hello-world  
  1. 前一个命令应该没有错误,并且你应该看到一个 Hello from Docker! 的消息:
        Unable to find image 'hello-world:latest' locally 
        latest: Pulling from library/hello-world 
        b04784fba78d: Pull complete 
        Digest: sha256:
          f3b3b28a45160805bb16542c9531888519430e9e6d6ffc09d72261b0d26ff74f 
        Status: Downloaded newer image for hello-world:latest 

        Hello from Docker! 
        This message shows that your installation appears to be working
        correctly. 
        ... 

从软件包安装

按照以下步骤使用 .deb 软件包安装 Docker:

  1. apt.dockerproject.org/repo/pool/main/d/docker-engine/ 下载你选择的 .deb 软件包。

  2. 要安装已下载的软件包,请执行以下命令:

 sudo dpkg -i /<path to package>/<docker package>.deb
  1. 运行以下命令验证 Docker 安装:
 sudo docker run hello-world  

你应该看到以下输出:

        Hello from Docker! 
        This message shows that your installation appears to be working
        correctly. 

运行 Jenkins 容器

现在我们的 Docker 主机已准备好,让我们运行 Jenkins:

  1. 运行以下命令以启动 Jenkins 容器。这可能需要一些时间,因为 Docker 将尝试从 Docker Hub 下载 Jenkins Docker 镜像 (jenkins/jenkins:lts):
 docker run -d --name jenkins_dev -p 8080:8080 \
        -p 50000:50000 jenkins/jenkins:lts  

你应该看到以下输出:

        ...
 ...
 ... 
        d52829d9da9e0a1789a3117badc862039a0084677be6a771a959d8467b9cc267 
  1. 以下表格解释了我们在上一个命令中使用的 Docker 命令:
参数 描述
docker 用于调用 Docker 实用程序。
run 用于运行容器的 Docker 命令。
-d 此选项在后台运行容器。
--name 此选项允许您为容器命名。
-p 该选项用于将容器的端口与主机映射。
jenkins/jenkins:lts 用于创建容器的 Docker 镜像及其版本的名称。 jenkins/jenkins 是 Jenkins Docker 镜像,lts 是该镜像的特定版本。
  1. 要查看正在运行的容器列表,请执行以下命令:
 sudo docker ps --format "{{.ID}}: {{.Image}} {{.Names}}"

您应该看到以下输出:

        d52829d9da9e: jenkins/jenkins:lts jenkins_dev 

要使用 Jenkins 的最新 LTS 版本,请使用 jenkins/jenkins:lts Jenkins Docker 镜像。

要使用 Jenkins 的最新每周发布版本,请使用 jenkins/jenkins Jenkins Docker 镜像。

  1. 使用以下命令记下您的 Docker 主机 IP:
 sudo ip route  

您应该看到以下输出:

        default via 10.0.2.2 dev enp0s3 
        10.0.2.0/24 dev enp0s3  proto kernel  scope link  src 10.0.2.15 
        172.17.0.0/16 dev docker0  proto kernel  scope link  src 172.17.0.1 
        192.168.56.0/24 dev enp0s8  proto kernel  scope link
        src 192.168.56.107 
  1. 您的 Jenkins 服务器现在可通过http:<Docker 主机的 IP 地址>:8080访问。现在您应该能够看到 Jenkins 入门页面。

  2. 要继续进行 Jenkins 设置,您可能需要initialAdminPassword密钥。此文件位于/var/jenkins_home/secrets/内。您可以通过以下方式之一获取initialAdminPassword文件内的数据。您可以使用以下命令docker exec,如下所示:

 sudo docker exec -it jenkins_dev \
        cat /var/jenkins_home/secrets/initialAdminPassword

或者,通过登录到正在运行的 Jenkins 容器内,使用相同的docker exec命令,如下所示:

 sudo docker exec -it jenkins_dev bash
  1. 一旦您进入容器,请执行以下 Linux 命令以获取文件的内容:
 cat /var/jenkins_home/secrets/initialAdminPassword \ 

这两个命令都会打印initialAdminPassword文件的内容,类似于以下所示的内容:

 1538ededb4e94230aca12d10dd461e52 

这里,-i 选项允许您与 Docker 容器进行交互,而 -t 选项分配一个伪 -tty

  1. 当您仍在 Jenkins 容器内时,请注意jenkins_home目录位于/var/内,并且jenkins.war文件位于/usr/share/jenkins内。

jenkins_home 是一个非常重要的目录,其中包含您的 Jenkins 作业、构建、元数据、配置、用户等所有内容。

使用数据卷运行 Jenkins 容器

在前面的部分中,我们创建了一个 Jenkins 容器,但没有任何机制使jenkins_home目录内的数据持久化。简单来说,如果由于某种原因删除 Jenkins 容器,则会删除您的jenkins_home目录。

幸运的是,还有一种更好的方法来使用 Docker 运行 Jenkins,那就是使用数据卷。数据卷是特殊的目录,使数据持久化并独立于容器的生命周期。如果容器将数据写入数据卷,则删除容器仍会使数据可用,因为容器及其关联的数据卷是两个不同的实体。

让我们使用数据卷创建一个 Jenkins 容器:

  1. 使用以下命令运行 Jenkins 容器:
 sudo docker run -d --name jenkins_prod -p 8080:8080\
        -p 50000:50000 -v jenkins-home-prod:/var/jenkins_home \
        jenkins/jenkins:lts 
  1. -v jenkins-home-prod:/var/jenkins_home 选项将创建一个名为jenkins-home-prod的数据卷,并将其映射到容器内的/var/jenkins_home目录。

  2. 执行以下命令以查看 jenkins_prod Jenkins 容器内 /var/jenkins_home 目录的内容:

 sudo docker exec -it jenkins_prod ls -lrt /var/jenkins_home 

您应该看到以下输出:

        total 72 
        drwxr-xr-x  2 jenkins jenkins 4096 Jul 26 20:41 init.groovy.d 
        -rw-r--r--  1 jenkins jenkins  102 Jul 26 20:41
         copy_reference_file.log 
        drwxr-xr-x 10 jenkins jenkins 4096 Jul 26 20:41 war 
        -rw-r--r--  1 jenkins jenkins    0 Jul 26 20:41
         secret.key.not-so-secret 
        -rw-r--r--  1 jenkins jenkins   64 Jul 26 20:41 secret.key 
        drwxr-xr-x  2 jenkins jenkins 4096 Jul 26 20:41 plugins 
        drwxr-xr-x  2 jenkins jenkins 4096 Jul 26 20:41 jobs 
        drwxr-xr-x  2 jenkins jenkins 4096 Jul 26 20:41 nodes 
        -rw-r--r--  1 jenkins jenkins  159 Jul 26 20:41
          hudson.model.UpdateCenter.xml 
        -rw-------  1 jenkins jenkins 1712 Jul 26 20:41 identity.key.enc 
        drwxr-xr-x  2 jenkins jenkins 4096 Jul 26 20:41 userContent 
        -rw-r--r--  1 jenkins jenkins  907 Jul 26 20:41 nodeMonitors.xml 
        drwxr-xr-x  3 jenkins jenkins 4096 Jul 26 20:41 logs 
        -rw-r--r--  1 jenkins jenkins    6 Jul 26 20:41
          jenkins.install.UpgradeWizard.state 
        drwxr-xr-x  3 jenkins jenkins 4096 Jul 26 20:41 users 
        drwx------  4 jenkins jenkins 4096 Jul 26 20:41 secrets 
        -rw-r--r--  1 jenkins jenkins   94 Jul 26 20:41 jenkins.CLI.xml 
        -rw-r--r--  1 jenkins jenkins 1592 Jul 26 20:41 config.xml 
        drwxr-xr-x  2 jenkins jenkins 4096 Jul 26 20:41 updates 
  1. 要列出您的 Docker 卷,请执行以下命令:
 sudo docker volume ls 

您应该看到以下输出:

        DRIVER              VOLUME NAME 

        local               jenkins-home-prod 
  1. 现在您有一个带有持久 jenkins_home 目录的 Jenkins 容器。

测试数据卷

我们将通过执行以下步骤来测试我们的数据卷。

  1. 我们将对 Jenkins 服务器进行一些更改;这将修改 /var/jenkins_home 目录中的内容。

  2. 我们将删除 Jenkins 容器。

  3. 我们将创建一个新的 Jenkins 容器,该容器将使用相同的数据卷。

  4. 使用以下命令检查活动的 Jenkins 容器:

 sudo docker ps --format "{{.ID}}: {{.Image}} {{.Names}}"

您应该看到以下输出:

        5d612225f533: jenkins/jenkins:lts jenkins_prod 
  1. 使用 http://<Docker 主机的 IP 地址>:8080 访问 Jenkins 服务器。

  2. 使用以下命令获取 initialAdminPassword 文件的内容:

 sudo docker exec -it jenkins_prod \
        cat /var/jenkins_home/secrets/initialAdminPassword

您应该看到以下输出:

        7834556856f04925857723cc0d0523d7
  1. 在 Jenkins 页面的管理员密码字段下粘贴 initialAdminPassword 并继续进行 Jenkins 设置。

  2. 在创建第一个管理员用户步骤中创建一个新用户,如下所示的截图:

在 Jenkins 上创建第一个管理员用户

  1. 继续进行剩余的步骤。

  2. 执行以下命令以列出 /var/jenkins_home/users 目录的内容。这是您拥有所有用户帐户的位置:

 sudo docker exec -it jenkins_prod ls -lrt /var/jenkins_home/users 

输出应该如下所示:

        total 4 
        drwxr-xr-x 2 jenkins jenkins 4096 Jul 26 21:38 developer 
  1. 注意我们新创建的用户 developer 在 users 目录下列出。

  2. 现在让我们使用以下命令删除 jenkins_prod Jenkins 容器:

 sudo docker kill jenkins_prod
        sudo docker rm jenkins_prod 
  1. 使用以下命令列出现有的 Docker 容器(运行/停止):
 sudo docker ps -a --format "{{.ID}}: {{.Image}} {{.Names}}"

您应该看到以下输出。但是,您不应该在列表中看到 jenkins_prod

        3511cd609b1b: hello-world eloquent_lalande 
  1. 使用以下命令列出卷的内容:
 sudo docker volume ls 

您应该看到类似的内容。您可以看到删除容器并没有删除其关联的数据卷:

        DRIVER              VOLUME NAME 

        local               jenkins-home-prod 
  1. 现在让我们创建一个名为 jenkins_prod 的新 Jenkins 容器,该容器使用现有的 jenkins-home-prod 卷:
 sudo docker run -d --name jenkins_prod -p 8080:8080 \
        -p 50000:50000 -v jenkins-home-prod:/var/jenkins_home \
        jenkins/jenkins:lts 
  1. 尝试访问 Jenkins 仪表板,使用 http://<Docker 主机的 IP 地址>:8080。您将看不到 Jenkins 设置页面;相反,您应该看到登录页面。

  2. 使用我们之前创建的用户登录 Jenkins。您应该能够登录。这证明我们的整个 Jenkins 配置是完好的。

创建 Jenkins 的开发和分段实例

许多时候,您需要一个 Jenkins 生产服务器的开发或分段实例来测试新功能。Docker 可以轻松且安全地创建多个 Jenkins 服务器实例。

下面是如何做的。在此部分中,我们将使用我们的 Jenkins 生产实例创建一个开发和一个分段实例。

先决条件

在我们开始之前,请确保您准备好以下内容:

  • 我们需要一个运行 Jenkins 实例(生产)并利用数据卷的 Docker 主机

  • 参考使用数据卷运行 Jenkins 容器部分

创建一个空数据卷

我们将为我们的 Jenkins 的暂存和开发实例分别创建名为jenkins-home-stagingjenkins-home-development的数据卷:

  1. 要创建一个空的jenkins-home-staging数据卷,请运行以下命令:
 sudo docker volume create --name jenkins-home-staging 
  1. 要创建一个空的jenkins-home-development数据卷,请运行以下命令:
 sudo docker volume create --name jenkins-home-development
  1. 使用docker volume命令列出新创建的数据卷:
 sudo docker volume ls 

您应该看到以下输出:

        DRIVER              VOLUME NAME 

        local               jenkins-home-prod 
        local               jenkins-home-development 
        local               jenkins-home-staging
  1. 从前面的列表中,您可以看到新创建的名为jenkins-home-stagingjenkins-home-development的数据卷。

如果您已经按照前一节的步骤进行了操作,您还应该看到正在由我们的 Jenkins 生产实例jenkins_prod使用的数据卷jenkins-home-prod

在数据卷之间复制数据

现在我们有了新创建的空数据卷。让我们将jenkins-home-prod的内容复制到每一个数据卷:

  1. 使用以下命令将jenkins-home-prod的内容复制到jenkins-home-staging
 sudo docker run --rm -it --user root \
        -v jenkins-home-prod:/var/jenkins_home \
        -v jenkins-home-staging:/var/jenkins_home_staging \
        jenkins/jenkins:lts bash -c "cd /var/jenkins_home_staging \
        && cp -a /var/jenkins_home/* ." 
  1. 前一个命令将执行以下操作:

    • 它首先将使用 Jenkins 的 Docker 镜像jenkins/jenkins:lts创建一个交互式容器(容器是临时的)。

    • 在这个临时容器上执行的所有操作都将使用root用户。注意前一个命令中的--user root选项。

    • 它将jenkins-home-prod数据卷的内容挂载到容器内的/var/jenkins_home目录中。注意-v jenkins-home-prod:/var/jenkins_home选项。

    • 类似地,它将jenkins-home-staging数据卷的不存在内容挂载到容器内不存在的/var/jenkins_home_staging目录中。注意-v jenkins-home-staging:/var/jenkins_home_staging选项。

    • 然后,它将/var/jenkins_home的内容复制到/var/jenkins_home_staging。注意bash -c "cd /var/jenkins_home_staging && cp -a /var/jenkins_home/*"选项。

  2. 现在,使用以下命令将jenkins-home-prod的内容复制到jenkins-home-development

 sudo docker run --rm -it --user root \
        -v jenkins-home-prod:/var/jenkins_home \
        -v jenkins-home-development:/var/jenkins_home_development \
        jenkins/jenkins:lts bash -c "cd /var/jenkins_home_development \
        && cp -a /var/jenkins_home/* ." 
  1. 现在我们在所有三个数据卷上都有相同的数据:jenkins-home-prodjenkins-home-stagingjenkins-home-development

创建开发和暂存实例

现在我们已经为开发和暂存准备好了数据卷,让我们使用它们生成容器:

  1. 要创建名为jenkins_staging的 Jenkins 暂存实例,并使用jenkins-home-staging数据卷,请运行以下命令:
 sudo docker run -d --name jenkins_staging \
        -v jenkins-home-staging:/var/jenkins_home -p 8081:8080 \
        -p 50001:50000 jenkins/jenkins:lts

前一个命令将创建一个运行在端口8080上的 Jenkins 实例,并将其映射到 Docker 主机的端口8081。我们选择 Docker 主机上的不同端口,因为我们已经有我们的 Jenkins 生产实例jenkins_prod运行在端口8080上,该端口映射到 Docker 主机的端口8080

相同的原因也适用于将 Jenkins 实例上的端口50000映射到 Docker 主机上的端口50001

  1. 尝试使用http:<Docker 主机的 IP 地址>:8081访问您的 Jenkins 暂存实例。

  2. 同样地,要使用 jenkins-home-development 数据卷创建一个名为 jenkins_development 的 Jenkins 开发实例,请运行以下命令:

 sudo docker run -d --name jenkins_development \
        -v jenkins-home-development:/var/jenkins_home -p 8082:8080 \
        -p 50002:50000 jenkins/jenkins:lts 

上一个命令将创建一个运行在端口 8080 上并映射到 Docker 主机端口 8082 的 Jenkins 实例。我们选择 Docker 主机上的不同端口,因为端口 80808081 已经在 Docker 主机上被使用了。

同样的理由也适用于将 Jenkins 实例上的端口 50000 映射到 Docker 主机上的端口 50002

  1. 尝试使用 http:<Docker 主机的 IP 地址>:8082 访问您的 Jenkins 开发实例。

摘要

在本章中,我们学习了如何在 Apache Tomcat 服务器上安装 Jenkins,以及如何在各种操作系统上作为独立应用程序安装 Jenkins。我们还学习了如何在 Jenkins 服务器前面设置一个反向代理服务器(Nginx),并使用 SSL 安全连接。

最重要的是,我们学会了如何在 Docker 上运行 Jenkins。我们还看到了在 Docker 上使用数据卷的优势,并学习了如何利用它们来创建我们 Jenkins 服务器的按需实例(开发或者预备环境)。

当前章节的主要目标是向读者展示 Jenkins 在安装过程和支持的操作系统种类方面的多样性。Jenkins 管理将在第四章中讨论,配置 Jenkins

在下一章中,我们将快速概述 Jenkins 2.x 中的新特性。

新 Jenkins

在本章中,我们将看一些现在是 Jenkins 2.x 发行版的一部分的新功能。完成本章后,你将了解以下内容:

  • 新的 Jenkins 设置向导

  • Jenkins 作为代码的流水线(Jenkins 流水线作业)

  • Jenkins 阶段视图

  • Jenkins 声明式流水线语法

  • Jenkins 多分支流水线

  • Jenkins 流水线语法工具(片段生成器)

  • Jenkins 凭据

  • Jenkinsfile

  • Jenkins Blue Ocean

  • 在 Jenkins Blue Ocean 中创建流水线

Jenkins 设置向导

当你首次访问 Jenkins 时,会显示“入门向导”。我们已经在前一章节中完成了这个练习;尽管如此,在接下来的部分,我们将更深入地了解其中一些重要部分。

先决条件

在我们开始之前,请确保你已准备好以下内容:

  • 在前一章节讨论的任何平台上运行的 Jenkins 服务器(Docker、独立、云、虚拟机、Servlet 容器等)。

  • 确保你的 Jenkins 服务器可以访问互联网。这是下载和安装插件所必需的。

解锁 Jenkins

当你首次访问 Jenkins 时,会要求你使用一个秘密的初始管理员密码解锁它。这个密码存储在 initialAdminPassword 文件中,该文件位于你的 jenkins_home 目录内。该文件及其完整路径显示在 Jenkins 页面上,如下截图所示:

  • 在 Windows 上:你可以在 C:\Program Files (x86)\Jenkins\secrets 下找到该文件。如果你选择在其他位置安装 Jenkins,则在 <Jenkins 安装目录>\secrets 下寻找该文件。

  • 在 Linux 上:你可以在 /var/jenkins_home/secrets 下找到该文件:

解锁 Jenkins

initialAdminPassword 文件中获取密码,粘贴到管理员密码字段下,然后点击继续。

你始终可以使用 intialAdminPassword 文件中的密码和用户名 admin 登录 Jenkins。

自定义 Jenkins

接下来,会显示两个选项来安装 Jenkins 插件,如下截图所示:

自定义 Jenkins

选择安装建议的插件将安装 Jenkins 的所有通用插件,如 Git、Pipeline as Code 等(由 Jenkins 社区建议)。

选择“选择要安装的插件”将允许你安装你选择的插件。

在接下来的部分,我们将继续选择安装插件的选项。当你这样做时,你应该看到以下截图中显示的屏幕。以下页面将列出一些最受欢迎的插件,尽管这不是 Jenkins 插件的完整列表。你会注意到建议的插件已默认选中(打勾):

选择要安装的插件

您可以选择全部、无、或建议的插件。

选择完插件后,点击页面底部的安装按钮。以下截图显示了 Jenkins 插件安装:

安装 Jenkins 插件

创建第一个管理员用户

安装插件后,您将被要求创建管理员用户帐户,如下截图所示。以下管理员帐户与设置向导开始时使用的临时管理员用户帐户不同(初始管理员帐户):

创建您的第一个 Jenkins 用户

适当填写字段并点击“保存并完成”按钮。或者,您也可以选择忽略创建新的管理员用户,继续使用初始管理员用户,点击“继续作为管理员”。

接下来,在下一页上,您将看到一条消息,上面写着“Jenkins 准备就绪!您的 Jenkins 设置已完成。”点击“开始使用 Jenkins”以进入 Jenkins 仪表板。

新的 Jenkins 流水线任务

那些已经熟悉 Jenkins 的人都很清楚 freestyle Jenkins 任务。在 Jenkins 中创建流水线的经典方法是使用 freestyle job,其中每个 CI 阶段都使用 Jenkins 任务(freestyle)表示。

Jenkins freestyle 任务是基于 Web 的、GUI 驱动的配置。对 CI 流水线的任何修改都需要您登录 Jenkins 并重新配置每个 Jenkins freestyle 任务。

Pipeline as Code 的概念重新思考了我们创建 CI 流水线的方式。其思想是将整个 CI/CD 流水线编写为一段代码,提供一定程度的编程,并且可以进行版本控制。

以下是采用 Pipeline as Code 路线的一些优点:

  • 它是可编程的

  • 所有的 CI/CD 流水线配置都可以使用一个文件(Jenkinsfile)描述。

  • 它可以进行版本控制,就像任何其他代码一样

  • 它提供了使用声明性流水线语法定义流水线的选项,这是一种简单而优雅的编码流水线的方式

让我们来看看 Jenkins 流水线任务。我们将通过创建一个简单的 CI 流水线来看一下它并感受一下。

先决条件

在开始之前,请确保您准备好以下事项:

  • 在前一章讨论的任何平台上运行 Jenkins 服务器(Docker、独立、云、虚拟机、Servlet 容器等)。

  • 确保您的 Jenkins 服务器可以访问互联网。这是下载和安装插件所必需的。

  • 确保您的 Jenkins 服务器已安装所有建议的插件。请参阅 Customizing Jenkins 部分。

创建 Jenkins 流水线任务

按照以下步骤创建 Jenkins 流水线任务:

  1. 从 Jenkins 仪表板上,点击“新建项目”链接。

  2. 在结果页面上,您将看到各种类型的 Jenkins 任务供您选择。

  3. 选择管道,并使用输入项目名称字段为管道命名。

  4. 完成后,点击页面底部的确定按钮。

  5. 所有种类的 Jenkins 作业(自由形式、管道、多分支等)现在都带有一个特色标签,如下图所示:

Jenkins 作业中的新标签功能

  1. 通过点击管道选项卡,快速导航到管道部分。

  2. 以下截图描述了管道部分。让我们详细看看这个部分:

    • Definition字段提供两个选择——管道脚本和来自 SCM 的管道脚本。如果选择管道脚本选项,那么在脚本字段内定义你的管道代码。但是,如果选择来自 SCM 的管道脚本选项(截图中未显示),那么你的管道脚本(Jenkinsfile)将自动从版本控制系统中提取(我们将在接下来的部分中探讨这个选项)。

    • 要获取关于任何选项的简短描述,可以点击问号图标。

    • 管道语法是一个实用工具,帮助你将 GUI 配置转换为代码。(我们将在接下来的部分中探讨这个选项)。

管道部分

  1. 现在让我们在脚本字段内编写一些代码,看看管道是如何工作的。我们将尝试一些 Jenkins 提供的示例代码。

  2. 为此,点击尝试示例管道…字段,并选择 GitHub + Maven 选项,如下截图所示:

选择一个示例管道脚本。

  1. 这将在脚本字段中填充样本代码。

  2. 代码如下所示。它以声明性管道语法形式呈现:

      node { 
        def mvnHome 
        stage('Preparation') { // for display purposes 
          // Get some code from a GitHub repository 
          git 'https://github.com/jglick/
          simple-maven-project-with-tests.git' 
          // Get the Maven tool. 
          // ** NOTE: This 'M3' Maven tool must be configured 
          // **       in the global configuration.            
          mvnHome = tool 'M3' 
        } 
        stage('Build') { 
          // Run the maven build 
          if (isUnix()) { 
            sh "'${mvnHome}/bin/mvn'
            -Dmaven.test.failure.ignore clean package" 
          } else { 
            bat(/"${mvnHome}\bin\mvn"
            -Dmaven.test.failure.ignore clean package/) 
          }  
        } 
        stage('Results') { 
          junit '**/target/surefire-reports/TEST-*.xml' 
          archive 'target/*.jar' 
        } 
      } 
  1. 让我们快速浏览一下管道脚本(我们将在接下来的部分中详细探讨声明性管道语法):

    • node{} 是告诉 Jenkins 在 Jenkins 主服务器上运行整个管道脚本的主要容器。

    • node{}容器内部,还有三个更多的容器,如下所示:

                  stage('Preparation') {...} 
                  stage('Build') {...} 
                  stage('Results') {...}
    • 准备阶段将从 GitHub 存储库下载 Maven 源代码,并告诉 Jenkins 使用在全局配置中定义的 M3 Maven 工具(在运行管道之前我们需要这样做)。

    • 构建阶段将构建 Maven 项目。

    • 结果阶段将存档构建产物以及 JUnit 测试结果。

  1. 点击页面底部的保存按钮保存对管道作业的更改。

全局工具配置页面

在运行管道之前,重要的是我们查看 Jenkins 中的全局工具配置页面。这是你配置工具的地方,你认为这些工具将在所有管道中全局使用:例如 Java、Maven、Git 等等。

假设您有多个构建代理(Jenkins 从代理),用于构建您的 Java 代码,并且您的构建流水线需要 Java JDK、Maven 和 Git。您只需在全局工具配置中配置这些工具,Jenkins 将在构建代理(Jenkins 从代理)上构建您的代码时自动调用它们。您无需在任何构建代理上安装这些工具。

让我们在全局工具配置中配置 Maven 工具,以使我们的流水线工作起来。按照以下步骤进行操作:

  1. 要访问全局工具配置页面,请执行以下操作之一:

    1. 从 Jenkins 仪表板中,单击“管理 Jenkins” | “全局工具配置”。

    2. 或者,在浏览器中粘贴 URL http://<您的 Jenkins 服务器的 IP 地址>:8080/configureTools/

  2. 滚动到底部,找到 Maven 部分,然后单击“添加 Maven”按钮。然后,您将看到一系列选项,如下图所示。按照以下信息填写:

    1. 通过填写“名称”字段为您的 Maven 安装提供一个唯一的名称。(例如,我们的示例流水线中将其命名为 M3。)

    2. 默认情况下将显示“从 Apache 安装”。这将使 Jenkins 从 Apache 下载 Maven 应用程序:

在“全局工具配置”中配置 Maven

    1. 使用“版本”字段选择最新的 Maven 版本;我选择使用 Maven 3.5.0,如前面的截图所示。

首先,选择不同的安装程序,通过单击“删除安装程序”按钮删除现有的安装程序。接下来,单击“添加安装程序”下拉菜单,并选择不同的安装程序。除了从 Apache 安装之外,其他选项还有“运行批处理命令”、“运行 Shell 命令”和“提取 .zip/.tar.gz”(在截图中未显示)。

  1. 构建 Maven 项目还需要 Java 工具,但由于我们正在 Jenkins 主服务器上构建我们的代码(该服务器已安装了 Java JDK),因此我们现在可以跳过安装 Java 工具。

  2. 配置 Maven 完成后,滚动到页面底部,然后单击“保存”按钮。

Jenkins 流水线阶段视图

Jenkins 阶段视图 是 2.x 版本的新功能。它仅适用于 Jenkins 流水线和 Jenkins 多分支流水线作业。

Jenkins 阶段视图可以实时可视化流水线各个阶段的进度。让我们通过运行示例流水线来看看它的运作情况:

  1. 在 Jenkins 仪表板上,在“所有视图”选项卡下,您将看到您的流水线。

  2. 单击构建触发图标来运行流水线,如下图所示:

在 Jenkins 仪表板上查看流水线

  1. 要进入“阶段视图”,请单击您的流水线名称(同时也是指向流水线项目页面的链接)。

  2. 或者,您可以将鼠标悬停在流水线名称上,以获取包含一系列操作项和链接的下拉菜单,如下图所示:

流水线菜单的视图

  1. 舞台视图页面将看起来像以下截图:

舞台视图

  1. 要查看特定阶段的构建日志,请将鼠标悬停在色彩编码的状态框上,您应该看到查看日志的选项。单击它将打开一个小弹出窗口显示日志,如下所示:

Jenkins 单个阶段日志

  1. 要查看完整的构建日志,请在左侧查找“构建历史”。构建历史选项卡将列出所有已运行的构建。右键单击所需的构建编号,然后单击“控制台输出”:

访问控制台输出

声明性流水线语法

在先前的部分中,我们创建了一个 Jenkins 流水线,以查看和感受其各种组件。我们利用了遵循声明性语法的流水线脚本来定义我们的流水线。

声明性流水线语法是 Groovy 语法的更简化和结构化版本,后者由于其可编程性而更强大。在本节中,我们将更详细地了解声明性流水线语法。这很重要,因为在接下来的章节中,我们将使用相同的语法来定义我们的 CI 和 CD 流水线。

声明性流水线的基本结构

简而言之,声明性流水线是多个 node 块(节点)、stage 块(阶段)、指令和步骤的集合。一个 node 块可以有多个 stage 块,反之亦然。我们还可以并行运行多个阶段。让我们逐个详细了解各个部分。

node

node 块定义了 Jenkins 代理,其中包括其组成部分(阶段块、指令和步骤)应运行在其中。node 块结构如下所示:

node ('<parameter>') {<constituents>} 

以下提供了有关node 块的更多信息:

  • 定义stage、指令或步骤应运行的节点

  • 组成部分:多个 stage 块、指令或步骤

  • 必需:是

  • 参数:任意、标签

阶段块

stage 块是一组紧密相关的步骤和指令的集合,具有共同的目标。stage 块结构如下所示:

stage ('<parameter>') {<constituents>} 

以下提供了有关 stage 块的更多信息:

  • 定义:一组步骤和指令

  • 组成部分:多个 node 块、指令或步骤

  • 必需:是

  • 参数:阶段名称的字符串(必填)

指令

指令的主要目的是通过提供以下任何元素来协助 node 块、stage 块和步骤:环境、选项、参数、触发器、工具。

以下提供了有关 stage 块的更多信息:

  • 定义stage 应在其中运行的节点

  • 组成部分:环境、选项、参数、触发器、工具

  • 必需:不,但每个 CI/CD 流水线都有它

  • 参数:无

步骤

步骤是构成声明式流水线的基本元素。步骤可以是批处理脚本、shell 脚本或任何其他可执行命令。步骤有各种用途,例如克隆存储库、构建代码、运行测试、将构件上传到存储库服务器、执行静态代码分析等。在接下来的部分中,我们将看到如何使用 Jenkins 管道语法工具生成步骤。

以下提供了关于stage块的更多信息:

  • 定义: 它告诉 Jenkins 要做什么

  • 构成: 命令、脚本等。这是流水线的基本块

  • 必需:不,但每个 CI/CD 流水线都有它

  • 参数:无

以下是我们之前使用的管道代码。node块、stage块、指令和步骤都使用注释(//)进行了突出显示。正如你所见,node块内有三个stage块。一个node块可以有多个stage块。除此之外,每个stage块都包含多个步骤,其中一个还包含一个指令:

// Node block
node ('master') {
  // Directive 1
  def mvnHome

  // Stage block 1
  stage('Preparation') {    // Step 1
    git 'https://github.com/jglick/simple-maven-project-with-tests.git'
    // Directive 2
    mvnHome = tool 'M3' 
   }

   // Stage block 2 
   stage('Build') {
     // Step 2 
     sh "'${mvnHome}/bin/mvn' clean install" 
   } 

   // Stage block 3
   stage('Results') {
     // Step 3 
     junit '**/target/surefire-reports/TEST-*.xml'
     // Step 4
     archive 'target/*.jar' 
   } 

} 

在上述代码中,请注意以下行:node ('master') {。这里,字符串master是一个参数(label),告诉 Jenkins 使用 Jenkins 主节点来运行node块的内容。

如果您将参数值选择为任意,则所有阶段节点及其各自的步骤和指令将在任一可用 Jenkins 从属代理上执行。

在接下来的章节中,我们将更多地了解声明式流水线,在那里我们将尝试使用它编写一个 CI/CD 流水线。

有关声明式流水线语法的更多信息,请参阅jenkins.io/doc/book/pipeline/syntax/#declarative-sections

要获取与声明式流水线兼容的所有可用步骤的列表,请参考jenkins.io/doc/pipeline/steps/

Jenkins 管道语法工具

Jenkins 管道语法工具是创建管道代码的一种快速简便的方法。管道语法工具可在 Jenkins 管道任务内部使用;参见在创建 Jenkins 管道任务部分的屏幕截图:管道部分

在本节中,我们将重新创建我们在上一节中创建的管道,但这次使用管道语法工具。

先决条件

在我们开始之前,请确保你准备好了以下事项:

  • 在全局工具配置页面配置的 Maven 工具(参见全局工具配置页面部分)

  • 安装 Pipeline Maven Integration Plugin

  • 为构建 Maven 项目还需要 Java 工具,但由于我们在 Jenkins 主节点上构建我们的代码(该节点已经安装了 Java JDK),我们可以跳过安装 Java 工具

安装 Pipeline Maven Integration 插件

按照给定的步骤安装 Pipeline Maven Integration 插件。以下插件将允许我们在管道代码中使用 Maven 工具:

  1. 从 Jenkins 仪表板中,单击“管理 Jenkins”|“管理插件”|“可用”选项卡。

  2. 在“过滤器”字段中键入Pipeline Maven Integration以搜索相应的插件,如下截图所示:

插件管理器页面

  1. 单击复选框以选择相应的插件,然后单击“无需重启安装”按钮进行安装。

  2. 单击“无需重启安装”按钮后,您将看到插件正在安装,如下截图所示。Jenkins 将首先检查网络连接,然后安装依赖项,最后安装插件。

  3. 某些插件可能需要重启才能使用。要这样做,请检查选项“在安装完成且没有作业运行时重新启动 Jenkins”:

插件安装中

使用管道语法实用程序创建 Jenkins 管道

按照以下步骤创建新的 Jenkins 管道作业:

  1. 从 Jenkins 仪表板中,单击“新项目”链接。

  2. 在生成的页面上,您将看到各种类型的 Jenkins 作业供选择。

  3. 选择管道,并使用“输入项目名称”字段为管道命名。

  4. 完成后,单击页面底部的“确定”按钮。

  5. 我们将通过单击“管道”选项卡快速导航到管道部分。

  6. 在“管道”选项卡下,单击名为“管道语法”的链接。这将打开一个新选项卡,如下截图所示:

管道语法页面

  1. 我们将使用以下片段生成器为各种块和步骤创建管道代码。

  2. 首先让我们生成一个node块的代码:

    1. 在管道语法页面上,在“步骤”部分下,选择node:使用“示例步骤”字段分配节点,如下所示。

    2. 在“标签”字段中添加字符串master。这样做告诉 Jenkins 使用 Jenkins 主节点作为执行我们管道的首选节点。

    3. 单击“生成管道脚本”按钮生成代码。

    4. 复制生成的代码并将其保存在文本编辑器中:

生成node块的代码

  1. 现在,让我们创建两个名为PreparationBuildstage块:

    1. 在管道语法页面上,在“步骤”部分下,选择stage:使用“示例步骤”字段,如下所示。

    2. 在“阶段名称”字段中添加字符串Preparation

    3. 单击“生成管道脚本”按钮生成代码。

    4. 复制生成的代码并将其粘贴到我们之前生成的node块中:

为阶段块生成代码

  1. 类似地,重复步骤 9以创建一个名为 构建stage 块。 将生成的代码粘贴到 准备stage 块)之后的 node 块中。

  2. 到目前为止,我们的管道代码应该看起来像以下内容(不包括 // some block 行):

      node('master') {

        stage('Preparation') {
        }

        stage('Build') {
        }

      }
  1. 现在让我们创建一个步骤来从 GitHub 下载源代码:

    1. 在管道语法页面的步骤部分,在示例步骤字段下选择 git: 使用 Git 的步骤,如以下截图所示。

    2. 在 Repository URL 字段中,添加示例 GitHub 仓库的链接:https://github.com/jglick/simple-maven-project-with-tests.git

    3. 其余选项保持不变。

    4. 点击生成管道脚本按钮生成代码。

    5. 复制生成的代码,并将其粘贴到我们之前生成的 准备stage 块)中:

为 Git 步骤生成代码

  1. 接下来,让我们生成一个指令,告诉 Jenkins 使用我们在全局工具配置中配置的 M3 Maven 工具:

    1. 在管道语法页面的步骤部分,在示例步骤字段下选择 withMaven: 使用 Maven 环境 的步骤,如以下截图所示。

    2. 在 Maven 字段中,选择 M3,这是我们在全局工具配置中配置的 Maven 工具。

    3. 其余选项保持不变。

    4. 点击生成管道脚本按钮生成代码。

    5. 复制生成的代码,并将其粘贴到我们之前生成的 构建stage 块)中:

为 withMaven 指令生成代码

  1. 最后,为我们的 Maven 构建命令生成一个管道代码:

    1. 在管道语法页面的步骤部分,在示例步骤字段下选择 sh: 使用 Shell 脚本 的步骤,如以下截图所示。 这是创建 Shell 脚本的步骤。

    2. 在 Shell 脚本字段中,键入 mvn -Dmaven.test.failure.ignore clean package,这是构建、测试和打包代码的 Maven 命令。 这将是我们的 Shell 脚本的内容。

    3. 点击生成管道脚本按钮生成代码。

    4. 复制生成的代码,并将其粘贴到我们之前生成的 withMaven(指令)中:

为 Maven 构建生成代码

  1. 我们最终的管道脚本应该看起来像以下内容(不包括 // some block 行):
      node('master') {

        stage('Preparation') {
          git 'https://github.com/jglick/
          simple-maven-project-with-tests.git'
        }

        stage('Build') {
          withMaven(maven: 'M3') {
            sh 'mvn -Dmaven.test.failure.ignore clean
            package'
          }
        }

      }
  1. 现在切换到管道作业配置页面。

  2. 滚动到管道部分,并将上述管道代码粘贴到脚本字段中。

  3. 点击页面底部的保存按钮。

在接下来的章节中,当我们尝试使用声明性管道语法创建 CI/CD 管道时,我们将看到更多示例,利用管道语法工具。

多分支管道

在本节中,我们将了解 Jenkins 中的多分支管道作业。 这是 Jenkins 发布 2.x 版本中添加的新功能之一。

多分支管道允许你自动为源代码仓库上的每个分支创建一个管道。如下截图所示。多分支管道使用存储在版本控制仓库中与你的源代码一起的 Jenkinsfile 进行工作。Jenkinsfile 只是定义了你的 CI 管道的管道脚本:

为新分支自动生成管道

除此之外,多分支管道设计用于在 Git/GitHub 仓库的任何分支上有新的代码更改时触发构建。如下截图所示:

使用多分支管道进行持续集成

先决条件

在我们开始之前,请确保你已准备好以下内容:

  • 配置在全局工具配置页面中的 Maven 工具(参考:全局工具配置页面)。

  • 安装 Pipeline Maven Integration 插件。

  • 为了构建 Maven 项目还需要 Java 工具,但由于我们正在 Jenkins 主节点上构建我们的代码(它已经安装了 Java JDK),我们可以跳过安装 Java 工具。

  • 安装 GitHub 插件(如果你在 Jenkins 设置向导中选择安装了推荐的插件,则已安装)。

  • 确保你的 Jenkins URL 可以从互联网访问。如果你正在使用一个临时或者开发环境来进行这个练习,并且你的 Jenkins 服务器没有域名,那么你的 Jenkins 服务器可能无法从互联网访问。要使你的 Jenkins URL 在互联网上可访问,参考附录中的 将你的本地服务器暴露在互联网上 部分,支持工具和安装指南

在 Jenkins 中添加 GitHub 凭据

为了使 Jenkins 与 GitHub 通信,我们需要在 Jenkins 中添加 GitHub 账户凭据。我们将使用 Jenkins 凭据插件来完成这个任务。如果你已经按照本章开始时讨论的 Jenkins 设置向导的步骤进行操作,你会在 Jenkins 仪表板上找到凭据功能(请参阅左侧菜单)。

按照给定的步骤将 GitHub 凭据添加到 Jenkins 中:

  1. 从 Jenkins 仪表板,点击凭据 | 系统 | 全局凭据(无限制)。

  2. 在全局凭据(无限制)页面上,从左侧菜单中点击添加凭据链接。

  3. 你将看到一堆字段需要配置(参见下面的截图):

    1. 在 Kind 字段中选择用户名与密码。

    2. 在 Scope 字段中选择 Global(Jenkins、节点、项目、所有子项目等)。

    3. 将你的 GitHub 用户名添加到用户名字段。

    4. 将你的 GitHub 密码添加到密码字段。

    5. 通过在 ID 字段中输入一个字符串给你的凭据添加一个唯一的 ID。

    6. 在描述字段中添加一些有意义的描述。

    7. 完成后点击保存按钮:

在 Jenkins 中添加 GitHub 凭据

  1. 这就是您如何在 Jenkins 中保存凭据。我们马上就会用到这些 GitHub 凭据。

在 Jenkins 中配置 GitHub 的 Webhooks

现在我们已经在 Jenkins 中保存了 GitHub 帐户凭据,让我们配置 Jenkins 以与 GitHub 进行通信。我们将通过在 Jenkins 配置中配置 GitHub 设置来实现这一点。

仔细遵循给定的步骤,在 Jenkins 中配置 GitHub 设置:

  1. 从 Jenkins 仪表板上,点击“管理 Jenkins” | “配置系统”。

  2. 在结果 Jenkins 配置页面上,向下滚动到 GitHub 部分。

  3. 在 GitHub 部分下,点击“添加 GitHub 服务器”按钮,然后从可用的下拉列表中选择 GitHub 服务器。这样做会显示一系列选项供您配置。

  4. 让我们逐一配置它们,如下所示:

    1. 通过向 Name 字段添加字符串来为您的 GitHub 服务器命名。

    2. 在 API URL 字段下,如果您使用的是公共 GitHub 帐户,请添加https://api.github.com(默认值)。否则,如果您使用的是 GitHub Enterprise,则指定其相应的 API 终端点。

    3. 确保已选中“管理钩子”选项:

配置 GitHub 服务器

    1. 点击高级按钮(你会看到两个按钮;点击第二个)。这样做会显示一些更多的字段来配置。

    2. 在“附加操作”字段下,点击“管理其他 GitHub 操作”,然后从可用列表中选择“将登录名和密码转换为令牌”(您只会看到一个选择)。

    3. 这将进一步揭示新的字段以进行配置。

    4. 选择“来自凭据”选项(默认情况下处于活动状态)。使用凭据字段,选择我们在上一节中创建的 GitHub 凭据(ID: github_credentials)。

    5. 接下来,点击“创建令牌凭据”按钮。这将在您的 GitHub 帐户上生成一个新的个人访问令牌:

将 GitHub 凭据转换为令牌

    1. 要查看您在 GitHub 上的个人访问令牌,请登录到您的 GitHub 帐户,然后导航到设置 | 开发人员设置 | 个人访问令牌:

GitHub 上的个人访问令牌

    1. 完成后,点击 Jenkins 配置页面底部的保存按钮。

    2. 同时在 Jenkins 凭据中还将添加相应个人访问令牌的条目。要查看它,请导航到 Jenkins 仪表板 | 凭据 | 系统 | api.github.com,然后您应该会看到一条 Kind 为 secret text 的凭据条目。

  1. 我们在 Jenkins 中的 GitHub 配置还没有完成。按照以下剩余步骤进行:

    1. 从 Jenkins 仪表板上,点击“管理 Jenkins” | “配置系统”。

    2. 向下滚动到 GitHub 部分。

    3. 使用凭据字段,选择新生成的凭据的密钥类型(Jenkins 中的个人访问令牌条目)。

    4. 现在,点击测试连接按钮来测试 Jenkins 和 GitHub 之间的连接。

    5. 完成后,在你的 Jenkins 配置页面底部点击保存按钮:

测试 Jenkins 和 GitHub 之间的连接

  1. 我们现在已经完成了在 Jenkins 中配置 GitHub 设置的步骤。

在 GitHub 上创建一个新仓库

在这个部分,我们将在 GitHub 上创建一个新的仓库。确保你已经在执行以下步骤的机器上安装了 Git(参考 附录 中的 在 Windows/Linux 上安装 Git 部分,支持工具和安装指南)。

按照以下步骤在 GitHub 上创建一个仓库:

  1. 登录你的 GitHub 账户。

  2. 为了保持简单,我们将重用仓库中的源代码 github.com/jglick/simple-maven-project-with-tests.git。这是我们一直在使用的用于创建 Jenkins 管道的仓库。

  3. 重新使用 GitHub 仓库的最简单方法是分叉它。要这样做,只需从你的互联网浏览器访问上述仓库,然后点击分叉按钮,如下截图所示:

分叉一个 GitHub 项目

  1. 完成后,你的 GitHub 账户上将会看到上述仓库的复制品。

使用 Jenkinsfile

Jenkins 多分支管道利用 Jenkinsfile。在接下来的部分中,我们将学习如何创建 Jenkinsfile。我们将重用我们在上一部分创建的示例管道脚本来创建我们的 Jenkinsfile。按照给定的步骤:

  1. 登录你的 GitHub 账户。

  2. 导航到分叉后的仓库 simple-maven-project-with-tests

  3. 进入仓库页面后,点击创建新文件按钮来创建一个新的空文件,这将成为我们的 Jenkinsfile,如下截图所示:

在 GitHub 上创建一个新文件

  1. 通过填写空文本框,命名你的新文件为 Jenkinsfile,如下截图所示:

在 GitHub 上命名你的新文件

  1. 将以下代码添加到你的 Jenkinsfile 中:
      node ('master') { 
        checkout scm 
        stage('Build') { 
          withMaven(maven: 'M3') { 
            if (isUnix()) { 
              sh 'mvn -Dmaven.test.failure.ignore clean package' 
            }  
            else { 
              bat 'mvn -Dmaven.test.failure.ignore clean package' 
            } 
          } 
        }   
        stage('Results') { 
          junit '**/target/surefire-reports/TEST-*.xml' 
          archive 'target/*.jar' 
        } 
      } 
  1. 完成后,通过添加有意义的评论来提交新文件,如下截图所示:

在 GitHub 上提交你的新文件

在 Jenkins 中创建一个多分支管道

按照以下步骤创建一个新的 Jenkins 管道作业:

  1. 从 Jenkins 仪表板中,点击新项目链接。

  2. 在生成的页面上,你将看到各种类型的 Jenkins 作业供选择。

  3. 选择多分支管道,并使用输入项目名称字段为你的管道命名。

  4. 完成后,点击页面底部的 OK 按钮。

  5. 滚动到分支源部分。这是我们配置要使用的 GitHub 仓库的地方。

  6. 点击添加源按钮并选择 GitHub。你将被呈现一个配置字段列表。让我们一个接一个地看看它们(见下面的截图):

    1. 对于凭证字段,选择我们在前一节创建的 GitHub 账户凭据(类型为用户名和密码)。

    2. 在所有者字段下,指定你的 GitHub 组织或 GitHub 用户账户的名称。

    3. 一旦你这样做了,仓库字段将列出你 GitHub 账户上的所有仓库。

    4. 在仓库字段下选择 simple-maven-project-with-tests

    5. 将其余选项保留为默认值:

配置多分支流水线

  1. 滚动到底部并点击保存按钮。

重新注册 Webhooks

在我们继续之前,让我们重新注册所有 Jenkins 流水线的 Webhooks:

  1. 要这样做,请从 Jenkins 仪表盘上点击 管理 Jenkins | 配置系统。

  2. 在 Jenkins 配置页面上,向下滚动到 GitHub 部分。

  3. 在 GitHub 部分,点击高级…按钮(你会看到两个,点击第二个)。

  4. 这将显示一些额外的字段和选项。点击重新注册所有作业的钩子按钮。

  5. 前述操作将在你的 GitHub 账户内的相应仓库上为我们的多分支流水线创建新的 Webhooks。按以下步骤查看 GitHub 上的 Webhooks:

    1. 登录到你的 GitHub 账户。

    2. 转到你的 GitHub 仓库,我们这里是 simple-maven-project-with-tests

    3. 点击仓库设置,如下截图所示:

仓库设置

    1. 在仓库设置页面,从左侧菜单中点击 Webhooks。你应该看到你的 Jenkins 服务器的 Webhooks,如下截图所示:

GitHub 仓库上的 Webhooks

Jenkins 多分支流水线运行中

按照给定的步骤:

  1. 从 Jenkins 仪表盘上,点击你的多分支流水线。

  2. 在你的 Jenkins 多分支流水线页面上,从左侧菜单中点击 扫描仓库现在 链接。这将扫描具有 Jenkinsfile 的分支的仓库,并将立即为每个具有 Jenkinsfile 的分支运行一个流水线,如下截图所示:

用于主分支的流水线

  1. 在您的多分支流水线页面上,从左侧菜单中,点击"Scan Repository Log"。您将看到类似于以下所示的内容。注意高亮显示的代码。您可以看到master分支符合标准,因为它有一个 Jenkinsfile,为其安排了一个流水线。由于测试分支上没有 Jenkinsfile,因此没有为其安排流水线:
Started by user nikhil pathania 
[Mon Aug 14 22:00:57 UTC 2017] Starting branch indexing... 
22:00:58 Connecting to https://api.github.com using ******/****** (credentials to access GitHub account) 
22:00:58 Connecting to https://api.github.com using ******/****** (credentials to access GitHub account) 
Examining nikhilpathania/simple-maven-project-with-tests 

 Checking branches... 

 Getting remote branches... 

 Checking branch master 

 Getting remote pull requests... 
 'Jenkinsfile' found 
 Met criteria 
Scheduled build for branch: master 

 Checking branch testing 
 'Jenkinsfile' not found 
 Does not meet criteria 

 2 branches were processed 

  Checking pull-requests... 

  0 pull requests were processed 

Finished examining nikhilpathania/simple-maven-project-with-tests 

[Mon Aug 14 22:01:00 UTC 2017] Finished branch indexing. Indexing took 2.3 sec 
Finished: SUCCESS 
  1. 您不需要始终扫描存储库。GitHub Webhooks 已配置为在 GitHub 存储库上进行推送或创建新分支时自动触发流水线。请记住,各个分支上也应该存在 Jenkinsfile,以告诉 Jenkins 在发现存储库变化时需要执行什么操作。

创建一个新的特性分支来测试多分支流水线

现在让我们从主分支创建一个特性分支,并查看 Jenkins 是否能够为其运行一个流水线:

  1. 为此,请登录到您的 GitHub 帐户。

  2. 转到您的 GitHub 仓库; 在我们的情况下是simple-maven-project-with-tests

  3. 点击"Branch: master"按钮,在空文本框中输入一个新分支的名称。接下来,点击"Create branch: feature"选项来创建一个名为 feature 的新分支,如下面的截图所示:

创建一个特性分支

  1. 这应该会立即在 Jenkins 中触发一个用于我们的新特性分支的流水线:

新特性分支的流水线

Jenkins 蓝色海洋

Jenkins Blue Ocean 是与 Jenkins 交互的全新方式。它更像是主要 Jenkins 应用程序的 UI 助手。以下是 Jenkins Blue Ocean 的一些特性:

  • 改进的可视化效果

  • 流水线编辑器

  • 个性化

  • 用于 Git 和 GitHub 的快速简易流水线设置向导

您使用经典 Jenkins 界面创建的流水线可以在新的 Jenkins 蓝色海洋中进行可视化,反之亦然。正如我之前所说,Jenkins 蓝色海洋是主要 Jenkins 应用程序的 UI 助手。

在接下来的部分中,我们将在 Blue Ocean 中可视化我们在上一部分中创建的 Jenkins 流水线。我们还将创建一个新的流水线,只是为了看看并感受一下新的 Jenkins Blue Ocean 界面。

安装 Jenkins 蓝色海洋插件

为了使用 Jenkins 蓝色海洋插件,我们需要为 Jenkins 安装 Blue Ocean 插件。按照以下步骤操作:

  1. 从 Jenkins 仪表板,点击"Manage Jenkins | Manage Plugins"。

  2. 在插件管理器页面上,点击"Available"选项卡。

  3. 使用过滤选项,搜索Blue Ocean,如下面的截图所示:

安装 Jenkins 蓝色海洋插件

  1. 从项目列表中选择 Blue Ocean 并点击"Install without restart"。你只需要 Blue Ocean 而不需要其他东西。

  2. Blue Ocean 的依赖列表很长,因此您将在安装插件/升级页面上看到许多与 Blue Ocean 插件一起安装的东西。

在 Blue Ocean 中查看您的常规 Jenkins 流水线。

在本节中,我们将尝试可视化我们在前几节中创建的现有 Jenkins 流水线:

  1. 在 Jenkins 仪表板上,您现在应该看到左侧菜单上有一个名为“打开蓝色海洋”的新链接。

  2. 单击“打开蓝色海洋”链接以转到 Jenkins Blue Ocean 仪表板。 您应该看到以下内容(请参阅以下屏幕截图):

    1. 管理链接将带您进入“管理 Jenkins”页面。

    2. Pipelines 链接将带您进入您当前看到的 Jenkins Blue Ocean 仪表板。

    3. 图标(方形内的箭头)将带您进入经典 Jenkins 仪表板。

    4. 新建流水线按钮将打开基于 Git 和 GitHub 的项目的流水线创建向导。

    5. 流水线列表(e高亮显示):

图片

Jenkins 蓝色海洋仪表板

  1. 让我们来看看我们的多分支流水线。 从 Jenkins Blue Ocean 仪表板中点击您的多分支流水线。 这样做将打开相应的多分支流水线页面,如下所示:

    1. 按钮(a高亮显示)将带您进入流水线配置页面。

    2. 活动标签将列出所有当前和过去的流水线。

    3. 分支标签将为您显示每个分支的流水线的汇总视图。

    4. Pull Requests 标签将列出分支上所有开放的拉取请求。

    5. 按钮(e高亮显示)用于重新运行流水线:

图片

在 Blue Ocean 中的多分支流水线。

  1. 现在让我们看看个别的构建页面。 要这样做,请从 Jenkins 流水线页面(请参阅前面的屏幕截图)中单击任何构建,然后您将进入相应流水线的构建页面,如下所示:

    1. Changes 标签将列出触发构建的代码更改。

    2. Artifacts 标签将列出构建生成的所有工件。

    3. 按钮(c高亮显示)将重新运行您的构建。

    4. 此部分(d高亮显示)显示有关您的构建的一些指标。

    5. 此阶段视图(e高亮显示)将列出所有顺序和并行阶段。

    6. 步骤结果部分将向您显示您选择的特定阶段的所有步骤(在下面的屏幕截图中,我选择了阶段“结果”)。

    7. 每个列出的步骤(g高亮显示)都可以展开并查看其日志:

图片

在 Blue Ocean 中的构建页面

这是您的 Jenkins 流水线在 Blue Ocean 中的简短概述(使用经典 Jenkins UI 创建的流水线)。 它几乎展示了所有内容。 但是,我鼓励读者继续探索。

在 Blue Ocean 中创建流水线。

在这一部分中,我们将看到如何从 Jenkins 蓝色海洋仪表板创建一个新的流水线。我们将查看 Blue Ocean 中的新流水线创建向导。在开始之前,请准备好以下事项:

按照给定的步骤:

  1. 从 Jenkins 蓝色海洋仪表板中,点击新的流水线按钮。Jenkins 将要求您在 Git 和 GitHub 之间进行选择。对于我们当前的练习,我们将选择 GitHub:

在 Git 和 GitHub 仓库之间进行选择

  1. 接下来,Jenkins 将要求您为您的 GitHub 帐户提供 GitHub 访问令牌。点击这里创建一个访问密钥的链接以创建一个新的访问密钥:

GitHub 访问令牌字段

  1. 在一个新的选项卡中,系统会要求您登录到您的 GitHub 帐户。

  2. 登录后,您将直接进入 GitHub 设置页面以创建一个新的个人访问令牌。

  3. 在令牌描述字段中键入一个简短的描述,以标识您的令牌。保留选择范围部分下的选项默认值:

创建一个 GitHub 个人访问令牌

  1. 点击页面底部的生成新令牌按钮以生成一个新的个人访问令牌:

GitHub 个人访问令牌

  1. 复制新创建的个人访问令牌并将其粘贴到您的 GitHub 访问令牌字段中,然后点击连接按钮(参见以下截图)。

  2. 接下来,点击列出的组织:

选择 GitHub 帐户

  1. 您可以在新流水线和自动发现 Jenkinsfile 之间进行选择。在以下示例中,我们将选择新流水线选项:

在创建和发现流水线之间进行选择

  1. 接下来,系统将要求您从 GitHub 帐户的可用存储库列表中选择一个存储库。如果列表中没有列出所需的存储库,您可以使用搜索选项来查找所需的存储库。在我们当前的示例中,我们将选择hello-world-example存储库:

选择一个存储库

  1. Jenkins 接下来会要求你创建一个流水线。由于在相应的仓库中找不到 Jenkinsfile,请点击创建流水线按钮以创建一个 Jenkinsfile:

创建一个新的流水线

  1. 创建流水线的页面如下所示。在左侧,你会看到流水线的可视化,右侧找到选择块、阶段和步骤的工具(类似于我们在上一部分看到的流水线语法工具):

Blue Ocean 流水线编辑器

  1. 让我们首先选择一个代理来运行我们的流水线。从“流水线设置”中,使用代理字段,选择标签选项。然后在标签字段下键入 master,如下截图所示。通过这种方式,我们告诉 Jenkins 在 Jenkins 主服务器上运行我们的流水线:

创建一个节点块

  1. 接下来,让我们创建一个名为 Build 的阶段,用来构建我们的源代码。点击流水线可视化上的 + 按钮即可。

  2. 你将被要求命名新的阶段。在“命名你的阶段”字段下输入 Build,如下截图所示:

创建一个构建阶段

  1. 接下来,我们将添加一个构建我们的 Maven 代码的步骤。点击+ 添加步骤按钮。

  2. 你将被要求从可用步骤列表中选择,如下截图所示:

步骤菜单

  1. 我们的是一个 Maven 项目。因此,我们可能需要先设置 Maven 环境,告诉 Jenkins 可以使用哪个 Java 和 Maven 工具。

  2. 为此,请使用搜索框搜索“提供 Maven 环境”(按名称查找步骤):

选择提供 Maven 环境步骤

并非所有的 Jenkins 插件都与 Jenkins Blue Ocean 兼容。目前这个列表还很小。但预计随着时间的推移会不断增长。

  1. 点击“提供 Maven 环境”步骤时,会显示一个字段配置列表,如下截图所示。在 Maven 字段下键入 M3,其余选项保持不变:

配置提供 Maven 环境步骤

  1. 在配置页面底部,点击+ 添加步骤按钮以创建一个构建我们的 Maven 代码的新子步骤。

  2. 如果你的 Jenkins 主服务器是 Linux 机器,从可用步骤列表中选择 Shell 脚本。如果是 Windows 机器,选择 Windows 批处理脚本。

  3. 在 Shell 脚本/Windows 批处理脚本的文本框中键入以下代码:

        mvn clean install 

配置 shell 脚本子步骤

  1. 点击返回箭头返回到上一个菜单。现在你应该在子步骤部分看到你的新步骤,即 Shell 脚本,如下截图所示:

Shell 脚本作为一个子步骤

  1. 点击返回箭头返回到上一个菜单。

  2. 接下来,让我们创建一个名为 Results 的阶段,在此阶段我们将存档我们构建的构件和 XML 结果报告。 要这样做,请点击可视化流水线上的+按钮。

  3. 您将被要求为新阶段命名。 请在“命名您的阶段”字段下键入Results,如下截图所示:

创建一个结果阶段

  1. 接下来,我们将在新阶段上添加一些步骤。 第一个将是发布我们的测试结果报告的步骤。 要这样做,请点击“+ 添加步骤”按钮。

  2. 从可用步骤列表中选择发布 JUnit 测试结果报告。 您将看到一系列配置选项:

    1. 在“测试结果”字段下添加**/target/surefire-reports/TEST-*.xml

    2. 将其余选项保持不变:

配置发布 JUnit 测试结果报告步骤

  1. 点击返回箭头以返回到上一个菜单。

  2. 再次点击“+ 添加步骤”按钮以添加新步骤。

  3. 从可用步骤列表中选择存档构件。 您将看到一系列配置选项:

    1. 在“构件”字段下添加target/*.jar

    2. 将其余选项保持不变:

配置存档构件步骤

  1. 点击返回箭头以返回到上一个菜单。

  2. 最后,点击页面右上角的保存按钮以保存您的流水线配置。

  3. 弹出窗口将要求您添加一些描述并选择提交流水线配置的分支。

  4. 完成后,点击保存并运行按钮:

保存流水线

  1. 这将立即在相应分支上运行流水线,如下截图所示:

主分支上的成功构建

  1. 您会注意到在主分支下的存储库中创建了一个新文件:

源代码中列出的 Jenkinsfile

  1. 文件内容应为:
pipeline { 
  agent { 
    node { 
      label 'master' 
    } 

  } 
  stages { 
    stage('Build') { 
      steps { 
        withMaven(maven: 'M3') { 
          sh 'mvn clean install' 
        } 

      } 
    } 
    stage('Results') { 
      steps { 
        junit '**/target/surefire-reports/TEST-*.xml' 
        archiveArtifacts 'target/*.jar' 
      } 
    } 
  } 
}

摘要

在前一章中,我们几乎体验了 Jenkins 的所有新功能。 我们选择了适度的示例以保持我们的流水线简单。 然而,在接下来的章节中,我们将学习如何使用 Jenkins 的所有新功能创建一个完整的 CI/CD 流水线。

在下一章中,我们将探讨 Jenkins 中的一些管理任务。

配置 Jenkins

在本章中,我们将学习如何执行一些基本的 Jenkins 管理任务,如下所示:

  • 更新/安装/卸载/降级 Jenkins 插件

  • 手动安装 Jenkins 插件

  • 执行 Jenkins 备份和恢复

  • 在各个平台(Windows/Linux/servlet)上升级 Jenkins

  • 升级运行在 Docker 容器中的 Jenkins

  • 在 Jenkins 中创建和管理用户

  • 在 Jenkins 中学习各种身份验证方法

  • 在 Jenkins 中配置各种授权方法

Jenkins 配置项繁多。 安装的插件越多,需要配置的就越多。 在本章中,我们将仅涵盖 Jenkins 中的基本管理任务。 我们将在接下来的章节中更多地了解 Jenkins 配置,在那里我们将尝试添加更多插件到 Jenkins 以实现持续集成CI)和持续交付CD)。

Jenkins 插件管理器

Jenkins 的大部分功能来自插件。 Jenkins 插件是安装后增强 Jenkins 功能的软件片段。 在 Jenkins 中安装的插件表现为 Jenkins 作业内的参数或可配置项,或者作为声明性流水线语法的步骤下的一部分。

以下截图显示了 Jenkins 系统配置。 这是配置 SonarQube 工具(一个静态代码分析工具)的设置。 只有安装了 SonarQube 的 Jenkins 插件后才能使用相应的配置:

Jenkins 系统配置中的 SonarQube 设置

在 Jenkins 中有一个特殊的部分来管理插件。 在本节中,我们将学习如何使用 Jenkins 插件管理器管理插件:

  1. 从 Jenkins 仪表板中单击管理 Jenkins

  2. 进入管理 Jenkins 页面后,单击管理插件。 您还可以使用<Jenkins URL>/pluginManager链接访问相同的 Jenkins 插件管理器页面。

  3. 您将看到以下四个选项卡:更新、可用、已安装和高级。

更新 Jenkins 插件

更新选项卡列出了所有需要更新的插件,如下图所示:

更新 Jenkins 插件

要更新插件,请通过单击相应复选框选择它,然后单击立即下载并在重启后安装按钮。

要更新更新选项卡下列出的所有插件,请单击页面底部的全部。 这将选择所有插件。 然后,单击立即下载并在重启后安装按钮以安装更新。

更新选项卡上,在页面底部,您会看到一个名为立即检查的按钮。 单击它以刷新在更新选项卡下显示的插件列表。 这将检查插件更新。

安装新的 Jenkins 插件

可用标签列出了所有可用于 Jenkins 的插件。已安装在你的 Jenkins 实例上的插件不会在这里列出。

下面的屏幕截图显示了 Jenkins 的可用插件列表:

插件根据其功能分组

要安装插件,请通过点击其相应复选框来选择它。然后,在页面底部点击立即安装按钮(立即安装插件)或者立即下载并在重启后安装按钮(名字已经很清楚了)。

就像更新标签一样,在这里你也会看到一个名为立即检查的按钮。点击它将刷新可用标签下的插件列表。

卸载或降级 Jenkins 插件

已安装标签列出了当前安装在你的 Jenkins 实例上的所有插件。如下面的屏幕截图所示,你可以看到卸载插件以及降级插件的选项。

如果你的 Jenkins 实例变得不稳定或 CI/CD 流水线在插件更新后没有良好表现,你可以选择降级插件:

已安装的 Jenkins 插件列表

配置 Jenkins 的代理设置

高级标签下,你将看到一个名为 HTTP 代理配置的部分。这是你配置代理设置以便 Jenkins 从互联网获取更新的地方:

HTTP 代理配置设置

如果你的 Jenkins 服务器没有在任何防火墙后面,并且可以直接访问互联网,那么请将这些字段留空。

当你尝试安装或升级 Jenkins 插件时,Jenkins 使用 HTTP 代理配置详细信息。它还使用这些信息来更新“更新”标签和“可用”标签中的 Jenkins 插件列表。

要测试你的代理设置,请按照以下步骤进行:

  1. HTTP 代理配置部分,点击高级...按钮。

  2. 测试 URL字段中添加一个网址,并点击验证代理按钮。

  3. 你应该看到一个消息:成功,如下面的屏幕截图所示。

  4. 点击提交按钮保存设置:

检查代理设置

手动安装 Jenkins 插件

高级标签下,在HTTP 代理配置部分之后,你将看到另一个名为上传插件的部分。它提供了一个安装或升级 Jenkins 插件的功能。

当您的 Jenkins 实例无法访问互联网并且您需要一个新的插件或需要升级现有插件时,此功能非常有用。想象一下,您有一个运行在本地局域网内但无法访问互联网的 Jenkins 实例,或者我们可以说是 Jenkins 的在线插件仓库。在这种情况下,您将首先从在线 Jenkins 仓库下载所需的 Jenkins 插件,然后使用可移动介质将其传输到 Jenkins 主服务器,并最终使用上传插件部分来安装所需的 Jenkins 插件。

让我们尝试按照给定步骤手动安装插件:

  1. 从可以访问互联网的计算机上,打开网站:updates.jenkins-ci.org/download/plugins/

  2. 上述网站包含了所有可用于 Jenkins 的插件列表,如下面的屏幕截图所示:

Jenkins 插件索引

  1. 在以下示例中,我们将安装一个名为logstash的插件。

  2. 在索引页面上,搜索logstash并点击它。

  3. 您将看到相应插件的所有可用版本。点击您需要的版本(我选择安装最新版本):

插件可用版本列表

  1. 这将在您的系统上下载一个.hpi文件。

  2. 下载插件时,同样重要的是下载它的依赖项(其他 Jenkins 插件)。

  3. 必须在安装所需插件之前安装所有依赖项(Jenkins 插件)。

  4. 将此.hpi文件(logstash.hpi)复制到您的 Jenkins 服务器或任何可以访问您的 Jenkins 仪表板的计算机上。

  5. 现在,请登录到您的 Jenkins 服务器。从 Jenkins 仪表板,导航到管理 Jenkins | 管理插件 | 高级

  6. 高级选项卡下的上传插件部分,执行以下操作(如下面的屏幕截图所示):

  7. 单击文件字段下的浏览...按钮。

  8. 从结果窗口中,上传已下载的.hpi文件。

  9. 完成后,点击上传按钮:

手动上传 Jenkins 插件

  1. Jenkins 现在将继续进行插件安装。

Jenkins 备份和恢复

如果有人意外删除了重要的 Jenkins 配置会发生什么?尽管可以通过我们将在用户管理部分中看到的严格的用户权限来避免这种情况,但想象一下这样一种情况:某人正在处理 Jenkins 配置,希望将其恢复到之前稳定的 Jenkins 配置。

从我们目前了解的内容来看,我们知道整个 Jenkins 配置存储在 Jenkins 主目录下。它是C:\jenkins(Windows),/var/jenkins_home(Apache Tomcat),/var/lib/jenkins(Linux)。在接下来的部分中,我们将学习如何使用插件来备份和恢复 Jenkins 配置,即周期性备份插件。

安装周期性备份插件

按照以下步骤安装周期性备份插件:

  1. 从 Jenkins 仪表板上,点击管理 Jenkins | 管理插件

  2. 插件管理器页面上,点击可用选项卡。

  3. 使用过滤器选项,搜索周期性备份,如下面的截图所示:

安装周期性备份插件

  1. 从项目列表中选择周期性备份并点击无需重启安装。你只需要蓝色海洋和其他什么都不需要。

配置周期性备份插件

在我们开始使用之前,我们需要告诉周期性备份插件要备份什么,备份到哪里以及备份频率是多少。按照以下步骤操作:

  1. 从 Jenkins 仪表板转到管理 Jenkins | 周期性备份管理器

  2. 当你第一次访问周期性备份管理器时,你会看到以下通知:

周期性备份插件尚未配置。点击这里进行配置。

  1. 点击单击此处进行配置链接。

  2. 你将被带到周期性备份管理器页面,并且你会发现很多配置选项。让我们逐一查看它们(如下面的截图所示)。

  3. 根目录,<你的 Jenkins 主目录>,是你的 Jenkins 主目录。

  4. 临时目录字段应该是位于 Jenkins 服务器机器上的一个目录。正如其名称所示,该目录用作备份/恢复过程中执行归档/解档操作的临时位置。它可以是任何目录,并且应该位于 Jenkins 主目录之外。

  5. 备份计划(cron)字段是你定义何时或多频繁进行备份的地方。不要将此字段留空。请注意,该字段接受 cron 语法。例如,要每天午夜备份一次,请使用以下不带引号的 cron 语法:0 0 * * *

  6. 验证 cron 语法按钮用于验证你在备份计划(cron)字段中输入的 cron 语法是否正确。

  7. 位置中的最大备份数字段告诉 Jenkins 不要存储大于此处描述的数量的备份。

  8. 存储时间不超过(天)字段告诉 Jenkins 删除任何早于此值的备份。

  9. 文件管理策略下,你有两个选择:仅配置(ConfigOnly)和完全备份(FullBackup)。如果你选择了仅配置选项,Jenkins 将备份 Jenkins 主目录中的所有.xml文件以及所有作业的config.xml文件。但是,如果选择完全备份,则 Jenkins 将备份整个 Jenkins 主目录。

  10. 在 存储策略 下,您有三个选择: NullStorage,TarGzStorage 和 ZipStorage(支持多卷)。您可以选择适合您需求的选项。

  11. 在 备份位置 下,您可以添加多个备份位置来存储您的备份。要这样做,请点击添加位置按钮并选择本地目录。接下来,在 备份目录路径 字段下,添加您希望 Jenkins 存储备份的位置。同时,不要忘记勾选启用此位置复选框。您可以选择多个位置并将它们全部启用。

周期性备份配置

创建 Jenkins 备份

现在我们已经配置了周期性备份插件,让我们运行一个备份以测试我们的设置。为此,请在周期性备份管理器页面上,点击左侧菜单中的立即备份!链接。

在备份进行中,您将在周期性备份管理器页面上看到通知,显示为 Creating backup…。

一旦备份完成,您将在同一页面上看到它列在备份列表中,如下图所示:

备份列表

恢复 Jenkins 备份

现在,让我们测试恢复 Jenkins 备份。但在我们这样做之前,让我们进行一些配置更改,以查看恢复操作是否有效。我们将通过在配置系统页面上进行一些配置更改来实现这一点:

  1. 从 Jenkins 仪表板,点击管理 Jenkins | 配置系统

  2. 配置系统页面上,更改以下字段的值。

  3. 将 # of executors 字段的值从2更改为5

  4. 将安静期字段的值从5更改为10

  5. 点击页面底部的保存按钮。

  6. 现在,让我们将 Jenkins 恢复到上述更改之前的状态。

  7. 从 Jenkins 仪表板,点击管理 Jenkins | 周期性备份管理器

  8. 在结果页面上,选择我们在前一节中创建的备份,并点击恢复选定的备份按钮。

  9. 您将看到以下消息:

恢复备份…

  1. 刷新页面,在 Jenkins 仪表板上点击管理 Jenkins | 配置系统

  2. 您将会发现 # of executors 字段的值为两个,安静期字段的值为五。

查看备份和恢复日志

您可以查看关于 Jenkins 备份和恢复的完整日志。要查看详细日志,请执行以下步骤:

  1. 从 Jenkins 仪表板,点击管理 Jenkins | 系统日志

  2. 在日志页面,转至日志记录器部分,点击org.jenkinsci.plugins.periodicbackup

  3. 您将在此找到备份和恢复操作的完整日志,如下图所示:

Jenkins 周期性备份日志

升级 Jenkins

Jenkins 有两种发布版本:LTS 发布每周发布Jenkins 每周发布 包含新功能和错误修复,而 LTS(长期支持) 发布 是特殊的发布版本,在 12 周的时间内被视为稳定。建议您始终为您的 Jenkins 服务器选择一个 LTS 发布

Jenkins 下载页面

Jenkins 本身会在有新版本可用时通知您(前提是您的 Jenkins 服务器可以访问互联网),如下面的截图所示:

Jenkins 通知有新版本可用

升级运行在 Tomcat 服务器上的 Jenkins

在接下来的部分中,我们将学习如何更新运行在 servlet 内的 Jenkins(Apache Tomcat)。按照给定的步骤操作:

  1. 以 root 用户身份登录到您的 Apache Tomcat 服务器机器。

  2. 使用以下命令在 /tmp 目录下下载最新的(LTS)版本的 jenkins.war

 cd /tmp 
 wget http://mirrors.jenkins.io/war-stable/latest/jenkins.war

要下载特定版本的 Jenkins(LTS),请转到以下链接:mirrors.jenkins.io/war-stable/ 并选择所需的 Jenkins 版本(例如,mirrors.jenkins.io/war-stable/2.73.1/jenkins.war)。

要下载特定版本的 Jenkins(每周发布),请转到以下链接:mirrors.jenkins.io/war/ 并选择所需的 Jenkins 版本(例如,mirrors.jenkins.io/war/2.78/jenkins.war)。

  1. 在我们升级 Jenkins 之前,重要的是我们备份我们的 jenkins_home 目录。请参考创建 Jenkins 备份部分。

在升级 Jenkins 之前始终运行 Jenkins 的备份。

  1. 现在,使用以下命令停止 tomcat 服务:
 systemctl stop tomcat
  1. 接下来,前往当前 jenkins.war 文件所在的位置。在我们的情况下,它是 /opt/tomcat/webapps
 cd /opt/tomcat/webapps/

如果您选择仅使用 Tomcat 服务器运行 Jenkins,则可能在 webapps 目录下找到 ROOT.war 而不是 jenkins.war。请参考在 Apache Tomcat 服务器上独立安装 Jenkins部分,来自第二章,安装 Jenkins

  1. 备份您现有的 jenkins.warROOT.war 并将其放置在 webapps 目录之外的某个位置(例如,/tmp 目录):
 cp jenkins.war /tmp/jenkins.war.last.stable.version

或者:

 cp ROOT.war /tmp/ROOT.war.last.stable.version
  1. 现在,在 webapps 目录内删除当前的 jenkins.warROOT.war 文件:
 rm –r jenkins.war

或者:

 rm –r ROOT.war
  1. 接下来,将您从 /tmp 目录下载的新的 jenkins.war 移动到 webapps 目录。如果您仅使用 Apache Tomcat 服务器运行 Jenkins,则将 destination.war 文件重命名为 ROOT.war
 mv /tmp/jenkins.war /opt/tomcat/webapps/jenkins.war

或者:

 mv /tmp/jenkins.war /opt/tomcat/webapps/ROOT.war
  1. 现在,使用以下命令启动 Tomcat 服务:
 systemctl start tomcat
  1. 登录到您的 Jenkins 实例。要确认 Jenkins 版本,请查看 Jenkins 仪表板的右下角,您将找到一个新的 Jenkins 版本号。

升级运行在 Windows 上的独立 Jenkins

在 Windows 上升级独立 Jenkins 服务器是一个简单的任务。按照给定的步骤进行:

  1. jenkins.io/download/下载最新的jenkins.war。或者,如果您正在寻找要升级到的特定 Jenkins 版本,则从以下链接下载:mirrors.jenkins.io/war-stable/

  2. 在我们升级 Jenkins 之前,重要的是我们备份我们的jenkins_home目录。参考创建 Jenkins 备份部分下的Jenkins 备份和恢复部分。

在升级 Jenkins 之前始终运行 Jenkins 备份。

在 Jenkins 独立实例(运行在 Windows 机器上)上,jenkins.war文件位于jenkins_home目录内。因此,备份jenkins_home目录就足够了。

  1. 接下来,停止 Jenkins 服务。要执行此操作,请从 Windows 运行执行services.msc。这将打开 Windows 服务页面。

  2. 搜索 Jenkins 服务(通常命名为 Jenkins)。停止 Jenkins 服务,如下面的屏幕截图所示:

停止 Jenkins 服务

  1. 或者,您也可以使用以下命令从 Windows 命令提示符(以管理员身份运行)停止 Jenkins 服务:
 net stop Jenkins

输出如下:

 The Jenkins service is stopping.
 The Jenkins service was stopped successfully.
  1. 接下来,将位于C:\Program Files (x86)\Jenkins\下的jenkins.war文件替换为新下载的jenkins.war文件。

  2. 替换jenkins.war文件后,从服务窗口启动 Jenkins 服务,如下面的屏幕截图所示:

启动 Jenkins 服务

  1. 或者,您也可以使用以下命令从 Windows 命令提示符(以管理员身份运行)启动 Jenkins 服务:
 net start Jenkins

输出如下:

 The Jenkins service is starting.
 The Jenkins service was started successfully.
  1. 登录到您的 Jenkins 实例。要确认 Jenkins 版本,请查看 Jenkins 仪表板的右下角,您应该看到一个新的 Jenkins 版本号。

升级运行在 Ubuntu 上的独立 Jenkins

在接下来的章节中,我们将学习如何更新运行在 Ubuntu 上的 Jenkins。按照给定的步骤进行:

  1. 以 root 用户身份登录到您的 Jenkins 服务器机器。

  2. 使用以下命令在/tmp目录下下载最新的(LTS)版本jenkins.war文件:

 cd /tmp 
 wget http://mirrors.jenkins.io/war-stable/latest/jenkins.war

要下载特定版本的 Jenkins(LTS),请转到以下链接:mirrors.jenkins.io/war-stable/,并选择所需的 Jenkins 版本(例如,mirrors.jenkins.io/war-stable/2.73.1/jenkins.war)。

要下载特定版本的 Jenkins(Weekly),请转到以下链接:mirrors.jenkins.io/war/,然后选择所需版本的 Jenkins(例如,mirrors.jenkins.io/war/2.78/jenkins.war)。

  1. 在我们升级 Jenkins 之前,重要的是我们备份我们的jenkins_home目录。参考Jenkins 备份和还原部分下的创建 Jenkins 备份部分。

在升级 Jenkins 之前,始终运行 Jenkins 备份。

  1. 现在,使用以下命令停止jenkins服务:
 systemctl stop jenkins
  1. 接下来,转到当前jenkins.war文件存在的位置。在我们的情况下,它是/usr/share/jenkins/
 cd /usr/share/jenkins/
  1. 对您现有的jenkins.war进行备份,并将其放置在jenkins目录之外的某个地方(例如,/tmp目录):
 cp jenkins.war /tmp/jenkins.war.last.stable.version
  1. 现在,删除jenkins目录中的当前jenkins.war文件:
 rm –r jenkins.war
  1. 接下来,将您从/tmp目录下载的新jenkins.war文件移动到jenkins目录:
 mv /tmp/jenkins.war /usr/share/jenkins/jenkins.war
  1. 现在,使用以下命令启动jenkins服务:
 systemctl start jenkins
  1. 登录到您的 Jenkins 实例。要确认 Jenkins 版本,请查看 Jenkins 仪表板的右下角,您将找到一个新的 Jenkins 版本号。

升级运行在 Docker 容器上的 Jenkins

在下一节中,我们将学习如何更新运行在 Docker 容器内的 Jenkins 实例:

如果您正在使用数据卷为您的jenkins_home目录运行 Jenkins 实例,则以下部分适用。参见第二章中的在 Docker 上运行 Jenkins,使用数据卷运行 Jenkins 容器部分,安装 Jenkins

  1. 登录到您的 Docker 主机机器。

  2. 使用以下命令查找正在运行的 Jenkins 容器:

 sudo docker ps --format "{{.ID}}: {{.Image}} {{.Names}}"

输出如下所示:

 d52829d9da9e: jenkins/jenkins:lts jenkins_prod
  1. 您应该会收到类似于先前片段的输出。注意 Jenkins 容器名称,在我的示例中是jenkins_prod

  2. 我们将使用以下 Docker 命令停止然后删除正在运行的 Jenkins 容器。但是,在您停止和删除 Jenkins 实例之前,请确保 Jenkins 服务器上没有作业在运行:

 sudo docker stop <your jenkins container name>
 sudo docker rm <your jenkins container name>
  1. 使用以下命令列出您的 Docker 主机上可用的 Docker 镜像。您可以看到我们有一个 Jenkins Docker 镜像:jenkins/jenkins:lts。但是,那已经不是最新的了:
 sudo docker images

输出如下所示:

 REPOSITORY        TAG      IMAGE ID        CREATED             SIZE
 jenkins/jenkins   lts      6376a2961aa6    7 weeks ago         810MB
 hello-world       latest   1815c82652c0    3 months ago        1.84kB
  1. 使用以下命令下载最新的 Jenkins Docker 镜像:
 sudo docker image pull jenkins/jenkins:2.73.1

上述命令可能需要一段时间来下载 Jenkins Docker 镜像。

在编写本章时,2.73.1 是最新的 Jenkins 发布版本(LTS)。通过修改命令选择所需版本的 Jenkins。

  1. 下载完成后,再次执行sudo docker images命令,如以下片段所示。注意新的 Jenkins Docker 镜像。在我的示例中,它是jenkins/jenkins:2.73.1
 sudo docker images

输出如下所示:

 REPOSITORY          TAG     IMAGE ID       CREATED             SIZE jenkins/jenkins     2.73.1  c8a24e6775ea   24 hours ago        814MB jenkins/jenkins     lts     6376a2961aa6   7 weeks ago         810MB hello-world         latest  1815c82652c0   3 months ago        1.84kB
  1. 现在让我们使用新下载的 Jenkins Docker 镜像启动一个新的 Jenkins 容器(我们将重用旧的 Jenkins 容器名称):
 sudo docker run -d --name jenkins_prod \
      -p 8080:8080 -p 50000:50000 \ 
      -v jenkins-home-prod:/var/jenkins_home \
      jenkins/jenkins:2.73.1
  1. 以下表格解释了我们之前使用的 Docker 命令:
docker 用于调用 Docker 实用程序。
run 这是一个运行容器的 Docker 命令。
-d 此选项在后台运行容器。
--name 此选项为容器命名。
-p 此选项用于将容器的端口映射到主机。
jenkins/jenkins:2.73.1 用于创建容器的 Docker 镜像及其版本的名称。jenkins/jenkins 是 Jenkins Docker 镜像,2.73.1 是该镜像的特定版本。
  1. 登录到您的 Jenkins 实例。您应该看到所有的作业/设置都完好无损。要确认 Jenkins 版本,请查看 Jenkins 仪表板的右下角,您将找到一个新的 Jenkins 版本号。

用户管理

让我们看看 Jenkins 在用户管理领域提供了什么。从 Jenkins 仪表板中,点击“管理 Jenkins | 配置全局安全”以访问“配置全局安全”页面。

您还可以通过使用 <Jenkins URL>/configureSecurity/ 链接访问“配置全局安全”页面。

在接下来的部分,我们将坚持与用户身份验证和权限相关的选项。我们将在即将到来的章节中查看其他安全选项。

启用/禁用 Jenkins 的全局安全

一旦进入“配置全局安全”页面,您会看到“启用安全性”选项已经启用。应始终将“启用安全性”选项设置为启用状态;禁用它将使 Jenkins 对于任何拥有 Jenkins URL 的人都可访问,而不受任何限制。

启用/禁用计算机记住用户凭据

当用户尝试访问 Jenkins 时,他们将被提供在他们各自的计算机上被记住的选项,如下截图所示:

在此计算机上记住我选项

这个行为默认启用。要禁用此功能,请勾选“禁用记住我”选项,该选项位于“配置全局安全”页面下。

身份验证方法

Jenkins 提供了多种可供选择的身份验证方法。以下是可用选项的列表:

  • 委派给 Servlet 容器

  • Jenkins 自己的用户数据库

  • LDAP

  • Unix 用户/组数据库

Jenkins 的身份验证方法

默认情况下启用了 Jenkins 自己的用户数据库选项。我们在 Jenkins 设置向导期间创建的初始用户都存储在 Jenkins 自己的用户数据库中。没有任何实际的数据库,所有用户信息都保存为 XML 文件。让我们快速查看每种身份验证方法。

委派给 Servlet 容器

该选项仅在您从 servlet 容器(如 Apache Tomcat 等)运行 Jenkins 服务器时才能使用。启用此选项将允许 Jenkins 使用 servlet 容器的领域对用户进行身份验证。

例如,在 第二章的 安装 Jenkins在 servlet 容器中运行 Jenkins 小节下的 配置 Apache Tomcat 服务器 子节中,我们修改了 tomcat-user.xml 文件以创建用户和访问。这是一个UserDatabaseRealm的示例。

这意味着,如果您的 Jenkins 服务器正在 Apache Tomcat 服务器上运行,并且您已配置了UserDatabaseRealm,那么在tomcat-user.xml文件中定义的所有用户都将能够访问 Jenkins。

请参考以下网站,查看 Apache Tomcat 支持的所有领域类型:tomcat.apache.org/tomcat-8.0-doc/realm-howto.html#Standard_Realm_Implementations.

Jenkins 的自有用户数据库

此选项默认启用。在此方案下,Jenkins 将所有用户信息存储在 XML 文件中。这个选项适用于小型组织或者如果您正在探索 Jenkins 并且尚未将其纳入组织。

还有一个选项可以允许用户在登录页面注册。要启用它,请在 Jenkins 的自有用户数据库中选中允许用户注册选项。

这将在 Jenkins 登录页面上启用一个名为创建帐户的链接,如下面的截图所示:

允许用户注册选项

作为新用户,当您点击创建帐户链接时,将要求您填写一些关于自己的基本信息,例如用户名、密码、电子邮件、全名等。一旦您填写完必要信息,就可以访问 Jenkins。

作为新用户,您在 Jenkins 上被允许看到/执行的操作取决于 Jenkins 内的授权设置。我们将在本章后面学习有关授权设置的更多信息。

LDAP

这是大多数组织中最广泛使用的身份验证方法之一。如果在访问控制 | 安全领域部分下未看到LDAP选项,请检查LDAP 插件

如下面的截图所示,以下选项允许 Jenkins 使用 LDAP 服务器对用户进行身份验证。请联系您组织中的 IT 管理团队提供 LDAP 服务器详细信息(如果您的组织使用 LDAP)。

有关 LDAP 配置的更多信息,请参阅 LDAP 插件页面:wiki.jenkins.io/display/JENKINS/LDAP+Plugin

Unix 用户/组数据库

如果 Jenkins 安装在 Unix/Linux 机器上,则以下选项有效。当启用时,Jenkins 将权限委托给底层操作系统。换句话说,配置在底层操作系统上的所有用户/组都可以访问 Jenkins。

您无需在 Jenkins 中配置任何内容即可使此选项生效。但是,底层操作系统上的所有用户都应该能够访问/etc/shadow文件

使用以下命令使/etc/shadow文件对所有用户可访问:

sudo chmod g+r /etc/shadow

在 Jenkins 中创建新用户

如果您使用 Jenkins 自己的用户数据库作为认证方法,则以下部分仅适用。执行以下步骤手动将用户添加到您的 Jenkins 服务器中。

  1. 从 Jenkins 仪表板中,单击管理 Jenkins | 管理用户

  2. 管理用户页面上,从左侧菜单中,单击创建用户

  3. 在结果页面上,您将被要求提供有关用户的一些基本信息,如下图所示:

在 Jenkins 中创建用户

  1. 填写相应值的字段,然后单击创建用户按钮。

只有在使用 Jenkins 自己的用户数据库作为认证方法时,才会提供“管理用户”链接。

人员页面

人员页面显示所有可以访问 Jenkins 服务器的用户,如下图所示:

Jenkins 人员页面

Jenkins 中的用户信息和设置

单击任何特定用户 ID 或名称(参见下图)以获取有关相应用户的信息。您将被带到用户状态页面,如下图所示:

用户状态页面

在用户的状态页面的左侧菜单中,您将看到以下选项:状态构建配置我的视图凭据。让我们详细探讨其中一些:

  • 构建页面将显示由当前用户运行的所有 Jenkins 构建的信息。

  • 我的视图页面将带您进入当前用户可以访问的视图。如果没有为当前用户配置视图,则我的视图页面将显示默认的全部视图(Jenkins 仪表板)。

  • 凭据链接将带您进入凭据页面。但是,凭据页面将显示与当前用户相关的其他信息,如下图所示:

Jenkins 凭据作用域限制为一个用户

授权方法

Jenkins 提供了各种授权方法供选择。以下是可用选项的列表:

  • 任何人都可以做任何事情

  • 传统模式

  • 已登录用户可以做任何事情

  • 基于矩阵的

  • 基于项目的矩阵授权策略

默认情况下启用了已登录用户可以做任何事情选项。让我们快速浏览一下每种授权方法。

要访问 Jenkins 授权设置,请从 Jenkins 仪表板导航到管理 Jenkins | 配置全局安全 | 访问控制

任何人都可以做任何事

当您选择此选项时,Jenkins 不执行任何授权。任何具有对 Jenkins 的访问权限的人都可以获得完全控制权,包括匿名用户。不推荐此选项。

兼容模式

当您选择此选项时,Jenkins 的行为方式与发布 1.164 版之前的方式相同。简单来说,Jenkins 将寻找一个名为Admin的用户(无论您使用的是什么身份验证方法)。这个Admin用户将被赋予管理员特权,而其余用户将被视为匿名用户。再次强调,不推荐此选项。

已登录用户可以做任何事

这是您安装和设置新 Jenkins 服务器时 Jenkins 默认附带的身份验证设置。名称不言自明,即已登录用户默认为管理员。同样,不推荐此选项。

已登录用户可以做任何事字段下,有一个名为允许匿名读取访问的选项(默认情况下已禁用)。当选中(启用)此选项时,任何具有对 Jenkins URL 的访问权限的人都将直接进入 Jenkins 仪表板,具有对所有 Jenkins 作业的只读访问权限。但是,您需要登录才能编辑 Jenkins 作业或查看 Jenkins 的配置。

基于矩阵的安全性

这是 Jenkins 中最广泛使用的授权方法之一。让我们通过以下步骤详细探讨它:

  1. 通过选择它启用基于矩阵的安全授权方法。您将看到以下矩阵:

基于矩阵的安全配置

  1. 从前面的屏幕截图中,您可以看到列代表 Jenkins 中的各种项目,而行代表各种用户。在矩阵底部有一个选项可添加用户。

  2. 让我们添加一些用户并为他们提供一些权限。

  3. 要添加用户,请在要添加的用户/组字段中输入用户的确切用户名,然后单击添加按钮。

  4. 您可以从以下屏幕截图中看到,我已添加了四个用户(请参阅People page部分以查看您可以在此处添加的用户列表)。如果您正在使用 Jenkins 的自己的用户数据库,则创建一些用户(请参阅在 Jenkins 内部创建新用户部分):

将用户添加到矩阵中

  1. 现在,让我们通过选择适当的复选框为它们授予权限。您可以从以下屏幕截图中看到,我已经给用户jenkins_admin完全访问权限。用户jenkins_developerjenkins_tester已被授予读取和执行 Jenkins 作业的访问权限,而用户jenkins_user仅被授予读取权限:

使用矩阵提供权限

  1. 将其余设置保持不变,然后单击页面底部的保存按钮。

  2. 为了检查配置,请以每个用户的身份登录,并确认在 Jenkins 仪表板上看到的内容。

基于项目的矩阵授权策略

在前一节中,我们看到了基于矩阵的安全授权功能,它使我们对用户和权限有了相当大的控制能力。

但是,想象一种情况,你的 Jenkins 服务器已经发展到包含数百个 Jenkins 作业和许多用户的阶段,并且你希望在作业级别(项目级别)上控制用户权限。

在这种情况下,我们需要基于项目的矩阵授权策略:

作业级别的用户权限

让我们学习如何配置基于项目的矩阵授权策略。执行以下步骤:

  1. 要访问 Jenkins 授权设置,请从 Jenkins 仪表板导航到管理 Jenkins | 配置全局安全 | 访问控制

  2. 选择基于项目的矩阵授权策略选项。你将看到以下矩阵:

基于项目矩阵授权策略配置

  1. 现在,添加一个用户并给予其完全权限。要添加用户,请在“要添加的用户/组”字段中输入用户的完整用户名,然后单击“添加”按钮。

  2. 从以下屏幕截图中可以看到,我为用户jenkins_admin添加了完全权限:

将用户添加到矩阵中

  1. 将其余设置保持不变,然后单击页面底部的保存按钮。

  2. 接下来,在 Jenkins 仪表板上右键单击任何一个 Jenkins 作业,然后选择配置

  3. 在作业配置页面,向下滚动到启用基于项目的安全选项并启用它。

  4. 当你启用基于项目的安全性时,将出现一个矩阵表格,如以下屏幕截图所示:

Jenkins 作业中的基于项目的安全配置

  1. 让我们添加一些用户并为他们分配权限。

  2. 要添加用户,请在“要添加的用户/组”字段中输入用户的完整用户名,然后单击“添加”按钮。

  3. 从以下屏幕截图中可以看到,我给用户jenkins_developer添加了一些权限:

使用矩阵提供权限

  1. 完成后,单击页面底部的保存按钮。

  2. 现在以刚刚为相应的 Jenkins 作业赋予权限的用户登录(在我们的示例中为jenkins_developer)。

  3. 你会发现用户只能看到它具有访问权限的 Jenkins 作业。

  4. 同样,你可以在 Jenkins 中为你创建的每个作业配置用户权限。

概要

在本章中,我们看到了如何通过一些实际示例来配置 Jenkins 中的一些基本但重要的元素。Jenkins 升级、Jenkins 备份和 Jenkins 用户管理是本章中我们学到的一些重要内容。

下一章将介绍 Jenkins 主从架构以及 Jenkins 分布式构建系统

分布式构建

Jenkins 的主从架构使得在多个从机器上分发工作变得更容易。本章节主要讨论在不同平台配置 Jenkins 从节点的相关内容。以下是我们将要涵盖的主题:

  • Jenkins 节点管理器概览

  • 在独立的 Linux 机器上安装 Jenkins 从节点

  • 在独立的 Windows 机器上安装 Jenkins 从节点

  • 安装和配置 Docker 插件用于创建按需的 Jenkins 从节点

分布式构建和测试

在接下来的章节中,让我们简单了解一下分布式构建和测试。想象一下,你有一个非常庞大的单元测试或集成测试套件。如果你可以将它们分为小部分,然后并行运行,那就可以了。要并行运行它们,你需要多个克隆的构建/测试机器。如果你已经设置好了,无论是使用 Docker 还是其他机制,那么剩下的就是将它们变成 Jenkins 从节点代理了。

以下示例展示了 Jenkins 流水线如何利用 Jenkins 中的分布式构建/测试农场进行构建、单元测试和集成测试。你会看到,我们有两类 Jenkins 从节点代理:用于构建和单元测试的独立 Jenkins 从节点,以及用于集成测试的独立 Jenkins 从节点。

单元测试分布在三个用于构建和单元测试的 Jenkins 从节点代理中(第一类),而集成测试分布在两个用于集成测试的 Jenkins 从节点代理中(第二类)。

使用 Jenkins 独立从节点进行分布式构建和测试

Jenkins 从节点代理使用标签进行分类。我们将在接下来的章节中详细了解标签的内容。

使用 Docker 按需生成 Jenkins 从节点也更好、更容易。如下图所示,这是我们之前讨论的相同概念的 Docker 版本。这里使用 Docker 镜像按需创建 Jenkins 从节点。

你可以看到在以下示例中,我们有两种类型的 Docker 镜像:用于构建和单元测试的 Docker 镜像,以及用于集成测试的 Docker 镜像。这些 Docker 从节点代理是使用这些 Docker 镜像创建的。单元测试分布在三个用于构建和单元测试的 Docker 从节点代理中(第一类),而集成测试则分布在两个用于集成测试的 Docker 从节点代理中(第二类)。

同样在这里,Docker 从节点代理使用标签进行分类。我们将在接下来的章节中详细了解标签的内容:

使用 Jenkins 和 Docker 从节点代理进行分布式构建和测试

Jenkins 管理节点页面

在接下来的章节中,我们将看一下 Jenkins 管理节点页面:

  1. 从 Jenkins 仪表盘上,点击管理 Jenkins | 管理节点

  2. 在左侧,你会看到一个菜单;选项如以下截图所示:

Jenkins 管理节点页面

  1. 在右侧,您还将看到一个显示可用 Jenkins 从机列表的表格,如下截图所示:

可用节点列表

  1. 由于我们尚未配置任何 Jenkins 从机,列表(如前面的截图所示)只包含一个条目:即主机。

  2. 表格除了节点的名称外,还显示有关节点的其他有用信息,例如架构、可用磁盘空间量和响应时间。

  3. 要启用/禁用有关每个节点显示的信息量,点击配置链接(请参阅Jenkins 管理节点页面截图)。这将带您前往下一页,如下截图所示:

预防性节点监控选项

  1. 选中/取消选中相关选项以启用/禁用它们。“空闲空间阈值”选项很重要。如果可用磁盘空间和临时空间的空闲量低于指定值(默认为1GB),则节点将离线。这可以防止 Jenkins 流水线在磁盘空间不足的从机上运行导致最终失败。

添加 Jenkins 从机 – 独立的 Linux 机器/虚拟机

在接下来的部分,我们将尝试将一个独立的 Linux 机器添加为 Jenkins 从机。确保您即将添加的 Jenkins 从机上已安装了 Java。按照以下步骤操作:

  1. 从 Jenkins 仪表板中,点击管理 Jenkins | 管理节点

  2. 从左侧菜单中,点击新建节点。在生成的页面上,您将被要求为您的节点提供一个名称并选择类型,如下截图所示:

添加名称和选择代理类型(从机类型)

  1. 节点名称字段下添加一个有意义的名称,并选择代理类型。目前,只有一种类型的代理可供选择:即永久代理。这些代理主要是物理机器和虚拟机。

  2. 点击确定按钮继续。

  3. 在生成的页面上,您将看到以下配置选项,如下截图所示:

Jenkins 从机配置

让我们逐一查看它们:

  1. 我们已经使用了“名称”字段为我们的 Jenkins 从机命名。

  2. 使用“描述”字段添加有关 Jenkins 从机的一些注释:例如,用途、类型、可构建或测试的内容以及已安装的工具。

  3. “执行器数量”字段用于描述 Jenkins 从机(代理)被允许同时运行的平行构建数量。选择大于1的值,比如3,将允许 Jenkins 从机并行运行三个构建。这可能导致每个构建所需时间比平常长。请明智选择。

  4. 远程根目录字段 用于定义 Jenkins 从机上的目录路径,该路径将作为 Jenkins 执行构建活动的专用工作空间。

  5. 标签字段 是最重要的。您可以向 Jenkins 从机添加多个标签(用空格分隔)。为了在特定的从机上运行流水线,您将使用其标签,如前面的屏幕截图所示。我们添加了一个 maven-build-1 标签,表示它是一个 Jenkins 从机用于构建 Maven 项目。

  6. 使用字段 用于定义 Jenkins 如何在此节点上安排构建。它包含两个选项,如下所示:

    • 尽可能使用此节点:这是默认选项。此模式使当前 Jenkins 从机对所有未配置为在特定 Jenkins 从机上运行的流水线开放。

    • 仅构建与该节点匹配标签表达式的作业:在此模式下,Jenkins 将仅在此节点上构建项目,当该项目被限制在特定节点上使用标签表达式,并且该表达式与此节点的名称和/或标签匹配时。

  7. 启动方法字段 描述了 Jenkins 如何启动此 Jenkins 从机。它包含四个选项,如下所示。在下面的示例中,我们将使用 SSH 方法启动我们的 Jenkins 从机。请参阅 通过 SSH 启动 Jenkins 从机 部分:

    • 通过 Java Web Start 启动代理:这允许使用 Java Web Start 启动代理。在这种情况下,必须在代理机器上打开一个 Java 网络启动协议(JNLP)文件,该文件将建立到 Jenkins 主机的 TCP 连接。如果您通过配置全局安全页面启用了安全性,您可以自定义 Jenkins 主机将监听传入 JNLP 代理连接的端口。

    • 通过在主机上执行命令来启动代理:这通过让 Jenkins 从主机执行一个命令来启动一个代理。当主机能够在另一台机器上远程执行进程时,例如,通过 SSH 或远程 shell(RSH)时,使用此选项。

    • 通过 SSH 启动从机代理:这通过安全的 SSH 连接发送命令来启动从机代理。从机需要从主机可达,并且您将需要提供一个可以登录目标机器的帐户。不需要 root 权限。

    • 让 Jenkins 作为 Windows 服务控制此 Windows 从机:这通过内置到 Windows 中的远程管理设施启动 Windows 从机。适用于管理 Windows 从机。从机需要从主机可达。

  8. 可用性字段定义了 Jenkins 如何启动、停止和使用 Jenkins 从机。它有三个选项,如下所示:

    • 尽可能保持此代理在线:在此模式下,Jenkins 将尽可能保持此代理在线。如果代理下线,例如,由于临时网络故障,Jenkins 将定期尝试重新启动它。

    • 在特定时间在线和离线此代理:在此模式下,Jenkins 将在预定时间将此代理上线,保持在线一段指定时间。如果代理在预定上线时间内离线,Jenkins 将定期尝试重新启动它。在此代理在线时间达到“预定上线时间”字段指定的分钟数后,它将被下线。如果选中了“在构建运行时保持在线”复选框,并且预定将代理下线,Jenkins 将等待正在进行的任何构建完成。

    • 当需求时上线此代理,并在空闲时下线:在此模式下,如果有需求,即如果有排队构建符合以下条件:它们至少已在队列中等待指定的需求延迟时间段

    • 它们可以由此代理执行(例如,具有匹配的标签表达式)

如果:

      • 此代理上没有正在运行的活动构建

      • 此代理至少已处于指定的空闲延迟时间段中空闲

将环境变量传递给 Jenkins 的节点

按照给定的步骤传递环境变量:

  1. 你将看到一个名为节点属性的部分。使用这些选项,你可以将预定义的环境变量传递给 Jenkins 的节点和工具位置。

  2. 如下图所示,你可以将环境变量传递给 Jenkins 的节点。可以传递多个环境变量(通过点击添加按钮)。这些环境变量在 Jenkins 管道执行期间可用:

将环境变量传递给 Jenkins 的节点

随着 Jenkins 中 Pipeline as Code 功能的推出,可以在 Jenkins 管道代码(管道脚本/Jenkinsfile)中定义和使用环境变量。因此,定义环境变量选项(如前面的截图所示)变得不太重要。

将工具位置传递给 Jenkins 的节点

如下图所示,你可以指定 Jenkins 节点上某些工具的位置,覆盖全局配置:

将工具位置传递给 Jenkins 的节点

通过 SSH 启动 Jenkins 节点代理

要通过 SSH 启动节点代理,请按照以下步骤:

  1. 当你选择通过 SSH 启动节点代理选项时,会出现以下选项,如下图所示。

  2. 主机字段是你可以定义 Jenkins 节点代理机器的 IP 地址或主机名的地方。

  3. 凭据字段允许你选择保存在 Jenkins 内的相关凭据,以验证 Jenkins 节点代理。要创建新凭据,请点击凭据字段旁边的“添加”按钮(创建一个用户名和密码类型的凭据):

配置通过 SSH 属性启动从属代理

您用于验证 Jenkins 从属代理的用户应该对远程根目录字段下定义的目录路径具有读/写权限。

  1. 最后一个选项,主机密钥验证策略,定义了 Jenkins 在连接时验证远程主机呈现的 SSH 密钥的方式。此选项仅在使用以下凭据时有效:种类:SSH 用户名与私钥。有四个可用选项,如下所示:

    • 已知主机文件验证策略:这将检查用户 Jenkins 在其下执行的 known_hosts 文件(~/.ssh/known_hosts),以查看是否存在与当前连接匹配的条目。此方法不会对 known_hosts 文件进行任何更新,而是将文件用作只读源,并期望拥有适当访问权限的人员根据需要更新文件,可能使用 ssh 主机名 命令启动连接并适当地更新文件。

    • 手动提供密钥验证策略:这检查远程主机提供的密钥是否与配置此连接的用户设置的密钥匹配。

    • 已知受信任密钥验证策略:这将检查远程密钥是否与当前为此主机标记为受信任的密钥匹配。根据配置,密钥将自动受信任于第一次连接,或者将要求授权用户批准该密钥。将要求授权用户批准远程主机呈现的任何新密钥。

    • 无验证验证策略:这不对远程主机呈现的 SSH 密钥执行任何验证,允许所有连接,而不管它们呈现的密钥是什么。

  2. 一旦您完成了所有选项的配置,请单击保存按钮。

关于活动 Jenkins 从属代理的更多信息

在接下来的部分,我们将看看我们刚刚添加的 Jenkins 从属代理可用的各种其他可配置选项。Jenkins 还提供了关于其从属代理的许多常规信息,我们将在这里看到。按照以下步骤:

  1. 从 Jenkins 仪表板中,单击管理 Jenkins | 管理节点。

  2. 在右侧,您还将看到一个表格,其中显示了可用的 Jenkins 从属代理列表。新添加到列表中的是我们新添加的 Jenkins 从属代理。

  3. 单击 Jenkins 从属代理名称以访问其配置和元数据。

  4. 在结果页面(Jenkins 从属代理状态页面)上,您将在左侧菜单中看到一些选项,如下图所示:

img/0110ad53-fefb-415b-b8c1-07a7259ca3b2.png

Jenkins 从属代理页面

  1. 大多数前述链接(来自前述屏幕截图)是不言自明的。但是,让我们详细查看其中一些。

  2. 日志链接是您将找到与 Jenkins 从属节点相关的所有日志的地方。在添加 Jenkins 从属节点后,如果它没有上线,您需要查看日志。连接到 Jenkins 从属节点时遇到的认证问题、权限问题以及其他所有问题都会在此列出。请参阅以下屏幕截图:

Jenkins 从属节点日志

  1. 系统信息链接将向您显示有关相应 Jenkins 从属节点的大多数系统信息,例如系统属性和环境变量。请参阅上述屏幕截图。您不会经常访问此处。尽管如此,在调试由于系统工具、环境变量等引起的构建错误时,这很有用:

Jenkins 从属节点系统信息

  1. 构建历史链接将向您显示在相应的 Jenkins 从属节点上执行的所有构建的时间线。

  2. 在 Jenkins 从属节点状态页面上,您将看到附加到相应 Jenkins 从属节点的标签,以及与以下 Jenkins 从属节点关联的项目的信息。请参阅以下屏幕截图:

Jenkins 从属节点状态页面

  1. 有一个选项可以通过点击“将此节点暂时脱机”按钮将 Jenkins 从属节点临时脱机。当您点击该按钮时,将会要求您在将 Jenkins 从属节点脱机之前添加一个注释(可选):

使 Jenkins 从属节点脱机

  1. 要将脱机节点重新上线,请从 Jenkins 状态页面上点击“使此节点重新上线”按钮:

启动 Jenkins 从属节点

添加 Jenkins 从属节点 – 独立的 Windows 机器/虚拟机

在以下部分,我们将尝试将独立的 Windows 机器添加为 Jenkins 从属节点。确保您的即将成为 Jenkins 从属节点的机器上已安装了 Java。按照以下步骤操作:

  1. 从左侧菜单中,点击“新建节点”。在生成的页面上,您将被要求为您的节点提供名称并选择类型,如下面的屏幕截图所示:

  2. 从 Jenkins 仪表板中,点击管理 Jenkins | 管理节点

添加名称并选择代理类型(从属类型)

  1. 在“节点名称”字段下添加有意义的名称,并将代理类型选择为永久代理。这些代理类型主要是物理机器和虚拟机。还有一种选项可以克隆现有的 Jenkins 从属节点。要这样做,请选择“复制现有节点”选项,并在“从字段”下输入 Jenkins 从属节点源的名称。

  2. 然而,在以下示例中,我们将选择永久代理选项。

  3. 单击“确定”按钮继续。

  4. 在生成的页面上,您将看到以下配置选项,如下面的屏幕截图所示。我们已经在之前看过它们:

Jenkins 从节点配置

  1. 由于这是一个 Windows 构建代理,我们有两种方式可以启动 Jenkins 从节点,如下所示:

    • 通过 Java Web Start 启动代理:这允许使用 Java Web Start 启动代理。在这种情况下,必须在代理机器上打开一个 JNLP 文件,该文件将建立到 Jenkins 主服务器的 TCP 连接。如果您通过配置全局安全性页面启用了安全性,您可以自定义 Jenkins 主服务器将监听传入 JNLP 代理连接的端口。

    • 让 Jenkins 作为 Windows 服务控制此 Windows 从节点:这将通过 Windows 内置的远程管理功能启动 Windows 从节点。适用于管理 Windows 从节点。从节点需要从主服务器可达的 IP。

通过 Java Web Start 启动 Jenkins 从节点

在下一节中,我们将学习如何使用 Java Web Start 方法在 Windows 上启动 Jenkins 从节点。

  1. 对于 启动方法 字段,请选择通过 Java Web Start 启动代理。

  2. 点击保存按钮。

  3. 从 Jenkins 管理节点页面,点击 Jenkins 从节点名称。在我们的示例中,它是standalone-windows-slave

  4. 在结果页面(Jenkins 从节点状态页面)上,您将看到以下选项,如下所示:

Jenkins 从节点连接方法(Java Web Start)

  1. 在 Jenkins 服务器上不执行任何操作。

  2. 现在,登录到您准备用作 Jenkins 从节点的机器(Windows)并打开 Jenkins 仪表板。

  3. 从 Jenkins 仪表板,点击管理 Jenkins | 管理节点。

  4. 从 Jenkins 管理节点页面,点击 Jenkins 从节点名称。在我们的示例中,它是standalone-windows-slave

  5. 现在,要么按照以下截图中所示运行命令,要么点击启动按钮。

  6. 如果选择点击启动按钮,则会看到以下弹出窗口,如下截图所示:

打开 slave-agent.jnlp 文件

  1. 选择 打开方式 选项为 Java(TM) Web Start Launcher(默认)选项,然后点击 确定按钮。

  2. 您将收到另一个弹出窗口,询问您是否希望运行此应用程序。如下截图所示,点击运行:

运行 Jenkins 远程代理

  1. 最后,您将看到一个小窗口显示 Jenkins 从节点连接状态为已连接,如下截图所示:

Jenkins 从节点代理窗口。

  1. 您的 Jenkins 从节点(Windows)现在已连接。要将其作为 Windows 服务,点击文件(上一张截图),然后选择安装为服务。

  2. 打开运行实用程序并输入命令services.msc以打开 Windows 服务实用程序。在服务列表中,您会发现 Jenkins 从节点代理服务,如下截图所示:

Jenkins 从节点列为 Windows 服务。

  1. 右键单击 Jenkins 从机 Windows 服务,选择属性。

  2. 在属性窗口中,转到登录选项卡。在登录为部分下,选择此账户选项,并提供管理员账户的详细信息(在 Jenkins 从机上具有管理员特权的用户),如下截图所示:

Jenkins 从机服务属性

  1. 您的 Jenkins 从机(Windows 上)现已安装。

添加 Jenkins 从机 - Docker 容器

在接下来的部分中,我们将学习如何安装和配置 Docker 插件,该插件将允许我们从 CI 流水线生成按需的 Jenkins 从机(Docker 容器)。 Docker 容器由 CI 流水线启动,一旦构建完成,它们将被销毁。在接下来的部分中,我们只会看到配置部分。在下一章中,我们将看到这个过程的实际运行。

先决条件

在我们开始之前,请确保您准备好以下内容:

  • 在以下任一平台上运行 Jenkins 服务器:Docker、独立、云、虚拟机、servlet 容器等(参考第二章,安装 Jenkins)。

  • 您的 Jenkins 服务器应该有访问互联网的权限。这是下载和安装插件所必需的。

  • 您的 Jenkins 服务器可以使用 GitHub 插件与 GitHub 进行交互(请参考第三章中的在 Jenkins 中添加 GitHub 凭证从 Jenkins 配置 GitHub 上的 Webhooks部分, 全新的 Jenkins)。

  • 您的 Jenkins 服务器还可能需要配置 Java、Git 和 Maven。(请参考第三章中全局工具配置页面部分下的全新 Jenkins 流水线任务子部分, 全新的 Jenkins)。

  • 一个 Docker 服务器。

设置 Docker 服务器

要安装 Docker,您需要拥有以下 Ubuntu 操作系统之一(64 位)的计算机:Yakkety Yak 16.10、Xenial Xerus 16.04 或 Trusty Tahr 14.04。确保还安装了curl。按照给定的步骤设置 Docker 服务器。

设置仓库

按照以下给出的步骤设置仓库:

  1. 执行以下命令让apt使用一个仓库:
 sudo apt-get install apt-transport-https ca-certificates
  1. 使用以下命令添加 Docker 的官方 GPG 密钥:
 curl -fsSL https://yum.dockerproject.org/gpg | sudo apt-key add -
  1. 验证密钥 ID 是否完全是58118E89F3A912897C070ADBF76221572C52609D,使用以下命令:
 apt-key fingerprint 58118E89F3A912897C070ADBF76221572C52609D
  1. 您应该看到类似的输出:
 pub 4096R/2C52609D 2015-07-14
 Key fingerprint = 5811 8E89 F3A9 1289 7C07 0ADB F762 2157 2C52 609D
 Uid Docker Release Tool (releasedocker) docker@docker.com
  1. 使用以下命令设置一个稳定的仓库来下载 Docker:
 sudo add-apt-repository \
        "deb https://apt.dockerproject.org/repo/ubuntu-$(lsb_release -cs) \
        main"

建议始终使用仓库的稳定版本。

使用 apt-get 安装 Docker

现在您已经设置好了仓库,请执行以下步骤安装 Docker:

  1. 使用以下命令更新apt软件包索引:
 sudo apt-get update
  1. 要安装最新版本的 Docker,请执行以下命令:
 sudo apt-get -y install docker-engine
  1. 然而,如果您希望安装特定版本的 Docker,请执行以下命令:
 apt-cache madison docker-engine
  1. 这将给出可用版本的列表:
 docker-engine | 1.16.0-0~trusty |
        https://apt.dockerproject.org/repo
        ubuntu-trusty/main amd64 Packages
 docker-engine | 1.13.3-0~trusty |
        https://apt.dockerproject.org/repo
        ubuntu-trusty/main amd64 Packages 

前面命令的输出取决于在前一部分配置的仓库类型,即设置仓库

  1. 接下来,执行以下命令来安装特定版本的 Docker:
 sudo apt-get -y install docker-engine=<VERSION_STRING>

例子:sudo apt-get -y install docker-engine=1.16.0-0~trusty

  1. docker服务会自动启动。要验证 Docker 是否已安装并运行,请运行以下命令:
 sudo docker run hello-world 
  1. 如果前面的命令运行没有任何错误,并且你看到了hello world消息,那意味着 Docker 已经安装并运行。
 Hello from Docker!
 This message shows that your installation appears to be
        working correctly.

使用 .deb 软件包安装 Docker

如果由于某些原因,你无法使用上述的仓库方法安装 Docker,你可以下载.deb包。

  1. apt.dockerproject.org/repo/pool/main/d/docker-engine/下载你选择的.deb软件包。

  2. 要安装下载的软件包,请输入以下内容:

 sudo dpkg -i /<path to package>/<docker package>.deb
  1. 运行以下命令验证你的 Docker 安装:
 sudo docker run hello-world
  1. 如果前面的命令运行没有任何错误,并且你看到了hello world消息,那意味着 Docker 已经安装并运行。
 Hello from Docker!
 This message shows that your installation appears to be
        working correctly.

启用 Docker 远程 API

Jenkins(通过 Docker 插件)使用Docker 远程 API与 Docker 服务器进行通信。Docker 远程 API 允许外部应用程序使用 REST API 与 Docker 服务器通信。Docker 远程 API 也可以用于获取 Docker 服务器内所有运行的容器的信息。

要启用 Docker 远程 API,我们需要修改 Docker 的配置文件。根据你的操作系统版本和在你的计算机上安装 Docker 的方式,你可能需要选择正确的配置文件进行修改。以下是适用于 Ubuntu 的两种方法。

修改 docker.conf 文件

遵循以下步骤修改 docker.conf 文件。这些配置是允许 Jenkins 与 Docker 主机通信的重要配置:

  1. 登录到你的 Docker 服务器,确保你有sudo权限。

  2. 执行以下命令来编辑docker.conf文件:

 sudo nano /etc/init/docker.conf
  1. docker.conf 文件中,找到包含 DOCKER_OPTS=的行。

你会在 docker.conf 文件中找到两处包含DOCKER_OPTS=变量的地方。首先,在预启动脚本部分,然后在后启动脚本部分。在预启动脚本部分使用DOCKER_OPTS=变量。

  1. DOCKER_OPTS的值设置为以下内容:
        DOCKER_OPTS='-H tcp://0.0.0.0:4243 -H unix:///var/run/docker.sock'
  1. 前面的设置将将 Docker 服务器绑定到 Unix 套接字,以及 TCP 端口42430.0.0.0,这使得 Docker 引擎接受来自任何地方的连接。

如果你希望你的 Docker 服务器仅接受来自你的 Jenkins 服务器的连接,则将0.0.0.0替换为你的 Jenkins 服务器 IP。

  1. 使用以下命令重新启动 Docker 服务器:
 sudo service docker restart
  1. 要检查配置是否生效,请输入以下内容:
 curl -X GET http://<Docker server IP>:4243/images/json

前面的命令将列出 Docker 服务器上存在的所有镜像,如果有的话。

修改 docker.service 文件

按照以下步骤修改docker.service文件:

  1. 执行以下命令编辑docker.service文件:
 sudo nano /lib/systemd/system/docker.service
  1. docker.service文件中,转到包含ExecStart=的行。

  2. ExecStart=的值设置如下:

        ExecStart=/usr/bin/docker daemon -H fd:// -H tcp://0.0.0.0:4243
  1. 上述设置将 Docker 服务器绑定到 Unix 套接字。此外,在 TCP 端口4243上。0.0.0.0,它使 Docker 引擎接受来自任何地方的连接。

如果您希望您的 Docker 服务器仅接受来自您的 Jenkins 服务器的连接,请将0.0.0.0替换为您的 Jenkins 服务器 IP。

  1. 执行以下命令使 Docker 守护进程注意到修改后的配置:
 systemctl daemon-reload
  1. 使用以下命令重新启动 Docker 服务器:
 sudo service docker restart
  1. 要检查配置是否生效,请输入以下内容:
 curl -X GET http://<Docker server IP>:4243/images/json

如果有的话,上述命令将列出您的 Docker 服务器上存在的所有镜像。

安装 Docker 插件

要动态创建 Docker 容器(构建代理),我们需要为 Jenkins 安装 Docker 插件。为此,请按照以下步骤操作:

  1. 从 Jenkins 仪表板中,单击“管理 Jenkins | 管理插件 | 可用”选项卡。您将进入 Jenkins 管理插件页面。

  2. 在过滤字段中输入Docker Plugin,如下截图所示:

安装 Docker 插件

  1. 从列表中选择Docker 插件,然后单击无需重启安装按钮。

  2. 如果需要,请重新启动 Jenkins。

配置 Docker 插件

现在我们已经安装了 Docker 插件,让我们对其进行配置:

  1. 从 Jenkins 仪表板中,单击“管理 Jenkins | 配置系统”。

  2. 一旦进入配置系统页面,请滚动到底部的 Cloud 部分(参见下图)。

  3. 单击“添加新云”按钮,然后从可用选项中选择 Docker。

  4. 在结果页面上,您将找到许多要配置的设置。

  5. 使用“名称”字段为您的 Docker 服务器命名。

  6. 在 Docker URL 字段下添加您的 Docker 服务器 URL。

  7. 单击“测试连接”按钮以检查 Jenkins 是否可以与 Docker 服务器通信:

配置 Docker 插件以与 Docker 服务器通信

  1. 在页面底部,单击应用保存按钮。稍后我们会再次回到这里进行进一步的配置。

创建 Docker 镜像 - Jenkins 从属

启用 Docker 远程 API 使 Jenkins 与 Docker 服务器之间的通信成为可能。现在我们需要在 Docker 服务器上有一个 Docker 镜像。Jenkins 将使用此 Docker 镜像动态创建 Docker 容器(Jenkins 从属)。为此,请按照如下步骤操作:

  1. 登录到您的 Docker 服务器。输入以下命令以检查可用的 Docker 镜像:
 sudo docker images
  1. 从下图中,您可以看到我们的 Docker 服务器上已经有两个docker imagesubuntuhello-world):

列出 Docker 镜像

  1. 如果您的 Docker 服务器是一台刚刚备份的机器,则此时您将看不到任何镜像。

  2. 我们将从ubuntu Docker 镜像构建一个用于我们的用途的 Docker 镜像。为此,请使用以下命令下载ubuntu的 Docker 镜像:

 docker pull ubuntu

您可以在hub.docker.com/找到更多不同操作系统的 Docker 镜像。

  1. 拉取完成后,再次执行sudo docker images命令。现在,您应该可以看到一个用于 Ubuntu 的 Docker 镜像,如前面的截图所示。

  2. 现在,我们将使用我们需要运行构建所需的所有必要应用程序来升级我们的 Ubuntu Docker 镜像。它们如下所示:

    • Java JDK(最新版本)

    • Git

    • Maven

    • 用于登录到 Docker 容器的用户账户

    • sshd(用于接受 SSH 连接)

  3. 使用以下命令运行 Docker 容器,使用 Ubuntu Docker 镜像。这将创建一个容器,并打开其 bash shell:

 sudo docker run -i -t ubuntu /bin/bash
  1. 现在,安装所有所需的应用程序,就像您在任何普通的 Ubuntu 机器上执行的操作一样。让我们从创建jenkins用户开始:

    1. 执行以下命令,并按照下图中显示的用户创建步骤进行操作:
 adduser jenkins

创建用户

    1. 使用切换用户命令检查新用户:
 su jenkins
  1. 通过键入exit切换回根用户。

  2. 接下来,我们将安装 SSH 服务器。按顺序执行以下命令:

 apt-get update
 apt-get install openssh-server
 mkdir /var/run/sshd
  1. 接下来,使用以下命令安装 Git:
 apt-get install git
  1. 使用以下命令安装 Java JDK:
 apt-get install openjdk-8-jdk
  1. 使用以下命令安装 Maven:
 apt-get install maven
  1. 接下来,键入exit退出容器。

  2. 我们需要保存(commit)我们对 Docker 容器所做的所有更改。

  3. 通过列出所有未活动容器,获取我们最近工作的容器的CONTAINER ID,如下图所示:

 sudo docker ps -a

未活动容器列表

  1. 注意CONTAINER ID,并执行commit命令,以提交我们对容器所做的更改,如下所示:
 sudo docker commit <CONTAINER ID> <new name for the container>
  1. 如下图所示,我们将容器命名为maven-build-slave-0.1

Docker commit 命令

  1. 一旦您提交了更改,将创建一个新的 Docker 镜像。

  2. 执行以下 Docker 命令列出镜像:

 sudo docker images

列出 Docker 镜像

  1. 您可以看到我们的新 Docker 镜像,名称为maven-build-slave-0.1。现在,我们将配置我们的 Jenkins 服务器以使用 Docker 镜像来创建 Jenkins 从节点(构建代理)。

在 Jenkins 中添加 Docker 容器凭据

按照给定的步骤在 Jenkins 中添加凭据,以允许其与 Docker 通信:

  1. 从 Jenkins 仪表板导航到凭据 | 系统 | 全局凭据(无限制)。

  2. 点击左侧菜单上的添加凭据链接以创建新凭据(请参阅下图)。

  3. 选择用户名与密码作为类型

  4. 将范围字段保留为其默认值。

  5. 在 Username 字段下为你的 Docker 镜像添加一个用户名(按照我们的示例,是 jenkins)。

  6. 在 Password 字段下,添加密码。

  7. 在 ID 字段下添加一个 ID,并在描述字段下添加一些描述。

  8. 完成后,点击确定按钮:

在 Jenkins 中创建凭据

更新 Jenkins 中的 Docker 设置

按照给定步骤更新 Jenkins 中的 Docker 设置:

  1. 从 Jenkins 仪表板上,点击 Manage Jenkins | Configure System。

  2. 滚动到底部找到 Cloud 部分(见下图)。

  3. 在 Cloud 部分,点击添加 Docker 模板按钮,然后选择 Docker 模板。

  4. 你将会看到许多设置需要配置。然而,为了保持这个演示简单,让我们专注于重要的设置:

    1. 在 Docker Image 字段下,输入我们之前创建的 Docker 镜像的名称。在我们的案例中,它是 maven-build-slave-0.1

    2. 在 Labels 字段下,添加一个标签。Jenkins 流水线将使用此标签识别 Docker 容器。添加一个 docker 标签。

    3. 启动方法应该是 Docker SSH 计算机启动器。

    4. Credentials 字段下,选择我们创建的用于访问 Docker 容器的凭据。

    5. 确保 Pull 策略选项设置为 Never pull。

    6. 将其余选项保留为默认值。

    7. 完成后,点击应用然后保存:

配置 Docker 插件设置

  1. 现在你的 Jenkins 服务器已经设置好了,可以使用 Docker 随需创建 Jenkins 从节点。

摘要

在本章中,我们学习了如何在独立的 Windows 和 Linux 机器(物理/虚拟机)上添加和配置 Jenkins 从节点,使用了两种广泛使用的方法:通过 SSH 启动 Jenkins 从节点和通过 Java Web Start 启动 Jenkins 从节点。我们还学习了如何安装和配置 Jenkins 的 Docker 插件,该插件允许我们为 CI 创建按需的 Docker 容器(Jenkins 从节点)。

在下一章中,我们将学习如何使用 Jenkins 实现持续集成,并且我们将利用 Jenkins Docker 容器(Jenkins 从节点)来执行我们的 CI。

安装 SonarQube 和 Artifactory

在本章中,我们将学习 SonarQube,这是一个流行的开源工具,用于静态代码分析。我们还将学习 Artifactory,这是另一个流行的开源工具,用于版本控制二进制文件。在本章中,您将学习以下主题:

  • 安装独立的 SonarQube 服务器

  • 在 SonarQube 内创建项目

  • 为 SonarQube 安装构建破坏插件

  • 创建质量门和质量配置文件

  • 在 Jenkins 中安装和配置 SonarQube 插件

  • 安装独立的 Artifactory 服务器

  • 在 Artifactory 中创建存储库

  • 在 Jenkins 中安装和配置 Artifactory 插件

安装和配置 SonarQube

除了连续集成代码外,CI 流水线现在还包括执行连续检查的任务 —— 以连续的方式检查代码的质量。

连续检查涉及检查和避免质量低劣的代码。诸如 SonarQube 的工具帮助我们实现这一点。每次代码提交时,都会对代码进行代码分析。

此分析基于代码分析工具定义的一些规则。如果代码通过了错误阈值,它被允许进入其生命周期的下一步。但是,如果它超过了错误阈值,它就会被丢弃。

有些组织更喜欢在开发人员尝试提交代码时立即检查代码质量。如果分析结果良好,则允许提交代码,否则取消提交并要求开发人员重新处理代码。

SonarQube 是一个代码质量管理工具,允许团队管理、跟踪和改善其源代码的质量。它是一个基于 Web 的应用程序,包含可配置的规则、警报和阈值。它涵盖了七种代码质量参数,包括架构和设计、重复、单元测试、复杂度、潜在错误、编码规则和注释。

SonarQube 是一个开源工具,通过插件支持几乎所有流行的编程语言。SonarQube 还可以与 CI 工具(如 Jenkins)集成,以执行持续检查,我们很快就会看到。

那么,首先让我们学习如何安装 SonarQube。在接下来的部分中,我们将学习如何在 Ubuntu 16.04 上安装 SonarQube。

安装 Java

按照以下步骤安装 Java:

  1. 更新软件包索引:
sudo apt-get update
  1. 接下来,安装 Java。以下命令将安装 JRE:
sudo apt-get install default-jre
  1. 要设置 JAVA_HOME 环境变量,首先获取 Java 安装位置。通过执行以下命令执行此操作:
update-java-alternatives –l
  1. 您应该会得到类似的输出:
java-1.8.0-openjdk-amd64 1081 /usr/lib/jvm/java-1.8.0-openjdk-amd64
  1. 上述输出中的路径是 JAVA_HOME 的位置。复制它。

  2. 打开 /etc/environment 文件进行编辑:

sudo nano /etc/environment
  1. 将以下行添加到 /etc/environment 文件中,如下所示:
JAVA_HOME="/usr/lib/jvm/java-1.8.0-openjdk-amd64"
  1. 输入 Ctrl + X 并选择 Y 以保存并关闭文件。

  2. 接下来,使用以下命令重新加载文件:

 sudo source /etc/environment

下载 SonarQube 包

以下步骤将帮助您下载 SonarQube 包:

  1. 通过访问www.sonarqube.org/downloads/下载最新版本的 SonarQube 安装包。

建议您始终安装最新的 LTS* 版本 SonarQube。

  1. 移动至 /tmp 文件夹:
cd /tmp
  1. 使用 wget 下载 SonarQube ZIP 包,如下所示的命令。在这里,我下载 SonarQube 版本 5.6.7(LTS*):
wget https://sonarsource.bintray.com/Distribution/sonarqube/
sonarqube-5.6.7.zip
  1. 接下来,在 /opt 目录下解压 SonarQube ZIP 包,使用以下命令:
unzip sonarqube-5.6.7.zip -d /opt/

要使用 unzip 命令,请确保您的 Ubuntu 机器上安装了压缩工具。要安装 ZIP 工具,请执行以下命令:

**sudo apt-get install zip**

您也可以在另一台机器上下载 SonarQube ZIP 包,然后使用 WinSCP 将其移动到您的 SonarQube 服务器上。

  1. 移动到已解压的文件夹并列出其内容:
cd /opt/sonarqube-5.6.7/ 
ls -lrt

bin/文件夹包含了所有安装和启动 SonarQube 的脚本,而 logs/文件夹包含了 SonarQube 的日志。

运行 SonarQube 应用程序

按照以下步骤启动 SonarQube 服务器:

  1. 移动至 /opt/sonarqube-5.6.6/bin/linux-x86-64/。在我们当前的示例中,我们在 64 位 Linux 操作系统上启动 SonarQube:
cd /opt/sonarqube-5.6.6/bin/linux-x86-64/
  1. 运行 sonar.sh 脚本以启动 SonarQube,如下所示的命令:
./sonar.sh start
  1. 您应该会看到类似的输出:
Starting SonarQube... Started SonarQube.
  1. 要访问 SonarQube,请在您喜爱的网络浏览器中使用以下链接:http://localhost:9000/http://<IP-Address>:9000

目前在 SonarQube 中没有配置用户帐户。但是,默认情况下有一个用户名为admin、密码为admin的管理员帐户。

确保您至少有 4GB 的内存来运行 64 位版本的 SonarQube。

重置默认凭据并生成令牌

按照以下步骤重置凭据并生成一个令牌:

  1. 在您喜欢的浏览器中打开 SonarQube 链接并切换到管理员用户。

  2. 从 SonarQube 仪表板上,点击 Administrator | My Account | Security(选项卡)。

  3. 在结果页面下,执行以下操作来更改密码部分:

    1. 在 旧密码 字段下添加您的旧密码(admin)。

    2. 在 新密码 字段下添加一个新密码。

    3. 在 确认密码 字段中重新输入新密码。

    4. 完成后,点击更改密码按钮。

  4. 在同一页的令牌部分下,有一个选项来生成一个令牌。Jenkins 可以使用此令牌访问 SonarQube。执行以下步骤生成一个新令牌:

    1. 在令牌部分下,通过点击生成按钮在 生成令牌 字段下为您的新令牌添加一个名称。

    2. 新的令牌将会生成,如下截图所示。

    1. 复制并保存此令牌,因为我们稍后会用到它:

在 SonarQube 中创建一个令牌

在 SonarQube 中创建项目

在接下来的部分中,我们将在 SonarQube 中创建一个项目。该项目将用于显示静态代码分析:

  1. 从 SonarQube 仪表板,点击管理| 项目(选项卡)| 管理。

  2. 在结果页面上,点击“创建项目”按钮。

  3. 在结果窗口中,填写相应的详细信息,如下面的步骤所示:

    1. 在“名称”字段下添加一个名称。

    2. 在“键”字段下添加一个键。

    3. 点击“创建”按钮创建项目:

在 SonarQube 中创建一个项目

  1. 你可以在项目管理页面上看到你新创建的项目,如下图所示:

SonarQube 中新创建的项目

为 SonarQube 安装构建破坏插件

构建破坏插件适用于 SonarQube。它是专门为 SonarQube 设计的插件,而不是 Jenkins 插件。此插件允许 CI 系统(Jenkins)在质量门限条件不满足时强制失败 Jenkins 构建。要安装构建破坏插件,请执行以下步骤:

  1. 在下载插件之前,先参考兼容性表。这将帮助我们下载正确的插件版本。兼容性表可在github.com/SonarQubeCommunity/sonar-build-breaker上找到。

  2. github.com/SonarQubeCommunity/sonar-build-breaker/releases下载构建破坏插件。

  3. 移动到/tmp目录并下载构建破坏插件,使用以下命令:

cd /tmp

wget https://github.com/SonarQubeCommunity/
sonar-build-breaker/releases/download/2.2/
sonar-build-breaker-plugin-2.2.jar
  1. 将下载的.jar文件移动到位置opt/sonarqube-5.6.7/extensions/plugins/
cp sonar-build-breaker-plugin-2.2.jar \
/opt/sonarqube-5.6.7/extensions/plugins/
  1. 使用以下命令重新启动 SonarQube:
cd /opt/sonarqube-5.6.7/bin/linux-x86-64

sudo ./sonar.sh restart
  1. 你应该看到类似的输出:
Stopping SonarQube... Waiting for SonarQube to exit... Stopped SonarQube. Starting SonarQube... Started SonarQube.
  1. 成功重新启动后,转到 SonarQube 仪表板,并以管理员身份登录。

  2. 点击菜单栏上的管理链接。

  3. 在管理页面上,您将在“类别”侧边栏下看到“构建破坏器”选项,如下图所示;不需要操作:

在 SonarQube 中的构建破坏插件设置

  1. 构建破坏插件已成功安装。

创建质量门限

为了使构建破坏插件正常工作,我们需要创建一个质量门限;它只是一条带有一些条件的规则。当 Jenkins 流水线运行时,它将执行质量配置文件和质量门限。如果质量门限检查成功通过,则 Jenkins 流水线继续运行,但如果失败,则 Jenkins 流水线中止。尽管如此,分析仍然会发生。

按照以下步骤在 SonarQube 中创建一个质量门限:

  1. 从 SonarQube 仪表板,点击菜单栏上的“质量门限”链接。

  2. 在结果页面上,点击左上角的“创建”按钮。

  3. 您将看到一个弹出窗口,如下面的屏幕截图所示。在名称字段下添加您的质量门名称,并点击创建按钮:

创建一个新的质量门

  1. 您将在质量门页面上看到您的新质量门,如下面的屏幕截图所示:

新质量门

  1. 现在让我们通过从添加条件菜单中选择一个来为我们的质量门添加一个条件:

条件菜单

  1. 下面的屏幕截图显示了一个名为主要问题的条件。如果大于1但小于50,则是警告,如果大于50,则是错误,如下面的屏幕截图所示。这只是一个示例;您可以配置任意数量的条件:

配置质量门

  1. 接下来,让我们确保我们之前在 SonarQube 中创建的示例项目使用我们新创建的质量门。为此,请从 SonarQube 仪表板点击管理 | 项目(选项卡)| 管理。

  2. 在结果页面上,您将看到我们之前在 SonarQube 中创建的示例项目。点击它。

  3. 在结果页面上,点击管理(选项卡)| 质量门。

  4. 在质量门部分下,您将看到一个选项,可以从 SonarQube 中的可用质量门列表中选择质量门。选择我们最近创建的一个并点击更新按钮:

将质量门关联到项目

更新默认质量配置

在下一节中,我们将修改 Java(Sonar way)的默认质量配置,我们打算用于我们的静态代码分析。请按照以下步骤操作:

  1. 从 SonarQube 仪表板,点击菜单栏中的质量配置链接。在结果页面上,您将看到所有存在于 SonarQube 上的质量配置,如下面的屏幕截图所示:

SonarQube 中的质量配置列表

  1. 从上一个屏幕截图中,您可以看到 Java 的默认质量配置:Sonar way 包含 254 个活动规则。让我们尝试添加更多规则。

  2. 点击激活更多按钮。

  3. 在结果页面上,您将看到一些内容,如下面的屏幕截图所示:

未激活规则列表

  1. 这是您可以向质量配置添加和删除规则的地方。让我们激活所有 Java 的未激活规则。

  2. 要做到这一点,从页面右上角,点击批量更改 | 在 Sonar way 中激活,如下面的屏幕截图所示:

批量激活规则

  1. 您将看到一个弹出窗口询问您确认更改。点击应用按钮并继续。

  2. 接下来,从菜单栏中点击“质量配置文件”链接。 在结果页面上,点击 Java 的 Sonar way 质量配置文件,现在您应该看到比以前更多的规则。

在 SonarQube 上可见的规则列表和默认质量配置文件取决于安装的插件。 要获取所需语言的规则,请安装相应的 SonarQube 插件。

在 Jenkins 中安装 SonarQube 插件

按照以下步骤为 Jenkins 安装 SonarQube 插件:

  1. 从 Jenkins 仪表板中,点击“管理 Jenkins | 管理插件 | 可用(选项卡)”。 您将进入 Jenkins 管理插件页面。

  2. 在“过滤器”字段中输入SonarQube,如下面的截图所示:

安装 SonarQube 插件

  1. 从列表中选择“Jenkins 的 SonarQube 扫描仪”,然后点击“无需重新启动安装”按钮。

  2. 如有需要,请重新启动 Jenkins。

在 Jenkins 中配置 SonarQube 插件

现在我们已经安装了 SonarQube 插件,让我们来配置它:

  1. 从 Jenkins 仪表板中,点击“管理 Jenkins | 配置系统”。

  2. 一旦进入“配置系统”页面,请向下滚动到 SonarQube 服务器部分。

  3. 在 SonarQube 服务器部分,点击“添加 SonarQube”按钮。 您将看到要配置的设置,如下面的截图所示。 让我们逐一了解它们。

  4. 在“名称”字段中为您的 SonarQube 服务器命名。

  5. 在“服务器 URL”字段下输入 SonarQube 服务器的 URL。

  6. 在“默认部署者凭据”下添加 Artifactory 凭据。

  7. 在“服务器身份验证令牌”字段下输入我们在 SonarQube 中创建的令牌。

  8. 点击“测试连接”按钮以测试 Jenkins 与 Artifactory 的连接:

配置 SonarQube 插件

  1. 完成后,点击页面底部的“保存”按钮保存设置。

安装和配置 Artifactory

持续集成导致频繁的构建和打包。 因此,需要一种机制来存储所有这些二进制代码(构建、包、第三方插件等),这种机制类似于版本控制系统。

由于像 Git、TFS 和 SVN 这样的版本控制系统存储的是代码而不是二进制文件,我们需要一个二进制存储库工具。 一个与 Jenkins 紧密集成的二进制存储库工具(如 Artifactory 或 Nexus)提供了以下优势:

  • 跟踪构建(谁触发? 构建了什么代码?)

  • 依赖项

  • 部署历史

下图描述了二进制存储库工具(如 Artifactory)与 Jenkins 如何一起工作以存储构建产物。 在接下来的话题中,我们将学习如何通过创建一个 Jenkins 作业将代码上传到 Artifactory 来实现这一点:

Jenkins 流水线将构建产物推送到 Artifactory

在当前书籍中,我们将处理 Artifactory 来存储我们的构建。 Artifactory 是一个用于版本控制二进制文件的工具。 这些二进制文件可以是任何内容,从构建代码、软件包、可执行文件、Maven 插件等等。

在接下来的部分中,我们将在 Ubuntu 16.04 上设置 Artifactory。

安装 Java

按照以下步骤安装 Java:

  1. 更新软件包索引:
sudo apt-get update
  1. 接下来,安装 Java。以下命令将安装 JRE:
sudo apt-get install default-jre
  1. 要设置 JAVA_HOME 环境变量,首先获取 Java 安装位置。 通过执行以下命令执行此操作:
update-java-alternatives –l
  1. 您应该得到类似的输出:
java-1.8.0-openjdk-amd64 1081 /usr/lib/jvm/java-1.8.0-openjdk-amd64
  1. 在前面的输出中的路径是 JAVA_HOME 的位置。复制它。

  2. 打开 /etc/environment 文件进行编辑:

sudo nano /etc/environment
  1. /etc/environment 文件中添加以下行,如下所示:
JAVA_HOME="/usr/lib/jvm/java-1.8.0-openjdk-amd64"
  1. 输入 Ctrl + X 并选择 Y 保存并关闭文件。

  2. 接下来,使用以下命令重新加载文件:

 sudo source /etc/environment

下载 Artifactory 包

按照以下步骤下载 Artifactory 包:

  1. www.jfrog.com/open-source/bintray.com/jfrog/artifactory/jfrog-artifactory-oss-zip 下载 Artifactory 的最新版本(开源)。

  2. 要下载 Artifactory Pro,请访问 bintray.com/jfrog/artifactory-pro/bintray.com/jfrog/artifactory-pro/jfrog-artifactory-pro-zip

建议您始终安装 Artifactory 的最新 LTS 版本。

在下一章中,我们将使用 Artifactory Pro 演示代码推广,使用即将到来的章节中的属性。

参考 www.jfrog.com/confluence/display/RTF/Artifactory+Pro#ArtifactoryPro-ActivatingArtifactoryPro 了解激活 Artifactory Pro 的过程。

  1. 移动到 /tmp 文件夹:
cd /tmp
  1. 使用 wget 下载 Artifactory Pro ZIP 包,如下代码所示。这里,我正在下载 Artifactory 版本 5.5.2(LTS*):
wget https://jfrog.bintray.com/artifactory-pro/org/artifactory/pro/jfrog-artifactory-pro/5.5.2/jfrog-artifactory-pro-5.5.2.zip

您可以从不同的机器(从浏览器)下载 Artifactory ZIP 包,然后使用 WinSCP 将其移动到即将成为 Artifactory 服务器的位置。

  1. 接下来,在 /opt 目录中解压 SonarQube ZIP 包,如下所示:
sudo unzip jfrog-artifactory-pro-5.5.2.zip -d /opt/

或者,如果下载的 ZIP 包有奇怪的名字:

sudo unzip \
download_file\?file_path\=jfrog-artifactory-pro-5.5.2.zip \
–d /opt/

要使用 unzip 命令,请确保已在您的 Ubuntu 机器上安装了压缩工具。 要安装 ZIP 工具,请执行以下命令:

**sudo apt-get install zip**

  1. 移动到提取的文件夹并列出其内容:
cd /opt/artifactory-pro-5.5.2/ 
ls -lrt

bin/ 文件夹包含所有安装和启动 Artifactory 的脚本,logs/ 文件夹包含 Artifactory 日志。

运行 Artifactory 应用程序

按照给定的步骤启动 Artifactory 服务器:

  1. 进入 /opt/artifactory-pro-5.5.2/bin/ 目录并运行 installService.sh 脚本:
sudo ./installService.sh
  1. 您应该看到类似的输出:
Installing artifactory as a Unix service that will run as user artifactory Installing artifactory with home /opt/artifactory-pro-5.5.2
Creating user artifactory...creating... DONE

Checking configuration link and files in /etc/opt/jfrog/artifactory...
Moving configuration dir /opt/artifactory-pro-5.5.2/etc /opt/artifactory-pro-5.5.2/etc.original...creating the link and updating dir... DONE
Creating environment file /etc/opt/jfrog/artifactory/default...creating... DONE
** INFO: Please edit the files in /etc/opt/jfrog/artifactory to set the correct environment
Especially /etc/opt/jfrog/artifactory/default that defines ARTIFACTORY_HOME, JAVA_HOME and JAVA_OPTIONS
Initializing artifactory.service service with systemctl... DONE

Setting file permissions... DONE

************ SUCCESS ****************
Installation of Artifactory completed

Please check /etc/opt/jfrog/artifactory, /opt/artifactory-pro-5.5.2/tomcat and /opt/artifactory-pro-5.5.2 folders

You can activate artifactory with:
> systemctl start artifactory.service
  1. 启动 Artifactory 服务,使用以下任何命令之一:
sudo service artifactory start

或者:

sudo /etc/init.d/artifactory start

或者:

sudo systemctl start artifactory
  1. 您可以通过执行以下任何命令来检查 Artifactory 的安装:
service artifactory check

或者:

/etc/init.d/artifactory check 

或者:

sudo ./artifactoryctl check
  1. 通过导航至 http://<服务器 IP 地址>:8081/ 访问 Artifactory 仪表板。

目前在 Artifactory 中未配置任何用户帐户。但是,默认情况下存在一个 admin 帐户,用户名为 admin,密码为 password

确保您至少有 4 GB 的内存来运行 Artifactory 的 64 位版本。

重置默认凭据并生成 API 密钥

按照给定步骤重置 Artifactory 凭据:

  1. 使用以下链接访问 Artifactory 仪表板:http://<服务器 IP 地址>:8081/

  2. 使用 admin 的初始默认凭据登录。

  3. 从 Artifactory 仪表板,单击 Welcome, admin | Edit Profile。

  4. 在当前密码字段中输入您当前的密码,然后点击解锁按钮。

  5. 在生成的页面上,在个人设置下,添加您的电子邮件 ID。

  6. 在 Change Password 部分下,添加一个新密码以重置 admin 用户的默认凭据。

  7. 接下来,在 Authentication Settings 部分下,单击生成密钥(齿轮图标)以生成新的 API 密钥。

  8. 通过单击复制按钮复制生成的 API 密钥(参见下图)。

  9. 以后可能需要此 API 密钥进行身份验证:

Artifactory API 密钥

  1. 完成后,单击保存按钮。

在 Artifactory 中创建仓库

在接下来的部分中,我们将在 Artifactory 中创建一个通用仓库。该仓库将用于存储构建产物:

  1. 从 Artifactory 仪表板,在左侧菜单中,单击 Admin | Repositories | Local,如下图所示:

在 Artifactory 中创建一个本地仓库

  1. 生成的页面将显示当前可用的所有本地仓库,如下图所示:

所有本地仓库的列表

  1. 在右上角单击 New 按钮创建一个新的本地仓库(参见下图)。

  2. 将出现一个弹出窗口,列出各种类型的仓库供选择,如下图所示。选择 Generic 类型(参见下图):

选择各种类型仓库的选项

  1. 在 Repository Key 字段下添加一个值,为您的仓库命名,如下图所示。将其余设置保留为默认值:

命名我们的新本地仓库

  1. 完成后,单击保存 & 完成按钮。

  2. 现在我们有了新的本地仓库,如下图所示:

我们新创建的本地仓库

在 Jenkins 中添加 Artifactory 凭据

按照给定步骤在 Jenkins 中创建与 Artifactory 通信的凭据:

  1. 从 Jenkins 仪表板中,点击“凭据 | 系统 | 全局凭据(无限制)”。

  2. 在左侧菜单中点击“添加凭据”链接以创建一个新凭据(见下图)。

  3. 选择类型为用户名和密码。

  4. 将范围字段保留为其默认值。

  5. 在用户名字段下添加 Artifactory 用户名。

  6. 在密码字段下,添加密码。

  7. 在 ID 字段下添加一个 ID,在描述字段下添加一个描述。

  8. 完成后,点击“确定”按钮:

在 Jenkins 中添加 Artifactory 凭据

在 Jenkins 中安装 Artifactory 插件

按照给定步骤安装 Jenkins 的 Artifactory 插件:

  1. 从 Jenkins 仪表板中,点击“管理 Jenkins | 管理插件 | 可用(选项卡)”。你将被带到 Jenkins 管理插件页面。

  2. 在过滤字段中输入Artifactory,如下图所示:

安装 Artifactory 插件

  1. 从列表中选择 Artifactory 插件,然后点击“无需重新启动”按钮进行安装。

  2. 如有必要,重新启动 Jenkins。

配置 Artifactory 插件

现在我们已经安装了 Artifactory 插件,让我们来配置它:

  1. 从 Jenkins 仪表板中,点击“管理 Jenkins | 配置系统”。

  2. 进入“配置系统”页面后,一直向下滚动到“Artifactory”部分。

  3. 在 Artifactory 部分,点击“添加”按钮。你将看到以下设置以配置,如下图所示。让我们一一来看看它们。

  4. 使用服务器 ID 字段给你的 Artifactory 服务器命名。

  5. 在 URL 字段下输入 Artifactory 服务器 URL。

  6. 在“默认部署者凭据”下添加 Artifactory 凭据,如下图所示。

  7. 点击“测试连接”按钮测试 Jenkins 与 Artifactory 的连接:

配置 Artifactory 插件

  1. 完成后,点击页面底部的“保存”按钮以保存设置。

摘要

在本章中,我们学习了如何安装和配置 SonarQube 和 Artifactory。在今天的世界中,静态代码分析形成了 CI 流水线的重要组成部分(尽管不是必需的)。同样,Artifactory 是一个流行的工具,用于存储 CI 流水线生成的所有构建工件。一旦 CI 流水线完成,Artifactory 就成为了焦点。所有构建的工件都从 Artifactory 部署到各种测试环境中,并且我们通过 Artifactory 执行代码推进。

我们将在下一章中更多地了解这些工具,该章是关于使用 Jenkins 实现持续集成。

使用 Jenkins 进行持续集成

我们将从涵盖以下方面的持续集成CI)设计开始:

  • 一个分支策略

  • 一份 CI 工具清单

  • 一个 Jenkins 流水线结构

CI 设计将作为一个蓝图,指导读者回答 CI 的实施如何、为什么以及在哪里的问题。设计将涵盖实施端到端 CI 流水线所涉及的所有必要步骤。

本章讨论的 CI 设计应被视为实施 CI 的模板,而不是最终的模型。分支策略和所使用的工具都可以修改和替换以适应目的。

Jenkins CI 设计

几乎每个组织在甚至开始探索 CI 和 DevOps 工具之前都会创建一个。在本节中,我们将介绍一个非常通用的 CI 设计。

持续集成不仅包括 Jenkins 或任何其他类似的 CI 工具,它还涉及到代码版本控制方式、分支策略等方面。

不同的组织可能采用不同类型的策略来实现 CI,因为这完全取决于项目的需求和类型。

分支策略

拥有分支策略总是很好的。分支有助于组织您的代码。这是将您的工作代码与正在开发的代码隔离开来的一种方式。在我们的 CI 设计中,我们将从三种类型的分支开始:

  • 主分支

  • 集成分支

  • 功能分支

这个分支策略是 GitFlow 工作流分支模型的简化版本。

主分支

也可以称之为生产分支。它保存了已交付的代码的工作副本。该分支上的代码已通过了所有测试。在这个分支上不进行开发。

集成分支

集成分支也被称为主干分支。这是所有功能集成、构建和测试集成问题的地方。同样,在这里不进行开发。然而,开发人员可以从集成分支创建功能分支并在其上工作。

功能分支

最后,我们有功能分支。这是实际开发发生的地方。我们可以从集成分支创建多个功能分支。

以下插图显示了我们将作为 CI 设计一部分使用的典型分支策略。我们将创建两个功能分支,它们从集成/主干分支延伸出来,而这个分支本身则从主分支延伸出来:

图示

分支策略

在功能分支或集成分支上的提交(合并会创建一个提交)将经过构建、静态代码分析和集成测试阶段。如果代码成功通过这些阶段,结果包将被上传到 Artifactory(二进制存储库)。

CI 流水线

我们现在来到了 CI 设计的核心。我们将在 Jenkins 中创建一个多分支流水线,其中将包含以下阶段:

  1. 在推送事件(CI 流水线的初始化)上从版本控制系统VCS)获取代码。

  2. 构建和单元测试代码,并在 Jenkins 上发布单元测试报告。

  3. 对代码进行静态代码分析,并将结果上传到 SonarQube。如果错误数量超过质量门限的定义,则流水线失败。

  4. 在 Jenkins 上执行集成测试并发布单元测试报告。

  5. 将构建的工件与一些有意义的属性一起上传到 Artifactory。

前一 CI 流水线的目的是自动化持续构建、测试(单元测试和集成测试)、进行静态代码分析以及上传构建的工件到二进制存储库的过程。每个步骤的失败/成功都有报告。让我们详细讨论这些流水线及其组成部分。

CI 的工具集

我们正在实现 CI 的示例项目是一个简单的 Maven 项目。在这一章中,我们将看到 Jenkins 与许多其他工具密切合作。以下表格包含了我们将要看到的一切所涉及的工具和技术的列表:

技术 特点
Java 用于编码的主要编程语言
Maven 构建工具
JUnit 单元测试和集成测试工具
Jenkins 持续集成工具
GitHub 版本控制系统
SonarQube 静态代码分析工具
Artifactory 二进制存储库管理器

创建 CI 流水线

在本节中,我们将学习如何创建上一节中讨论的 CI 流水线。我们将执行以下步骤:

  • 我们将在 GitHub 上创建一个源代码存储库

  • 我们将创建一个 Jenkinsfile 来描述我们构建、单元测试、执行静态代码分析、集成测试和发布构建工件到 Artifactory 的方式

  • 我们将利用 Docker 生成构建代理来运行我们的 CI 流水线

  • 我们将在 Jenkins 中创建一个多分支流水线

非常重要的是,您已经配置了来自第三章的 Jenkins 从 GitHub 配置 Webhook 部分。

在 GitHub 上创建一个新的存储库

让我们在 GitHub 上创建一个新的存储库。确保您的机器上安装了 Git,以执行以下步骤:

  1. 登录到您的 GitHub 帐户。

  2. 在本章中,我们将使用来自 github.com/nikhilpathania/hello-world-greeting.git 的源代码作为示例。

  3. 尝试从上一个链接中提到的存储库中分叉。要做到这一点,只需从您的互联网浏览器访问存储库,然后点击 Fork 按钮,如下截图所示:

分叉一个 GitHub 项目

  1. 完成后,仓库的副本将会出现在您的 GitHub 账户下。

使用 SonarQube 用于 Maven 的扫描器。

理想情况下,我们需要 SonarQube 扫描器对项目进行静态代码分析。但是,我们将改为使用 Maven 的 SonarQube 扫描器实用程序,因为我们在当前章节中使用的示例源代码是一个 Maven 项目。

为此,在您的 .pom 文件中添加以下代码:

<properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <sonar.language>java</sonar.language>
</properties>

如果您已经 fork 了以下仓库,那么您不需要执行上一步:

github.com/nikhilpathania/hello-world-greeting.git

为 CI 编写 Jenkinsfile。

在接下来的章节中,我们将学习如何为我们的持续集成编写流水线代码。

生成一个 Docker 容器 - 构建代理。

首先,让我们创建流水线代码来创建一个 Docker 容器(Jenkins 从机),这将作为我们的构建代理。

如果你还记得,在添加 Jenkins 从机 - Docker 容器章节中来自第五章的 分布式构建,我们学习了如何创建一个用于创建 Docker 容器(Jenkins 从机)的 Docker 镜像(maven-build-slave-0.1)。我们将在此处使用相同的 Docker 镜像来生成 Jenkins 从机代理用于我们的 CI 流水线。

在我们的 Jenkinsfile 中,为了生成一个 Docker 容器(Jenkins 从机),我们需要编写一个代码块,标签为 docker

node('docker') {
}

dockermaven-build-slave-0.1 Docker 模板的标签。

我们希望在docker节点上执行以下任务:

  • 执行构建。

  • 执行单元测试并发布单元测试报告。

  • 执行静态代码分析并将结果上传到 SonarQube。

  • 执行集成测试并发布集成测试报告。

  • 将产物发布到 Artifactory。

所有前面的任务都是我们 CI 流水线的各个阶段。让我们为每一个编写流水线代码。

从 VCS 中下载最新的源代码。

我们希望我们的 Jenkins 流水线下载推送到 GitHub 仓库主分支的最新更改:

scm checkout

将上一步包装在一个名为 轮询 的阶段中:

stage('Poll') {
    scm checkout
}

执行构建和单元测试的流水线代码。

我们在当前章节中使用的示例项目是一个 Maven 项目。因此,用于构建的流水线代码是一个简单的 shell 脚本,运行 mvn clean 命令:

sh 'mvn clean verify -DskipITs=true';
junit '**/target/surefire-reports/TEST-*.xml'
archive 'target/*.jar'

其中 -DskipITs=true 是跳过集成测试并仅执行构建和单元测试的选项。

命令 junit '**/target/surefire-reports/TEST-*.xml' 让 Jenkins 能够在 Jenkins 流水线页面上发布 JUnit 单元测试报告。**/target/surefire-reports/TEST-*.xml 是生成单元测试报告的目录位置。

您的 Maven .pom 文件应该包含maven-surefire-pluginmaven-failsafe-plugin以使上一个命令工作。

您还需要 Jenkins JUnit 插件(默认安装)。

将上一步包装在一个名为 构建 & 单元测试 的阶段中:

stage('Build & Unit test'){
    sh 'mvn clean verify -DskipITs=true';
    junit '**/target/surefire-reports/TEST-*.xml'
    archive 'target/*.jar'
}

执行静态代码分析的流水线代码

执行静态代码分析的流水线代码是一个简单的 shell 脚本,将运行 Maven 命令,如下所示的命令块。这是通过 Maven 的 SonarQube 扫描器实用程序实现的。记住我们在 使用 SonarQube scanner for Maven 部分看到的配置:

sh 'mvn clean verify sonar:sonar -Dsonar.projectName=example-project
-Dsonar.projectKey=example-project -Dsonar.projectVersion=$BUILD_NUMBER';

-Dsonar.projectName=example-project 选项是传递 SonarQube 项目名称的选项。通过这种方式,我们所有的结果都将显示在我们在上一章中创建的 projectName=example-project 下。

类似地,-Dsonar.projectKey=example-project 选项允许 Maven 的 SonarQube 扫描器确认与 SonarQube 的 projectKey=example-project

-Dsonar.projectVersion=$BUILD_NUMBER 选项允许我们将 Jenkins 构建号与我们执行和上传到 SonarQube 的每个分析关联起来。$BUILD_NUMBER 是 Jenkins 的构建号环境变量。

将前一步骤包装在名为 Static Code Analysis 的阶段中:

stage('Static Code Analysis'){
    sh 'mvn clean verify sonar:sonar -Dsonar.projectName=example-project
    -Dsonar.projectKey=example-project -Dsonar.projectVersion=$BUILD_NUMBER';}

执行集成测试的流水线代码

执行集成测试的流水线代码是一个 shell 脚本,将运行 Maven 命令,如下所示的命令块:

sh 'mvn clean verify -Dsurefire.skip=true';
junit '**/target/failsafe-reports/TEST-*.xml'
archive 'target/*.jar'

其中 -Dsurefire.skip=true 是跳过单元测试仅执行集成测试的选项。

junit '**/target/failsafe-reports/TEST-*.xml' 命令使 Jenkins 能够在 Jenkins 流水线页面上发布 JUnit 单元测试报告。**/target/failsafe-reports/TEST-*.xml 是生成集成测试报告的目录位置。

将前一步骤包装在名为 Integration Test 的阶段中:

stage ('Integration Test'){
    sh 'mvn clean verify -Dsurefire.skip=true';
    junit '**/target/failsafe-reports/TEST-*.xml'
    archive 'target/*.jar'
}

要使上述命令生效,你的 Maven .pom 文件应包含 maven-surefire-pluginmaven-failsafe-plugin

您还需要 Jenkins JUnit 插件(默认安装)。

执行将构建工件发布到 Artifactory 的流水线代码

要将构建工件上传到 Artifactory,我们将使用 File Specs。下面是 File Specs 代码的示例:

"files": [
    {
      "pattern": "[Mandatory]",
      "target": "[Mandatory]",
      "props": "[Optional]",
      "recursive": "[Optional, Default: 'true']",
      "flat" : "[Optional, Default: 'true']",
      "regexp": "[Optional, Default: 'false']"
    }
  ]

以下表格说明了前述代码的参数:

参数 条件 描述
pattern [必填] 指定应上传到 Artifactory 的本地文件系统路径。您可以通过使用通配符或正则表达式来指定多个工件,正则表达式由 regexp 属性指定。如果使用 regexp,则需要使用反斜杠 \ 对表达式中使用的任何保留字符(例如 ., ? 等)进行转义。自 Jenkins Artifactory 插件版本 2.9.0 和 TeamCity Artifactory 插件版本 2.3.1 起,模式格式已简化,并对包括 Windows 在内的所有操作系统使用相同的文件分隔符 /
target [必填] 以以下格式指定 Artifactory 中的目标路径:[repository_name]/[repository_path]。如果模式以斜杠结尾,例如,repo-name/a/b/,那么b被视为 Artifactory 中的一个文件夹,并且文件将上传到其中。在repo-name/a/b的情况下,上传的文件将在 Artifactory 中重命名为b。为了灵活地指定上传路径,您可以包含形式为{1}, {2}, {3}...的占位符,它们被对应的括号中的源路径中的令牌所替换。有关更多详细信息,请参考 使用占位符 文章(www.jfrog.com/confluence/display/RTF/Using+File+Specs#UsingFileSpecs-UsingPlaceholders)
props [可选] 以分号(;)分隔的key=value对的列表,作为附加到上传属性的属性。如果任何键可以接受多个值,则每个值用逗号(,)分隔。例如,key1=value1;key2=value21,value22;key3=value3
flat [默认: true] 如果为true,构件将上传到指定的精确目标路径,并且源文件系统中的层次结构将被忽略。如果为false,构件将上传到目标路径,同时保留其文件系统层次结构。
recursive [默认: true] 如果为true,则还会从源目录的子目录中收集构建产物进行上传。如果为false,则仅上传源目录中明确定义的构建产物。
regexp [默认: false] 如果为true,命令将按照正则表达式解释描述要上传的构件的本地文件系统路径的模式属性。如果为false,命令将将模式属性解释为通配符表达式。

下面是我们在流水线中将使用的文件规范代码:

def server = Artifactory.server 'Default Artifactory Server'
def uploadSpec = """{
  "files": [
    {
       "pattern": "target/hello-0.0.1.war",
       "target": "example-project/${BUILD_NUMBER}/",
       "props": "Integration-Tested=Yes;Performance-Tested=No"
    }
  ]
}"""
server.upload(uploadSpec)

下表列出了上述代码中的参数:

参数 描述
def server = Artifactory.server 'Default Artifactory Server' 这行代码告诉 Jenkins 要使用 Jenkins 中配置的现有 Artifactory 服务器。在我们的例子中,它是默认的 Artifactory 服务器。
Default Artifactory Server 这是 Jenkins 内配置的 Artifactory 服务器的名称。
"pattern": "target/hello-0.0.1.war", 这行代码会查找目录target中名为hello-0.0.1.war的文件,而target目录又位于 Jenkins 工作目录内部。
"target": "example-project/${BUILD_NUMBER}/", 这行代码尝试将构建产物上传到名为helloworld-greeting-project的 Artifactory 仓库。它将构建产物放置在 Artifactory 仓库内的一个以构建编号命名的文件夹内。
${BUILD_NUMBER} 构建编号的 Jenkins 环境变量。
"props": "Integration-Tested=Yes;Performance-Tested=No" 此代码创建两个键值对并将它们分配给上载的工件。这些键值对可用作 Artifactory 中代码推广的标签。

将上一步放入名为Publish的阶段中:

stage ('Publish'){
    def server = Artifactory.server 'Default Artifactory Server'
    def uploadSpec = """{
      "files": [
        {
          "pattern": "target/hello-0.0.1.war",
          "target": "helloworld-greeting-project/${BUILD_NUMBER}/",
          "props": "Integration-Tested=Yes;Performance-Tested=No"
        }
      ]
    }"""
  server.upload(uploadSpec)
}

组合的 CI 管道代码

以下是将在 docker 节点内运行的完整组合代码:

node('docker') {
  stage('Poll') {
    checkout scm
  }
  stage('Build & Unit test'){
    sh 'mvn clean verify -DskipITs=true';
    junit '**/target/surefire-reports/TEST-*.xml'
    archive 'target/*.jar'
  }
  stage('Static Code Analysis'){
    sh 'mvn clean verify sonar:sonar -Dsonar.projectName=example-project
    -Dsonar.projectKey=example-project -Dsonar.projectVersion=$BUILD_NUMBER';
  }
  stage ('Integration Test'){
    sh 'mvn clean verify -Dsurefire.skip=true';
    junit '**/target/failsafe-reports/TEST-*.xml'
    archive 'target/*.jar'
  }
  stage ('Publish'){
    def server = Artifactory.server 'Default Artifactory Server'
    def uploadSpec = """{
      "files": [
        {
          "pattern": "target/hello-0.0.1.war",
          "target": "example-project/${BUILD_NUMBER}/",
          "props": "Integration-Tested=Yes;Performance-Tested=No"
        }
      ]
    }"""
    server.upload(uploadSpec)
  }
}

使用 Jenkinsfile

Jenkins 多分支管道使用 Jenkinsfile。在本节中,我们将学习如何创建 Jenkinsfile。我们将使用上一节中创建的示例管道脚本来创建我们的 Jenkinsfile。请按照以下步骤操作:

  1. 登录到您的 GitHub 帐户。

  2. 转到分叉的存储库.

  3. 进入存储库页面后,点击创建新文件按钮以创建一个新的空文件,这将是我们的 Jenkinsfile,如下截图所示:

在 GitHub 上创建一个新文件

  1. 在空文本框中填写Jenkinsfile作为您的新文件名称,如下截图所示:

在 GitHub 上为您的新文件命名

  1. 在您的 Jenkinsfile 中添加以下代码:
node('docker') {
  stage('Poll') {
    checkout scm
  }
  stage('Build & Unit test'){
    sh 'mvn clean verify -DskipITs=true';
    junit '**/target/surefire-reports/TEST-*.xml'
    archive 'target/*.jar'
  }
  stage('Static Code Analysis'){
    sh 'mvn clean verify sonar:sonar
    -Dsonar.projectName=example-project
    -Dsonar.projectKey=example-project
    -Dsonar.projectVersion=$BUILD_NUMBER';
  }
  stage ('Integration Test'){
    sh 'mvn clean verify -Dsurefire.skip=true';
    junit '**/target/failsafe-reports/TEST-*.xml'
    archive 'target/*.jar'
  }
  stage ('Publish'){
    def server = Artifactory.server 'Default Artifactory Server'
    def uploadSpec = """{
      "files": [
        {
          "pattern": "target/hello-0.0.1.war",
          "target": "example-project/${BUILD_NUMBER}/",
          "props": "Integration-Tested=Yes;Performance-Tested=No"
        }
      ]
    }"""
    server.upload(uploadSpec)
  }
}
  1. 完成后,通过添加有意义的评论提交新文件,如下截图所示:

在 GitHub 上提交您的新文件

在 Jenkins 中创建一个多分支管道

按以下步骤创建一个新的 Jenkins 管道作业:

  1. 从 Jenkins 仪表板中,点击新建项目链接。

  2. 在结果页面上,您将看到各种类型的 Jenkins 作业供您选择。

  3. 选择多分支 管道,并使用输入项目名称字段为您的管道命名。

  4. 完成后,点击页面底部的确定按钮。

  5. 滚动到 分支来源 部分。这是我们配置要使用的 GitHub 存储库的地方。

  6. 点击添加源按钮,选择 GitHub。您将看到一个配置字段的列表。我们逐一看一下它们(见下面的截图)。

  7. 对于凭据字段,选择我们在上一节中创建的 GitHub 帐户凭据(种类:带有用户名和密码的用户名)。

  8. 在所有者字段下,指定您的 GitHub 组织或 GitHub 用户帐户的名称。

  9. 一旦这样做,存储库字段将列出您 GitHub 帐户上的所有存储库。

  10. 在存储库字段下选择 hello-world-greeting

  11. 将其余选项保留为默认值:

配置多分支管道

  1. 滚动到底部的构建配置部分。确保 Mode 字段设置为按 Jenkinsfile,Script Path 字段设置为Jenkinsfile

构建配置

  1. 滚动到底部,点击保存按钮。

重新注册 Webhooks

现在,让我们重新注册所有 Jenkins 流水线的 Webhooks。为此,请执行以下步骤:

  1. 在 Jenkins 仪表板上,点击管理 Jenkins | 配置系统

  2. 在 Jenkins 配置页面上,向下滚动到 GitHub 部分。

  3. 在 GitHub 部分下,点击高级…按钮(您将看到两个按钮;点击第二个)。

  4. 这将显示更多字段和选项。点击重新注册所有作业的 hooks按钮。

  5. 上一步将为您在 GitHub 帐户内相应存储库上的我们的多分支流水线创建新的 Webhooks。请按照以下步骤在 GitHub 上查看 Webhooks:

    1. 登录您的 GitHub 帐户。

    2. 转到您的 GitHub 存储库,在我们的案例中是 hello-world-greeting

    3. 点击存储库设置按钮,如下图所示:

存储库设置

    1. 在存储库设置页面上,点击左侧菜单中的 Webhooks。您应该看到您的 Jenkins 服务器的 Webhooks,如下图所示:

GitHub 存储库上的 Webhooks

正在进行的持续集成

按照给定的步骤操作:

  1. 从 Jenkins 仪表板上,点击您的多分支流水线。

  2. 在 Jenkins 多分支流水线页面上,从左侧菜单中,点击立即扫描存储库链接。这将扫描分支和 Jenkinsfiles,并立即为每个具有 Jenkinsfile 的分支运行一个流水线,如下图所示:

主分支的流水线

  1. 在多分支流水线页面上,从左侧菜单中,点击扫描存储库日志。您将看到类似以下输出。注意高亮代码。您可以看到主分支符合条件,因为它有一个 Jenkinsfile,并为其安排了一个流水线。由于测试分支上没有 Jenkinsfile,因此没有为其安排流水线:
Started by user nikhil pathania
[Sun Nov 05 22:37:19 UTC 2017] Starting branch indexing...
22:37:19 Connecting to https://api.github.com using nikhilpathania@hotmail.com/****** (credentials to access GitHub account)
22:37:20 Connecting to https://api.github.com using nikhilpathania@hotmail.com/****** (credentials to access GitHub account)
Examining nikhilpathania/hello-world-greeting Checking branches...  
  Getting remote branches...    
    Checking branch master  
  Getting remote pull requests... ‘Jenkinsfile’ found    
    Met criteria
Changes detected: master (c6837c19c3906b0f056a87b376ca9afdff1b4411 1e5834a140d572f4d6f9665caac94828b779e2cd)Scheduled build for branch: master  
1 branches were processed  
Checking pull-requests...  
0 pull requests were processed
Finished examining nikhilpathania/hello-world-greeting
[Sun Nov 05 22:37:21 UTC 2017] Finished branch indexing. Indexing took 2.1 sec
Finished: SUCCESS

您不需要总是扫描存储库。GitHub Webhooks 已配置为在您的 GitHub 存储库上推送或新建分支时自动触发流水线。请记住,相应分支上还应该存在 Jenkinsfile,以告诉 Jenkins 在发现存储库中的更改时应该执行什么操作。

  1. 从您的 Jenkins 多分支流水线页面 (<Jenkins URL>/job/<Jenkins Multi-branch pipeline name>/),点击相应的分支流水线(见下图)。

  2. 在结果页面上,您将看到主分支流水线的阶段视图:

流水线阶段视图

  1. 要查看单元测试和集成测试结果,请点击页面下方最新测试结果链接,该链接在与阶段视图相同的页面上,如下截图所示:

  1. 在结果页面上,你将看到关于单元测试和集成测试执行的详细报告,如下截图所示:

使用 JUnit 插件的测试报告

  1. 你可以点击各个测试以获取更多细节。

  2. 在同一页面上,在左侧菜单中有一个名为“History”的链接,它提供了一段时间内与测试执行相关的指标数量的历史图表:

测试执行历史

在 SonarQube 中查看静态代码分析

让我们来看看作为我们 CI 流水线一部分执行的静态代码分析报告。按照以下步骤操作:

  1. 使用你喜欢的浏览器打开 SonarQube 链接。你应该看到类似以下截图的内容:

SonarQube 主页

  1. 从 SonarQube 仪表板,使用菜单选项,点击登录链接。

  2. 输入你的 SonarQube 凭据。

  3. 在结果页面上,在“PROJECTS”小部件下,点击example-project项目。

  4. 你将看到项目的静态代码分析概览(参见以下截图):

静态代码分析概述

  1. 点击“Measures | Coverage”。在结果页面上,你将得到你的代码覆盖率和单元测试结果报告的良好概览,如下截图所示:

代码覆盖率报告和单元测试报告

直接从 Jenkins 访问 SonarQube 分析

你可以直接从 CI 流水线中访问你的静态代码分析报告。按照以下步骤操作:

  1. 从你的 Jenkins 仪表板,点击你的多分支流水线。接下来,点击相应的分支流水线(我们示例中的 master)。

  2. 一旦你进入你的分支流水线,将鼠标悬停在“Static Code Analysis”阶段上,然后点击“Logs”。参见以下截图:

获取单个阶段日志

  1. 在名为“Stage Logs(静态代码分析)”的弹出窗口中向下滚动到底部。你应该看到一个链接,指向 SonarQube 分析页面。参见以下截图:

从 Jenkins 日志中的 SonarQube 分析链接

  1. 点击前述截图中显示的链接将直接带您到相应项目的 SonarQube 仪表板。

在 Artifactory 中查看构件

让我们看看上传到 Artifactory 后我们的构件是什么样子。按照以下步骤操作:

  1. 从你喜爱的浏览器访问 Artifactory 链接。从 Artifactory 仪表板,使用登录链接登录。

  2. 在左侧菜单中点击“Artifacts”选项卡。你应该在“Artifact Repository Browser”下看到你的仓库,如下截图所示:

构件库浏览器

  1. 展开仓库,您应该看到构建的构件和属性,如下截图所示:

CI 管道生成的构件

当质量门标准不符合时构建失败

在以下部分,我们将微调在上一章中创建的 SonarQube 质量门,使其应该使 Jenkins CI 管道失败。按照以下步骤模拟此场景:

  1. 登录到您的 SonarQube 服务器,然后从菜单栏中点击质量门。

  2. 从左侧菜单中,点击上一章中创建的质量门:example-quality-gate

  3. 现在,将 ERROR 字段的值从 50 改为 3

  4. 点击更新。最后,一切都应该如下截图所示:

更新 SonarQube 质量门

  1. 接下来,在 GitHub 仓库上进行一些更改,以触发 Jenkins 中的 CI 管道。

  2. 登录到 Jenkins,并导航到您的 Jenkins 多分支 CI 管道。您应该看到类似以下截图的内容:

失败的 CI 管道

  1. 点击相应管道的失败阶段以获取其日志。在弹出窗口中,滚动到底部。您应该看到管道失败的原因,如下截图所示(箭头):

带有质量门状态的 SonarQube 日志

摘要

在这一章中,我们学习了如何创建一个多分支 CI 管道,通过推送事件触发,执行构建、静态代码分析、集成测试,并将成功测试的二进制构件上传到 Artifactory。最后,我们从开发者的角度看到了整个 CI 管道的运行。

书中讨论的 CI 设计可以修改以适应任何类型项目的需求;用户只需确定可以与 Jenkins 一起使用的正确工具和配置。

在下一章中,我们将扩展我们的 CI 管道,在 QA 领域做更多事情。

使用 Jenkins 进行持续交付

我们将从一个覆盖以下领域的持续交付设计开始本章:

  • 分支策略

  • 持续交付工具列表

  • 一个 Jenkins 流水线结构

持续交付CD)设计将作为一个蓝图,指导读者回答 CD 的如何、为什么和在哪里实施的问题。设计将涵盖实施端到端 CD 流水线所涉及的所有必要步骤。

在本章讨论的 CD 设计应被视为实施 CD 的模板,而不是一个完整和最终的模型。所有使用的工具都可以修改和替换以适应目的。

Jenkins CD 设计

在这一节中,我们将介绍一个非常通用的 CD 设计。

分支策略

在第七章 Jenkins 使用持续集成 中,我们遵循了以下的分支策略:

  • 主分支

  • 集成分支

  • 功能分支

这个分支策略是 GitFlow 工作流 分支模型的一个精简版。

虽然 CI 可以在集成/开发分支或功能分支上执行,但 CD 只在集成和发布分支上执行。

发布分支

一些团队采用有发布分支的策略。发布分支是在成功测试的代码从主分支中发布到生产环境(分发给客户)后创建的。创建发布分支的目的是支持对相应发布的错误修复:

分支策略

CD 流水线

我们现在来到了 CD 设计的核心。我们不会创建一个新的流水线;相反,我们将在 Jenkins 中基于现有的 CI 多分支流水线上构建。新的 CD 流水线将包括以下阶段:

  1. 在推送事件(CI 流水线的初始化)上从版本控制系统VCS)获取代码。

  2. 构建和单元测试代码;在 Jenkins 上发布单元测试报告。

  3. 对代码进行静态代码分析并将结果上传到 SonarQube。如果错误数量超过质量门限定义的阈值,则流水线失败。

  4. 执行集成测试;在 Jenkins 上发布单元测试报告。

  5. 将构建好的产物与一些有意义的属性一起上传到 Artifactory。

  6. 将二进制文件部署到测试环境。

  7. 执行测试(质量分析)。

  8. 推广解决方案到 Artifactory 并将其标记为发布候选版本。

上述 CD 流水线的目的是自动化持续部署、测试(QA)并推动构建产物到二进制存储库的过程。每个步骤都会报告失败/成功。让我们详细讨论这些流水线及其组成部分。

在现实世界中,QA 可能包含多个测试阶段,例如性能测试、用户验收测试、组件测试等。为了简化问题,我们将在示例 CD 流水线中仅执行性能测试。

CD 工具集

我们正在实施 CI 的示例项目是一个简单的 Maven 项目。因此,我们将看到 Jenkins 与许多其他工具密切配合。

以下表格包含我们将要看到的所有工具和技术的列表:

工具/技术 描述
Java 主要用于编码的编程语言
Maven 构建工具
JUnit 单元测试和集成测试工具
Jenkins CI 工具
GitHub 版本控制系统
SonarQube 静态代码分析工具
Artifactory 二进制仓库管理器
Apache Tomcat 用于托管解决方案的应用服务器
Apache JMeter 性能测试工具

创建 Docker 镜像 - 性能测试

在本节中,我们将为我们的性能测试PT)创建一个 Docker 镜像。这个 Docker 镜像将被 Jenkins 用来创建 Docker 容器,在其中我们将部署我们构建的解决方案并执行我们的性能测试。按照以下步骤进行:

  1. 登录到您的 Docker 服务器。执行以下命令以检查可用的 Docker 镜像:
 sudo docker images
  1. 从以下截图中,您可以看到我已经在我的 Docker 服务器上有三个 Docker 镜像(ubuntuhello-worldmaven-build-slave-0.1):

列出 Docker 镜像

  1. 我们将使用 Ubuntu Docker 镜像构建一个新的 Docker 镜像来运行我们的 PT。

  2. 让我们升级我们的 Ubuntu Docker 镜像,添加我们运行测试所需的所有必要应用程序,如下所示:

    • Java JDK(最新版)

    • Apache Tomcat(8.5)

    • Apache JMeter

    • 用于登录 Docker 容器的用户账号

    • OpenSSH 守护程序(接受 SSH 连接)

    • Curl

  3. 执行以下命令以使用 Ubuntu Docker 镜像运行 Docker 容器。这将创建一个容器并打开其 bash shell:

sudo docker run -i -t ubuntu /bin/bash
  1. 现在,安装所有所需的应用程序,就像您在任何普通的 Ubuntu 机器上做的一样。让我们从创建一个jenkins用户开始:

    1. 执行以下命令,并按照以下所示的用户创建步骤进行:
adduser jenkins

创建用户

    1. 使用切换用户命令检查新用户:
su jenkins
  1. 输入exit切换回root用户。

  2. 接下来,我们将安装 SSH 服务器。按照以下命令的顺序执行:

apt-get update 
apt-get install openssh-server 
mkdir /var/run/sshd 
  1. 按照以下步骤安装 Java:

    1. 更新软件包索引:
apt-get update
    1. 接下来,安装 Java。执行以下命令将安装Java 运行时环境JRE):
apt-get install default-jre
  1. 安装 Tomcat 8.5 的最佳方法是下载最新的二进制版本,然后手动配置它:

    1. 移动到 /tmp 目录,并下载 Apache Tomcat 8.5,使用以下命令:
cd /tmp 
wget https://archive.apache.org/dist/tomcat/tomcat-8/v8.5.11/bin/apache-tomcat-8.5.11.tar.gz
    1. 我们将在 home/jenkins/ 目录中安装 Tomcat。为此,请首先切换到 jenkins 用户。在 /home/jenkins/ 中创建一个 tomcat 目录:
su jenkins 
mkdir /home/jenkins/tomcat
    1. 然后将存档解压到其中:
tar xzvf apache-tomcat-8*tar.gz \
-C /home/jenkins/tomcat --strip-components=1
  1. 输入 exit 切换回 root 用户。

  2. Apache JMeter 是执行性能测试的好工具。它是免费和开源的。它可以在 GUI 和命令行模式下运行,这使其成为自动化性能测试的合适选择:

    1. 切换到 /tmp 目录:
cd /tmp
    1. jmeter.apache.org/download_jmeter.cgi 下载 apache-jmeter-3.1.tgz,或者是最新的稳定版本:
wget https://archive.apache.org/dist/jmeter/binaries/apache-jmeter-3.1.tgz
    1. 我们将 JMeter 安装在 opt/jmeter/ 目录中。为此,请在 /opt 中创建一个 jmeter 目录:
mkdir /opt/jmeter
    1. 然后将存档解压到 /opt/jmeter/ 目录,并为其分配适当的权限:
tar xzvf apache-jmeter-3*.tgz \
-C /opt/jmeter --strip-components=1
 chown -R jenkins:jenkins /opt/jmeter/
 chmod -R 777 /opt/jmeter/
  1. 按照给定步骤安装 curl
apt-get install curl
  1. 按照给定的步骤保存我们对 Docker 镜像所做的所有更改:

    1. 输入 exit 退出容器。

    2. 我们需要保存(commit)我们对 Docker 容器所做的所有更改。

    3. 通过列出所有非活动容器,获取我们最近使用的容器的 CONTAINER ID,如下屏幕截图中在命令之后所示:

sudo docker ps -a

列出非活动容器

    1. 注意 CONTAINER ID,并执行以下命令保存(commit)我们对容器所做的更改:
sudo docker commit <CONTAINER ID> <new name for the container>
    1. 我已将我的容器命名为 performance-test-agent-0.1,如下屏幕截图所示:

Docker commit 命令

    1. 提交更改后,将创建一个新的 Docker 镜像。
    1. 执行以下 docker 命令以列出镜像,如下屏幕截图中在命令之后所示:
sudo docker images

列出 Docker 镜像

    1. 您可以看到我们的新 Docker 镜像,名称为 performance-test-agent-0.1。我们现在将配置我们的 Jenkins 服务器使用 performance-test-agent-0.1 Docker 镜像来创建 Jenkins 从节点(构建代理)。

在 Jenkins 中添加 Docker 容器凭据

按照给定的步骤在 Jenkins 中添加凭据,以允许其与 Docker 通信:

  1. 从 Jenkins 仪表板导航到凭据 | 系统 | 全局凭据(不受限制)

  2. 单击左侧菜单上的添加凭据链接以创建新的凭据(参见以下屏幕截图)。

  3. 选择类型用户名与密码

  4. 范围字段保留为其默认值。

  5. 用户名字段下为您的 Docker 镜像(按照我们的示例,为 jenkins)添加一个用户名。

  6. 密码字段下面添加密码。

  7. ID字段下添加一个 ID,并在描述字段下添加描述。

  8. 完成后,单击OK按钮:

在 Jenkins 内创建凭据

更新 Jenkins 内的 Docker 设置

按照给定的步骤更新 Jenkins 内的 Docker 设置:

  1. 从 Jenkins 仪表板中,点击管理 Jenkins | 配置系统

  2. 滚动到部分的底部。

  3. 在 Cloud 部分下,点击添加 Docker 模板按钮,然后选择Docker 模板

  4. 你将看到很多要配置的设置(参见下面的截图)。然而,为了保持这个演示简单,让我们坚持重要的设置。

  5. Docker 镜像字段下,输入我们之前创建的 Docker 镜像的名称。在我的情况下,它是performance-test-agent-0.1

  6. 标签字段下,添加一个标签。使用此标签,您的 Jenkins 管道将识别 Docker 容器。我添加了docker_pt标签。

  7. 启动方法应为 Docker SSH 计算机启动器。

  8. 凭据字段下,选择我们创建的用于访问 Docker 容器的凭据。

  9. 确保拉取策略选项设置为永不拉取。

  10. 将其余选项保持为默认值。

  11. 完成后,点击应用,然后点击保存

为集成测试创建 Docker 模板

使用 JMeter 创建性能测试

在本节中,我们将学习如何使用 JMeter 工具创建一个简单的性能测试。所述步骤应在您的本地机器上执行。以下步骤在具有 Ubuntu 16.04 的机器上执行。

安装 Java

按照给定步骤安装 Java:

  1. 更新软件包索引:
sudo apt-get update
  1. 接下来,安装 Java。以下命令将安装 JRE:
sudo apt-get install default-jre
  1. 要设置JAVA_HOME环境变量,首先获取 Java 安装位置。通过执行以下命令来执行此操作:
sudo update-alternatives --config java
  1. 复制结果路径并更新/etc/environment文件中的JAVA_HOME变量。

安装 Apache JMeter

按照给定步骤安装 Apache JMeter:

  1. 进入/tmp目录:
cd /tmp
  1. jmeter.apache.org/download_jmeter.cgi下载apache-jmeter-3.1.tgz,或者是最新的稳定版本:
wget https://archive.apache.org/dist/jmeter/binaries/apache-jmeter-3.1.tgz
  1. 我们将在/opt目录下安装 JMeter。为此,在/opt内创建一个jmeter目录:
mkdir /opt/jmeter
  1. 然后将归档文件解压到其中:
tar xzvf apache-jmeter-3*.tgz \
-C /opt/jmeter --strip-components=1

启动 JMeter

按照给定步骤启动 JMeter:

  1. 要启动 JMeter,请移动到 JMeter 安装目录并运行jmeter.sh脚本,使用以下命令:
cd /opt/jmeter/bin 
./jmeter.sh
  1. JMeter GUI 实用程序将在一个新窗口中打开。

创建性能测试用例

默认情况下,您将看到一个示例测试计划。我们将通过修改现有模板来创建一个新的测试计划:

  1. 将测试计划重命名为Hello_World_Test_Plan,如下截图所示:

创建测试计划

  1. 点击菜单项中的保存按钮或点击Ctrl + S,将其保存在examples文件夹内,如下截图所示:

保存测试计划

创建一个线程组

按照给定步骤创建一个线程组:

  1. 添加一个线程组。要这样做,请右键单击Hello_World_Test_Plan,然后选择添加 | 线程(用户) | 线程组

创建一个线程组

  1. 在生成的页面中,为你的线程组命名并填写以下选项:

    1. 选择继续以进行 采样器错误后要执行的操作

    2. 线程数(用户)添加为1

    3. 上升时间(秒)添加为1

    4. 循环次数添加为1

配置一个线程组

创建一个采样器

按照给定步骤创建一个采样器:

  1. 右键单击Hello_World_Test_Plan,然后选择添加 | 采样器 | HTTP 请求

添加一个采样器

  1. 适当命名 HTTP 请求并填写以下选项:

    1. 服务器名称或 IP添加为<您的测试服务器机器的 IP 地址>

    2. 添加端口号为8080

    3. 路径添加为/hello.0.0.1/

配置采样器

添加一个监听器

按照给定步骤添加一个监听器:

  1. 右键单击Hello_World_Test_Plan,然后选择添加 | 监听器 | 查看结果树

添加一个监听器

  1. 什么都不做;将所有字段保持原样。

  2. 点击菜单项中的保存按钮或点击Ctrl + S保存整个配置。

  3. /opt/jmeter/bin/examples.复制.jmx文件。

  4. 在你的 Maven 项目下,创建一个名为pt的文件夹,在src目录中,并将.jmx文件放入其中。

  5. 将代码上传到 GitHub。

CD 管道

我们拥有所有必需的工具,Docker 镜像已准备就绪。在本节中,我们将在 Jenkins 中创建一个管道,描述我们的 CD 过程。

为 CD 编写 Jenkinsfile

我们将在之前创建的 CI 管道基础上进行。让我们首先重新审视我们的 CI 管道,然后我们将作为 CD 过程的一部分添加一些新的阶段。

重新审视 CI 管道的代码

以下是作为 CI 的一部分的完整组合代码:

node('docker') {
  stage('Poll') {
    checkout scm
  }
  stage('Build & Unit test'){
    sh 'mvn clean verify -DskipITs=true';
    junit '**/target/surefire-reports/TEST-*.xml'
    archive 'target/*.jar'
  }
  stage('Static Code Analysis'){
    sh 'mvn clean verify sonar:sonar -Dsonar.projectName=example-project
    -Dsonar.projectKey=example-project
    -Dsonar.projectVersion=$BUILD_NUMBER';
  }
  stage ('Integration Test'){
    sh 'mvn clean verify -Dsurefire.skip=true';
    junit '**/target/failsafe-reports/TEST-*.xml'
    archive 'target/*.jar'
  }
  stage ('Publish'){
    def server = Artifactory.server 'Default Artifactory Server'
    def uploadSpec = """{
      "files": [
        {
          "pattern": "target/hello-0.0.1.war",
          "target": "example-project/${BUILD_NUMBER}/",
          "props": "Integration-Tested=Yes;Performance-Tested=No"
        }
      ]
    }"""
    server.upload(uploadSpec)
  }
}

用于存储构建产物的管道代码

Jenkins 管道使用称为 stash 的功能在节点之间传递构建产物。在接下来的步骤中,我们将 stash 一些希望传递到docker_pt节点的构建产物:

stash includes: 'target/hello-0.0.1.war,src/pt/Hello_World_Test_Plan.jmx', name: 'binary'

在上述代码中:

  • name:存储的名称

  • includes:要包含的逗号分隔文件

生成一个 Docker 容器 - 性能测试

首先,让我们创建一个管道代码,该代码将使用performance-test-agent-0.1 Docker 镜像为性能测试创建一个 Docker 容器(Jenkins 从节点):

node('docker_pt') {
}

其中docker_ptperformance-test-agent-0.1 Docker 模板的标签。

我们想要在docker_pt节点上执行以下任务:

  1. 启动 Tomcat。

  2. 将构建产物部署到测试环境上的 Tomcat。

  3. 执行性能测试。

  4. 在 Artifactory 中提升构建工件。

所有前述任务都是我们 CD 管道的各个阶段。让我们为每一个阶段编写管道代码。

启动 Apache Tomcat 的管道代码

在性能测试代理上启动 Apache Tomcat 的管道代码是一个简单的 shell 脚本,将运行 Tomcat 安装目录中存在的 ./startup.sh 脚本:

sh '''cd /home/jenkins/tomcat/bin
./startup.sh''';

将上述步骤包装在名为 启动 Tomcatstage 中:

stage ('Start Tomcat'){
    sh '''cd /home/jenkins/tomcat/bin
    ./startup.sh''';
}

部署构建工件的管道代码

部署构建工件的管道代码分为两个步骤。首先,我们将从上一个节点 Docker 块中存储的二进制包取出。然后,我们将未存储的文件部署到我们的测试环境中 Tomcat 安装目录下的 webapps 文件夹中。代码如下:

unstash 'binary'
sh 'cp target/hello-0.0.1.war /home/jenkins/tomcat/webapps/';

将上述步骤包装在名为 部署stage 中:

stage ('Deploy){
    unstash 'binary'
    sh 'cp target/hello-0.0.1.war /home/jenkins/tomcat/webapps/';
}

运行性能测试的管道代码

执行性能测试的管道代码是一个简单的 shell 脚本,调用 jmeter.sh 脚本并将 .jmx 文件传递给它。测试结果存储在一个 .jtl 文件中,然后进行归档。代码如下:

sh '''cd /opt/jmeter/bin/
./jmeter.sh -n -t $WORKSPACE/src/pt/Hello_World_Test_Plan.jmx -l $WORKSPACE/test_report.jtl''';

step([$class: 'ArtifactArchiver', artifacts: '**/*.jtl'])

以下表格给出了上述代码片段的描述:

代码 描述
./jmeter.sh -n -t <.jmx 文件的路径> -l <保存 .jtl 文件的路径> 这是执行性能测试计划(.jmx 文件)并生成测试结果(.jtl 文件)的 jmeter 命令。
step([$class: 'ArtifactArchiver', artifacts: '**/*.jtl']) 此行代码将归档所有扩展名为 .jtl 的文件。

将上一步包装在名为 性能测试stage 中:

stage ('Performance Testing'){
    sh '''cd /opt/jmeter/bin/
    ./jmeter.sh -n -t $WORKSPACE/src/pt/Hello_World_Test_Plan.jmx -l $WORKSPACE/test_report.jtl''';
    step([$class: 'ArtifactArchiver', artifacts: '**/*.jtl'])
}

在 Artifactory 中提升构建工件的管道代码

我们将在 Artifactory 中提升构建工件的方式是使用属性(键值对)功能。所有通过性能测试的构建都将应用一个 Performance-Tested=Yes 标签。代码如下:

withCredentials([usernameColonPassword(credentialsId: 'artifactory-account', variable: 'credentials')]) {
    sh 'curl -u${credentials} -X PUT "http://172.17.8.108:8081/artifactory/api/storage/example-project/${BUILD_NUMBER}/hello-0.0.1.war?properties=Performance-Tested=Yes"';
}

以下表格给出了上述代码片段的描述:

代码 描述
withCredentials([usernameColonPassword(credentialsId: 'artifactory-account', variable: 'credentials')]) {``} 我们在 Jenkins 中使用 withCredentials 插件将 Artifactory 凭据传递给 curl 命令。
curl -u<用户名>:密码 -X PUT "<artifactory 服务器 URL>/api/storage/<artifactory 存储库名称>?properties=key-value" 这是更新 Artifactory 中构建工件属性(键值对)的 curl 命令。curl 命令利用了 Artifactory 的 REST API 功能。

将上一步包装在名为 在 Artifactory 中提升构建stage 中:

stage ('Promote build in Artifactory'){
    withCredentials([usernameColonPassword(credentialsId: 'artifactory-account', variable: 'credentials')]) {
        sh 'curl -u${credentials} -X PUT "http://172.17.8.108:8081/artifactory/api/storage/example-project/${BUILD_NUMBER}/hello-0.0.1.war?properties=Performance-Tested=Yes"';
    }
}

组合 CD 管道代码

以下是完整的组合代码,将在 docker_pt 节点中运行:

node('docker_pt') {
  stage ('Start Tomcat'){
    sh '''cd /home/jenkins/tomcat/bin
    ./startup.sh''';
  }
  stage ('Deploy '){
    unstash 'binary'
    sh 'cp target/hello-0.0.1.war /home/jenkins/tomcat/webapps/';
  }
  stage ('Performance Testing'){
    sh '''cd /opt/jmeter/bin/
    ./jmeter.sh -n -t $WORKSPACE/src/pt/Hello_World_Test_Plan.jmx -l
    $WORKSPACE/test_report.jtl''';
    step([$class: 'ArtifactArchiver', artifacts: '**/*.jtl'])
  }
  stage ('Promote build in Artifactory'){
    withCredentials([usernameColonPassword(credentialsId:
      'artifactory-account', variable: 'credentials')]) {
        sh 'curl -u${credentials} -X PUT
        "http://172.17.8.108:8081/artifactory/api/storage/example-project/
        ${BUILD_NUMBER}/hello-0.0.1.war?properties=Performance-Tested=Yes"';
      }
  }
}

让我们将上述代码与 CI 的管道代码结合起来,得到完整的 CD 管道代码,如下所示:

node('docker') {
  stage('Poll') {
    checkout scm
  }
  stage('Build & Unit test'){
    sh 'mvn clean verify -DskipITs=true';
    junit '**/target/surefire-reports/TEST-*.xml'
    archive 'target/*.jar'
  }
  stage('Static Code Analysis'){
    sh 'mvn clean verify sonar:sonar -Dsonar.projectName=example-project
    -Dsonar.projectKey=example-project -Dsonar.projectVersion=$BUILD_NUMBER';
  }
  stage ('Integration Test'){
    sh 'mvn clean verify -Dsurefire.skip=true';
    junit '**/target/failsafe-reports/TEST-*.xml'
    archive 'target/*.jar'
  }
  stage ('Publish'){
    def server = Artifactory.server 'Default Artifactory Server'
    def uploadSpec = """{
      "files": [
        {
          "pattern": "target/hello-0.0.1.war",
          "target": "example-project/${BUILD_NUMBER}/",
          "props": "Integration-Tested=Yes;Performance-Tested=No"
        }
      ]
    }"""
    server.upload(uploadSpec)
  }
  stash includes: 'target/hello-0.0.1.war,src/pt/Hello_World_Test_Plan.jmx',
  name: 'binary'
}
node('docker_pt') {
  stage ('Start Tomcat'){
    sh '''cd /home/jenkins/tomcat/bin
    ./startup.sh''';
  }
  stage ('Deploy '){
    unstash 'binary'
    sh 'cp target/hello-0.0.1.war /home/jenkins/tomcat/webapps/';
  }
  stage ('Performance Testing'){
    sh '''cd /opt/jmeter/bin/
    ./jmeter.sh -n -t $WORKSPACE/src/pt/Hello_World_Test_Plan.jmx -l
    $WORKSPACE/test_report.jtl''';
    step([$class: 'ArtifactArchiver', artifacts: '**/*.jtl'])
  }
  stage ('Promote build in Artifactory'){
    withCredentials([usernameColonPassword(credentialsId:
      'artifactory-account', variable: 'credentials')]) {
        sh 'curl -u${credentials} -X PUT
        "http://172.17.8.108:8081/artifactory/api/storage/example-project/
        ${BUILD_NUMBER}/hello-0.0.1.war?properties=Performance-Tested=Yes"';
      }
  }
}

CD 运行情况

在您的 GitHub 代码上进行一些更改,或者仅从 Jenkins 仪表板触发 Jenkins 流水线:

  1. 登录到 Jenkins,并从 Jenkins 仪表板单击您的 Multibranch Pipeline。您应该会看到类似以下内容:

Jenkins CD 流水线实践

  1. 登录到 Artifactory 服务器,查看代码是否已使用下列属性上传和推广:

构建产物正在 Artifactory 中推广

  1. 让我们在 Jenkins Blue Ocean 中看看我们的 CD 流水线。要做到这一点,请导航到您的 Jenkins Multibranch CD 流水线(<Jenkins URL>/job/<Jenkins multibranch pipeline name>/)。

  2. 在流水线页面上,单击左侧菜单中的 Open Blue Ocean 链接。

  3. 您将被带到 Blue Ocean 中的 Multibranch Pipeline 页面,如以下截图所示:

  1. 单击主分支以查看其流水线。您应该会看到类似以下内容:

总结

在本章中,我们学习了如何创建一个端到端的 CD 流水线,在推送事件上触发,执行构建、静态代码分析和集成测试,将成功测试的二进制产物上传到 Artifactory,部署代码到测试环境,执行一些自动化测试,并在 Artifactory 中推广二进制产物。

书中讨论的 CD 设计可以修改以满足任何类型项目的需求。用户只需识别可以与 Jenkins 配合使用的正确工具和配置。

在下一章中,我们将学习有关持续部署的内容,它与持续交付有何不同,以及更多。

使用 Jenkins 进行持续部署

本章首先定义和解释了持续部署。我们还将尝试区分持续部署和持续交付。持续部署是持续交付流水线的一个简单、微调版本。因此,我们不会看到任何主要的 Jenkins 配置更改或任何新工具。

本章将涵盖以下主题:

  • 创建一个生产服务器

  • 在生产服务器上安装 Jenkins 从属节点

  • 创建一个 Jenkins 持续部署流水线

  • 持续交付的实施

什么是持续部署?

将生产就绪特性持续部署到生产环境或最终用户的过程称为持续部署

从整体上看,持续部署意味着,使生产就绪的特性立即上线,无需任何干预。这包括以敏捷方式构建特性、持续集成和测试,并将其部署到生产环境中,而无需任何中断。

持续部署从字面上讲意味着,在任何给定环境中持续部署任何给定包的任务。因此,将包部署到测试服务器和生产服务器的任务传达了持续部署的字面意义。

持续部署与持续交付的区别

首先,特性被开发,然后它们经历一个循环,或持续集成,或各种测试。任何通过各种测试的东西都被视为生产就绪的特性。然后,这些生产就绪的特性被标记为 Artifactory(本书未显示)中的标签,或者被保持分开,以将它们与非生产就绪的特性区分开。

这类似于制造生产线。原始产品经历修改和测试阶段。最终,成品被包装并存放在仓库中。根据订单,从仓库发货到各个地方。产品在包装后不会立即发货。

我们可以安全地称这种实践为持续交付。以下插图描述了持续交付的生命周期:

持续交付流水线

另一方面,持续部署的生命周期看起来有些如下所示。部署阶段是立即进行的,没有任何中断。生产就绪的特性立即部署到生产环境:

持续部署流水线

谁需要持续部署?

人们可能会心里想着以下几个问题:我如何在我的组织中实现持续部署可能会面临什么挑战需要多少测试来进行并自动化?问题不胜枚举。

然而,技术挑战只是一方面。更重要的是要决定我们是否真的需要它。我们真的需要持续部署吗?

答案是,并不总是以及不完全是每种情况。因为从我们对持续部署的定义以及前一个主题的理解来看,生产可用的功能会立即部署到生产环境中。

在许多组织中,业务部门决定是否将一个功能上线,或何时上线一个功能。因此,将持续部署视为一个选项,而不是强制性的。

另一方面,持续交付;这意味着以连续方式创建可供生产使用的功能,应该是任何组织的座右铭。

创建一个生产服务器

在接下来的部分中,让我们创建一个承载我们hello world应用程序的生产服务器。稍后我们将扩展我们的持续交付流程,自动在我们的生产服务器上部署完全测试的二进制文件。

在以下示例中,我们的生产服务器是一个简单的 Tomcat 服务器。让我们使用 Vagrant 创建一个。

安装 Vagrant

在本节中,我们将在 Ubuntu 上安装 Vagrant。请确保以root用户或具有 root 权限(sudo访问)的帐户执行这些步骤:

  1. 打开终端并输入以下命令以下载 Vagrant:
wget https://releases.hashicorp.com/vagrant/1.8.5/vagrant_1.8.5_x86_64.deb

或者,你也可以从 Vagrant 网站上下载最新的 Vagrant 软件包:www.vagrantup.com/downloads.html

Vagrant 下载网页

使用可用的最新版本的 Vagrant 和 VirtualBox。使用旧版本的 Vagrant 与新版本的 VirtualBox 或反之可能在创建 VM 时导致问题。

  1. 下载完成后,你应该会看到一个.deb文件。

  2. 执行以下命令使用下载的软件包文件安装 Vagrant。可能需要输入密码:

sudo dpkg -i vagrant_1.8.5_x86_64.deb 
sudo apt-get install -f
  1. 安装完成后,通过执行以下命令检查已安装的 Vagrant 版本:
vagrant --version
  1. 你应该会看到类似的输出:
Vagrant 1.8.5

安装 VirtualBox

Vagrant 需要 Oracle VirtualBox 来创建虚拟机。然而,并不仅限于 Oracle VirtualBox,你也可以使用 VMware。按照以下步骤在你的机器上安装 VirtualBox:

要使用 VMware 或 AWS 运行 Vagrant,请访问www.vagrantup.com/docs/getting-started/providers.html

  1. 将以下行添加到sources.list文件中,该文件位于/etc/apt目录中:
deb http://download.virtualbox.org/virtualbox/debian \
xenial contrib

根据你的 Ubuntu 发行版,用xenial替换为vividutopictrustyraringquantalpreciselucidjessiewheezysqueeze

  1. 使用以下命令下载并注册密钥。你应该期望两个命令都输出:OK
wget -q \
https://www.virtualbox.org/download/oracle_vbox_2016.asc -O- | 
sudo apt-key add - 
wget -q \
https://www.virtualbox.org/download/oracle_vbox.asc -O- | 
sudo apt-key add –

  1. 要安装 VirtualBox,请执行以下命令:
sudo apt-get update 
sudo apt-get install virtualbox-5.1
  1. 执行以下命令以查看已安装的 VirtualBox 版本:
VBoxManage –-version
  1. 您应该看到类似的输出:
5.1.6r110634

Ubuntu/Debian 用户可能希望安装dkms软件包,以确保在下次apt-get upgrade期间 Linux 内核版本更改时,VirtualBox 主机内核模块(vboxdrvvboxnetfltvboxnetadp)得到正确更新。对于 Debian 来说,它在 Lenny backports 中可用,在 Squeeze 及更高版本的正常仓库中可用。可以通过 Synaptic 软件包管理器或通过以下命令安装dkms软件包:

**sudo apt-get install dkms**

使用 Vagrant 创建一个虚拟机

在接下来的部分中,我们将使用 Vagrant 和 VirtualBox 生成一个将充当我们生产服务器的虚拟机。

创建一个 Vagrantfile

我们将创建一个 Vagrantfile 来描述我们的虚拟机。请按照以下步骤操作:

  1. 使用以下命令创建一个名为Vagrantfile的新文件:
sudo nano Vagrantfile
  1. 将以下代码粘贴到文件中:
# -*- mode: ruby -*-
# vi: set ft=ruby :
Vagrant.configure(2) do |config|
config.vm.box = "ubuntu/xenial64"

config.vm.define :node1 do |node1_config|
node1_config.vm.network "private_network", ip:"192.168.56.31"
node1_config.vm.provider :virtualbox do |vb|
vb.customize ["modifyvm", :id, "--memory", "2048"]
vb.customize ["modifyvm", :id, "--cpus", "2"]
end
end
end

根据需要选择 IP 地址、内存和 CPU 数量。

  1. 键入Ctrl + X,然后 Y 保存文件。

使用 Vagrant 生成一个虚拟机

在本节中,我们将使用刚刚创建的Vagrantfile创建一个虚拟机:

  1. 键入以下命令使用上述的Vagrantfile生成一个虚拟机:
 vagrant up node1
  1. Vagrant 将花费一些时间来启动机器。一旦完成,执行以下命令登录到新的虚拟机:
 vagrant ssh node1

输出如下:

Welcome to Ubuntu 16.04.2 LTS (GNU/Linux 4.4.0-83-generic x86_64)

 * Documentation:  https://help.ubuntu.com
 * Management:     https://landscape.canonical.com
 * Support:        https://ubuntu.com/advantage

 Get cloud support with Ubuntu Advantage Cloud Guest:
 http://www.ubuntu.com/business/services/cloud
0 packages can be updated.
0 updates are security updates.

ubuntu@ubuntu-xenial:~$
  1. 我们现在在虚拟机内。我们将升级我们的虚拟机,并安装我们运行应用程序所需的所有必要应用程序:

    • Java JDK(最新版)

    • Apache Tomcat(8.5)

    • 一个用于登录 Docker 容器的用户账户

    • 开启 SSH 守护进程—sshd(以接受 SSH 连接)

    • Curl

  2. 现在,按照您在任何正常 Ubuntu 机器上的操作方式安装所有必需的应用程序。让我们首先创建一个jenkins用户:

    1. 执行以下命令并按照用户创建步骤进行操作:
adduser jenkins

输出如下:

Adding user `jenkins' ...
Adding new group `jenkins' (1001) ...
Adding new user `jenkins' (1001) with group `jenkins' ...
Creating home directory `/home/jenkins' ...
Copying files from `/etc/skel' ...
Enter new UNIX password:
Retype new UNIX password:
passwd: password updated successfully
Changing the user information for jenkins
Enter the new value, or press ENTER for the default
 Full Name []: Nikhil Pathania
 Room Number []:
 Work Phone []:
 Home Phone []:
 Other []:
Is the information correct? [Y/n] Y
    1. 使用切换用户命令检查新用户:
su jenkins
  1. 通过键入exit切换回 root 用户。

  2. 接下来,我们将安装 SSH 服务器。按顺序执行以下命令(如果openssh-server应用程序和/var/run/sshd目录路径已存在,则忽略):

sudo apt-get update

sudo apt-get install openssh-server

sudo mkdir /var/run/sshd
  1. 跟随以下步骤安装 Java:

    1. 更新软件包索引:
sudo apt-get update
    1. 接下来,安装 Java。以下命令将安装 JRE:
sudo apt-get install default-jre
  1. 安装 Tomcat 8.5 的最佳方法是下载最新的二进制发行版,然后手动配置它:

    1. 切换到/tmp目录并使用以下命令下载 Apache Tomcat 8.5:
cd /tmp

wget https://archive.apache.org/dist/tomcat/tomcat-8/v8.5.11/bin/apache-tomcat-8.5.11-deployer.tar.gz
    1. 我们将在$HOME目录下安装 Tomcat。为此,请在$HOME内创建一个tomcat目录:
mkdir $HOME/tomcat
    1. 然后,将存档文件解压缩到其中:
sudo tar xzvf apache-tomcat-8*tar.gz \
-C $HOME/tomcat --strip-components=1
  1. 在终端中键入exit退出虚拟机。

在 Jenkins 内添加生产服务器凭据

为了使 Jenkins 与生产服务器通信,我们需要在 Jenkins 内添加账户凭据。

我们将使用 Jenkins 凭据插件来实现这一点。 如果您已经按照本章开头讨论的 Jenkins 设置向导进行操作,您将在 Jenkins 仪表板上找到凭据功能(请参阅左侧菜单):

按照给定的步骤进行操作:

  1. 从 Jenkins 仪表板,单击凭据 | 系统 | 全局凭据(无限制)。

  2. 在全局凭据(无限制)页面上,从左侧菜单中,单击添加凭据链接。

  3. 您将看到一堆字段供您配置。

  4. 对于类型字段,选择用户名与密码。

  5. 为范围字段选择全局(Jenkins、节点、项目、所有子项目等)。

  6. 在用户名字段下添加一个用户名。

  7. 在密码字段下添加一个密码。

  8. 通过在 ID 字段下键入字符串为您的凭据分配一个唯一的 ID。

  9. 在描述字段下添加一个有意义的描述。

  10. 完成后单击保存按钮:

在 Jenkins 内添加凭据

在生产服务器上安装 Jenkins 从节点

在本节中,我们将在生产服务器上安装一个 Jenkins 从节点。 这将允许我们在生产服务器上执行部署。 执行以下步骤:

  1. 从 Jenkins 仪表板,单击管理 Jenkins | 管理节点。

  2. 一旦在节点管理器页面上,从左侧菜单中单击新建节点。

  3. 为您的新 Jenkins 从节点命名,如下所示:

配置 Jenkins 从节点

创建 Jenkins 持续部署流水线

在下一节中,我们将扩展我们的持续交付流水线以执行部署。

重温 CD 流水线代码

以下是作为 CD 一部分的完整组合代码:

node('docker') {
  stage('Poll') {
    checkout scm
  }
  stage('Build & Unit test'){
    sh 'mvn clean verify -DskipITs=true';
    junit '**/target/surefire-reports/TEST-*.xml'
    archive 'target/*.jar'
  }
  stage('Static Code Analysis'){
    sh 'mvn clean verify sonar:sonar -Dsonar.projectName=example-project
    -Dsonar.projectKey=example-project
    -Dsonar.projectVersion=$BUILD_NUMBER';
  }
  stage ('Integration Test'){
    sh 'mvn clean verify -Dsurefire.skip=true';
    junit '**/target/failsafe-reports/TEST-*.xml'
    archive 'target/*.jar'
  }
  stage ('Publish'){
    def server = Artifactory.server 'Default Artifactory Server'
    def uploadSpec = """{
      "files": [
        {
           "pattern": "target/hello-0.0.1.war",
           "target": "example-project/${BUILD_NUMBER}/",
           "props": "Integration-Tested=Yes;Performance-Tested=No"
        }
      ]
    }"""
    server.upload(uploadSpec)
  }
  stash includes:
   'target/hello-0.0.1.war,src/pt/Hello_World_Test_Plan.jmx',
  name: 'binary'
}
node('docker_pt') {
  stage ('Start Tomcat'){
    sh '''cd /home/jenkins/tomcat/bin
    ./startup.sh''';
  }
  stage ('Deploy '){
    unstash 'binary'
    sh 'cp target/hello-0.0.1.war /home/jenkins/tomcat/webapps/';
  }
  stage ('Performance Testing'){
    sh '''cd /opt/jmeter/bin/
    ./jmeter.sh -n -t $WORKSPACE/src/pt/Hello_World_Test_Plan.jmx -l
    $WORKSPACE/test_report.jtl''';
    step([$class: 'ArtifactArchiver', artifacts: '**/*.jtl'])
  }
  stage ('Promote build in Artifactory'){
    withCredentials([usernameColonPassword(credentialsId:
     'artifactory-account', variable: 'credentials')]) {
      sh 'curl -u${credentials} -X PUT
      "http://192.168.56.102:8081/artifactory/api/storage/example-project/
      ${BUILD_NUMBER}/hello-0.0.1.war?properties=Performance-Tested=Yes"';
    }
  }
}

用于生产 Jenkins 从节点的流水线代码

首先,让我们为我们的 Jenkins 从节点 production-server 创建一个节点块:

node('production') {
}

其中production是 Jenkins 从节点 production-server 的标签。

我们希望将构建产物部署到生产服务器上的 Tomcat 上的production节点。

让我们为其编写流水线代码。

从 Artifactory 下载二进制文件的流水线代码

要从 Artifactory 下载构建产物,我们将使用文件规范。文件规范代码如下所示:

"files": [
    {
      "pattern": "[Mandatory]",
      "target": "[Mandatory]",
      "props": "[Optional]",
      "recursive": "[Optional, Default: 'true']",
      "flat" : "[Optional, Default: 'true']",
      "regexp": "[Optional, Default: 'false']"
    }
  ]

以下表描述了使用的各种参数:

参数 描述
pattern [必填]指定应上传到 Artifactory 的本地文件系统路径的工件。您可以使用通配符或由regexp属性指定的正则表达式指定多个工件。如果使用regexp,则需要使用反斜杠\转义表达式中使用的任何保留字符(例如.?等)。从 Jenkins Artifactory 插件的版本 2.9.0 和 TeamCity Artifactory 插件的版本 2.3.1 开始,模式格式已经简化,并且对于所有操作系统(包括 Windows),都使用相同的文件分隔符/
target [必填]指定 Artifactory 中目标路径的格式如下:[repository_name]/[repository_path]如果模式以斜杠结尾,例如,repo-name/a/b/,那么假定b是 Artifactory 中的一个文件夹,并且文件被上传到其中。在repo-name/a/b的情况下,上传的文件在 Artifactory 中被重命名为b。为了灵活指定上传路径,您可以在源路径中的对应令牌周围包含占位符形式的{1},{2},{3}...,这些占位符会被替换为相应的标记。有关更多详细信息,请参阅使用占位符文档。
props [可选]以分号(;)分隔的key=value对列表,将其附加为上传的属性。如果任何键可以具有多个值,则每个值由逗号(,)分隔。例如,key1=value1;key2=value21,value22;key3=value3
flat [默认值:true]如果为true,则工件将上传到指定的确切目标路径,并且源文件系统中的层次结构将被忽略。如果为false,则工件将上传到目标路径,同时保持其文件系统层次结构。
recursive [默认值:true]如果为true,则还从源目录的子目录中收集工件进行上传。如果为false,则仅上传源目录中明确指定的工件。
regexp [默认值:false]如果为true,则命令将解释模式属性(描述要上传的工件的本地文件系统路径)为正则表达式。如果为false,则命令将解释模式属性为通配符表达式。

以下是我们将在管道中使用的 File Specs 代码:

def server = Artifactory.server 'Default Artifactory Server'
def downloadSpec = """{
  "files": [
    {
        "pattern": "example-project/$BUILD_NUMBER/*.zip",
        "target": "/home/jenkins/tomcat/webapps/"
        "props": "Performance-Tested=Yes;Integration-Tested=Yes",
    }
  ]
}""
server.download(downloadSpec)

将前面的步骤包装在名为Deploy to Prodstage内:

stage ('Deploy to Prod'){
  def server = Artifactory.server 'Default Artifactory Server'
  def downloadSpec = """{
    "files": [
      {
        "pattern": "example-project/$BUILD_NUMBER/*.zip",
        "target": "/home/jenkins/tomcat/webapps/"
        "props": "Performance-Tested=Yes;Integration-Tested=Yes",
      }
    ]
  }""
server.download(downloadSpec)
}

Deploy to Prod阶段包装在production节点块内:

node ('production') {
  stage ('Deploy to Prod'){    def server = Artifactory.server 'Default Artifactory Server'
    def downloadSpec = """{
      "files": [
        {
          "pattern": "example-project/$BUILD_NUMBER/*.zip",
          "target": "/home/jenkins/tomcat/webapps/"
          "props": "Performance-Tested=Yes;Integration-Tested=Yes",
        }
      ]
    }""
    server.download(downloadSpec)
  }
}

组合连续部署管道代码

以下是组合的连续部署管道代码:

node('docker') {
  stage('Poll') {
    checkout scm
  }
  stage('Build & Unit test'){
    sh 'mvn clean verify -DskipITs=true';
    junit '**/target/surefire-reports/TEST-*.xml'
    archive 'target/*.jar'
  }
  stage('Static Code Analysis'){
    sh 'mvn clean verify sonar:sonar -Dsonar.projectName=example-project
    -Dsonar.projectKey=example-project
    -Dsonar.projectVersion=$BUILD_NUMBER';
  }
  stage ('Integration Test'){
    sh 'mvn clean verify -Dsurefire.skip=true';
    junit '**/target/failsafe-reports/TEST-*.xml'
    archive 'target/*.jar'
  }
  stage ('Publish'){
    def server = Artifactory.server 'Default Artifactory Server'
    def uploadSpec = """{
      "files": [
        {
          "pattern": "target/hello-0.0.1.war",
          "target": "example-project/${BUILD_NUMBER}/",
          "props": "Integration-Tested=Yes;Performance-Tested=No"
        }
      ]
    }"""
    server.upload(uploadSpec)
  }
  stash includes:
   'target/hello-0.0.1.war,src/pt/Hello_World_Test_Plan.jmx',
  name: 'binary'
}
node('docker_pt') {
  stage ('Start Tomcat'){
    sh '''cd /home/jenkins/tomcat/bin
    ./startup.sh''';
  }
  stage ('Deploy '){
    unstash 'binary'
    sh 'cp target/hello-0.0.1.war /home/jenkins/tomcat/webapps/';
  }
  stage ('Performance Testing'){
    sh '''cd /opt/jmeter/bin/
    ./jmeter.sh -n -t $WORKSPACE/src/pt/Hello_World_Test_Plan.jmx -l
    $WORKSPACE/test_report.jtl''';
    step([$class: 'ArtifactArchiver', artifacts: '**/*.jtl'])
  }
  stage ('Promote build in Artifactory'){
    withCredentials([usernameColonPassword(credentialsId:
     'artifactory-account', variable: 'credentials')]) {
      sh 'curl -u${credentials} -X PUT
      "http://192.168.56.102:8081/artifactory/api/storage/example-project/
      ${BUILD_NUMBER}/hello-0.0.1.war?properties=Performance-Tested=Yes"';
    }
  }
}
node ('production') {  stage ('Deploy to Prod'){    def server = Artifactory.server 'Default Artifactory Server'
    def downloadSpec = """{
      "files": [
        {
          "pattern": "example-project/$BUILD_NUMBER/*.zip",
          "target": "/home/jenkins/tomcat/webapps/"
          "props": "Performance-Tested=Yes;Integration-Tested=Yes",
        }
      ]
    }""
    server.download(downloadSpec)
  }
}

更新 Jenkinsfile

Jenkins 多分支 CD Pipeline 利用 Jenkinsfile。在本节中,我们将更新现有的 Jenkinsfile。按照给定的步骤进行操作:

  1. 登录到您的 GitHub 账户。

  2. 转到分叉出来的仓库。

  3. 在仓库页面上,点击Jenkinsfile。接下来,在结果页面上点击编辑按钮以编辑您的Jenkinsfile

  4. 用以下代码替换现有内容:

node('docker') {
  stage('Poll') {
    checkout scm
  }
  stage('Build & Unit test'){
    sh 'mvn clean verify -DskipITs=true';
    junit '**/target/surefire-reports/TEST-*.xml'
    archive 'target/*.jar'
  }
  stage('Static Code Analysis'){
    sh 'mvn clean verify sonar:sonar
    -Dsonar.projectName=example-project
    -Dsonar.projectKey=example-project
    -Dsonar.projectVersion=$BUILD_NUMBER';
  }
  stage ('Integration Test'){
    sh 'mvn clean verify -Dsurefire.skip=true';
    junit '**/target/failsafe-reports/TEST-*.xml'
    archive 'target/*.jar'
  }
  stage ('Publish'){
    def server = Artifactory.server
      'Default Artifactory Server'
    def uploadSpec = """{
      "files": [
        {
           "pattern": "target/hello-0.0.1.war",
           "target": "example-project/${BUILD_NUMBER}/",
           "props": "Integration-Tested=Yes;
             Performance-Tested=No"
        }
      ]
    }"""
    server.upload(uploadSpec)
  }
  stash includes:
   'target/hello-0.0.1.war,src/pt/Hello_World_Test_Plan.jmx',
  name: 'binary'
}
node('docker_pt') {
  stage ('Start Tomcat'){
    sh '''cd /home/jenkins/tomcat/bin
    ./startup.sh''';
  }
  stage ('Deploy '){
    unstash 'binary'
    sh 'cp target/hello-0.0.1.war /home/jenkins/tomcat/webapps/';
  }
  stage ('Performance Testing'){
    sh '''cd /opt/jmeter/bin/
    ./jmeter.sh -n -t $WORKSPACE/src/pt/Hello_World_Test_Plan.jmx
    -l $WORKSPACE/test_report.jtl''';
    step([$class: 'ArtifactArchiver', artifacts: '**/*.jtl'])
  }
  stage ('Promote build in Artifactory'){
    withCredentials([usernameColonPassword(credentialsId:
     'artifactory-account', variable: 'credentials')]) {
      sh 'curl -u${credentials} -X PUT
      "http://192.168.56.102:8081/artifactory/api/storage/
       example-project/${BUILD_NUMBER}/hello-0.0.1.war?
       properties=Performance-Tested=Yes"';
    }
  }
}
node ('production') {  stage ('Deploy to Prod'){    def server = Artifactory.server 
     'Default Artifactory Server'
    def downloadSpec = """{
      "files": [
        {
          "pattern": "example-project/$BUILD_NUMBER/*.zip",
          "target": "/home/jenkins/tomcat/webapps/"
          "props": "Performance-Tested=Yes;
             Integration-Tested=Yes",
        }
      ]
    }""
    server.download(downloadSpec)
  }
}
  1. 完成后,通过添加一个有意义的注释来提交新文件。

持续交付正在进行中

对您的 GitHub 代码进行一些更改,或者只需从 Jenkins 仪表盘触发 Jenkins 流水线。

登录到 Jenkins,从 Jenkins 仪表盘点击您的多分支流水线。您应该会看到类似以下截图的内容:

图片

Jenkins 中的持续部署流水线正在运行

摘要

这标志着持续部署的结束。在这一章中,我们学习了如何使用 Jenkins 实现持续部署。同时,我希望您已经清楚了持续交付与持续部署之间的区别。本章没有涉及到主要的设置或配置,因为在之前的章节中实现持续集成和持续交付时已经完成了所有必要的工作。

我真诚地希望这本书可以让您走出去,更多地尝试 Jenkins。

下次再见,加油!

支持工具和安装指南

本章将带您了解使您的 Jenkins 服务器可以通过互联网访问所需的步骤。我们还将介绍在 Windows 和 Linux 上安装 Git 所需的步骤。

将您的本地主机服务器暴露给互联网

您需要在 GitHub 上创建 Webhooks 以触发 Jenkins 中的管道。另外,对于 GitHub Webhooks 的工作,Jenkins 服务器可通过互联网访问非常重要。

在练习本书中描述的示例时,您可能会需要使您的 Jenkins 服务器可以通过互联网访问,该服务器安装在您的沙盒环境中。

在接下来的章节中,我们将使用一个名为 ngrok 的工具来实现这一目标。执行以下步骤使您的 Jenkins 服务器可以通过互联网访问:

  1. 登录到 Jenkins 服务器机器(独立的 Windows/Linux 机器)。如果您正在使用 Docker 运行 Jenkins,请登录到您的 Docker 主机机器(很可能是 Linux)。

  2. ngrok.com/download 下载 ngrok 应用程序。

  3. 您下载的是一个 ZIP 包。使用unzip命令解压它(要在 Ubuntu 上安装 ZIP 实用程序,执行sudo apt-get install zip)。

  4. 运行以下命令解压 ngrok ZIP 包:

unzip /path/to/ngrok.zip 
  1. 要在 Linux 上运行 ngrok,请执行以下命令:
./ngrok http 8080

或者,运行以下命令:

nohup ./ngrok http 8080 & 
  1. 要在 Windows 上运行 ngrok,请执行以下命令:
ngrok.exe http 8080 
  1. 您应该会看到类似的输出,如下所示;突出显示的文本是localhost:8080的公共 URL:
ngrok by @inconshreveable (Ctrl+C to quit)
Session Status online
Version 2.2.8
Region United States (us)
Web Interface http://127.0.0.1:4040
Forwarding http://8bd4ecd3.ngrok.io -> localhost:8080
Forwarding https://8bd4ecd3.ngrok.io -> localhost:8080
Connections ttl opn rt1 rt5 p50 p90
0 0 0.00 0.00 0.00 0.00
  1. 复制上述公共 URL。

  2. 登录到您的 Jenkins 服务器。从 Jenkins 仪表板,导航到 Manage Jenkins | Configure System。

  3. 在 Jenkins 配置页面上,向下滚动到 Jenkins 位置部分,并将使用 ngrok 生成的公共 URL 添加到 Jenkins URL 字段内。

  4. 单击保存按钮以保存设置。

  5. 现在,您将能够通过互联网访问您的 Jenkins 服务器使用公共 URL。

  6. 在 GitHub 上创建 Webhooks 时,请使用使用 ngrok 生成的公共 URL。

在 Windows/Linux 上安装 Git

以下各节中提到的步骤是在 Windows 和 Linux 上安装 Git 所需的:

在 Windows 上安装 Git

要在 Windows 上安装 Git,请按照以下步骤操作:

  1. 您可以从 git-scm.com/downloads 下载 Git:

  1. 单击下载的可执行文件并按照安装步骤进行操作。

  2. 接受许可协议并单击下一步。

  3. 选择所有组件并单击下一步,如下图所示:

  1. 选择 Git 使用的默认编辑器,然后单击下一步。

  2. 通过选择适当的环境来调整您的路径环境,并单击下一步,如下图所示:

  1. 选择使用 OpenSSH 作为 SSH 可执行文件,然后单击下一步:

  1. 选择将 OpenSSL 库用作 HTTPS 传输后端,然后点击下一步:

  1. 选择适合你的行结束转换方式,然后点击下一步。

  2. 选择终端模拟器,然后点击下一步。

  3. 选择启用文件系统缓存和启用 Git 凭据管理器选项,如下截图所示,然后点击安装:

  1. Git 安装应该现在开始。安装完成后,点击完成。

在 Linux 上安装 Git

在 Linux 上安装 Git,请执行以下步骤:

  1. 在 Linux 上安装 Git 很简单。在本节中,我们将在 Ubuntu(16.04.x)上安装 Git。

  2. 登录到你的 Ubuntu 机器。确保你拥有管理员权限。

  3. 如果你使用的是 GUI,请打开终端。

  4. 按顺序执行以下命令:

sudo apt-get update 
sudo apt-get install git
  1. 执行以下命令检查 Git 是否安装成功:
git --version
  1. 你应该得到以下结果:
git version 2.15.1.windows.2
posted @ 2024-05-20 11:58  绝不原创的飞龙  阅读(44)  评论(0编辑  收藏  举报