一, BlueOcean介绍
1.1 BlueOcean简介
- 提供了一套可视化操作界面来帮助创建、编辑 Pipeline 任务
- 它为开发人员提供了更具乐趣的Jenkins使用方式
- 实现了一种全新的、现代风格的用户界面
- 有助于任何规模的团队实现持续交付
1.2 BlueOcean特性
- 流水线编辑器:是一种直观并可视化的流水线编辑器
- 流水线的可视化:对流水线的可视化表示
- 流水线的诊断:即刻定位任务问题
- 个性化仪表盘:用户可以自定义仪表盘,只显示与自身相关的流水线
1.3 BlueOcean 安装
- 需要在 Jenkins plugin 中安装 BlueOceancha插件
1.4 Blue Ocean 创建Pipeline
-
打开 Blue Ocean
-
创建Pipeline(流水线)
-
编辑Pipeline
二, Pipeline
2.1 简介
- 借用Unix 中的Pipeline思路,一种高内聚低耦合的工具
- Jenkins 2.0 以上才会有
- 一系列 Jenkins 插件将整个持续集成用解释性代码 Jenkinsfile 来描述
- Jenkinsfile 使用方法:
- Jenkins 任务页面输入
- 源代码工程中编辑
- Jenkinsfile 语法类型:
- Declarative pipeline
- Scripts pipeline
2.2 创建Pipeline任务
-
新建Pipeline任务
-
流水线选择 Pipeline Script,选择模块添加Pipeline代码
-
利用Git源码库导入 Jenkins Pipeline
- Pipeline 的代码也可以放入 git 源码库进行管理
- 在Jenkins Pipeline 任务中选择 Pipeline script from SCM,然后添加 git 源码地址, 在Script Path中填写需要运行的Jenkinsfile文件所在的地址
- 例子源码位置: GitHub - princeqjzh/iPipeline
三, Jenkinsfile 语法
3.1 Jenkinsfile 简介
- Jenkinsfile 支持两种语法形式 :
- Declarative pipeline - v2.5之后引入,结构化方式
- Scripts pipeline - 基于 groovy 的语法
3.2 Jenkinsfile 语法参数 agent,stage,step
(1) Declarative 语句树
(2) Declarative Pipeline - agent
-
agent :定义pipeline执行节点
- 必须出现的指令
- 参数
- any:可以在任意agent上执行pipeline
- none:pipeline将不分配全局agent, 每个stage分配自己的agent
- label:指定运行节点的Label
- node:自定义运行节点配置,
- 指定 label
- 指定 customWorkspace
- docker:控制目标节点上的docker运行相关内容
-
举例说明:
pipeline {
agent {
label 'master'
customWorkspace 'myWorkspace'
}
}
(3) Declarative Pipeline - stages
- stages:
- 必须出现的指令
- 无参数
- 包含一个或多个stage的序列,Pipeline的大部分工作在此执行;
- 每个Pipeline 代码区间中必须只有一个stages
(4) Declarative Pipeline - stage
- stage:
- 必须出现的指令
- 无参数
- 包含在stages中
- Pipeline完成的所有实际工作都需要包含到stage中
- 需要定义stage的名字
(5) Declarative Pipeline - steps
-
steps:
- 必须出现的指令
- 无参数
- 具体执行步骤,包含在 stage 代码区间中
-
代码举例
pipeline {
agent {
node {
label 'master'
customWorkspace 'pipelineWorkspace'
}
}
stages {
stage('begin') {
parallel {
stage('begin') {
steps {
echo 'hello pipeline begin'
}
}
stage('Parallel Steps') {
steps {
sh 'echo "Begin Step"'
}
}
}
}
stage('running') {
parallel {
stage('running') {
steps {
echo 'hello pipeline running'
}
}
stage('running 2') {
steps {
sh 'echo "This is running 2"'
}
}
}
}
stage('finish') {
steps {
echo 'hello pipeline finish'
sh 'exit 0'
}
}
}
post {
success {
echo 'goodbye pipeline success!'
}
failure {
echo 'ops!!! pipeline failed....'
}
always {
echo 'always say goodbye'
}
}
}
3.3 Jenkinsfile 语法参数 post
-
post :定义Pipeline或stage运行结束时的操作
- 不是必须出现的指令
- 参数:
- always:无论Pipeline运行的完成状态如何都会运行
- changed:只有当前Pipeline运行的状态与先前完成的Pipeline的状态不同时,才能运行
- failure:仅当当前Pipeline处于“失败”状态时才运行
- success :仅当当前Pipeline具有“成功”状态时才运行
- unstable:只有当前Pipeline具有“不稳定”状态才能运行
- aborted:只有当前Pipeline处于“中止”状态时才能运行
-
post代码举例
pipeline {
agent any
stages {
stage('Test') {
steps {
echo 'This is test code'
sleep 2
sh 'exit 0'
}
}
}
post{
always {
echo 'always say goodbye'
}
success {
echo 'This is success exit'
}
failure {
echo 'This is failure exit'
}
}
}
3.3 Jenkinsfile 语法参数 options
-
options :定义pipeline 的专有属性
- 不是必须出现的指令
- 参数:
- 不是必须出现的指令
- buildDiscarder:保持构建的最大个数
- disableConcurrentBuilds:不允许并行执行pipeline任务
- timeout:pipeline 超时时间
- retry:失败后,重试整个Pipeline的次数
- timestamps:预定义由Pipeline生成的所有控制台输出时间
- skipStagesAfterUnstable:一旦构建状态进入了“Unstable”状态,就跳过此stage
-
代码举例
pipeline {
agent {
node{
label 'slaveNode'
customWorkspace "pipelineWorkspace"
}
}
options {
timeout(time: 30, unit: 'SECONDS')
buildDiscarder(logRotator(numToKeepStr: '2'))
retry(5)
}
stages {
stage('begin'){
steps {
echo 'hello pipeline begin'
sleep 2
}
}
stage('running'){
steps {
echo 'hello pipeline running'
sleep 2
}
}
stage('finish'){
steps {
echo 'hello pipeline finish'
sleep 2
sh 'exit 0'
}
}
}
post {
success {
echo 'goodbye pipeline success!'
sleep 2
}
failure {
echo 'ops!!! pipeline failed....'
sleep 2
}
always {
echo 'always say goodbye'
}
}
}
3.4 Jenkinsfile 语法参数 parameters
-
parameters :定义pipeline 的专有参数列表
- 不是必须出现的指令
- 参数:
- 支持数据类型:booleanParam, choice, credentials, file, text, password, run, string
- 类似参数化构建的选项
- 新建pipeline job时,需要同时配置参数化选项
- 新建pipeline job时,需要同时配置参数化选项
-
代码举例
pipeline {
agent {
node{
label 'slaveNode'
customWorkspace "myWorkspace"
}
}
parameters {
string(name: 'PERSON', defaultValue: 'Jenkins', description: '输入的文本参数')
}
stages {
stage('Test Parameters'){
steps {
echo "Hello ${params.PERSON}"
}
}
}
}
3.5 Jenkinsfile 语法参数 env_tools
-
环境工具变量的定义
-
设置位置: “Manage Jenkins”-> “Global Tool Configuration”
- 定义java_home
- 定义maven_home
- 定义java_home
-
Script 代码中引用环境变量,调用java、maven工具
stage('env tools') {
node('master'){
//定义maven java环境
def mvnHome = tool 'maven-3.6.0_master'
def jdkHome = tool 'jdk1.8_master'
//引用环境变量,配置PATH变量
env.PATH = "${mvnHome}/bin:${env.PATH}"
env.PATH = "${jdkHome}/bin:${env.PATH}"
//调用java mvn 工具
sh "java -version"
sh "mvn --version"
}
}
3.6 Jenkinsfile 语法参数 if-else &try-catch
(1) Scripts pipeline介绍
-
基于 groovy 语法定制的一种DSL语言
-
灵活性更高
-
可扩展性更好
-
Script pipeline 与 Declarative pipeline 程序构成方式有雷同之处,基本语句也有相似之处
-
Script pipeline 语句树
(2) Scripts pipeline: 流程控制之 – if/else
node {
stage('Example') {
if (env.BRANCH_NAME == 'master') {
echo 'I only execute on the master branch'
} else {
echo 'I execute elsewhere'
}
}
}
stage('Build') {
node {
echo "This is build stage."
}
}
* BRANCH_NAME为定义的变量参数,在键job时要选择参数化新增该参数
(3) Scripts pipeline: 流程控制 try-catch
stage('prepare') {
node {
echo "This is prepare stage."
}
}
stage('Test') {
node{
echo "This is test stage which run on the slave agent."
try {
echo "This is in the try block."
}catch (exc) {
echo "Something failed, I'm in the catch block."
}finally {
echo "Finally, I'm in the finally block."
}
}
}
3.7 Jenkinsfile 语法参数 environment
-
environment: 定义Pipeline或stage运行时的环境变量
-
不是必须出现的指令
-
无参数
-
代码示例
pipeline {
agent {
node{
label 'slave'
customWorkspace "myWorkspace"
}
}
environment {
hlw = 'hello world'
}
stages {
stage('Print environment_1'){
steps {
echo hlw
sleep 5
}
}
stage('Print environment_2'){
steps {
sh 'echo ${hlw}'
sleep 5
}
}
}
post {
success {
echo 'goodbye pipeline success!'
}
failure {
echo 'ops!!! pipeline failed....'
sleep 5
}
always {
echo 'always say goodbye'
}
}
}
3.8 Jenkinsfile 语法参数triggers
-
triggers:定义了Pipeline自动化触发的方式
- 不是必须出现的指令
- 参数:
- cron:接受一个cron风格的字符串来定义Pipeline触发的常规间隔
- pollSCM:接受一个cron风格的字符串来定义 Jenkins 检查SCM源更改的常规间隔;如果存在新的更改,则Pipeline将被重新触发。
-
代码示例
pipeline {
agent {
node{
label 'slaveNode'
customWorkspace "myWorkspace"
}
}
triggers {
cron('H/2 * * * *')
}
stages {
stage('Test Parameters'){
steps {
echo "Hello world"
}
}
}
}
四,质量门禁
4.1 概念
- 质量门禁是为了控制达标率的检查任务
- 设置质量门禁的好处
- 通过检查达标状态来评估产品质量,控制产品发布
- 利用自动化任务来控制产品的代码质量,减少人为干预因素
- 加速产品研发的迭代速度
4.2 质量门禁系统演练环境
- 项目运行平台:Jenkins;持续集成持续交付平台
- 质量门禁任务平台: Sonar Qube; 一款用于代码质量管理的开源工具,它主要用于管理源代码的质量。 通过插件形式,可以支持众多计算机语言。
- Java + Maven
- Docker
4.3 环境搭建
(1)Jenkins: 需要安装 SonarQube Scanner for Jenkins 插件
(2)搭建 SonarQube Server
- Docker 搭建
- 实战演练项目地址: iquality_gate: 质量门禁演示工程,测试实战小例子。
- iQualityGate 项目根目录下运行 docker-compose up -d 命令,对应的SonarQube Server docker 容器会自动启动
(3)Jenkins中的配置
-
在Jenkins 系统设定中配置SonarQube Server
-
登陆SonarQube (首次登陆用户名和密码都是admin)
(4)Sonar Qube中的配置
-
设定WebHook, administration → Configuration → Webhooks
-
添加Jenkins的webhook URL, http://your_jenkins:port/sonarqube-webhook
-
关闭用户访问强制认证的限制 Administration → Configuration → General Settings → Security → Force user authentication (关闭它)
(4)添加门禁 设定指标
-
新建SonarQube 门禁
-
设定门禁类型为:代码覆盖率 (Coverage)
-
设定门禁触发条件为:小于80%
-
覆盖范围:全部代码
(5)质量门禁运行
-
质量门禁在持续交付流程中的应用
-
运行项目需要导入对应的质量门禁依赖
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.example</groupId>
<artifactId>QualityGate_Sample</artifactId>
<packaging>jar</packaging>
<version>1.0</version>
<name>QualityGate_Sample</name>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<junit-version>4.7</junit-version>
<sonar.host.url>http://localhost:9000</sonar.host.url>
<sonar.jacoco.reportPath>${project.basedir}/../target/jacoco.exec</sonar.jacoco.reportPath>
</properties>
<dependencies>
<!--junit-->
<dependency>
<groupId>org.junit.platform</groupId>
<artifactId>junit-platform-commons</artifactId>
<version>1.4.1</version>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId>
<version>5.4.0</version>
</dependency>
<dependency>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
<version>5.4.0</version>
</dependency>
<!-- log4j -->
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.16</version>
</dependency>
</dependencies>
<build>
<finalName>QualityGate_Sample</finalName>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.3</version>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.22.1</version>
<configuration>
<testFailureIgnore>false</testFailureIgnore>
<includes>
<include>**/*.java</include>
</includes>
</configuration>
</plugin>
<plugin>
<groupId>org.jacoco</groupId>
<artifactId>jacoco-maven-plugin</artifactId>
<version>0.8.3</version>
<executions>
<execution>
<id>default-prepare-agent</id>
<goals>
<goal>prepare-agent</goal>
</goals>
</execution>
<execution>
<id>default-report</id>
<phase>prepare-package</phase>
<goals>
<goal>report</goal>
</goals>
</execution>
<execution>
<id>default-check</id>
<goals>
<goal>check</goal>
</goals>
<configuration>
<rules>
<rule implementation="org.jacoco.maven.RuleConfiguration">
<element>BUNDLE</element>
<limits>
implementation is needed only for Maven 2
<limit implementation="org.jacoco.report.check.Limit">
<counter>COMPLEXITY</counter>
<value>COVEREDRATIO</value>
<minimum>0.60</minimum>
</limit>
</limits>
</rule>
</rules>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
- 创建交付任务
- 在交付任务流水线中添加质量门禁
- 正向用例演示:测试代码覆盖率 > 80% ==> 门禁通过
- 负向用例演示:测试代码覆盖率 < 80% ==> 门禁失败
- 查看质量门禁覆盖率