Skip to main content

Jenkins

目的

本文描述 Jenkins 安装部署步骤以及简单的配置与使用方法。

环境与软件

本章内容安装及运行所需软件:

项目版本说明
操作系统CentOS 7
OpenJDK 81.8.0Java 开发工具包
Git1.8.3.1软件配置管理工具(SCM: Software Configuration Management)
Maven3.6.3软件项目管理工具,制品库(Artifact Repository)
Jenkins2.235.4持续集成工具

安装部署

安装 Git

通过 yum 安装

yum install -y git

使用主机名访问服务器前开发环境需要先设置 /etc/hosts 文件:

192.168.1.247  gitlab.dxsuite.cn

生成 SSH 密钥及公钥

为从代码库拉取代码,需要在本地生成 SSH 密钥及公钥,并将公钥文件提交给持续集成管理员。

公钥文件被部署到 Gitlab 中后,开发者方可通过公钥文件访问授权的代码库。

通过以下命令生成 SSH 密钥和公钥(将 yourname 替换为实际用户名,密码可不填写):

$ ssh-keygen -t rsa -C "yourname"
Enter file in which to save the key (~/.ssh/id_rsa): ~/.ssh/yourname
Enter passphrase (empty for no passphrase):
Enter same passphrase again:

生成的公钥文件为 ~/.ssh/yourname.pub

安装 OpenJDK 8

yum install -y java-1.8.0-openjdk java-1.8.0-openjdk-devel

安装 Maven

下载页面:

https://maven.apache.org/download.cgi

下载链接:

https://mirrors.bfsu.edu.cn/apache/maven/maven-3/3.6.3/binaries/apache-maven-3.6.3-bin.tar.gz

编辑 ~/.m2/settings.xml 设置 Maven 中央库国内镜像:

<?xml version="1.0" encoding="UTF-8"?>
<settings xmlns="http://maven.apache.org/SETTINGS/1.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/SETTINGS/1.0.0
https://maven.apache.org/xsd/settings-1.0.0.xsd">

<localRepository/>

<interactiveMode/>

<offline/>

<pluginGroups/>

<servers/>

<mirrors>
<mirror>
<id>aliyun</id>
<name>aliyun</name>
<url>http://maven.aliyun.com/nexus/content/groups/public/</url>
<mirrorOf>central</mirrorOf>
</mirror>
</mirrors>

<proxies/>

<profiles/>

<activeProfiles/>

</settings>

设置环境变量

注:下方jdk路径、maven文件夹名称以实际下载名称为准

export JAVA_HOME="/usr/lib/jvm/java-1.8.0-openjdk-1.8.0.262.b10-0.el7_8.x86_64"
export M2_HOME="/opt/maven-3.6.3"
export PATH="${PATH}:${JAVA_HOME}/bin:${M2_HOME}/bin"

下载并启动 Jenkins

下载页面:

https://www.jenkins.io/download/

WAR 文件下载链接:

http://mirrors.jenkins.io/war-stable/2.235.4/jenkins.war

启动 Jenkins

java -Xms512m -Xmx512m -jar jenkins.war --httpPort=8080 &>./jenkins.log &

之后便可通过以下链接访问(设服务器 IP 地址为 10.211.55.102):

http://10.211.55.102:8080/

管理员初始密码记录于 ~/.jenkins/secrets/initialAdminPassword 文件中。

可以通过 Manage Jenkins → Manage Plugins 安装插件:

插件说明
Locale可以设定 Jenkins 界面语言,语言代码如 en_USzh_CNja_JPko_KR
Blue Ocean可以使 Pipeline 编辑可视化
Generic Webhook Trigger通用的 Webhook 触发器
JaCoCo代码覆盖率插件
SonarQube ScannerSonarQube 插件
Warnings Next Generation集成了原来的 Checkstyle、FindBugs、PMD 等静态代码检查插件的功能

配置与使用

创建流水线作业(Pipeline)

在项目跟路径下创建名为 Jenkinsfile 的文件,并设置以下内容:

pipeline {
agent any
stages {
stage('build') {
steps {
sh 'mvn clean install'
}
}
}
}

可以创建两种类型的流水线作业:普通流水线作业(Pipeline)和多分支流水线作业(Multibranch Pipeline)。

普通流水线作业同时只能对一个分支进行构建。多分支流水线作业实为普通流水线作业的分组,为每一个分支创建一个流水线作业。

普通流水线作业

