devops学习笔记-jenkins pipeline流水线发布

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了devops学习笔记-jenkins pipeline流水线发布相关的知识,希望对你有一定的参考价值。

jenkins pipeline

介绍

要实现CD,先要实现CI。CD Pipeline就是一个代码文件,里面把你项目业务场景都通过Groovy代码和Pipeline语法实现,一个一个业务串联起来,全部实现自动化,从代码仓库到生产环境完成部署的自动化流水线。这个过程就是一个典型的CD Pipeline。官网建议我们把Pipeline代码放在一个名称为Jenkinsfile的文本文件中,并且把这个文件放在项目代码的根目录,采用版本管理工具管理。

一个Jenkinsfile或者一个Pipeline代码文件,我们可以使用两个脚本模式去写代码,这两种分类叫:Declarative Pipeline 和 Scripted Pipeline.

​Declarative相对于Scripted有两个优点。

1)、第一个是提供更丰富的语法功能;

2)、第二个是写出来的脚本可读性和维护性更好;​

jenkins是一个非常著名的CI服务器平台,支持很多不同第三方(插件的形式)集成自动化测试。Jenkins UI 配置已经满足不了这么复杂的自动化需求,加入Pipeline功能之后,Jenkins 表现更强大。

​Pipeline主要有一下特点

  • Code代码:Pipeline是用代码去实现,并且支持check in到代码仓库,这样项目团队人员就可以修改,更新Pipeline脚本代码,支持代码迭代。
  • Durable耐用:Pipeline支持在Jenkins master(主节点)上计划之内或计划外的重启下也能使用。
  • Pausable可暂停:Pipeline支持可选的停止和恢复或者等待批准之后再跑Pipeline代码。
  • Versatile丰富功能:Pipeline支持复杂和实时的CD需求,包括循环,拉取代码,和并行执行的能力。
  • Extensible可扩展性:Pipeline支持DSL的自定义插件扩展和支持和其他插件的集成。

jenkins pipline流程图

devops学习笔记-jenkins

​第1步.开发(IDE)提交代码到项目仓库服务器(gitlab);

第2步.jenkins开始执行Pipeline代码文件,开始从(gitlab)仓库git clone代码;

第3步.jenkins启动Pipeline里面第一个stage(阶段);

第4步.图里面第一个Stage从仓库检出(Checkout)代码;

第5步.接着进入第二Stage构建(Build)检出的代码;

第6步.然后进入测试(Test)的阶段,执行各种自动化测试验证;

第7步.然后测试结束,到运维的部署(Deploy)阶段;

第8步.部署结束,输出报告,整个自动化流程工作完成;

等待触发构建,开始重复下一轮1到8步骤。

jenkins pipline概念

  • 流水线pipline

流水线是用户定义的一个CD流水线模型 。流水线的代码定义了整个的构建过程, 他通常包括构建, 测试和交付应用程序的阶段 。

  • 节点(node)

节点是一个机器,它是jenkins环境的一部分。

  • 阶段(stage)

stage 块定义了在整个流水线的执行任务的概念性地不同的的子集(比如 "Build", "Test" 和 "Deploy" 阶段), 它被许多插件用于可视化 或Jenkins流水线目前的 状态/进展.

  • 步骤(step)

step为一个单一任务,它告诉jenkins在待定的时间点要做什么

pipline流水线语句说明

在声明式流水线语法中, pipeline 块定义了整个流水线中完成的所有的工作。

Jenkinsfile (Declarative Pipeline)
pipeline
agent any //在任何可用的代理上,执行流水线或者它的任何阶段
stages
stage(Build) //定义Build阶段
steps
// 执行Build阶段的相关步骤


stage(Test) //定义Test阶段
steps
// 执行Test阶段的相关步骤


stage(Deploy) //定义Deploy阶段
steps
// 执行deploy阶段的相关步骤




关于流水线的具体语法,参考官方手册​​https://www.jenkins.io/zh/doc/book/pipeline/syntax/​

