Jenkins 不完全指南

296 阅读7分钟

Jenkins 不完全指南

Jenkins 是什么?

Jenkins 是一款由 Java 编写的开源的持续集成工具(ci/cd)

Jenkins 的安装

CentOS7 以下可以直接使用 yum 安装

Centos8 及以上可以使用 dnf 安装,将 yum 命令替换为 dnf 命令即可;没有dnf 可以自行安装 yum install dnf

Jenkins 依赖 java 环境,请确保已安装 java, 在终端输入 java 敲击回车验证

  • yum 源导入
#添加Yum源
sudo wget -O /etc/yum.repos.d/jenkins.repo https://pkg.jenkins.io/redhat-stable/jenkins.repo

#导入密钥
sudo rpm --import https://pkg.jenkins.io/redhat-stable/jenkins.io.key
  • 安装/卸载
# 升级 yum 源中的所有包
sudo yum upgrade

#安装
sudo yum install jenkins

#卸载
yum remove jenkins

#想卸干净点,执行下面命令
rm -rf /etc/sysconfig/jenkins.rpmsave
rm -rf /var/cache/jenkins/
rm -rf /var/lib/jenkins/
rm -rf /var/log/jenkins
rm -rf /usr/lib/jenkins

Jenkins 的启动/重启/停止/状态

# 启动 Jenkins 服务
systemctl start jenkins
# 重启 Jenkins 服务
systemctl restart jenkins
# 停止 Jenkins 服务
systemctl stop jenkins
# 查看 Jenkins 服务状态
systemctl status jenkins

Jenkins 运行在机器的 8080 端口,使用云服务器的同学记得到防火墙放行端口。

初始化 Jenkins

在浏览器输入 http://<你的服务器 IP>:8080 就可以访问到 Jenkins 的解锁界面了。

首次进入初始化 Jenkins 需要输入一段命令来查看密码,在服务器终端执行:

cat /var/lib/jenkins/secrets/initialAdminPassword

把控制台输出的密码复制到 Jenkins 解锁界面中,就到插件安装界面了

安装插件

我们选择左边的默认安装推荐插件,然后静等插件安装完成。

