Jenkins
目的
本文描述 Jenkins 安装部署步骤以及简单的配置与使用方法。
环境与软件
本章内容安装及运行所需软件:
项目 | 版本 | 说明 |
---|---|---|
操作系统 | CentOS 7 | |
OpenJDK 8 | 1.8.0 | Java 开发工具包 |
Git | 1.8.3.1 | 软件配置管理工具(SCM: Software Configuration Management) |
Maven | 3.6.3 | 软件项目管理工具,制品库(Artifact Repository) |
Jenkins | 2.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
):
管理员初始密码记录于 ~/.jenkins/secrets/initialAdminPassword
文件中。
可以通过 Manage Jenkins → Manage Plugins
安装插件:
插件 | 说明 |
---|---|
Locale | 可以设定 Jenkins 界面语言,语言代码如 en_US 、zh_CN 、ja_JP 、ko_KR 等 |
Blue Ocean | 可以使 Pipeline 编辑可视化 |
Generic Webhook Trigger | 通用的 Webhook 触发器 |
JaCoCo | 代码覆盖率插件 |
SonarQube Scanner | SonarQube 插件 |
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 的步骤:
将用于部署 Agent 的服务器上的用户的 SSH Key 复制到 Master 服务器
设 Master 服务器 IP 地址为
10.211.55.102
;Jenkins-Master-URL
为10.211.55.102:8080
ssh-copy-id -i ~/.ssh/id_rsa.pub cicd@10.211.55.102
通过
Manage Jenkins → Configure Global Security
设置Agents
:
- TCP 端口固定:如
8081
- 通过
Manage Jenkins → Manage Nodes and Clouds → New Node
添加 Agent:
- Node Name:如
node103
- Permanent Agent:添加第一个节点是必选
- # of executors:根据需要设置
- Remote root directory:如
/var/jenkins
(Jenkins 会在该路径下创建remoting
和workspace
等文件夹) - Labels:如
openjdk,centos
- Usage:根据需要设置
- Launch method:
Launch agent by connecting it to the master
- Availability:根据需要设置
点击节点列表中新建节点的名称将显示 Agent 启动方式说明,从说明中取得连接密钥
在部署 Agent 的服务器上下载 Agent 程序的 JAR 文件,下载地址为:http://
Jenkins-Master-URL
/jnlpJars/agent.jar在部署 Agent 的服务器上执行 Agent 程序的 JAR 文件:
java -jar agent.jar -jnlpUrl http://Jenkins-Master-URL/computer/node103/slave-agent.jnlp -secret 密钥 -workDir "/var/jenkins/workspace"
要添加其他 Agent,继续第 3 步
Pipeline 语法说明
Pipeline 是 Jenkins 流水线作业插件:
流水线作业通过 Jenkinsfile 配置
Jenkinsfile 遵循 Groovy 语法,但有如下例外:
- 根节点必须为一个块,即
pipeline {}
- 不可使用分号作为语句的分隔符,每条语句必须独占一行
- 代码块仅可由段(Section)、指令(Directive)、步骤(Step)或赋值语句构成
- 属性引用语句将被视为无参数方法调用,如
input
将被视为input()
- 根节点必须为一个块,即
Pipeline 内置了
echo
、sh
等步骤函数Groovy 中有参数的函数可以省略括号,因此
echo 'Hello'
与echo('Hello')
等价Groovy 中每行结尾的分号不是必须的
Groovy 通过
{}
封装闭包(Closure)
最简 Jenkinsfile:
pipeline {
agent any
stages {
stage('Build') {
steps {
echo 'Hello, World!'
}
}
}
}
Pipeline 中的段(Section):
段 | 位置 | 作用/说明 |
---|---|---|
agent (必须) | pipeline 、stage | 在何处执行作业 |
stages (必须) | pipeline 、stage | 定义流水线作业的各阶段 |
steps (必须) | stage | 定义一个阶段的各步骤 |
post | pipeline 、stage | 根据流水线或一个阶段的完成状态执行额外的步骤 |
parallel | stage | 并行作业 |
matrix | stage | 矩阵式并行作业 |
Pipeline 中的指令(Directive):
指令 | 位置 | 作用/说明 |
---|---|---|
tools | pipeline 、stage | 定义需要自动安装并设置到 PATH 环境变量的工具支持的工具有 JDK、Maven、Gradle 若 agent none 被指定则该指令将被忽略 |
options | pipeline 、stage | 对流水线作业进行配置 |
environment | pipeline 、stage | 通过键志对设置环境变量 可以通过 credentials(credentialName) 获取在 Jenkins 中预定义的凭证 |
parameters | pipeline 、input | 用户定义变量,在步骤中可以通过 params 对象访问 |
triggers | pipeline | 触发器,应用于未使用 Web Hook 的场景 |
stage | stages 、parallel | 一个 stages 块中至少需要存在一个 stage 指令stage 接受一个字符串参数作为阶段名必须包含一个且仅可包含 steps 、stages 、parallel 、matrix 中的一个块若一个 stage 已在一个 parallel 或 matrix 中则它不可嵌套 parallel 或 matrix |
input | stage | 提示用户输入,阶段将被暂停 |
when | stage | 描述一个阶段的执行条件 |
Jenkins cron 语法:
分钟MINUTE | 小时HOUR | 日期DOM (Day Of Month) | 月份MONTH | 星期DOW (Day Of Week) |
---|---|---|---|---|
0~59 | 0~23 | 1~31 | 1~12 | 0~7 (0 和 7 均为周日) |
*
代表所有有效值F-T
代表范围,如DOW
为1-5
时代表周一到周五F-T/N
或*/N
代表间隔,如HOUR
为9-22/4
时代表上午 9 点到晚上 22 点每 4 小时A,B,...,Z
代表枚举,如MONTH
为1,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 (必须)、docker 、dockerfile |
customWorkspace | 字符串 | 执行流水线或阶段的工作空间的路径,用于替代默认工作空间 | node 、docker 、dockerfile |
reuseNode | 布尔 | 默认为 false ,开启时将重用顶级 agent 指定的容器和工作空间 | stage 中的 agent 的 docker 、dockerfile |
args | 字符串 | 传递给 docker run 命令的参数 | docker 、dockerfile |
Jenkins 常用内置环境变量:
变量 | 说明 |
---|---|
BUILD_NUMBER | 构建编号 |
BRANCH_NAME | 多分支构建时 |
BUILD_URL | 当前构建的 Jenkins 页面的URL |
GIT_BRANCH | Git 代码库分支名 |
常用步骤:
参考链接:Pipeline Steps
步骤 | 参数(多个参数时 * 标记的为必须参数) | 说明 |
---|---|---|
echo | - | 将文本输出到构建日志 |
error | String message | 生成错误(但不向日志中输出 Stack Trace) |
isUnix | - | 检查当前操作系统是否为类 Unix 操作系统 |
sh bat powershell | String script *String encoding Boolean returnStatus Boolean returnStdout | 执行 Shell/BAT/PowerShell 脚本encoding 为输出日志的编码将 returnStatus 设置为 true 则无论执行结果是否成功都视为成功将 returnStdout 设置为 true 则会将标准输出作为返回值(而不是输出到构建日志中),除非发生错误若同时设置了 returnStatus 和 returnStdout 将使用 returnStatus |
pwd | - | 获取当前路径 |
dir | String path | 切换目录 |
deleteDir | - | 删除当前目录 |
fileExists | String file | 检查文件是否存在 |
readFile | String file *String encoding | 读取文件 |
writeFile | String file *String text *String encoding | 写入文件 |
stash | String name *Boolean allowEmpty String excludes String includes Boolean useDefaultExcludes | 暂存文件,用于跨 Jenkins 服务器节点文件传递,Jenkins 会将文件打包成 TAR |
unstash | String name | 取出暂存的文件 |
retry | int count | 重试执行代码块,直到成功或达到 count 参数指定的最大次数 |
sleep | int time String unit | 暂停作业 time 参数指定的时长,时间单位参数 unit 的可选值有 NANOSECONDS 、MICROSECONDS 、MILLISECONDS 、SECONDS 、MINUTES 、HOURS 、DAYS |
流水线或步骤的完成状态:
上次完成状态 → ↓ 本次完成状态 | aborted | unstable | failure | success |
---|---|---|---|---|
aborted | always unsuccessful cleanup | always changed unsuccessful cleanup | always changed unsuccessful cleanup | always changed regression unsuccessful cleanup |
unstable | always changed unsuccessful cleanup | always cleanup unsuccessful | always changed unsuccessful cleanup | always changed regression unsuccessful cleanup |
failure | always changed unsuccessful cleanup | always changed unsuccessful cleanup | always unsuccessful cleanup | always changed regression unsuccessful cleanup |
success | always 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¶meter2=value2
Jenkins-Crumb: {crumb}取得构建信息
GET /job/{jobName}/lastBuild/api/json
GET /job/{jobName}/{buildNumber}/api/json
响应数据的
number
和id
为构建编号(Build Number)。将
/api/jsno
替换为consoleText
可下载控制台输出文本。删除作业
DELETE /job/{jobName}/
注意:最后的斜线(
/
)必须。
设置 SonarQube 质量门禁
在 Jenkins 中安装 SonarQube Scanner 插件
该插件将为 Jenkins 提供用于接收 SonarQube 扫描结果的 Webhook,端点为
POST /sonarqube-webhook/
以管理员身份登录 SonarQube,并通过
Administration > Configuration > Webhooks
创建 Webhook假设 Jenkins 地址为
https://jenkins.example.com
,那么 URL 应设置为https://jenkins.example.com/sonarqube-webhook/
在 SonarQube 中通过
Administration > Security > Users
为用户创建 Token在 Jenkins 中通过
Manage Jenkins > Configure System > SonarQube servers
添加 SonarQube 配置,指定配置的名称及 SonarQube 服务器地址,并在Server authentication token
下添加并选择 SonarQube 用户 Token在 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