jenkins上使用pipeline

在我之前的jenkins上,使用pipeline方式重新建立一个ITEM。

流程如下:

devops学习笔记-jenkins

1 拉取gitlab仓库代码

2 通过mvn构建项目

3 通过sonarqube做代码质量检测,本次实验暂时不涉及。

4 通过docker制作自定义镜像

5 将自定义镜像推送到harbor仓库,此时需要编写一个脚本,来判断镜像容器是否存在

准备jenkinsfile

在gitlab上,新增一个Jenkinsfile,注意大小写,不然jenkins识别不到。也可以通过IDE的VCS版本控制将编写好的Jenkinsfile推送到gitlab中。

devops学习笔记-jenkins


devops学习笔记-jenkins

Jenkinsfile准备好的文件内容如下,当前指明步骤,没有填充步骤的详细内容。pipline脚本的语法基本上跟groovy一致。

//所有的脚本命令都放在pipeline中
pipeline
//指定任务在哪个集群节点中执行
agent any

//申明全局变量,后期使用
environment
key =value

stages
stage(拉取git仓库代码)
steps
echo 拉取git仓库代码-SUCCESS


stage(通过maven构建项目)
steps
echo 通过maven构建项目-SUCCESS


stage(通过SonarQube做代码质量检测)
steps
echo 通过SonarQube做代码质量检测-SUCCESS


stage(通过docker制作自定义镜像)
steps
echo 通过docker制作自定义镜像-SUCCESS


stage(将自定义镜像推送到Harbor)
steps
echo 将自定义镜像推送到Harbor-SUCCESS


stage(通过Publish Over SSH 通知目标服务器)
steps
echo 通过Publish Over SSH 通知目标服务器-SUCCESS




完成简单Jenkinsfile编写后,在gitlab上保存即可。

jenkins上新建pipeline

在jenkins上新建一个ITEM,名称为mytest3。

devops学习笔记-jenkins

job类型选择Pipeline

devops学习笔记-jenkins

配置参数

勾选"This project is parameterized",添加git参数,如下所示:

devops学习笔记-jenkins

名称为tag,这个参数将作为jenkins的全局参数使用。参数类型为表标签,代表从gitlab使用不同的标签拉取代码。默认值为origin/master,代表默认从gitlab的master分支拉取代码。

配置流水线

找到pipeline选项卡,按照如下填写:

devops学习笔记-jenkins

说明:

1.推荐使用 Pipeline script from SCM,代表从gitlab上读取jenkinsfile;

2.需要填写正确的gitlab仓库地址和账号密码,同时要确保gitlab上仓库中的根目录要存在Jenkinsfile

3.指定在gitlab仓库中jenkinsfile的目录路径和文件名称。

点击应用保存,完成流水线配置。

测试流水线

因为的我们的jenkinsfile中虽然写明了构建步骤,但是没有写构建步骤的内容与动作,我们可以先测试下目前流水线是否能够正常构建。

devops学习笔记-jenkins

构建完成后,我们等清楚的看到每个流水线步骤执行结果,花费时间等,看能看到每个步骤的日志。

devops学习笔记-jenkins

注意,流水线步骤是串行顺序执行,如果前一个步骤执行报错失败,那么后面的步骤将不会执行。

配置流水线步骤

完成流水线的基本结构的jenkinsfile编写和测试后,需要按照之前的构建步骤填写jenkinsfile中步骤。

由于我们的执行步骤都是在jenkins上或者目标服务器上执行脚本或者使用插件动作,所以我们需要使用jenkins的流水线语法工具,将我们定义的步骤转换为jenkins的流水线步骤语法。

devops学习笔记-jenkins

devops学习笔记-jenkins

定义全局变量

使用environment定义全局变量,这些变量可以给后面的pipeline脚本的调用。

    //申明全局变量,后期使用
