什么是Jenkins流水线?
Jenkins Pipeline(或简单的称为“流水线”)是一套插件,支持实现并集成持续的交付管道到Jenkins。
Jenkins 流水线提供了一套可扩展的工具,用于将“简单到复杂”的交付管道建模为“代码”。Jenkins流水线的定义通常写入到一个文本文件(称为Jenkinsfile
)中,该文件又被检入到项目的源代码控制库中
有关管道和更新的更多信息Jenkinsfile
,请参阅用户手册中相应的流水线和 使用Jenkinsfile部分。
运行多个步骤
流水线由多个步骤组成,允许您构建,测试和部署应用程序。Jenkins 流水线允许您以简单的方式撰写多个步骤,可以帮助您对任何类型的自动化过程建模。
想象一个“步骤”就像执行单个动作的单个命令一样。当一个步骤成功时,它将转到下一步。当一个步骤未能正确执行时,管道将失败。
当管道中的所有步骤都成功完成时,管道被视为已成功执行。
Pipeline设计三个基本概念:
Stage: 一个流水线可以划分为若干个Stage,每个Stage代表一组操作。注意,Stage是一个逻辑分组的概念,可以跨多个Node。
Node: 一个Node就是一个Jenkins节点,或者是Master,或者是Agent,是执行Step的具体运行期环境。
Step:Step是最基本的操作单元,小到创建一个目录,大到构建一个Docker镜像,由各类Jenkins Plugin提供。
在Linux, BSD, and Mac OS系统下操作(以下文章都是基于服务器写的, 没有写windows平台)
在Linux、BSD和Mac OS (基于unix)系统中,sh
步骤用于在流水线中执行shell命令。
最简单的流水线
Jenkinsfile (Declarative Pipeline)
node {
echo 'Hello World'
}
可以执行多行shell命令
Jenkinsfile(声明式管道)
pipeline {
agent any
stages {
stage('Build') {
steps {
sh 'echo "Hello World"'
sh '''
echo "可以执行多行shell命令"
ls -lah
'''
}
}
}
}
超时,重试
有一些强大的步骤可以“包装”其他的步骤,这些步骤可以很容易地解决问题,比如重新尝试(retry
)步骤直到成功或退出,如果步骤花费太长(timeout
)。
Jenkinsfile (Declarative Pipeline)
pipeline {
agent any
stages {
stage('Deploy') {
steps {
retry(3) {
sh './flakey-deploy.sh'
}
timeout(time: 3, unit: 'MINUTES') {
sh './health-check.sh'
}
}
}
}
}
“Deploy”阶段重试了flakely-Deploy.sh
脚本3次,然后等待healthy-check.sh
脚本执行最多3分钟。如果healthy-check脚本在3分钟内没有完成,流水线将在”Deploy”阶段被标记为失败。
“Wrapper”步骤(如timeout
和retry
)可能包含其他步骤,包括timeout
或retry
。
我们可以一起组成这些步骤。例如,如果我们想重试我们的部署5次,但是在失败之前不要花费超过3分钟的时间
Jenkinsfile (Declarative Pipeline)
pipeline {
agent any
stages {
stage('Deploy') {
steps {
timeout(time: 3, unit: 'MINUTES') {
retry(5) {
sh './flakey-deploy.sh'
}
}
}
}
}
}
整理
当流水线完成执行时,您可能需要运行清理步骤或根据管道的结果执行一些操作。这些操作可以在post
部分执行。
Jenkinsfile (Declarative Pipeline)
pipeline {
agent any
stages {
stage('Test') {
steps {
sh 'echo "失败!"; exit 1'
}
}
}
post {
always {
echo '这将会一直运行'
}
success {
echo '只有在成功的情况下才会运行'
}
failure {
echo '只有在失败时才会运行'
}
unstable {
echo '只有当运行被标记为不稳定时才会运行'
}
changed {
echo '只有当管道的状态发生变化时才会运行'
echo '例如,如果管道以前失败了,但是现在成功了。'
}
}
}
定义执行环境
每个示例中都出现了agent
指令, 该agent
指令告诉了Jenkins属于哪个agent
下, 以及如何执行流水线或其子集, agent
对所有流水线来说都是必须的
在引擎盖下, agent
会导致如下几件事:
- 示例中代码由Jenkins线性执行, 只要agent有效, 这些步骤就会按顺序执行
- 同时将会分配一个
agent
专属的workspace, 该workspace将包含从源代码检出的文件以及流水线的任何其他工作文件
有几种方法可以定义 流水线中使用的代理, 本文不讲docker容器
混合其他代理,在执行一个流水线时可以提供很大的灵活性
使用环境变量
环境变量可以全局设置,如下面的示例或每个阶段。正如您所预料的那样,为每个阶段设置环境变量意味着它们仅适用于定义它们的阶段。
Jenkinsfile (Declarative Pipeline)
pipeline {
agent any
environment {
DISABLE_AUTH = 'true'
DB_ENGINE = 'sqlite'
}
stages {
stage('Build') {
steps {
sh 'printenv'
}
}
}
}
这种从Jenkinsfile
中定义环境变量的方法对于指导脚本非常有用。比如一个Makefile
, 以不同的方式配置构建或测试,以在Jenkins内部运行它们。
环境变量的另一个常见用途是在构建或测试脚本中设置或覆盖“虚拟”凭证,因为将凭证直接放入Jenkinsfile
中(显然)是个坏主意。Jenkins流水线允许用户快速、安全地访问Jenkinsfile
中预定义的凭证,而不需要知道它们的值。
环境中的凭证
记录测试和artifacts
虽然测试是一个良好的持续交付管道的关键部分,但大多数人不希望筛选数千行控制台输出来查找有关失败测试的信息。为了简化操作,只要您的测试运行器可以输出测试结果文件,Jenkins就可以记录和汇总测试结果。Jenkins通常与junit
步骤捆绑在一起,但如果您的测试运行器无法输出JUnit样式的XML报告,那么还有其他插件可以处理任何广泛使用的测试报告格式。
为了收集我们的测试结果和工件,我们将使用该post
部分。
Jenkinsfile (Declarative Pipeline)
pipeline {
agent any
stages {
stage('Test') {
steps {
// sh 'make check || true', 使用内联shell conditional(sh 'make || true')可确保该 sh步骤始终能看到零退出代码,从而为该junit步骤提供捕获和处理测试报告的机会。
sh './gradlew check'
}
}
}
post {
always {
// junit捕获并关联与包含模式(build/reports/**/*.xml)匹配的JUnit XML文件。
junit 'build/reports/**/*.xml'
}
}
}
这将始终抓住测试结果,让Jenkins跟踪他们,计算趋势并报告他们。未通过测试的管道将被标记为“UNSTABLE”,在Web UI中用黄色表示。这与红色表示的“失败”状态不同
当出现测试失败时,从Jenkins抓取构建的artifacts以进行本地分析和调查通常很有用。这是由Jenkins的内置支持,用于存储“artifacts”,这是Pipeline执行期间生成的文件。
这很容易通过archiveArtifacts
步骤和文件匹配表达式来完成,如下例所示:
Jenkinsfile (Declarative Pipeline)
pipeline {
agent any
stages {
stage('Build') {
steps {
sh './gradlew build'
}
}
stage('Test') {
steps {
sh './gradlew check'
}
}
}
post {
always {
//archiveArtifacts捕获与包含模式(build/libs/**/*.jar)匹配的文件,并将它们保存到Jenkins主文件中以供日后检索。
archiveArtifacts artifacts: 'build/libs/**/*.jar', fingerprint: true
junit 'build/reports/**/*.xml'
}
}
}
如果在archiveArtifacts
步骤中指定了多个参数,那么每个参数的名称都必须在步骤代码中显式地指定,即artifacts
的路径、文件名和fingerprint
,以选择该选项。如果您只需指定artifacts的路径和文件名,则可以省略参数名称artifacts,例如
archiveArtifacts 'build/libs/**/*.jar'
在Jenkins中记录测试和artifacts对于快速轻松地向团队中的各个成员提供信息非常有用。在下一节中,我们将讨论如何告诉团队成员管道中发生的事情
清理和通知
由于管道的post
部分保证在管道执行结束时运行,因此我们可以添加一些通知或其他步骤来执行终结、通知或其他管道结束任务。
Jenkinsfile (Declarative Pipeline)
pipeline {
agent any
stages {
stage('No-op') {
steps {
sh 'ls'
}
}
}
post {
always {
echo '不管怎样,我已经做完了'
deleteDir() /* 清理我们的 workspace */
}
success {
echo '我成功了!'
}
unstable {
echo '我现在不稳定 :/'
}
failure {
echo '我失败了 :('
}
changed {
echo '跟之前的不一样了...'
}
}
}
有很多方法可以发送通知,下面是一些演示如何发送关于流水线的通知的信息,比如邮件
post {
failure {
mail to: 'team@example.com',
subject: "Failed Pipeline: ${currentBuild.fullDisplayName}",
body: "Something is wrong with ${env.BUILD_URL}"
}
}
现在,如果事情失败,不稳定甚至成功,团队将得到通知,我们可以通过令人兴奋的部分完成我们的持续交付管道:运输!
部署
最基本的连续交付管道至少应有三个阶段,这些阶段应在Jenkinsfile
进行定义:Build, Test 和Deploy。在本节中,我们主要关注Deploy阶段,但应该注意到,稳定的Build和Test阶段是任何部署活动的重要前提。
Jenkinsfile (Declarative Pipeline)
pipeline {
agent any
stages {
stage('Build') {
steps {
echo 'Building'
}
}
stage('Test') {
steps {
echo 'Testing'
}
}
stage('Deploy') {
steps {
echo 'Deploying'
}
}
}
}
作为部署环境的阶段
一个常见的模式是扩展阶段的数量,以捕获额外的部署环境,比如“分段环境”或“生产”,如下面的代码片段所示。
stage('Deploy - Staging') {
steps {
sh './deploy staging'
sh './run-smoke-tests'
}
}
stage('Deploy - Production') {
steps {
sh './deploy production'
}
}
在这个例子中,我们假设任何“smoke tests”都是由我们运行的。./run-smoke-tests
脚本足以胜任或验证发布到生产环境。这种自动部署代码到生产的流水线可以被看作是“持续部署”的实现。虽然这是一种崇高的理想,但对于许多人来说,持续部署可能并不实用,但仍然可以享受持续交付的好处。Jenkins流水线很容易支持这两种方式。
要求人类输入进行
通常在阶段之间,特别是在环境阶段之间,您可能希望在继续之前进行人工输入。例如,判断应用程序是否处于足够好的状态以“促进”生产环境。这可以通过输入步骤来完成。在下面的示例中,“完整性检查”阶段实际上是阻塞了输入,并且在没有人确认进度的情况下不会进行。
Jenkinsfile (Declarative Pipeline)
pipeline {
agent any
stages {
/* "Build" and "Test" stages omitted */
stage('Deploy - Staging') {
steps {
sh './deploy staging'
sh './run-smoke-tests'
}
}
stage('Sanity check') {
steps {
input "分段环境看起来还可以吗?"
}
}
stage('Deploy - Production') {
steps {
sh './deploy production'
}
}
}
}
结论
本次导游向您介绍了使用Jenkins和Jenkins 流水线的基础知识。由于Jenkins具有极高的可扩展性,因此可以对其进行修改和配置,以处理几乎任何自动化方面的问题。要详细了解Jenkins可以执行的操作,请查看 用户手册或 Jenkins博客以获取最新的事件,教程和更新。