假如插件安装失败,不要慌,我们分析下情况(欢迎大家补充)

  • 被墙了
    1. 尝试开启科学上网(推荐
    2. 换源,这里推荐清华源
  • 操作不对
    1. 点击重试,一般多试几次就可以
    2. 重新阅读本教程一遍
    3. 卸载 jenkins,重新把安装流程走一边
    4. 手动下载插件
    5. 重启服务器

创建用户

安装成功之后,根据提示创建管理员用户,到此,我们的Jenkins就安装成功了,也创建了我们自己的管理员账户

新建任务

本教程不赘述自由风格(Freestyle project)软件项目,因太过简单,教程烂大街

现在我们可以新建任务了,点击主界面左侧的新建任务,选择构建一个流水线(Pipeline)软件项目,给任务取个名字

Jenkins Pipeline 是什么?(大概看看,不懂可以跳过,因为我也不太懂)

Jenkins Pipeline(或简称为 "Pipeline")是一套插件,将持续交付的实现和实施集成到 Jenkins 中。持续交付 Pipeline 自动化的表达了这样一种流程:将基于版本控制管理的软件持续的交付到您的用户和消费者手中。 Jenkins Pipeline 提供了一套可扩展的工具,用于将“简单到复杂”的交付流程实现为“持续交付即代码”。Jenkins Pipeline 的定义通常被写入到一个文本文件(称为 Jenkinsfile )中,该文件可以被放入项目的源代码控制库中!!厉害吧👍

配置流水线

Pipeline 可以两种方式来配置

建议把 Jenkinsfile(Pipeline 脚本) 跟项目源码一块加入到版本控制中,这样方便项目成员了解构建构建和流程。当然出于安全,有些环境变量和参数等可以管理在 Jenkins 管理平台上,具体后续会有介绍

  • 配置 git 仓库的方式来获取到 pipeline 脚本(推荐
    1. 定义(Definition)选择 Pipeline script from SCM
    2. SCM 选择 Git
    3. 配置 Jenkinsfile 所在仓库地址
    4. 选择 Credentials,添加凭证(重要!没有的话配置一下 git ssh 连接信息)
    5. 选择脚本路径(Script Path)路径(通常默认 Jenkinsfile 即可)
  • 在配置页面直接写 pipeline 脚本

pipeline 脚本

有些插件安装后可以直接在 pipeline 中使用,如发送邮件的 Extended E-mail Notification,安装后可以直接 steps { emailext to: 'mafeifan@qq.com', subject: "test", body: "an email"} 来发送邮件

pipeline 能使用 Declarative Pipeline(声明式)Scripted Pipeline(脚本化)两种语法进行编写, 都是使用 groovy 来实现的

推荐使用 Declarative Pipeline(声明式),也是官方最新推荐的

例:声明式pipeline

pipeline {
  agent any
   // stages 包含一个或多个阶段(stage)的容器
  stages {
     // stage 阶段,pipleline流水线由一个或多个阶段(stage)组成,每个阶段必须有名称,这里build就是此阶段的名称
     stage('build') {
       // steps,阶段中的一个或多个具体步骤(step)的容器
       steps {
         // 这是是具体的步骤,真正”做事“的,不可再拆分的最小操作
         echo "hello world"
       }  
     }
  }
}
  • 所有的声明必须包含在 pipeline 语句块中。
  • 块只能由 stage, directives (指令,后续会讲到) 或 steps 组成。
  • agent:指定流水线的执行位置,流水线中的每个阶段都必须在某个地方(物理机,虚拟机或 Docker 容器)执行,agent 部分即指定具体在哪里执行。
  • echo 是内置命令,用来输出一段文本,还有些命令是安装插件后才有的,参见官方文档。
  • step: 步骤,可拆分最小单元,真正“做事”的语句。如 echo "hello world" 表示输出一句话。

例:脚本式 pipeline

node {
      /* .. snip .. */
      withEnv(["PATH+MAVEN=${tool 'M3'}/bin"]) {
          sh 'mvn -B verify'
      }
}

groovy 是什么

Groovy 是用于 Java虚拟机的一种敏捷的动态语言,它是一种成熟的面向对象编程语言,既可以用于面向对象编程,又可以用作纯粹的脚本语言。使用该种语言不必编写过多的代码,同时又具有闭包和动态语言中的其他特性

  • 写 pipeline 就是写 Groovy 代码,Jenkins pipeline 其实就是基于 Groovy 语言实现的一种 DSL,了解一些 Groovy 语法知识是很有必要的

  • 不想本地安装 Groovy 环境的话,可以打开 groovy-playground.appspot.com/ 运行线上 groovy 代码,直接查看结果,该网站可能需要会科学上网

必要的 Groovy 语法知识

  • 定义变量和方法用def关键字,def name="jack"
  • 语句最后的分号不是必需的
  • 方法调用时可以省略括号
def say(String name = "world") {
  return "hi " + name
}
// 调用
say name = "jack"
  • 双引号支持插值,单引号不会解析变量,原样输出
def name = 'world'
// 结果: hello world
print "hello ${name}"
// 结果: hello ${name}
print 'hello ${name}
  • 三双引号和三单引号都支持换行,只有三双引号支持插值
def foo = """ line one
line two
${name}
"""
  • 支持闭包
// 定义闭包
def codeBlack = {print "hello closure"}
// 闭包当做函数调用
codeBlack
// 闭包可以赋值给变量,或者作为参数传递
def pipeline(closure) {
  closure()
}
pipeline(codeBlack)

// 因为括号是非必需的,下面几种写法结果是一样的,是不是和 Jenkins pipeline 很像呢
pipeline( {print "hello closure"} )
pipeline { 
  print "hello closure"
} 
pipeline codeBlack
  • 闭包的另一个用法
def stage(String name, closure) {
  println name
  closure()
}

// 正在情况下,我们这样使用stage函数

stage("stage name", {
   println "closure"
})

// 最终打印
/*
stage name
closure
*/
// 但是,在Groovy里,可以直接这么写

stage("stage name") {
  print "closure"
}

Jenkins 环境变量

环境变量可以被看作是 pipeline 与 Jenkins 交互的媒介。比如,可以在 pipeline 中通过 BUILD_ NUMBER 变量知道构建任务的当前构建次数。环境变量可以分为 Jenkins 内置变量和自定义变量。

Jenkins 内置变量

在 pipeline 执行时,Jenkins 通过一个名为 env 的全局变量,将 Jenkins 内置环境变量暴露出来。其使用方法有多种,示例如下:

pipeline {
  agent any
  stages {
    stage('Example') {
      steps {
         echo "Running ${env.BUILDNUMBER} on ${env.JENKINS_URL}" # 方法1
         echo "Running $env.BUILDNUMBER on $env.JENKINS_URL"  # 方法2
         echo "Running ${BUILDNUMBER} on ${JENKINS_URL}"   # 方法3 不推荐,难排查
      }
    }
  }
}

默认 env 的属性可以直接在 pipeline 中引用。所以以上方法都是合法的。但是不推荐方法三,因为出现变量冲突时,非常难查问题。

通过访问 <Jenkins master的地址>/pipeline-syntax/globals#env 来获取完整列表。在列表中,当一个变量被声明为 "For a multibranch project"时,代表只有多分支项目才会有此变量。

实际工作中经常用到的变量:

  • BUILD_ NUMBER:构建号,累加的数字。在打包时,它可作为制品名称的一部分,比如server-2.jar。
  • BRANCH_ NAME:多分支pipeline项目支持。当需要根据不同的分支做不同的事情时就会用到,比如通过代码将release分支发布到生产环境中、master分支发布到测试环境中。
  • BUILD_ URL:当前构建的页面URL。如果构建失败,则需要将失败的构建链接放在邮件通知中,这个链接就可以是BUILD _URL。
  • GIT BRANCH:通过git拉取的源码构建的项目才会有此变量。

在使用 env 变量时,需要注意不同类型的项目,env 变量所包含的属性及其值是不一样的。比如普通 pipeline 任务中的 GIT BRANCH 变量的值为 origin/master,而在多分支 pipeline 任务中 GIT BRANCH 变量的值为 master。 所以,在 pipeline 中根据分支进行不同行为的逻辑处理时,需要留意。

自定义变量

  1. pipeline提供的environment指令中定义
pipeline {
    agent any
    environment {
        // 覆盖默认的PATH变量值
        PATH="/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin"
        name='jack'
    }
    stages {
        stage("test env") {
            steps {
                sh "printenv"  #调试,打印所有env变量
                echo "${name}"  # jack
                echo "${env.name}"  # jack
            }
        }
    }
}

environment指令可以用在pipeline中定义,作用域就是整个pipeline,当定义在stage阶段,只在当前stage有效

  1. 环境变量的互相引用

在调试pipeline时,可以再开始阶段加一句 sh 'printenv' 将所有env变量打印出来

自定义变量时,为避免命名冲突,可根据项目或公司加上统一前缀,如__server_name,__就是前缀

environment {
    __server_name = 'email-server'
    __version = "${BUILD_NUMBER}"
    __artifact_name = "${__server_name}-${__version}.jar"
}
  1. 自定义全局环境变量 定义全局环境变量可以跨pipeline使用 进入Jenkins -- Manage Jenkins -- 找到Global properties -- 勾选Environment variables

自定义全局环境变量会被加入env属性列表中,所以使用时可以直接用${env.g_name}引用

  1. 动态定义变量
pipeline {
    agent any
    
    environment {
       _version = createVersion()
    }
    
    stages {
        stage ('build') {
            steps {
                script {
                    echo "${_version}"
                }
            }
        }
    }
}

def createVersion() {
    return new Date().format('yyyyMM') + "-${env.BUILD_NUMBER}"
}

Pipeline 中的指令

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

  • Jenkins pipeline支持的指令有:
  • environment: 用于设置环境变量,可定义在stage或pipeline部分。
  • tools: 可定义在pipeline或stage部分。它会自动下载并安装我们指定的工具,并将其加入PATH变量中。
  • input: 定义在stage部分,会暂停 pipeline,提示你输入内容。
  • options: 用于配置 Jenkins pipeline 本身的选项,比如 options {retry (3) }指当pipeline失败时再重试2次。options指令 可定义在stage或pipeline部分。
  • parallel: 并行执行多个step。在pipeline插件 1.2版本后,parallel开始支 持对多个阶段进行并行执行。
  • parameters: 与input不同,parameters是 执行pipeline前传入的一些参数。
  • triggers: 用于定义执行pipeline的触发器。
  • when: 当满足when定义的条件时,阶段才执行。

在使用指令时,需要注意的是每个指令都有自己的"作用域"。如果指令使用的位置不正确,Jenkins将会报错。

options 指令用于配置整个 Jenkins pipeline 本身的选项

pipeline {
    agent any
    options {
        timeout(time: 1, unit: 'HOURS') 
        disableConcurrentBuilds()
    }
    stages {
        stage('Example') {
            steps {
                echo 'Hello World'
            }
        }
    }
}
  • 整个pipeline执行超过一个小时将中止
  • 禁止pipeline同时执行,避免抢占资源或调用冲突

stage 的 options 指令类似于流水线根目录上的 options

pipeline {
    agent any
    stages {
        stage('Example') {
            options {
                timeout(time: 1, unit: 'HOURS') 
            }
            steps {
                echo 'Hello World'
            }
        }
    }
}
  • 指定 Example 阶段的执行超时时间, 在此之后,Jenkins 将中止流水线运行

拓展

在实际使用中,我们很多项目都需要单元测试以及导出报告的 stage,这时这两个stage 我们应该能够服用量,否则的话每个 Job 的 pipeline 都需要写一遍。有几种方式可以实现复用

  • 将公共的 pipeline 步骤导入到 Global Pipeline LIbraries,这个不是我们要讲的,感兴趣的话可以去官网看看: Jenkins 共享库

  • 由于 pipeline 是用 groovy 脚本编写的,那么我们可以将公共的步骤抽出来,形成一个公共代码库,当需要引用公共库中的 stage 时,只需要将对应的 groovy 脚本 load 进来即可,这样做的好处是可以随时的修改,并且省去了上传到 Jenkins 共享库 的步骤