本文将介绍JenkinsPipeline参数详解的详细情况,特别是关于jenkins的pipeline的相关信息。我们将通过案例分析、数据研究等多种方式,帮助您更全面地了解这个主题,同时也将涉及一些关
本文将介绍Jenkins Pipeline 参数详解的详细情况,特别是关于jenkins的pipeline的相关信息。我们将通过案例分析、数据研究等多种方式,帮助您更全面地了解这个主题,同时也将涉及一些关于CI/CD:Jenkins Pipeline 实践、Gitlab+Jenkins学习之路(十)之Jenkins按角色授权和Pipeline、Gitlab_ansible_jenkins 三剑客⑤jenkins Pipeline-job 的使用、Jenkins Pipeline的知识。
本文目录一览:- Jenkins Pipeline 参数详解(jenkins的pipeline)
- CI/CD:Jenkins Pipeline 实践
- Gitlab+Jenkins学习之路(十)之Jenkins按角色授权和Pipeline
- Gitlab_ansible_jenkins 三剑客⑤jenkins Pipeline-job 的使用
- Jenkins Pipeline
Jenkins Pipeline 参数详解(jenkins的pipeline)
Pipeline 是什么
Jenkins Pipeline 实际上是基于 Groovy 实现的 CI/CD 领域特定语言(DSL),主要分为两类,一类叫做 Declarative Pipeline
,一类叫做 Scripted Pipeline
。
Declarative Pipeline
体验上更接近于我们熟知的 travis CI
的 travis.yml
,通过声明自己要做的事情来规范流程,形如:
pipeline {
agent any
stages {
stage(''Build'') {
steps {
//
}
}
stage(''Test'') {
steps {
//
}
}
stage(''Deploy'') {
steps {
//
}
}
}
}
而 Scripted Pipeline
则是旧版本中 Jenkins 支持的 Pipeline 模式,主要是写一些 groovy 的代码来制定流程:
node {
stage(''Build'') {
//
}
stage(''Test'') {
//
}
stage(''Deploy'') {
//
}
}
一般情况下声明式的流水线已经可以满足我们的需要,只有在复杂的情况下才会需要脚本式流水线的参与。
过去大家经常在 Jenkins 的界面上直接写脚本来实现自动化,但是现在更鼓励大家通过在项目中增加 Jenkinsfile
的方式把流水线固定下来,实现 Pipeline As Code
,Jenkins 的 Pipeline 插件将会自动发现并执行它。
语法
Declarative Pipeline
最外层有个 pipeline
表明它是一个声明式流水线,下面会有 4 个主要的部分: agent
,post
,stages
,steps
,我会逐一介绍一下。
Agent
agent
主要用于描述整个 Pipeline 或者指定的 Stage 由什么规则来选择节点执行。Pipeline 级别的 agent 可以视为 Stage 级别的默认值,如果 stage 中没有指定,将会使用与 Pipeline 一致的规则。在最新的 Jenkins 版本中,可以支持指定任意节点 (any
),不指定 (none
),标签 (label
),节点 (node
),docker
,dockerfile
和 kubernetes
等,具体的配置细节可以查看文档,下面是一个使用 docker 的样例:
agent {
docker {
image ''myregistry.com/node''
label ''my-defined-label''
registryUrl ''https://myregistry.com/''
registryCredentialsId ''myPredefinedCredentialsInJenkins''
args ''-v /tmp:/tmp''
}
}
Tips:
- 如果 Pipeline 选择了 none,那么 stage 必须要指定一个有效的 agent,否则无法执行
- Jenkins 总是会使用 master 来执行 scan multibranch 之类的操作,即使 master 配置了 0 executors
- agent 指定的是规则而不是具体的节点,如果 stage 各自配置了自己的 agent,需要注意是不是在同一个节点执行的
Stages && Stage
Stages 是 Pipeline 中最主要的组成部分,Jenkins 将会按照 Stages 中描述的顺序从上往下的执行。Stages 中可以包括任意多个 Stage,而 Stage 与 Stages 又能互相嵌套,除此以外还有 parallel
指令可以让内部的 Stage 并行运行。实际上可以把 Stage 当作最小单元,Stages 指定的是顺序运行,而 parallel 指定的是并行运行。
接下来的这个 case 很好的说明了这一点:
pipeline {
agent none
stages {
stage(''Sequential'') {
stages {
stage(''In Sequential 1'') {
steps {
echo "In Sequential 1"
}
}
stage(''In Sequential 2'') {
steps {
echo "In Sequential 2"
}
}
stage(''Parallel In Sequential'') {
parallel {
stage(''In Parallel 1'') {
steps {
echo "In Parallel 1"
}
}
stage(''In Parallel 2'') {
steps {
echo "In Parallel 2"
}
}
}
}
}
}
}
}
除了指定 Stage 之间的顺序关系之外,我们还可以通过 when
来指定某个 Stage 指定与否:比如要配置只有在 Master 分支上才执行 push,其他分支上都只运行 build
stages {
stage(''Build'') {
when {
not { branch ''master'' }
}
steps {
sh ''./scripts/run.py build''
}
}
stage(''Run'') {
when {
branch ''master''
}
steps {
sh ''./scripts/run.py push''
}
}
}
还能在 Stage 的级别设置 environment
,这些就不展开了,文档里有更详细的描述。
Steps
steps
是 Pipeline 中最核心的部分,每个 Stage 都需要指定 Steps。Steps 内部可以执行一系列的操作,任意操作执行出错都会返回错误。完整的 Steps 操作列表可以参考 Pipeline Steps Reference,这里只说一些使用时需要注意的点。
- groovy 语法中有不同的字符串类型,其中
''abc''
是 Plain 字符串,不会转义${WROKSPACE}
这样的变量,而"abc"
会做这样的转换。此外还有'''''' xxx ''''''
支持跨行字符串,"""
同理。 - 调用函数的
()
可以省略,使得函数调用形如updateGitlabCommitStatus name: ''build'', state: ''success''
,通过,
来分割不同的参数,支持换行。 - 可以在声明式流水线中通过
script
来插入一段 groovy 脚本
Post
post
部分将会在 pipeline 的最后执行,经常用于一些测试完毕后的清理和通知操作。文档中给出了一系列的情况,比较常用的是 always
,success
和 failure
。
比如说下面的脚本将会在成功和失败的时候更新 gitlab 的状态,在失败的时候发送通知邮件:
post {
failure {
updateGitlabCommitStatus name: ''build'', state: ''failed''
emailext body: ''$DEFAULT_CONTENT'', recipientProviders: [culprits()], subject: ''$DEFAULT_SUBJECT''
}
success {
updateGitlabCommitStatus name: ''build'', state: ''success''
}
}
每个状态其实都相当于于一个 steps
,都能够执行一系列的操作,不同状态的执行顺序是事先规定好的,就是文档中列出的顺序。
Shared Libraries
同一个 Team 产出的不同项目往往会有着相似的流程,比如 golang 的大部分项目都会执行同样的命令。这就导致了人们经常需要在不同的项目间复制同样的流程,而 Shared Libraries 就解决了这个问题。通过在 Pipeline 中引入共享库,把常用的流程抽象出来变成一个的指令,简化了大量重复的操作。
在配置好 lib 之后,Jenkins 会在每个 Pipeline 启动前去检查 lib 是否更新并 pull 到本地,根据配置决定是否直接加载。
所有的 Shared Libraries 都要遵循相同的项目结构:
(root)
+- src # Groovy source files
| +- org
| +- foo
| +- Bar.groovy # for org.foo.Bar class
+- vars
| +- foo.groovy # for global ''foo'' variable
| +- foo.txt # help for ''foo'' variable
+- resources # resource files (external libraries only)
| +- org
| +- foo
| +- bar.json # static helper data for org.foo.Bar
目前我们的使用比较低级,所以只用到了 vars
来存储全局的变量。
vars 下的每一个 foo.groovy
文件都是一个独立的 namespace,在 Pipeline 中可以以 foo.XXX
的形式来导入。比如我们有 vars/log.groovy
:
def info(message) {
echo "INFO: ${message}"
}
def warning(message) {
echo "WARNING: ${message}"
}
那么 Jenkinsfile 中就可以这样调用:
// Jenkinsfile
steps {
log.info ''Starting''
log.warning ''Nothing to do!''
}
大家可能已经注意到了,在 groovy
文件中,我们可以直接像在 steps
中一样调用已有的方法,比如 echo
和 sh
等。
我们也能在 groovy
文件中去引用 Java 的库并返回一个变量,比如:
#!/usr/bin/env groovy
import java.util.Random;
def String name() {
def rand = new Random()
def t = rand.nextInt(1000)
return String.valueOf(t)
}
这样就能够在 JenkinsFile
中去设置一个环境变量:
// Jenkinsfile
environment {
NAME = random.name()
}
除了定义方法之外,我们还能让这个文件本身就能被调用,只需要定义一个 call 方法:
#!/usr/bin/env groovy
def call() {
sh "hello, world"
}
还能够定义一个新的 section,接受一个 Block:
def call(Closure body) {
node(''windows'') {
body()
}
}
这样可以让指定的 Body 在 windows 节点上调用:
// Jenkinsfile
windows {
bat "cmd /?"
}
常用技巧
发送邮件通知
主要使用 emailext
,需要在 Jenkins 的配置界面事先配置好,可用的环境变量和参数可以参考文档 Email-ext plugin
emailext body: ''$DEFAULT_CONTENT'', recipientProviders: [culprits(),developers()], subject: ''$DEFAULT_SUBJECT''
结果同步到 gitlab
同样需要配置好 gitlab 插件,在 Pipeline 中指定 options
:
// Jenkisfile
options {
gitLabConnection(''gitlab'')
}
然后就可以在 post 中根据不同的状态来更新 gitlab 了:
// Jenkisfile
failure {
updateGitlabCommitStatus name: ''build'', state: ''failed''
}
success {
updateGitlabCommitStatus name: ''build'', state: ''success''
}
文档参考:Build status configuration
构建过程中可用的环境变量列表
Jenkins 会提供一个完整的列表,只需要访问 <your-jenkins-url>/env-vars.html/
即可,别忘了需要使用 "${WORKSPACE}"
在 checkout 前执行自定义操作
在 Multibranch Pipeline 的默认流程中会在 checkout 之前和之后执行 git clean -fdx
,如果在测试中以 root 权限创建了文件,那么 jenkins 会因为这个命令执行失败而报错。所以我们需要在 checkout 之前执行自定义的任务:
#!/usr/bin/env groovy
// var/pre.groovy
def call(Closure body) {
body()
checkout scm
}
在 Jenkinsfile 中配置以跳过默认的 checkout 行为:
// Jenkisfile
options {
skipDefaultCheckout true
}
在每个 stage 中执行自定义的任务即可:
// Jenkisfile
stage(''Compile'') {
agent any
steps {
pre {
sh ''pre compile''
}
sh ''real compile''
}
}
总结
Jenkins 作为使用最为广泛的 CI/CD 平台,网上流传着无数的脚本和攻略,在学习和开发的时候一定要从基本出发,了解内部原理,多看官方的文档,不要拿到一段代码就开始用,这样才能不会迷失在各式各样的脚本之中。
更重要的是要结合自己的业务需求,开发和定制属于自己的流程,不要被 Jenkins 的框架限制住。比如我们是否可以定义一个自己的 YAML 配置文件,然后根据 YAML 来生成 Pipeline,不需要业务自己写 Pipeline 脚本,规范使用,提前检查不合法的脚本,核心的模块共同升级,避免了一个流程小改动需要所有项目组同步更新。这是我现在正在做的事情,有机会再跟大家分享~
CI/CD:Jenkins Pipeline 实践
目录
- 1 Jenkins2.X Pipeline
- 1.0 CI/CD
- 1.1 pipeline 简介
- 1.2 Jenkinsfile
- 1.3 流水线语法
- 1.3.1 脚本式流水线
- 1.3.2 声明式流水线
- 1.4 Blue Ocean
- 1.5 流水线的优势
- 2 多分支流水线实践
- 2.1 配置简述
- 2.2 新建project
- 2.3 脚本编写
- 2.3.1 代码拉取
- 2.3.2 Maven打包
- 2.3.3 设置环境变量
- 2.3.4 构建镜像
- 2.3.5 测试
- 2.3.5.1 启动服务以及环境容错处理
- 2.3.5.2 测试
- 2.3.5.3 发布Html报告
- 2.3.6 推送镜像到仓库
- 2.3.7 部署到远程机器上
- 2.3.8 构建后操作
- 2.3.8.1 环境清理
- 2.3.8.2 发送邮件
- 2.3.9 配置
- 3 完整流水线脚本
- 4总结
1 Jenkins2.X Pipeline
1.0 CI/CD
持续集成 (Continuous integration)是一种软件开发实践,即团队开发成员经常集成它们的工作,通过每个成员每天至少集成一次,也就意味着每天可能会发生多次集成。每次集成都通过自动化的构建(包括编译,发布,自动化测试)来验证,从而尽早地发现集成错误。
持续部署(continuous deployment)是通过自动化的构建、测试和部署循环来快速交付高质量的产品。某种程度上代表了一个开发团队工程化的程度,毕竟快速运转的互联网公司人力成本会高于机器,投资机器优化开发流程化相对也提高了人的效率,让 engineering productivity 最大化。
1.1 pipeline 简介
pipeline,即流水线,是jenkins2.X的新特性,是jenkins官方推荐使用的持续集成方案。与传统的自由风格项目不同,它是通过jenkins DSL 编写代码来实现。相比于之前用户只能通过Web界面进行配置的方式来定义Jenkins任务,现在通过使用jenkins DSL 和 Groovy 语言编写程序,用户可以定义流水线并执行各种任务。
1.2 Jenkinsfile
那么重点来了,流水线代码写在哪里呢?
答案就是Jenkinsfile。
在jenkins 2 中,流水线配置可以从jenkins中剥离出来。在自由风格等项目中,任务的配置都是以配置文件的形式保存在jenkins的服务器上的,这意味这所有的配置的变更都依赖于jenkins的web界面。当配置中使用了许多插件时,去维护他人构建的配置就十分繁琐。在流水线项目中,可以在Web界面中编写流水线脚本,也可以将脚本以文本形式保存在外部的版本控制系统中,这个文本就是Jenkinsfile。
对于git项目,推荐使用多分支流水线。将任务配置和流水线信息保存在Jenkinsfile中,把jenkinsfile保存在项目的根目录下。不同的项目和分支都会有自己的Jenkinsfile,其内容各不相同。这样一个多分支流水线 project 可以对不同的分支代码进行持续集成和持续部署。
使用Jenkinsfile可以像管理项目中代码一样通过文件的形式来管理jenkins任务,支持历史追溯和差异对比等功能。
1.3 流水线语法
流水线语法有两种:一种是脚本式流水线,另一种是声明式流水线。下面对两种语法进行简单介绍。更详细的内容请查阅官方文档。
1.3.1 脚本式流水线
流水线代码就是 Groovy 脚本,其中插入了部分针对jenkins的DSL步骤。这种方式几乎没有结构上的约束,程序流程也基于Groovy语法结构实现。这种方式更加灵活,但是需要会使用Groovy。
Jenkinsfile (Scripted Pipeline)
node {
stage('Example') {
if (env.BRANCH_NAME == 'master') {
echo 'I only execute on the master branch'
} else {
echo 'I execute elsewhere'
}
}
}
1.3.2 声明式流水线
相对于脚本式流水线的灵活,声明式流水线比较严谨。它的结构更加清晰,更加接近自由风格类型的项目。同时,清晰的结构有助于错误检查,上手简单,对Blue Ocean(下面会讲到)的支持也好。官方推荐使用这种语法格式。
通过下面的示例,可以看到一个stage就是一个阶段,每个阶段内是步骤和相关配置。agent 标识了阶段在哪个节点上卖弄执行。相关语法会在下面结合实际项目进行讲解。
如果声明式流水线不能满足我们的需求,那么我们可以在声明式脚本中使用脚本式流水线脚本,具体方法在下一章中。
Jenkinsfile (Declarative Pipeline)
pipeline {
agent none
stages {
stage('Example Build') {
agent { docker 'maven:3-alpine' }
steps {
echo 'Hello, Maven'
sh 'mvn --version'
}
}
stage('Example Test') {
agent { docker 'openjdk:8-jre' }
steps {
echo 'Hello, JDK'
sh 'java -version'
}
}
}
}
在本文的实践环节中,会使用声明式语法来演示一个多分支流水线的project。
1.4 Blue Ocean
Blue Ocean 是 jenkins2 中全新的可视化界面(需求安装Blue Ocean插件)。它为流水线的每一个阶段都添加了图形化展示,可以查看每一个阶段的状态和进展,对每个阶段、每个任务都有点选式日志查看的功能,十分清晰。
1.5 流水线的优势
- 灵活性:通过脚本的方式要比只依赖于WEB界面配置的方式要灵活。
- 可追溯性:jenkinsfile管理在源码下,可对配置进行历史追溯和差异比对。
- 清晰性:结构清晰,便于排错。
- 可恢复性:可以基于某一个版本的配置进行重新运行。
2 多分支流水线实践
2.1 配置简述
已经安装pipeline相关插件。实践的对象是一个git项目。一共三个分支:maste、test、script。每个分支下都有一个Jenkinsfile。
三个分支的配置基本相同,主要步骤如下:
拉取代码—>maven打包—>构建镜像—>测试—>推送harbor仓库—>部署发布
上述基本完成了一个项目的持续集成和持续部署
2.2 新建project
新建一个多分支流水线project,源码管理选择git,然后填上项目的git地址。如果权限正常的话,在保存后Jenkins会扫描项目的所有分支下的Jenkinsfile,自动创建流水线并执行。
点击左侧的打开Blue Ocean进入可视化界面。
2.3 脚本编写
2.3.1 代码拉取
持续集成的源头就是获取最新的代码。让我们看下在pipeline 脚本中是如何做的。
stage('Git Pull') {
steps {
git(url: 'https://gitee.com/GJXing/luckymoney.git', branch: 'master',credentialsId: '6cde17d1-5480-47df-9e08-e0880762b496')
echo 'pull seccess'
}
}
- url: 源代码地址
- branch:git分支
- credentialsId:凭证(username and password)
echo 是输出信息,提示拉取成功,此处可有可无。
2.3.2 Maven打包
项目是一个SpringBoot的Java项目,通过maven构建jar包。
stage('Maven Build') {
steps {
sh 'mvn clean install'
}
}
sh 就是执行shell 命令
注意:在test分支中做了testNG测试,此时执行 ‘mvn clean install’ 会在打包时进行测试。如果test分支此阶段不想做测试,则打包时忽略测试
stage('Maven Build') {
steps {
sh 'mvn clean install -Dmaven.test.skip=true'
}
}
将jar包保存为“制品”
假设我们想保存script分支构建得到的jar包,那么可以通过
archive 'target/luckymoney-0.0.1-SNAPSHOT.jar'
进入Blue Ocean 查看制品
2.3.3 设置环境变量
在进行下一阶段前,先解决一个比较重要的问题,在流水线中如何配置环境变量。
environment {
IMAGE_NAME = 'harbor.guojiaxing.red/public/springbootdemo'
CONTAINER_NAME = 'luckymoney'
}
声明式流水线的环境变量配置是声明在environment块中。这里我声明了两个环境变量,一个是镜像名称,一个是容器名称。这两个变量在后面的阶段中会反复使用。
environment 可以声明在pipeline块下作用于整个配置,也可以声明在一个stage下只作用于一个阶段。
环境变量的调用方式与shell一样,如:${CONTAINER_NAME}
2.3.4 构建镜像
pipeline 针对docker做了分装,其自己定义了一套语法规则来进行容器的操作。
例如:
build(image[,args])
使用当前目录的Dockerfile,运行docker build来创建一个镜像并打上标签。
Image.run([args,command])
使用docker run来运行一个镜像,同时返回一个容器。
Image.pull()
运行 docker pull
除了以上列出的几个,还有其他的许多方法。但是我并不愿意使用这些方法。原因有两个,一个是docker 命令本身就不复杂,使用起来就比较方便。另一个原因是使用docker命令比二次分装的方法更加灵活。
下面正式开始进行镜像的构建
stage('Build Image') {
steps {
sh '''VERSION=$(date +%Y%m%d%H%M%s)
echo "$(date +%Y%m%d%H%M%s)" > ${WORKSPACE}/VERSION
echo "building image: ${IMAGE_NAME}_${BRANCH_NAME}:${VERSION}"
docker build -t ${IMAGE_NAME}_${BRANCH_NAME}:${VERSION} .'''
}
}
镜像由镜像名称和镜像TAG构成。
对于镜像名称,由于是多分支流水线,这里采用基础镜像名称+分支名称组合的形式。
tag的作用就是表明版本,此处采用构建时间,精确到秒。将构建时间保存在文件中,之后所有的阶段都读取该文件来获取版本。当然我们还可以选择构建号或自定义等变量作为tag(如下),但是这种方式在唯一性方面不如时间方式。此处可根据实际业务进行选择。
sh ' docker build -t ${IMAGE_NAME}_${BRANCH_NAME}:${BUILD_NUMBER} .'
2.3.5 测试
在每次构建后,我们都应该对当前版本的代码做自动化测试,通过冒烟等测试来评估当前版本的质量。保证我们要发布版本的质量是过关的,如果任何一个测试步骤失败则后续阶段不会继续,应用也不会发布。这也是持续集成的重要思想。
2.3.5.1 启动服务以及环境容错处理
严格的说,服务的启动不应该和测试放在一个阶段,应该在一个单独的阶段中执行,此处为了方便进行了简写。
了解docker就会知道,同名的容器没有被删除,那么容器是无法启动的。如果由于上次构建失败或其他原因导致目标容器名称的容器存在,那么在容器启动前进行环境清理就很由必要。
steps {
script {
try {
sh '''environmental_clean(){
docker_ps=`docker ps | grep ${CONTAINER_NAME}_${BRANCH_NAME}`
docker_psa=`docker ps -a | grep ${CONTAINER_NAME}_${BRANCH_NAME}`
if [[ 0 -eq $docker_ps ]];
then
#容器未启动
echo "容器${CONTAINER_NAME}_${BRANCH_NAME}未启动"
else
echo "停止容器"
docker stop ${CONTAINER_NAME}_${BRANCH_NAME}
fi
if [[ 0 -eq $docker_psa ]];
then
echo "容器${CONTAINER_NAME}_${BRANCH_NAME}不存在"
else
echo "删除容器"
docker rm ${CONTAINER_NAME}_${BRANCH_NAME}
fi
}
#docker 环境清理
environmental_clean'''
}
catch (exc) {
echo '环境不需要清理'
}
}
脚本很简单,通过判断docker进程是否存在来停止或删除容器。
重点是通过script块在声明式代码中引用了脚本式的代码。为什么要这样做呢?
前面已经讲过了这是一个容错处理,如果环境不干净就清理,但如果环境中无目标容器名称的容器从在,在‘docker_ps=docker ps | grep ${CONTAINER_NAME}_${BRANCH_NAME}
’执行完后会返回-1,与shell脚本不同,pipeline规定当返回结果不是表示成功时,流水线就会终止,此处为了流水线可以继续走下去,用try catch做异常处理。
如果不借助脚本式语法,声明式流水线可以在sh步骤开始加入 ‘set +e’,则在出现错误后不会停止。此处主要是为了演示如何在声明式代码中引用脚本式的代码。
启动容器
sh '''VERSION=$(cat ${WORKSPACE}/VERSION)
docker run -dit --name=${CONTAINER_NAME}_${BRANCH_NAME} ${IMAGE_NAME}_${BRANCH_NAME}:${VERSION}'''
2.3.5.2 测试
流水线不仅可以串行也可以并行。在测试阶段我们就可以进行并行操作。
如图所示,在test分支的Test阶段,ui自动化、接口自动化、性能测试、单元测试等都可以并行执行。
在pipeline脚本中 parallel 块内的 stage 块会并行执行。
parallel {
stage('接口自动化测试') {
steps {
sh '''echo "进行接口自动化测试"
mvn clean test
echo "自动化测试完成" '''
}
}
stage('UI自动化测试') {
steps {
echo 'ui test'
}
}
}
2.3.5.3 发布Html报告
将html报告进行发布。
在testNG执行完后会在项目test-output目录下生成report.html,将报告发布。安装 HTML Publisher plugin 插件。
post {
always {
publishHTML([
allowMissing: false,
alwaysLinkToLastBuild: false,
keepAll: true,
reportDir: "test-output",
reportFiles: "report.html",
reportName:"testNg report"
])
}
}
post块的作用是在所有步骤最后执行,可以作用于整个pipeline或一个阶段内。always表示不管是成功还是失败都执行。
同样在制品中查看
点击报告查看(出现样式问题点击这里)
2.3.6 推送镜像到仓库
代码测试完成后就可以将镜像推送到远程仓库了。
仓库是我自己搭建的harbor。
stage('Push to Harbor') {
steps {
withCredentials(bindings: [usernamePassword(credentialsId: 'e8dc0fa7-3547-4b08-8b7b-d9e68ff6c18f', passwordVariable: 'password', usernameVariable: 'username')]) {
sh 'docker login -u $username -p $password harbor.guojiaxing.red'
}
sh '''export VERSION=$(cat ${WORKSPACE}/VERSION)
echo "docker push ${IMAGE_NAME}_${BRANCH_NAME}:${VERSION}"
docker push ${IMAGE_NAME}_${BRANCH_NAME}:${VERSION}'''
}
pipeline中的鉴权方式是withCredentials(),这需要事先在jenkins配置中保存凭据。
2.3.7 部署到远程机器上
安装 SSH Pipeline Steps 插件。配置username and password 凭据。
stage('ssh deploy') {
steps {
script {
def remote = [:]
remote.name = 'gjx_server'
remote.host = 'www.guojiaxing.red'
remote.allowAnyHosts = true
withCredentials([usernamePassword(credentialsId: 'gjx-server', passwordVariable: 'password', usernameVariable: 'username')]) {
remote.user = "${username}"
remote.password = "${password}"
}
sshCommand remote: remote, command: "docker pull ${IMAGE_NAME}_${BRANCH_NAME}:${BUILD_NUMBER}"
}
}
ssh pipeline 更多的操作请查阅官方文档
2.3.8 构建后操作
2.3.8.1 环境清理
在作用于pipeline全局的post中进行环境清理
always {
script {
try{
sh '''environmental_clean(){
docker_ps=`docker ps | grep ${CONTAINER_NAME}_${BRANCH_NAME}`
docker_psa=`docker ps -a | grep ${CONTAINER_NAME}_${BRANCH_NAME}`
if [[ 0 -eq $docker_ps ]];
then
#容器未启动
echo "容器${CONTAINER_NAME}_${BRANCH_NAME}未启动"
else
echo "停止容器"
docker stop ${CONTAINER_NAME}_${BRANCH_NAME}
fi
if [[ 0 -eq $docker_psa ]];
then
echo "容器${CONTAINER_NAME}_${BRANCH_NAME}不存在"
else
echo "删除容器"
docker rm ${CONTAINER_NAME}_${BRANCH_NAME}
fi
}
#docker 环境清理
environmental_clean
export BUILD_NUMBER=$(cat ${WORKSPACE}/BUILD_NUMBER)
docker rmi ${IMAGE_NAME}_${BRANCH_NAME}:${BUILD_NUMBER}'''
}
catch (exc) {
echo '镜像不需要删除'
}
}
2.3.8.2 发送邮件
安装 Email Extension Plugin 插件并完成邮件配置
在作用于pipeline全局的post中编写邮件配置
failure {
emailext (
subject: "Failed: Job '${env.JOB_NAME} [${env.BUILD_NUMBER}]' 自动化测试结果",
body: '''<body leftmargin="8" marginwidth="0" topmargin="8" marginheight="4" offset="0">
<table width="95%" cellpadding="0" cellspacing="0">
<tr>
<td><br />
<b><font color="#0B610B">构建信息</font></b>
<hr size="2" width="100%" align="center" /></td>
</tr>
<tr>
<td>
<ul>
<li>构建名称:${JOB_NAME}</li>
<li>构建结果: <span> ${BUILD_STATUS}</span></li>
<li>构建编号:${BUILD_NUMBER}</li>
<li>构建地址:<a href="${BUILD_URL}">${BUILD_URL}</a></li>
<li>GIT 分支:${BRANCH_NAME}</li>
<li>变更记录: ${CHANGES,showPaths=true,showDependencies=true,format="<pre><ul><li>提交ID: %r</li><li>提交人:%a</li><li>提交时间:%d</li><li>提交信息:%m</li><li>提交文件:<br />%p</li></ul></pre>",pathFormat=" %p <br />"}
</ul>
</td>
</tr>
</table>
</body>
</html>
''',
to: "XXX802003@qq.com",
from: "XXX34093915@163.com",
attachLog: true,
compressLog: true
)
}
success {
emailext (
subject: "SUCCESSFUL: Job '${env.JOB_NAME} [${env.BUILD_NUMBER}]' 自动化测试结果",
body: '''<body leftmargin="8" marginwidth="0" topmargin="8" marginheight="4" offset="0">
<table width="95%" cellpadding="0" cellspacing="0">
<tr>
<td><br />
<b><font color="#0B610B">构建信息</font></b>
<hr size="2" width="100%" align="center" /></td>
</tr>
<tr>
<td>
<ul>
<li>构建名称:${JOB_NAME}</li>
<li>构建结果: <span> ${BUILD_STATUS}</span></li>
<li>构建编号:${BUILD_NUMBER}</li>
<li>构建地址:<a href="${BUILD_URL}">${BUILD_URL}</a></li>
<li>GIT 分支:${BRANCH_NAME}</li>
<li>变更记录: ${CHANGES,showPaths=true,showDependencies=true,format="<pre><ul><li>提交ID: %r</li><li>提交人:%a</li><li>提交时间:%d</li><li>提交信息:%m</li><li>提交文件:<br />%p</li></ul></pre>",pathFormat=" %p <br />"}
</ul>
</td>
</tr>
</table>
</body>
</html>
''',
to: "XXX802003@qq.com",
from: "xxx34093915@163.com",
attachLog: true,
compressLog: true
)
}
failure 为构建失败时执行,success 为构建成功时执行。
查看邮件:
2.3.9 配置
options {
disableConcurrentBuilds()
timeout(time: 1, unit: 'HOURS')
}
triggers {
pollSCM('H/15 * * * *')
}
disableConcurrentBuilds() 表示多分支不允许同时构建
timeout(time: 1, unit: ‘HOURS’) 表示超时时间,1小时超时则构建失败
pollSCM(‘H/15 * * * *’) 表示每15分钟 轮询扫描源代码,如果有修改则构建,无修改则不构建。
3 完整流水线脚本
script分支下Jenkinsfile
4总结
通过此次 Jenkins Pipeline 实践,对比于传统的自由风格项目,感受到流水线工程的强大和方便之处,也加深了我对CI/CD的理解。
此次从代码拉取到打包到测试再到部署,使用了maven、docker、testNG和harbor等工具,基本上覆盖了一般业务的部署流程。对于一门新技术或工具的学习,我认为具体用到什么内容就学什么内容,没有必要把一个工具或技术完完全全掌握,一般也很难全部掌握。正所谓用到的才是有用的。即使如此,此次实践也覆盖了pipeline 80%以上的语法内容。
pipeline很强大、很好用,并且它还在不断的完善中,随着时间推移,未来其在CI/CD领域一定会有更大的作用。
Gitlab+Jenkins学习之路(十)之Jenkins按角色授权和Pipeline
-
一、Jenkins按角色授权
当一个公司的开发分为多个组别,或者是多个项目等等。用于公司内部测试,让开发人员自行构建测试,此时不可能让所有的开发都在公用一个构建,这样变得很混乱,为了解决这一问题,jenkins也提供了角色授权的机制。每个开发有着对应的账号和权限,可以自行新建,构建,测试,发布等。角色授权需要安装的插件:Role-based Authorization Strategy
(1)系统配置
系统管理-->Configure Global Security-->访问控制-->授权策略-->Role-Base Strategy
(2)新建用户
系统管理-->管理用户-->新建用户
这里创建一个java用户和php用户,用于区分php和java项目的构建
(3)用户关联自己相关job,无法查看其他的job
建立项目角色,并对该用户进行项目的授权(包括Job的构建,取消,配置,创建,删除等等)
注意此处的添加,一个是Role是随意填写,最好规范点。Pattern是正则匹配,比如此处匹配的是所有包含Java开头的项目和php开头的项目
系统管理-->Manage and Assign Roles --> Manage Roles-->Project roles
配置好项目的权限,使用java用户或php用户登录是没有新建项目的权限,如需新增这样的权限,需要在Global roles中进行配置,新增一个角色(比如新增一个可以创建新项目的权限角色:new job,可登录查看的角色read):
然后系统管理-->Manage and Assign Roles -->Assign Roles进行添加对应的权限
使用php登录查看,可以看到php用户可以看到对应php开头的项目,但是没有新建项目的权限:
-
二、Jenkins的Pipeline(代码流水线管理)
Pipeline(代码流水线管理)
Pipeline名词顾名思义就是流水线的意思,因为公司可能会有很多项目。如果使用jenkins构建完成后,开发构建项目需要一项一项点击,比较麻烦。所以出现pipeline名词。
(1)下载pipeline。这样只需要构建一个项目,就会帮我们完成所有相关项目
搜索插件pipeline
等待安装完成
(2)新建一个pipeline的项目
配置pipeline项目,使用Pipeline script脚本:
node {
stage ''build php-deploy''
build ''php-deploy''
stage ''build java''
build ''java''
}
为了解决各个项目的依赖关系关系,使用pipeline的脚本进行控制。
第一步构建php项目,第二步构建java项目。Pipeline的脚本语法在Pipeline Syntax中有展示
Pipeline Syntax的使用,如图:
立即构建p1的项目,如图:
代码流水线的功能就介绍到此!
Gitlab_ansible_jenkins 三剑客⑤jenkins Pipeline-job 的使用
Pipeline-job 的使用
创建 Pipeline 任务
找到 root 用户的 id
编写 pipeline 脚本
#!groovy
pipeline{
agent {node {label ''master''}}
environment {
PATH="/bin/:sbin:usr/bin:usr/sbin:/usr/local/bin"
}
parameters {
choice(
choices: ''dev\nprod'',
description: ''choose deploy environment'',
name: ''deploy_env''
)
string (name: ''version'', defaultValue: ''1.0.0'', description: ''build version'')
}
stages {
stage("checkout test repo") {
steps {
sh ''git config --global http.sslVerify false''
dir ("${env.WORKSPACE}") {
git branch: ''master'', credentialsId: "6bdd72fd-dcc1-4977-9978-4982aae37dc9", url: ''https://root@gitlab.example.com/root/test-repo.git''
}
}
}
stage("Print env variable") {
steps {
dir ("${env.WORKSPACE}") {
sh """
echo "[INFO] print env variable"
echo "current deployment environment is $deploy_env" >> test.properties
echo "the build is $version" >> test.properties
echo "[INFO] Done..."
"""
}
}
}
stage("check test properties") {
steps{
dir ("${env.WORKSPACE}") {
sh """
echo "[INFO] check test properties"
if [ -s test.properties ]
then
cat test.properties
echo "[INFO] done..."
else
echo "test.properties is empty"
fi
"""
echo "[INFO] build finished..."
}
}
}
}
}
编译结果:
Jenkins 与基础应用集成
打开 shell 模块编辑
编写测试脚本
#!/bin/sh
user=`whoami`
if [ $user == ''deploy'' ]
then
echo "hello, my name is $user"
else
echo "sorry, i am not $user"
fi
ip addr
cat /etc/system-release
free -m
df -h
py_cmd=`which python`
$py_cmd --version
带参数的界面
添加参数选项
脚本
#!/bin/sh
echo "current deploy environment is $deploy_env"
echo "the build is $version"
echo "the password is $pass"
if $bool
then
echo "request is appoved"
else
echo "request is rejected"
fi
编译结果
Jenkins 和 git 的集成
Jenkins Pipeline
jenkins + pipeline 构建自动化部署
pipeline {
agent any
tools {
maven ''maventool''
}
stages {
stage (''初始化'') {
steps {
sh ''''''
echo "PATH = ${PATH}"
echo "M2_HOME = ${M2_HOME}"
''''''
}
}
stage(''拉取代码'') { // for display purposes
steps {
git branch: ''release-2.0'', credentialsId: ''7cb3c8ca-b916-49eb-95fc-be3b243c3a93'', url: ''http://url:9080/Shtel-PaaS/Shtel-PaaS-DevOps/paas-devops-pipeline.git''
sh ''git checkout v2.0.1''
}
}
stage(''maven构建'') {
steps {
// Run the maven build
sh "mvn clean -U package -Dmaven.test.skip=true"
}
}
stage(''拉取部署剧本'') { // for display purposes
steps {
sh "rm -rf paas-svc-k8s-deploy-playbook"
dir("paas-svc-k8s-deploy-playbook") {
git branch: ''dev'', credentialsId: ''7cb3c8ca-b916-49eb-95fc-be3b243c3a93'', url: ''http://url:9080/configserver/paas-svc-k8s-deploy-playbook.git''
// sh ''git checkout v0.1''
}
}
}
stage(''拉取配置集''){ // for desplay purposes
steps {
sh "rm -rf deploy_config_set"
dir("deploy_config_set"){
git branch: ''dev'', credentialsId: ''7cb3c8ca-b916-49eb-95fc-be3b243c3a93'', url: ''http://url:9080/configserver/deploy_config_set''
}
}
}
stage(''放置发布包'') {
steps {
sh "cp target/*.tar.gz paas-svc-k8s-deploy-playbook/roles/paas-svc/files"
}
}
stage(''根据包,修改脚本中的版本号''){
steps{
sh "sh paas-svc-k8s-deploy-playbook/roles/paas-svc/templates/set_version.sh"
}
}
stage(''执行部署'') {
steps {
ansiblePlaybook credentialsId: ''paas-ce-77'', extras: ''--extra-vars=\''@./deploy_config_set/paas-devops-pipeline/dev.yml\'' -e "env=dev"'', installation: ''ansible-playbook'', inventory: ''paas-svc-k8s-deploy-playbook/inventory/inventory'', playbook: ''paas-svc-k8s-deploy-playbook/playbooks/deploy-dev-k8s.yml''
}
}
}
}
# -----------------------------------------------------------------------------------------------------
pipeline {
agent any
tools {
maven ''maventool''
}
stages {
stage (''初始化'') {
steps {
sh ''''''
echo "PATH = ${PATH}"
echo "M2_HOME = ${M2_HOME}"
''''''
}
}
stage(''拉取devops-common代码'') {
steps {
sh "rm -rf *"
git branch: ''release-2.0'', credentialsId: ''7cb3c8ca-b916-49eb-95fc-be3b243c3a93'', url: ''http://url:9080/Shtel-PaaS/Shtel-PaaS-DevOps/paas-devops-common.git''
sh ''git checkout v2.0.1''
}
}
stage(''maven构建devops-common包'') {
steps {
sh "mvn clean deploy -DaltDeploymentRepository=paas::default::http://url:8082/repository/maven-snapshots/"
}
}
}
}
今天关于Jenkins Pipeline 参数详解和jenkins的pipeline的讲解已经结束,谢谢您的阅读,如果想了解更多关于CI/CD:Jenkins Pipeline 实践、Gitlab+Jenkins学习之路(十)之Jenkins按角色授权和Pipeline、Gitlab_ansible_jenkins 三剑客⑤jenkins Pipeline-job 的使用、Jenkins Pipeline的相关知识,请在本站搜索。
本文标签: