2.Jenkins之Pipeline使用
目录
概念
是一套运行在 Jenkins 上的工作流框架,将原来独立运行于单个或者多个节点 的任务连接起来,实现单个任务难以完成的复杂流程编排和可视化的工作。
优势
代码:Pipeline以代码的形式实现,通常被检入源代码控制,使团队能够编辑,审查和迭代其传送流程。
持久:无论是计划内的还是计划外的服务器重启,Pipeline都是可恢复的。
可停止:Pipeline可接收交互式输入,以确定是否继续执行Pipeline。
多功能:Pipeline支持现实世界中复杂的持续交付要求。它支持fork/join、循环执行,并行执行任务的功能。
可扩展:Pipeline插件支持其DSL的自定义扩展 ,以及与其他插件集成的多个选项。
插件安装
需要安装插件Pipeline
安装后,在Jenkins中"新建Item"时会出现一个选项
PipeLine语法
#声明式:
pipeline {
agent any
stages { #整个流水线的所有执行阶段。通常stages只有1个,里面包含多个stage
stage('拉取代码' ) { #流水线中的某个阶段,可能出现多个。一般分为拉取代码,编译构建,部署等阶段。
steps { #代表一个阶段内需要执行的逻辑。steps里面是shell脚本,git拉取代码,ssh远程发布等任意内容
echo '拉取代码'
}
}
stage('编译代码 ') {
steps {
echo '编译代码'
}
}
stage('发布运行 ') {
steps {
echo '发布运行'
}
}
}
}
#脚本式:
node {
stage('拉取代码' ) {
echo '拉取代码'
}
stage('编译代码 ') {
echo '编译代码'
}
stage('发布运行 ') {
echo '发布运行'
}
}
实现拉取->编译->部署
整体配置项没变,和第一篇一样,只不过展现的形式变了
最终生成好的PipeLine
不论是声明式还是脚本式,实际执行的内容一样,只不过结构不同
node {
stage('拉取代码' ) {
checkout([$class: 'GitSCM', branches: [[name: '*/master1']], extensions: [], userRemoteConfigs: [[credentialsId: '1dabcacf-ffda-4c45-ad9b-32f9a640f4d9', url: 'https://gitee.com/RollBack2010/jekins-study.git']]])
}
stage('编译代码 ') {
sh 'mvn clean package'
}
stage('发布运行 ') {
sshPublisher(publishers: [sshPublisherDesc(configName: 'jarPath', transfers: [sshTransfer(cleanRemote: false, excludes: '', execCommand: '''cd /usr/local/project
./start.sh''', execTimeout: 120000, flatten: false, makeEmptyDirs: false, noDefaultExcludes: false, patternSeparator: '[, ]+', remoteDirectory: '', remoteDirectorySDF: false, removePrefix: 'target/', sourceFiles: 'target/demo-0.0.1-SNAPSHOT.jar')], usePromotionTimestamp: false, useWorkspaceInPromotion: false, verbose: false), sshPublisherDesc(configName: 'jarPath1', transfers: [sshTransfer(cleanRemote: false, excludes: '', execCommand: '''cd /usr/local/project1
./start.sh''', execTimeout: 120000, flatten: false, makeEmptyDirs: false, noDefaultExcludes: false, patternSeparator: '[, ]+', remoteDirectory: '', remoteDirectorySDF: false, removePrefix: 'target/', sourceFiles: 'target/demo-0.0.1-SNAPSHOT.jar')], usePromotionTimestamp: false, useWorkspaceInPromotion: false, verbose: false)])
}
}
命令生成方式
进入“流水线语法”生成页面
拉取
编译
部署
执行Build
会完成下载、编译、部署、启动流程
PipeLine脚本存放到项目中
以上都是将命令存放到Jenkins中,这样无法记录脚本修改记录,也容易丢失,所以将脚本放到项目中,通过git进行管理
创建Jenkinsfile
存放到项目根目录,名字也可以改,不过Jenkins默认找这个,文件内容就是上面的脚本内容
Jenkins中修改配置
执行Build
会完成下载、编译、部署、启动流程
通过参数构建
上面拉取代码的分支都是写死在Jenkinsfile中,现在把这个设置为传入变量
第一步,jenkins项目配置
第二步,修改Jenkinsfile脚本
#*/master1 -> */${branch}
#由
checkout([$class: 'GitSCM', branches: [[name: '*/master1']], extensions: [], userRemoteConfigs: [[credentialsId: 'ff8ba3ca-be5f-4535-bb37-08de5ef208f9', url: 'https://gitee.com/RollBack2010/jekins-study.git']]])
#修改为
checkout([$class: 'GitSCM', branches: [[name: '*/${branch}']], extensions: [], userRemoteConfigs: [[credentialsId: 'ff8ba3ca-be5f-4535-bb37-08de5ef208f9', url: 'https://gitee.com/RollBack2010/jekins-study.git']]])
第三步,使用
对于在“片段生成器”中未提供的插件使用
我想实现,拉取代码编译完成后,在部署前,先去对应服务器上把正在运行的服务停止,否则直接启动会报端口占用
第一步,安装插件SSH Pipeline Steps
第二步,发现插件未提供代码片段生成
第三步,打开对应的README
根据文档及各种搜索引擎实现
本次实现的完整Pipeline脚本
#第一步.先定义要去哪台服务器上执行停止脚本
def remote = [:]
remote.name = 'test' #起个名字
remote.host = '192.168.0.104' #服务器ip
remote.user = 'root'
remote.password = '123'
remote.allowAnyHosts = true
pipeline {
agent any
stages {
stage('拉取代码' ) {
steps {
checkout([$class: 'GitSCM', branches: [[name: '*/${branch}']], extensions: [], userRemoteConfigs: [[credentialsId: 'ff8ba3ca-be5f-4535-bb37-08de5ef208f9', url: 'https://gitee.com/RollBack2010/jekins-study.git']]])
}
}
stage('编译代码 ') {
steps {
sh 'mvn clean package'
}
}
#第二步.添加一个管道
stage('停止服务 ') {
steps {
#执行对应服务器上的一个脚本
sshCommand remote: remote, command: "bash /usr/local/project/stop.sh"
}
}
stage('发布运行 ') {
steps {
sshPublisher(publishers: [sshPublisherDesc(configName: 'jarPath', transfers: [sshTransfer(cleanRemote: false, excludes: '', execCommand: '''cd /usr/local/project
./start.sh''', execTimeout: 120000, flatten: false, makeEmptyDirs: false, noDefaultExcludes: false, patternSeparator: '[, ]+', remoteDirectory: '', remoteDirectorySDF: false, removePrefix: 'target/', sourceFiles: 'target/demo-0.0.1-SNAPSHOT.jar')], usePromotionTimestamp: false, useWorkspaceInPromotion: false, verbose: false)])
}
}
}
}
stop.sh脚本内容
#!/bin/sh -l
#在jenkins "Execute shell"中先刷新环境变量,否则会报各种找不到命令
source /etc/profile
#定义一个全局变量,用于存放服务的进程
processNum
#定义个函数,用于获得进程,并将进程赋值给上面定义的变量
#这个函数逻辑为:
# 1.通过jps -l命令,获得所有运行的java进程
# 2.通过awk命令,查询jar包叫 “project-0.0.1-SNAPSHOT.jar”的(此处可改成各种正则条件匹配)
# 3.通过cut命令,根据“ ”切分awk匹配出来的记录,然后获得进程
function checkProcessNum()
{
processNum=$(jps -l | awk -F " " '/demo-0.0.1-SNAPSHOT.jar/' | cut -d " " -f 1)
}
#调用一下函数,获得进程
checkProcessNum
echo "当前运行进程号为:"$processNum"执行kill命令"
#执行kill命令,当然,这块应该再加个if判断进程是否存在更好
kill $processNum
echo "kill命令已执行,循环检查是否正常停止"
#isDown:0:服务未停 1:服务已停
isDown=0
#循环检查是否停止,因为可能有线程还未执行完,无法停止
while [ $isDown -eq 0 ]
do
echo "每隔1秒查询下项目端口是否存在,存在说明还没停止"
sleep 1s
#每等待1秒调用函数查询进程是否存在
checkProcessNum
if [ ! $processNum ]
then
#进程终止了,停止循环
echo "服务停止了"
isDown=1
elif [ $processNum ]
then
echo "服务还在运行中"
fi
done
echo "服务已停止"