environment
user_name=user //harbor仓库用户名
harbor_password=Harbor12345 //harbor仓库密码
harbor_addr=192.168.85.3:8090 //harbor仓库地址
harbor_repo=test // harbor仓库名称
container_port=8080 //容器暴露端口
host_port=8092 //宿主机暴露端口

拉取git代码

在示例步骤中选择"checkout:Check out from version control",表示jenkins从gitlab拉取代码。

devops学习笔记-jenkins

填写完成后,点击生成流水线脚本。将生成的流水线脚本,添加补充到我们的jenkinsfile对应的步骤中。

stage(拉取git仓库代码) 
steps
checkout([$class: GitSCM, branches: [[name: $tag]], extensions: [], userRemoteConfigs: [[credentialsId: fc7dffd0-2911-45da-ba46-7a9f7e00a41a, url: http://192.168.85.6/root/mytest.git]]]) //此处为流水线脚本生成
echo 拉取git仓库代码-SUCCESS


通过maven构建项目

同样使用流水线语法生成脚本,不过这次使用”sh:Shell Script"方式,表示在jenkins上使用maven构建打包并生成的jar包。

/usr/local/apache-maven-3.8.6/bin/mvn clean package -DskipTest #mvn打包命令

devops学习笔记-jenkins

将生成的流水线语法添加到jenkinsfile中。

stage(通过maven构建项目) 
steps
sh /usr/local/apache-maven-3.8.6/bin/mvn clean package -DskipTest
echo 通过maven构建项目-SUCCESS

通过SonarQube代码检测

本次流水线配置不涉及此处(我没想好。。。。)

通过docker制作自定义镜像

在jenkins上,将maven构建jar包移动到docker目录下,然后使用docker命令构建镜像。

mv target/*.jar ./docker/   #将jenkins中target目录生成的jar包移动到当前docker目录下
docker build -t $JOB_NAME:$tag ./docker/ #docker构建镜像,$JOB_NAME为jenkins
#全局变量,本次为mytest3
# $tag为jenkins自定义git参数,读取gitlab
#仓库中的tag

使用流水线语法生成脚本

devops学习笔记-jenkins

将生成的流水线脚本添加到jenkinsfile中

    stage(通过docker制作自定义镜像) 
steps
sh mv target/*.jar ./docker/
docker build -t $JOB_NAME:$tag ./docker/
echo 通过docker制作自定义镜像-SUCCESS


将自定义镜像推送的到Harbor

采用shell脚本的方式,登录harbor仓库,本地打上镜像标签,将制作的docker镜像推送到harbor仓库

docker login -u $user_name -p $harbor_password $harbor_addr   #变量为前面enivronment定义的全局变量
docker tag $JOB_NAME:$tag $harbor_addr/$harbor_repo/$JOB_NAME:$tag #$JOB_NAME为jenkins内置的全局变量
docker push $harbor_addr/$harbor_repo/$JOB_NAME:$tag #$tag为自定义git参数的变量

使用流水线语法生成脚本

devops学习笔记-jenkins

将生成的脚本添加到 jenkinsfile中。

    stage(将自定义镜像推送到Harbor) 
steps
sh docker login -u $user_name -p $harbor_password $harbor_addr
docker tag $JOB_NAME:$tag $harbor_addr/$harbor_repo/$JOB_NAME:$tag
docker push $harbor_addr/$harbor_repo/$JOB_NAME:$tag
echo 将自定义镜像推送到Harbor-SUCCESS



通过publish over ssh通知目标服务器

需要通过jenkins的publish over ssh插件,通知目标服务器从harbor行拉取镜像运行容器。拉取镜像和运行容器,要满足以下逻辑:

  • 告知目标服务器拉取哪个镜像
  • 判断当前服务器是否正在运行容器,有的话需要删除
  • 如果目标服务器已经存在当前镜像,有的话需要删除
  • 目标服务器拉取harbor上的镜像
  • 将拉取下来的镜像运行成容器

编写shell脚本,并将脚本传输到目标服务器上,由于是实验环境,目标服务器和jenkins其实就是一台机器,所以不用将脚本文件传送。

vim deploy.sh

#!/usr/bin/bash
#script_name:deploy.sh
#部署脚本
#1.告知目标服务器拉取哪个镜像
#2.判断当前服务器是否正在运行容器,需要删除
#3.如果目标服务器已经存在当前镜像,需要删除
#4.目标服务器拉取harbor上的镜像
#5.将拉取下来的惊醒运行成容器
#定义部署信息参数

harbor_addr=$1
harbor_repo=$2
project=$3
version=$4
host_port=$5
container_port=$6

#测试部署的信息
ImageName=$harbor_addr/$harbor_repo/$project:$version
echo $ImageName

#判断当前服务器上是否存在docker镜像,存在则停止并删除容器
ContainerId=$(docker ps -a | grep $project | awk print $1)
echo $ContainerId
ImageId=$(docker images | grep $harbor_addr/$harbor_repo/$project | awk print $3)

if [ "$ContainerId" != "" ];then
docker stop $ContainerId
docker rm $ContainerId
fi


#Image=$( docker images | grep $harbor_addr/$harbor_repo/$project | awk print $1":"$2)
Tag=$( docker images | grep $project | awk print $2)

echo $Tag

#判断版本,如果存在当前版本,则删除该版本的镜像
if [[ "$Tag" =~ "$version" ]] ;then #判断是否包含版本
docker rmi -f $ImageId #如果存在当前版本,则删除镜像
fi

docker login -u user -p Harbor12345 $harbor_addr #登录harbor仓库
docker pull $ImageName #拉取镜像

#运行镜像
docker run -d -p $host_port:$container_port --name $project $ImageName

echo "SUCESS!!"

在本地测试脚本,保证脚本运行没有问题。

devops学习笔记-jenkins

在流水线语法中,使用”sshPublisher:Send build artifacts over SSH",生成脚本

cd /root/jenkins_shell/ && sh -x deploy.sh $harbor_addr $harbor_repo $JOB_NAME $tag $host_port $container_port #执行脚本,脚本参数使用前面environment定义的全局变量

devops学习笔记-jenkins

以下为生成的脚本:

devops学习笔记-jenkins

注意要将生成的脚本中的符号改为“, 不然脚本无法通过jenkins去执行

sshPublisher(publishers: [sshPublisherDesc(configName: localhost, transfers: [sshTransfer(cleanRemote: false, excludes: , execCommand: ”cd /root/jenkins_shell/ && sh -x deploy.sh $harbor_addr $harbor_repo $JOB_NAME $tag $host_port $container_port“, execTimeout: 120000, flatten: false, makeEmptyDirs: false, noDefaultExcludes: false, patternSeparator: [, ]+, remoteDirectory: , remoteDirectorySDF: false, removePrefix: , sourceFiles: )], usePromotionTimestamp: false, useWorkspaceInPromotion: false, verbose: false)])

将生成的脚本添加到jenkinsfile中。

    stage(通过Publish Over SSH 通知目标服务器) 
steps
sshPublisher(publishers: [sshPublisherDesc(configName: localhost, transfers: [sshTransfer(cleanRemote: false, excludes: , execCommand: "cd /root/jenkins_shell/ && sh -x deploy.sh $harbor_addr $harbor_repo $JOB_NAME $tag $host_port $container_port", execTimeout: 120000, flatten: false, makeEmptyDirs: false, noDefaultExcludes: false, patternSeparator: [, ]+, remoteDirectory: , remoteDirectorySDF: false, removePrefix: , sourceFiles: )], usePromotionTimestamp: false, useWorkspaceInPromotion: false, verbose: false)])
echo 通过Publish Over SSH 通知目标服务器-SUCCESS

最终的jenkinsfile

完成了以上的步骤后,最终的jenkinsfile内容如下:

//所有的脚本命令都放在pipeline中
pipeline
//指定任务在哪个集群节点中执行
agent any

//申明全局变量,后期使用
environment
user_name=user
harbor_password=Harbor12345
harbor_addr=192.168.85.3:8090
harbor_repo=test
container_port=8080
host_port=8092

stages
stage(拉取git仓库代码)
steps
checkout([$class: GitSCM, branches: [[name: $tag]], extensions: [], userRemoteConfigs: [[credentialsId: fc7dffd0-2911-45da-ba46-7a9f7e00a41a, url: http://192.168.85.6/root/mytest.git]]])
echo 拉取git仓库代码-SUCCESS


stage(通过maven构建项目)
steps
sh /usr/local/apache-maven-3.8.6/bin/mvn clean package -DskipTest
echo 通过maven构建项目-SUCCESS


stage(通过SonarQube做代码质量检测)
steps
//不好弄
echo 通过SonarQube做代码质量检测-SUCCESS


stage(通过docker制作自定义镜像)
steps
sh mv target/*.jar ./docker/
docker build -t $JOB_NAME:$tag ./docker/
echo 通过docker制作自定义镜像-SUCCESS


stage(将自定义镜像推送到Harbor)
steps
sh docker login -u $user_name -p $harbor_password $harbor_addr
docker tag $JOB_NAME:$tag $harbor_addr/$harbor_repo/$JOB_NAME:$tag
docker push $harbor_addr/$harbor_repo/$JOB_NAME:$tag
echo 将自定义镜像推送到Harbor-SUCCESS


stage(通过Publish Over SSH 通知目标服务器)
steps
sshPublisher(publishers: [sshPublisherDesc(configName: localhost, transfers: [sshTransfer(cleanRemote: false, excludes: , execCommand: "cd /root/jenkins_shell/ && sh -x deploy.sh $harbor_addr $harbor_repo $JOB_NAME $tag $host_port $container_port", execTimeout: 120000, flatten: false, makeEmptyDirs: false, noDefaultExcludes: false, patternSeparator: [, ]+, remoteDirectory: , remoteDirectorySDF: false, removePrefix: , sourceFiles: )], usePromotionTimestamp: false, useWorkspaceInPromotion: false, verbose: false)])
echo 通过Publish Over SSH 通知目标服务器-SUCCESS





在gitlab上编写jenkinsfile的时候,有时候它会自动换行,添加不必要的换行符\\n,从而导致jenkins读取报错。可以尝试用以下方式避免。

devops学习笔记-jenkins

运行pipeline

完成jenkinsfile的编写后,在jenkins运行构建。如下所示:

devops学习笔记-jenkins

devops学习笔记-jenkins

构建过程

devops学习笔记-jenkins

构建输出日志

devops学习笔记-jenkins

流水线构建成功

devops学习笔记-jenkins

harbor上检查效果

检查harbor上是否完成上传了镜像

devops学习笔记-jenkins

devops学习笔记-jenkins

devops学习笔记-jenkins

确认通过流水线,jenkins生成镜像并上传到harbor

目标服务器上检查效果

devops学习笔记-jenkins

devops学习笔记-jenkins

目标服务器上确认了从docker拉取了镜像,并生成了容器运行。

访问业务

devops学习笔记-jenkins

确认容器业务征程运行。


总结

1 pipeline流水线语法有一定的学习曲线,需要不停参考官方指导才能指导。

2 官方提供了pipeline构建流程参考示例,需要耐心研究。

3 实现生产上jenkins,sonarqube,harbor等最好不要用容器化部署,不太容易与jenkins集成,本次没有配置sonarqube代码检测,也是这个原因


以上是关于devops学习笔记-jenkins pipeline流水线发布的主要内容,如果未能解决你的问题,请参考以下文章

得云社 | DevOps社区 Jenkins Area Meetup

干掉 Jenkins?顶级 DevOps 工具链大盘点

DEVOPS技术实践_18:Jenkins的Pinpeline对于参数的使用

云原生 | Devops篇Jenkins安装与实战

python 学习笔记 - Queue & Pipes,进程间通讯

Ionic2学习笔记:Pipe