通过 Jenkins 管理页面创建类型为 Pipeline 的项目:

  • Build Triggers → Poll SCM 中填写 cron 表达式,以设置从 Git 库拉取代码的频率

  • Pipeline → definition 设置为 Pipline script from SCM 从而使得 Jenkins 从 Git 库拉取代码并执行 Jenkinsfile 中的工作流

    • Repositories → Reposigory URL 中设置 Git 库地址
    • Branch Specifier 中指定分支
    • Script Path 中指定 Pipeline 定义文件名(默认为 Jenkinsfile

多分支流水线作业

通过 Jenkins 管理页面创建类型为 Multibranch Pipeline 的项目:

  • Branch Sources 中添加类型为 Git 的源

    • Project Repositories 中设置 Git 库地址
    • Credentials 中设置凭证
    • Behaviors 中设置 Discover branches 和分支过滤条件(如 Filter by name (with regular expression)
  • Scan Multibranch Pipeline Triggers 设置自动扫描分支的频率

  • Orphaned Item Strategy 中设置孤儿历史数据的保留频率

第一次通过 SSH 访问 Git 仓库时需要设置凭证:

  • 凭证类型选择 SSH Username with private key
  • 设置用户名(Username
  • Private Key 中输入 SSH 私钥文件(~/.ssh/id_rsa)的内容
  • jenkins 用户的 SSH 公钥添加到 Git 服务器用户的 authorized_keys 中(通过 ssh-copy-id 命令)或 GitLab 用户的 SSH Keys 中

通过 Manage Jenkins → Manage Credentials → Jenkins (System) → Global credentials (unrestricted) 可以查看添加的凭证。

Jenkins 会将项目代码拉取到 ~/.jenkins/workspace 路径下。

每次流水作业执行数据位于 ~/.jenkins/jobs/项目名/builds/作业编号 下。

Jenkins 节点管理

Jenkins 可以部署为一主(Master)多代理(Agent)的集群结构以分散构建压力。

添加 Agent 的步骤:

  1. 将用于部署 Agent 的服务器上的用户的 SSH Key 复制到 Master 服务器

    设 Master 服务器 IP 地址为 10.211.55.102Jenkins-Master-URL10.211.55.102:8080

    ssh-copy-id -i ~/.ssh/id_rsa.pub cicd@10.211.55.102
  2. 通过 Manage Jenkins → Configure Global Security 设置 Agents

  • TCP 端口固定:如 8081
  1. 通过 Manage Jenkins → Manage Nodes and Clouds → New Node 添加 Agent:
  • Node Name:如 node103
  • Permanent Agent:添加第一个节点是必选
  • # of executors:根据需要设置
  • Remote root directory:如 /var/jenkins(Jenkins 会在该路径下创建 remotingworkspace 等文件夹)
  • Labels:如 openjdk,centos
  • Usage:根据需要设置
  • Launch method:Launch agent by connecting it to the master
  • Availability:根据需要设置
  1. 点击节点列表中新建节点的名称将显示 Agent 启动方式说明,从说明中取得连接密钥

  2. 在部署 Agent 的服务器上下载 Agent 程序的 JAR 文件,下载地址为:http://Jenkins-Master-URL/jnlpJars/agent.jar

  3. 在部署 Agent 的服务器上执行 Agent 程序的 JAR 文件:

    java -jar agent.jar -jnlpUrl http://Jenkins-Master-URL/computer/node103/slave-agent.jnlp -secret 密钥 -workDir "/var/jenkins/workspace"
  4. 要添加其他 Agent,继续第 3 步

Pipeline 语法说明

Pipeline 是 Jenkins 流水线作业插件:

  • 流水线作业通过 Jenkinsfile 配置

  • Jenkinsfile 遵循 Groovy 语法,但有如下例外:

    • 根节点必须为一个块,即 pipeline {}
    • 不可使用分号作为语句的分隔符,每条语句必须独占一行
    • 代码块仅可由段(Section)、指令(Directive)、步骤(Step)或赋值语句构成
    • 属性引用语句将被视为无参数方法调用,如 input 将被视为 input()
  • Pipeline 内置了 echosh 等步骤函数

  • Groovy 中有参数的函数可以省略括号,因此 echo 'Hello'echo('Hello') 等价

  • Groovy 中每行结尾的分号不是必须的

  • Groovy 通过 {} 封装闭包(Closure)

最简 Jenkinsfile:

pipeline {
agent any
stages {
stage('Build') {
steps {
echo 'Hello, World!'
}
}
}
}

Pipeline 中的段(Section):

位置作用/说明
agent(必须)pipelinestage在何处执行作业
stages(必须)pipelinestage定义流水线作业的各阶段
steps(必须)stage定义一个阶段的各步骤
postpipelinestage根据流水线或一个阶段的完成状态执行额外的步骤
parallelstage并行作业
matrixstage矩阵式并行作业

Pipeline 中的指令(Directive):

指令位置作用/说明
toolspipelinestage定义需要自动安装并设置到 PATH 环境变量的工具
支持的工具有 JDK、Maven、Gradle
agent none 被指定则该指令将被忽略
optionspipelinestage对流水线作业进行配置
environmentpipelinestage通过键志对设置环境变量
可以通过 credentials(credentialName) 获取在 Jenkins 中预定义的凭证
parameterspipelineinput用户定义变量,在步骤中可以通过 params 对象访问
triggerspipeline触发器,应用于未使用 Web Hook 的场景
stagestagesparallel一个 stages 块中至少需要存在一个 stage 指令
stage 接受一个字符串参数作为阶段名
必须包含一个且仅可包含 stepsstagesparallelmatrix 中的一个块
若一个 stage 已在一个 parallelmatrix 中则它不可嵌套 parallelmatrix
inputstage提示用户输入,阶段将被暂停
whenstage描述一个阶段的执行条件

Jenkins cron 语法:

分钟
MINUTE
小时
HOUR
日期
DOM (Day Of Month)
月份
MONTH
星期
DOW (Day Of Week)
0~590~231~311~120~7
(0 和 7 均为周日)
  • * 代表所有有效值
  • F-T 代表范围,如 DOW1-5 时代表周一到周五
  • F-T/N*/N 代表间隔,如 HOUR9-22/4 时代表上午 9 点到晚上 22 点每 4 小时
  • A,B,...,Z 代表枚举,如 MONTH1,3,5,7,8,10,12 时代表一月、三月、五月、七月、八月、十月、十二月
  • 使用 H(Hash)代表任意时间,如 H(0-29)/10 * * * * 代表前半个小时每十分钟,可能为 :01、:11、:21,也可能为 :09、:19、:29
  • H/5 * * * *, 代表每5分钟
  • H */2 * * *, 代表每2小时

Jenkinsfile 示例:

参考链接:Pipeline Syntax

pipeline {
// 在何处执行 Pipeline 或 Stage
agent any

// 定义执行流水线作业前需要安装的工具
// 工具名称必须先通过 Jenkins 的 Manage Jenkins → Global Tool Configuration 定义
tools {
// 安装 Java SDK
jdk 'open-jdk-1.8'
// 安装 Apache Maven
maven 'apache-maven-3.6.3'
// 安装 Gradle
gradle 'gradle-6.6'
}

// options 指令用于配置 pipeline 或 stage(仅部分步骤可用)
options {
// 该选项只能作用于 pipeline,保存构建历史的最大记录数
buildDiscarder(logRotator(numToKeepStr: '10'))
// 默认情况下 Jenkins 会将源码拉取到工作空间根目录(~/.jenkins/workspace)下,通过该选项可以指定检出目标工作空间子路径名
checkoutToSubdirectory('subdir')
// 通过该选项禁止一个 pipeline 被并发执行
disableConcurrentBuilds()
// 禁止 Jenkins Master 重启后恢复 Pipeline
disableResume()
// 当 agent 为 Docker 或 Dockerfile 时,指定在一个 Jenkins 节点上每个 stage 都分别运行在一个新的容器中
newContainerPerStage()
// 是否仅为当前作业开启或禁用分支索引触发器
overrideIndexTriggers(true)
// 是否保留暂存的文件(buildCount 默认值为 1,即仅保留最近一次暂存的文件)
preserveStashes(buildCount: 5)
// 静默时长,参数单位为秒
quietPeriod(30)
// 重试次数
retry(3)
// 跳过代码检出
skipDefaultCheckout()
// 跳过进入到 unstable 状态的阶段
skipStagesAfterUnstable()
// 设置超时时长,单位可以为 SECONDS、MINUTES、HOURS
timeout(time: 10, unit: 'MINUTES')
// 在控制台数据的内容前添加时间戳
timestamps()
// 当并行任务中的一个失败时立刻停止所有其他任务
parallelsAlwaysFailFast()
}

// 设置环境变量
environment {
PROJECT_NAME = 'CodeletCloud'
RETRY_TIMES = '0'
// 若 my-credential-name 为用户名密码(Username and Password)或 SSH 私钥(SSH with Private Key)凭证的名称,
// 且用户名或私钥内容为 "secret",密码为 "Pa5sW0rd",
// 则当凭证为用户名密码时 SERVICE_CREDENTIALS 的值将为 "secret:Pa5sW0rd",
// 当凭证为 SSH 私钥时 SERVICE_CREDENTIALS 的值将为临时创建的 SSH Key 文件的地址,
// 另外还将生成两个额外的环境变量 SERVICE_CREDENTIALS_USR 和 SERVICE_CREDENTIALS_PSW,值分别为 "secret" 和 "Pa5sW0rd";
SERVICE_CREDENTIALS = credentials('my-credential-name')
}

// 设置用户定义参数
parameters {
string(name: 'FAMILY_NAME', defaultValue: 'Kim', description: 'Family name')
text(name: 'COMMENT', defaultValue: '...', description: 'Comment on something')
booleanParam(name: 'SWITCH', defaultValue: true, description: 'On/Off')
choice(name: 'COLORS', choices: ['Red', 'Green', 'Blue'], description: '')
password(name: 'PASSWORD', defaultValue: 'Pa5sW0rd', description: '')
}

// 触发执行当前流水线作业的条件
triggers {
// 周一到周五,每 4 小时,任意分钟执行
cron('H */4 * * 1-5')
// 周一到周五,每 4 小时,任意分钟拉取一次代码,如果存在更新则执行
pollSCM('H */4 * * 1-5')
// 若任意上游任务以最小阈值结束则执行
upstream(upstreamProjects: 'job1,job2', threshold: hudson.model.Result.SUCCESS)
}

// 定义流水线的各阶段
stages {
// 定义流水线的一个阶段
// 一个阶段必须包含一个且仅可包含 steps、stages、parallel、matrix 中的一个块
// 若一个 stage 已在一个 parallel 或 matrix 中则它不可嵌套 parallel 或 matrix
stage('Build') {
// 对当前阶段的配置,仅可使用如下步骤
options {
retry(3)
skipDefaultCheckout()
timeout(time: 10, unit: 'MINUTES')
timestamps()
}
// 设置作用域为当前阶段的环境变量
environment {
// ...
}
// 提示用户输入
input {
// 必须,提示消息
message 'Continue?'
// 可选,输入项的 ID,默认为阶段名
id 'build-continue'
// 可选,确认按钮文本
ok 'Yes'
// 可选,允许提交该输入的用户的名称的列表,通过逗号分隔
submitter 'Kim,Kwon'
// 可选,用于存储提交者名称的环境变量
submitterParameter 'BUILD_CONTINUE_SUBMITTER'
// 可选,要求提交者设置的参数的列表
parameters {
// 设置在后续步骤中直接通过 DO_DEPLOY 访问的参数
choice(name: 'DO_DEPLOY', choices: ['Yes', 'No'], description: 'Deploy to server or not')
}
}
// 当所有条件满足时才执行当前阶段
when {
// 默认情况下 agent、input、options 会先于 when 执行
// 通过以下步骤可以使 when 先于 agent 执行
beforeAgent true
// 通过以下步骤可以使 when 先于 input 执行,beforeInput 优先于 beforeAgent
beforeInput true
// 通过以下步骤可以使 when 先于 options 执行,beforeOptions 优先于 beforeInput 和 beforeAgent
beforeOptions true
// 检查当前分支名称是否为指定的名称,仅适用于多分支构建
branch 'development'
// 可以使用正则表达式,comparator 参数可以为 EQUALS(默认)、GLOB、REGEXP
branch pattern: 'release-\\\\d+', comparator: 'REGEXP'
// 检查当前是否正在构建一个标签(Git Tag)
buildingTag()
// 检查变更日志是否匹配给定的正则表达式
changelog '.*\\\\[ready\\\\].*'
// 检查变更的文件中是否有文件名匹配指定格式的文件
changeset '**/*.js'
// 设置 comparator 参数以指定比较方式,可选值有 GLOB(默认,ANT 风格,默认大小写不敏感)、EQUALS(完全相等)、REGEXP(正则表达式)
changeset pattern: '[a-zA-Z]+Test\\\\.java', comparator: 'REGEXP'
// 设置 caseSensitive 参数以使大小写敏感
changeset pattern: '*Test.java', caseSensitive: true
// 检查当前构建是否在变更请求上,变更请求指的是:
// • GitHub 和 Bitbucket 的拉取请求(Pull Request)
// • GitLab 的合并请求(Merge Request)
// • Gerrit 的变更
// 不指定任何参数时则在所有变更请求上执行
changeRequest()
// 可以指定过滤条件参数,可选参数有 id、target、branch、fork、url、title、author、authorDisplayName、authorEmail
// 每个参数对应一个以 CHANGE_ 开头的环境变量
// 例如,仅在开发分支上执行:
changeRequest target: 'master'
// 设置 comparator 参数指定比较方式,可选值有 EQUALS(默认)、GLOB、REGEXP
changeRequest authorEmail: '[\\\\w_-.]+@codelet.net', comparator: 'REGEXP'
// 检查环境变量是否等于给定的值
environment name: 'DEPLOY_TO', value: 'development'
// 检查变量是否等于给定的值
equals expected: 2, actual: currentBuild.number
// 检查 Groovy 表达式的执行结果是否为真(null 将被视为假)
expression { return params.DEBUG_BUILD }
// 检查标签名是否匹配指定的格式
tag 'release-*'
// 设置 comparator 参数以指定比较方式,可选值有 GLOB(默认)、EQUALS、REGEXP
tag pattern: 'release-\\\\d+', comparator: 'REGEXP'
// 非逻辑运算,多个条件需要通过分号分隔
not {
// ...
}
// 与逻辑运算,多个条件需要通过分号分隔
allOf {
// ...
}
// 或逻辑运算,多个条件需要通过分号分隔
anyOf {
// ...
}
// 检查当前构建的触发器(如 SCMTrigger、TimerTrigger、UpstreamCause)
triggeredBy 'SCMTrigger'
triggeredBy cause: 'UserIdCause', detail: 'vlinde'
}
// 一个阶段的步骤
steps {
// 执行 echo 命令,输出文本
echo '执行构建'
// 可以通过 env 对象引用 Jenkins 内置环境变量,也可以直接引用
echo "Build No.: ${env.BUILD_NUMBER}"
// 通过 params 对象引用用户定义参数
echo "Hello, ${params.FAMILY_NAME}"
// 执行 Shell 脚本
sh 'echo `date "+%Y-%m-%d %H:%M:%S"`'
// 进程休眠指定的时长
sleep(time: 10, unit: 'SECONDS')
// 发送邮件
mail(from: 'jenkins@codelet.net', to: 'jinhy@livebridge.com.cn', subject: '标题', body: '邮件内容')
// 重试执行指定次数,直到成功或全部失败为止
retry(count: 3) {
// 执行 Groovy 脚本
script {
RETRY_TIMES = RETRY_TIMES.toInteger() + 1
echo "Retry Times: ${RETRY_TIMES}"
}
}
// 执行 Groovy 脚本
script {
echo "Is Unix: ${isUnix()}" // 检查当前操作系统是否为类 Unix 操作系统(返回 true/false)
echo "Current Dir: ${pwd()}" // 获取当前路径
if (fileExists(file: 'README.md')) { // 检查文件是否存在
def content = readFile(file: 'README.md', encoding: 'UTF-8') // 读取文件内容
echo "${content}"
} else {
echo 'No such file: README.md'
}
writeFile(file: 'README.md', text: "Time: ${new Date().toString()}", encoding: 'UTF-8') // 写入文件
}
// 切换目录,相对路径时为相对源码根路径的相对路径
dir(path: 'temp') {
// 删除当前路径
deleteDir()
}
// 触发新的构建作业
build(
job: 'downstream-job', // 下游作业名称
parameters: [ // 传递给下游作业的参数
string(name: 'depth', value: '1')
],
propagate: true, // 开启时(默认)下游构建作业的状态将作为该步骤的状态,否则将视为成功
quietPeriod: 10, // 静默时长(等待下游流水线的时长),单位为秒,默认由下游确定
wait: true // 是否等待下游完成,默认等待
)
// 将状态设置为 unstable
unstable 'timeout'
}
// 所有步骤完成之后的处理
post {
always {
echo '无论本次完成状态如何都会执行'
}
changed {
echo '本次完成状态与上一次完成状态不同时执行'
}
fixed {
echo '上次完成状态为 unstable 或 failure,本次完成状态为 success 时执行'
}
regression {
echo '上次完成状态为 success,本次完成状态为 aborted、unstable 或 failure'
}
aborted {
echo '任务被(人为)中止时执行'
}
unstable {
echo '被设置为 unstable 时执行'
}
failure {
echo '存在失败的步骤时执行'
}
unsuccessful {
echo '完成状态不为成功时执行'
}
success {
echo '所有步骤均成功时执行'
}
cleanup {
echo '在其他所有条件块执行完成后执行'
}
}
}
stage('Test') {
// 将 failFast 设置为 true,使得并行作业中的一个发生错误时立刻停止所有其他作业
// 与 parallelsAlwaysFailFast 选项的作用相同
failFast true
// 通过 parallel 指令执行并行阶段
parallel {
stage('JUnit') {
steps {
echo '执行 JUnit 测试'
}
}
stage('SonarQube') {
steps {
echo '执行代码质量扫描'
}
}
stage('JaCoCo') {
steps {
echo '执行代码覆盖率测试'
}
}
}
}
stage('Deploy') {
failFast true
// 定义矩阵式并行任务
// 必须包含一个 axes 和一个 stages 块
matrix {
// 定义矩阵的坐标轴,每个轴由名称及可选值组成,
// 各坐标轴的各值之间的每种组合被成为一个 Cell,每个 Cell 都对应一次 Stages 执行(除非通过 excludes 排除);
// matrix 中还可以使用以下指令,作为 Matrix Cell-Level Directive:agent、environment、input、options、post、tools、when
axes {
axis {
name 'PLATFORM'
values 'linux', 'mac', 'windows'
}
axis {
name 'BROWSER'
values 'chrome', 'edge', 'firefox', 'safari'
}
axis {
name 'ARCHITECTURE'
values '32bit', '64bit'
}
}
// 排除组合,如排除 Mac + 32bit、Windows + Safari 浏览器组合
excludes {
exclude {
axis {
name 'PLATFORM'
values 'mac'
}
axis {
name 'ARCHITECTURE'
values '32bit'
}
}
exclude {
axis {
name 'PLATFORM'
values 'windows'
}
axis {
name 'BROWSER'
values 'safari'
}
}
}
// 每种组合都会执行的步骤
stages {
stage('DeployFrontend') {
steps {
echo '执行部署'
}
}
}
}
}
}

// 所有阶段完成后的处理
post {
// always、changed、fixed……
}
}

Pipeline agent 示例:

// 在任何可用的 Agent 上执行流水线或阶段作业
agent any

// 应用于顶层时,每一个 stage 必须包含自己的 agent 部分
agent none

// 选择标签为指定值的 Agent
agent {
label 'centos7 && openjdk8'
}

// 与 agent { label 'agent-label' } 等价
agent {
node {
label 'centos7 && openjdk8'
}
}

// 使用 node 可以指定更多参数,如 customWorkspace 等
agent {
node {
label 'centos7 && openjdk8'
customWorkspace '/some/other/path'
}
}

// Docker
agent {
docker {
image 'maven:3-alpine'
label 'my-defined-label'
args '-v /tmp:/tmp'
}
}

// Docker,指定仓库及凭证
agent {
docker {
image 'my-registry.com/node'
label 'my-defined-label'
registryUrl 'https://my-registry.com/'
registryCredentialsId 'myPredefinedCredentialsInJenkins'
}
}

// Dockerfile
agent {
dockerfile {
filename 'Dockerfile.build'
dir 'build'
label 'my-defined-label'
additionalBuildArgs '--build-arg version=1.0.2'
args '-v /tmp:/tmp'
}
}

// Dockerfile
agent {
dockerfile {
filename 'Dockerfile.build'
dir 'build'
label 'my-defined-label'
registryUrl 'https://my-registry.com/'
registryCredentialsId 'myPredefinedCredentialsInJenkins'
}
}

// Kubernetes
agent {
kubernetes {
label podlabel
yaml """
kind: Pod
metadata:
name: jenkins-agent
spec:
containers:
- name: kaniko
image: gcr.io/kaniko-project/executor:debug
imagePullPolicy: Always
command:
- /busybox/cat
tty: true
volumeMounts:
- name: aws-secret
mountPath: /root/.aws/
- name: docker-registry-config
mountPath: /kaniko/.docker
restartPolicy: Never
volumes:
- name: aws-secret
secret:
secretName: aws-secret
- name: docker-registry-config
configMap:
name: docker-registry-config
"""
}
}

Agent 通用选项:

选项数据类型作用适用于
label字符串匹配 Jenkins Agent 或 Docker 镜像等的标签node(必须)、dockerdockerfile
customWorkspace字符串执行流水线或阶段的工作空间的路径,用于替代默认工作空间nodedockerdockerfile
reuseNode布尔默认为 false,开启时将重用顶级 agent 指定的容器和工作空间stage 中的 agentdockerdockerfile
args字符串传递给 docker run 命令的参数dockerdockerfile

Jenkins 常用内置环境变量:

变量说明
BUILD_NUMBER构建编号
BRANCH_NAME多分支构建时
BUILD_URL当前构建的 Jenkins 页面的URL
GIT_BRANCHGit 代码库分支名

常用步骤:

参考链接:Pipeline Steps

步骤参数(多个参数时 * 标记的为必须参数)说明
echo-将文本输出到构建日志
errorString message生成错误(但不向日志中输出 Stack Trace)
isUnix-检查当前操作系统是否为类 Unix 操作系统
sh
bat
powershell
String script *
String encoding
Boolean returnStatus
Boolean returnStdout
执行 Shell/BAT/PowerShell 脚本
encoding 为输出日志的编码
returnStatus 设置为 true 则无论执行结果是否成功都视为成功
returnStdout 设置为 true 则会将标准输出作为返回值(而不是输出到构建日志中),除非发生错误
若同时设置了 returnStatusreturnStdout 将使用 returnStatus
pwd-获取当前路径
dirString path切换目录
deleteDir-删除当前目录
fileExistsString file检查文件是否存在
readFileString file *
String encoding
读取文件
writeFileString file *
String text *
String encoding
写入文件
stashString name *
Boolean allowEmpty
String excludes
String includes
Boolean useDefaultExcludes
暂存文件,用于跨 Jenkins 服务器节点文件传递,Jenkins 会将文件打包成 TAR
unstashString name取出暂存的文件
retryint count重试执行代码块,直到成功或达到 count 参数指定的最大次数
sleepint time
String unit
暂停作业 time 参数指定的时长,时间单位参数 unit 的可选值有 NANOSECONDSMICROSECONDSMILLISECONDSSECONDSMINUTESHOURSDAYS

流水线或步骤的完成状态:

上次完成状态
本次完成状态
abortedunstablefailuresuccess
abortedalways
unsuccessful
cleanup
always
changed
unsuccessful
cleanup
always
changed
unsuccessful
cleanup
always
changed
regression
unsuccessful
cleanup
unstablealways
changed
unsuccessful
cleanup
always
cleanup
unsuccessful
always
changed
unsuccessful
cleanup
always
changed
regression
unsuccessful
cleanup
failurealways
changed
unsuccessful
cleanup
always
changed
unsuccessful
cleanup
always
unsuccessful
cleanup
always
changed
regression
unsuccessful
cleanup
successalways
changed
cleanup
always
changed
fixed
cleanup
always
changed
fixed
cleanup
always
cleanup

Jenkins REST API

REST API 文档可通过 Jenkins 的 /api 端点查看。

访问 REST API 时需要指定用户名及密码,如 http://username:password@jenkins.example.com/job/job-name/config.xml

发送 POST 请求时需要先取得 Crumb(面包屑,防止跨域攻击),并将其设置为 Jenkins-Crumb 请求头。

调用 REST API 后如果发生服务器错误,Jenkins 会返回 Logging ID,此时可通过 Manage Jenkins → System Log → All Jenkins logs 查看系统日志,并通过 Logging ID 定位日志内容。

如果一个作业位于一个文件夹下,那么其资源路径为 /job/{folderName}/job/{jobName}

  • 取得 Crumb

    GET /crumbIssuer/api/json
    GET /crumbIssuer/api/xml

    将响应数据的 crumb 作为后续请求的 Jenkins-Crumb 请求头。

  • 取得作业配置(Get Job)

    GET /job/{jobName}/config.xml

    返回的文件为服务器上的 ~/.jenkins/jobs/{jobName}/config.xml

  • 创建作业(Create Job)

    POST /createItem?name={jobName}
    Content-Type: application/xml
    Jenkins-Crumb: {crumb}

    <flow-definition plugin="workflow-job@2.39">
    <actions>
    <org.jenkinsci.plugins.pipeline.modeldefinition.actions.DeclarativeJobAction plugin="pipeline-model-definition@1.7.1"/>
    <org.jenkinsci.plugins.pipeline.modeldefinition.actions.DeclarativeJobPropertyTrackerAction plugin="pipeline-model-definition@1.7.1">
    <jobProperties/>
    <triggers/>
    <parameters/>
    <options/>
    </org.jenkinsci.plugins.pipeline.modeldefinition.actions.DeclarativeJobPropertyTrackerAction>
    </actions>
    <description></description>
    <keepDependencies>false</keepDependencies>
    <properties>
    <hudson.plugins.jira.JiraProjectProperty plugin="jira@3.1.1"/>
    <com.dabsquared.gitlabjenkins.connection.GitLabConnectionProperty plugin="gitlab-plugin@1.5.13">
    <gitLabConnection></gitLabConnection>
    </com.dabsquared.gitlabjenkins.connection.GitLabConnectionProperty>
    <org.jenkinsci.plugins.workflow.job.properties.PipelineTriggersJobProperty>
    <triggers>
    <hudson.triggers.SCMTrigger>
    <spec>H/5 * * * *</spec>
    <ignorePostCommitHooks>false</ignorePostCommitHooks>
    </hudson.triggers.SCMTrigger>
    </triggers>
    </org.jenkinsci.plugins.workflow.job.properties.PipelineTriggersJobProperty>
    </properties>
    <definition class="org.jenkinsci.plugins.workflow.cps.CpsScmFlowDefinition" plugin="workflow-cps@2.82">
    <scm class="hudson.plugins.git.GitSCM" plugin="git@4.3.0">
    <configVersion>2</configVersion>
    <userRemoteConfigs>
    <hudson.plugins.git.UserRemoteConfig>
    <url>git@gitlab.codelet.net:codedance/2020/clorder/clorder-backend.git</url>
    <credentialsId>0a6c87de-e06b-44cb-ac11-6b46bee8f972</credentialsId>
    </hudson.plugins.git.UserRemoteConfig>
    </userRemoteConfigs>
    <branches>
    <hudson.plugins.git.BranchSpec>
    <name>*/development</name>
    </hudson.plugins.git.BranchSpec>
    </branches>
    <doGenerateSubmoduleConfigurations>false</doGenerateSubmoduleConfigurations>
    <submoduleCfg class="list"/>
    <extensions/>
    </scm>
    <scriptPath>Jenkinsfile</scriptPath>
    <lightweight>true</lightweight>
    </definition>
    <triggers/>
    <disabled>false</disabled>
    </flow-definition>

    数据部分的内容参照取得作业配置(Get Job)的返回结果,注意删除首行的 <?xml version='1.1' encoding='UTF-8'?> 部分。

  • 复制作业(Copy Job)

    POST /createItem?name={newJobName}&mode=copy&from={fromJobName}
    Jenkins-Crumb: {crumb}
  • 执行构建

    POST /job/{jobName}/build
    Jenkins-Crumb: {crumb}
    POST /job/{jobName}/buildWithParameters?parameter1=value1&parameter2=value2
    Jenkins-Crumb: {crumb}
  • 取得构建信息

    GET /job/{jobName}/lastBuild/api/json
    GET /job/{jobName}/{buildNumber}/api/json

    响应数据的 numberid 为构建编号(Build Number)。

    /api/jsno 替换为 consoleText 可下载控制台输出文本。

  • 删除作业

    DELETE /job/{jobName}/

    注意:最后的斜线(/)必须。

设置 SonarQube 质量门禁

  1. 在 Jenkins 中安装 SonarQube Scanner 插件

    该插件将为 Jenkins 提供用于接收 SonarQube 扫描结果的 Webhook,端点为 POST /sonarqube-webhook/

  2. 以管理员身份登录 SonarQube,并通过 Administration > Configuration > Webhooks 创建 Webhook

    假设 Jenkins 地址为 https://jenkins.example.com,那么 URL 应设置为 https://jenkins.example.com/sonarqube-webhook/

  3. 在 SonarQube 中通过 Administration > Security > Users 为用户创建 Token

  4. 在 Jenkins 中通过 Manage Jenkins > Configure System > SonarQube servers 添加 SonarQube 配置,指定配置的名称及 SonarQube 服务器地址,并在 Server authentication token 下添加并选择 SonarQube 用户 Token

  5. 在 Jenkins Pipeline 中使用 SonarQube Scanner 插件提供的 Step

    pipeline {
    agent any
    stages {
    stage('编译测试') {
    steps {
    sh "./mvnw clean install -U"
    }
    }
    stage('代码扫描') {
    steps {
    withSonarQubeEnv("SonarQube") {
    sh "./mvnw sonar:sonar -Dsonar.host.url=${env.SONAR_HOST_URL} -Dsonar.coverage.jacoco.xmlReportPaths=`pwd`/*-starter/target/site/jacoco-aggregate/jacoco.xml"
    }
    timeout(time: 5, unit: 'MINUTES') {
    waitForQualityGate abortPipeline: true
    }
    }
    }
    }
    }

    withSonarQubeEnv("SonarQube"):参数为上述第 2 步中设置的配置名,在其代码块中可以使用 SonarQube Scanner 插件提供的环境变量,如 env.SONAR_HOST_URL 为上述第 2 步中设置的 SonarQube 服务器地址

    waitForQualityGate abortPipeline: true:在 withSonarQubeEnv 之后执行,等待 SonarQube 服务器回调 Jenkins 的 SonarQube Webhook