目录
- 一、简介
- 二、Groovy
- 2.1 HelloWorld
- 2.2 Pipeline script from SCM
- 三、Jenkinsfile
- 3.1 拉取代码
- 3.2 代码质量检测
- 3.3 构建代码
- 3.4 制作镜像并发布镜像仓库
- 3.5 部署到目标服务器
- 3.6 完整的Jenkinsfile
- 3.7 参数配置
- 3.8 通过参数构建
- 四、添加邮件通知
- 4.1 配置Jenkins邮件配置
- 4.2 生成Pipeline语法
- 4.3 邮件发送内容
- 完整Jenkinsfile文件
一、简介
从零开始带你实现一套自己的CI/CD(一)Jenkins
从零开始带你实现一套自己的CI/CD(二)Jenkins+Sonar Qube
从零开始带你实现一套自己的CI/CD(三)Jenkins+Harbor
通过前面的文章,我们已经实现了Jenkins 自由风格部署项目,每个步骤流程都要通过不同的方式设置,并且构建过程中整体流程是不可见的,无法确认每个流程花费的时间,并且问题不方便定位问题。
Jenkins的Pipeline
可以让项目的发布整体流程可视化,明确执行的阶段,可以快速的定位问题。并且整个项目的生命周期可以通过一个Jenkinsfile文件管理,而且Jenkinsfile
文件是可以放在项目中维护。
所以Pipeline相对自由风格或者其他的项目风格更容易操作。
下面我们就来介绍一下使用Jenkins Pipeline构建项目。
二、Groovy
2.1 HelloWorld
使用Jenkins Pipeline部署项目,需要编写Jenkinsfile文件,Jenkinsfile文件使用groovy语言进行编写的。
下面是groovy编写的HelloWorld程序:
pipeline {
agent any
stages {
stage('Hello') {
steps {
echo 'Hello World'
}
}
}
}
点击应用 保存,返回项目点击立即构建。
2.2 Pipeline script from SCM
但是我们并不在Jenkins这里编写脚本,而是把Jenkinsfile文件放在项目里,Jenkins从Git仓库拉去代码执行Jenkinsfile文件中的脚本。
需要将Jenkins流水线定义为Pipeline script from SCM
,输入Git仓库的地址。
在项目中新建一个Jenkinsfile
文件:
pipeline {
agent any
stages {
stage('拉取Git代码') {
steps {
echo '拉取Git代码'
}
}
stage('检测代码质量') {
steps {
echo '检测代码质量'
}
}
stage('构建代码') {
steps {
echo '构建代码'
}
}
stage('制作自定义镜像并发布Harbor') {
steps {
echo '制作自定义镜像并发布Harbor'
}
}
stage('基于Harbor部署工程') {
steps {
echo '基于Harbor部署工程'
}
}
}
}
然后通过Jenkins进行构建,可以看到每个步骤构建的过程。
三、Jenkinsfile
上面的脚本只是输出了日志,现在我们将一一实现上面的每个步骤。
Jenkins为我们提供了生成Groovy脚本的方法。
3.1 拉取代码
进入流水线语法,选择checkout
,填入Git地址,点击生成流水线语法
即可。
checkout([$class: 'GitSCM', branches: [[name: '*/master']], extensions: [], userRemoteConfigs: [[url: 'https://gitee.com/L1692312138/jenkins-demo.git']]])
我们将这个脚本直接粘贴到上面拉取Git代码的地方。
3.2 代码质量检测
执行脚本进行Sonar代码质量检测
/var/jenkins_home/sonar-scanner/bin/sonar-scanner -Dsonar.sources=./ -Dsonar.projectname=${JOB_NAME} - Dsonar.projectKey=${JOB_NAME} -Dsonar.java.binaries=target/ -Dsonar.login=31388be45653876c1f51ec02f0d478e2d9d0e1fa
Sonar可以在此处生成Token:
sh '/var/jenkins_home/sonar-scanner/bin/sonar-scanner -Dsonar.sources=./ -Dsonar.projectname=${JOB_NAME} -Dsonar.projectKey=${JOB_NAME} -Dsonar.java.binaries=target/ -Dsonar.login=7d66af4b39cfe4f52ac0a915d4c9d5c513207098'
3.3 构建代码
执行shell脚本进行Mavne打包(注意:Jenkins安装Mavne的位置)
/var/jenkins_home/apache-maven-3.8.6/bin/mvn clean package -DskipTests
sh '/var/jenkins_home/apache-maven-3.8.6/bin/mvn clean package -DskipTests'
3.4 制作镜像并发布镜像仓库
cp ./target/*.jar ./deploy/
cd ./deploy
docker build -t ${JOB_NAME}:${tag} .
docker login -u ${harborUser} -p ${harborPasswd} ${harborHost}
docker tag ${JOB_NAME}:${tag} ${harborHost}/${harborRepo}/${JOB_NAME}:${tag}
docker push ${harborHost}/${harborRepo}/${JOB_NAME}:${tag}
sh '''cp ./target/*.jar ./deploy/
cd ./deploy
docker build -t ${JOB_NAME}:${tag} .'''
sh '''docker login -u ${harborUser} -p ${harborPasswd} ${harborHost}
docker tag ${JOB_NAME}:${tag} ${harborHost}/${harborRepo}/${JOB_NAME}:${tag}
docker push ${harborHost}/${harborRepo}/${JOB_NAME}:${tag}'''
3.5 部署到目标服务器
连接到目标服务器,执行目标服务器准备好的deploy.sh脚本
deploy.sh $harbor_url $harbor_project_name $JOB_NAME $tag $container_port $host_port
sshPublisher(publishers: [sshPublisherDesc(configName: '131', transfers: [sshTransfer(cleanRemote: false, excludes: '', execCommand: 'deploy.sh $harbor_url $harbor_project_name $JOB_NAME $tag $container_port $host_port', execTimeout: 120000, flatten: false, makeEmptyDirs: false, noDefaultExcludes: false, patternSeparator: '[, ]+', remoteDirectory: '', remoteDirectorySDF: false, removePrefix: '', sourceFiles: '')], usePromotionTimestamp: false, useWorkspaceInPromotion: false, verbose: false)])
注意:在之前的文章中已经准备了deploy.sh
脚本和配置了目标服务器
。
3.6 完整的Jenkinsfile
pipeline {
agent any
environment{
harborHost = '192.168.153.131:80'
harborRepo = 'helloworld'
harborUser = 'admin'
harborPasswd = 'Harbor12345'
}
// 存放所有任务的合集
stages {
stage('Pull Code') {
steps {
checkout([$class: 'GitSCM', branches: [[name: '${tag}']], extensions: [], userRemoteConfigs: [[url: 'https://gitee.com/L1692312138/jenkins-demo.git']]])
}
}
// stage('Sonar Scan') {
// steps {
// sh '/var/jenkins_home/sonar-scanner/bin/sonar-scanner -Dsonar.sources=./ -Dsonar.projectname=${JOB_NAME} -Dsonar.projectKey=${JOB_NAME} -Dsonar.java.binaries=target/ -Dsonar.login=7d66af4b39cfe4f52ac0a915d4c9d5c513207098'
// }
// }
stage('Maven Build') {
steps {
sh '/var/jenkins_home/apache-maven-3.8.6/bin/mvn clean package -DskipTests'
}
}
stage('Push Harbor') {
steps {
sh '''cp ./target/*.jar ./deploy/
cd ./deploy
docker build -t ${JOB_NAME}:${tag} .'''
sh '''docker login -u ${harborUser} -p ${harborPasswd} ${harborHost}
docker tag ${JOB_NAME}:${tag} ${harborHost}/${harborRepo}/${JOB_NAME}:${tag}
docker push ${harborHost}/${harborRepo}/${JOB_NAME}:${tag}'''
}
}
stage('Publish Over SSH') {
steps {
sshPublisher(publishers: [sshPublisherDesc(configName: '131', transfers: [sshTransfer(cleanRemote: false, excludes: '', execCommand: "deploy.sh $harborHost $harborRepo $JOB_NAME $tag $container_port $host_port", execTimeout: 120000, flatten: false, makeEmptyDirs: false, noDefaultExcludes: false, patternSeparator: '[, ]+', remoteDirectory: '', remoteDirectorySDF: false, removePrefix: '', sourceFiles: '')], usePromotionTimestamp: false, useWorkspaceInPromotion: false, verbose: false)])
}
}
}
}
因为博主的机器是arm64架构,sonar-scanner不支持这个架构,所以注释了。
3.7 参数配置
在Jenkinsfile中使用了$符号取值,我们需要配置这些变量。
- Git 参数 tag
- 字符参数 container_port
- 字符参数 host_port
3.8 通过参数构建
可以看到构建成功了
去Harbor也可以看到镜像已经上传
目标服务器容器也已经运行了
Jenkins Pipeline构建成功!
四、添加邮件通知
在项目构建成功后,发送邮件通知构建结果
4.1 配置Jenkins邮件配置
下载Jenkins插件 Email Extension Plugin
进入QQ邮箱设置:
开启POP3/SMTP服务
邮箱 | POP3服务器(端口995) | SMTP服务器(端口465或587) |
---|---|---|
qq.com | pop.qq.com | smtp.qq.com |
生成授权码
在Jenkins设置中配置 系统管理员邮件地址
在Jenkins设置中配置邮件通知
点击 Test Configuration 测试配置是否成功
4.2 生成Pipeline语法
post {
always {
emailext body: '${FILE,path="email.html"}', subject: '【构建通知】:$PROJECT_NAME - Build # $BUILD_NUMBER - $BUILD_STATUS!', to: 'xxxx@qq.com'
}
}
4.3 邮件发送内容
在项目中新建email.html
文件:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>${ENV, var="JOB_NAME"}-第${BUILD_NUMBER}次构建日志</title>
</head>
<body leftmargin="8" marginwidth="0" topmargin="8" marginheight="4"
offset="0">
<table width="95%" cellpadding="0" cellspacing="0" style="font-size: 11pt; font-family: Tahoma, Arial, Helvetica, sans-serif">
<tr>
本邮件由系统自动发出,无需回复!<br/>
各位同事,大家好,以下为${PROJECT_NAME }项目构建信息</br>
<td><font color="#CC0000">构建结果 - ${BUILD_STATUS}</font></td>
</tr>
<tr>
<td><br />
<b><font color="#0B610B">构建信息</font></b>
<hr size="2" width="100%" align="center" /></td>
</tr>
<tr>
<td>
<ul>
<li>项目名称 : ${PROJECT_NAME}</li>
<li>构建编号 : 第${BUILD_NUMBER}次构建</li>
<li>触发原因: ${CAUSE}</li>
<li>构建状态: ${BUILD_STATUS}</li>
<li>构建日志: <a href="${BUILD_URL}console">${BUILD_URL}console</a></li>
<li>构建 Url : <a href="${BUILD_URL}">${BUILD_URL}</a></li>
<li>工作目录 : <a href="${PROJECT_URL}ws">${PROJECT_URL}ws</a></li>
<li>项目 Url : <a href="${PROJECT_URL}">${PROJECT_URL}</a></li>
</ul>
<h4><font color="#0B610B">失败用例</font></h4>
<hr size="2" width="100%" />
$FAILED_TESTS<br/>
<h4><font color="#0B610B">最近提交</font></h4>
<hr size="2" width="100%" />
<ul>
${CHANGES_SINCE_LAST_SUCCESS, reverse=true, format="%c", changesFormat="<li>%d [%a] %m</li>"}
</ul>
详细提交: <a href="${PROJECT_URL}changes">${PROJECT_URL}changes</a><br/>
</td>
</tr>
</table>
</body>
</html>
完整Jenkinsfile文件
pipeline {
agent any
environment{
harborHost = '192.168.153.131:80'
harborRepo = 'helloworld'
harborUser = 'admin'
harborPasswd = 'Harbor12345'
}
// 存放所有任务的合集
stages {
stage('Pull Code') {
steps {
checkout([$class: 'GitSCM', branches: [[name: '${tag}']], extensions: [], userRemoteConfigs: [[url: 'https://gitee.com/L1692312138/jenkins-demo.git']]])
}
}
// stage('Sonar Scan') {
// steps {
// sh '/var/jenkins_home/sonar-scanner/bin/sonar-scanner -Dsonar.sources=./ -Dsonar.projectname=${JOB_NAME} -Dsonar.projectKey=${JOB_NAME} -Dsonar.java.binaries=target/ -Dsonar.login=7d66af4b39cfe4f52ac0a915d4c9d5c513207098'
// }
// }
stage('Maven Build') {
steps {
sh '/var/jenkins_home/apache-maven-3.8.6/bin/mvn clean package -DskipTests'
}
}
stage('Push Harbor') {
steps {
sh '''cp ./target/*.jar ./deploy/
cd ./deploy
docker build -t ${JOB_NAME}:${tag} .'''
sh '''docker login -u ${harborUser} -p ${harborPasswd} ${harborHost}
docker tag ${JOB_NAME}:${tag} ${harborHost}/${harborRepo}/${JOB_NAME}:${tag}
docker push ${harborHost}/${harborRepo}/${JOB_NAME}:${tag}'''
}
}
stage('Publish Over SSH') {
steps {
sshPublisher(publishers: [sshPublisherDesc(configName: '131', transfers: [sshTransfer(cleanRemote: false, excludes: '', execCommand: "deploy.sh $harborHost $harborRepo $JOB_NAME $tag $container_port $host_port", execTimeout: 120000, flatten: false, makeEmptyDirs: false, noDefaultExcludes: false, patternSeparator: '[, ]+', remoteDirectory: '', remoteDirectorySDF: false, removePrefix: '', sourceFiles: '')], usePromotionTimestamp: false, useWorkspaceInPromotion: false, verbose: false)])
}
}
}
post {
always {
emailext body: '${FILE,path="email.html"}', subject: '【构建通知】:$PROJECT_NAME - Build # $BUILD_NUMBER - $BUILD_STATUS!', to: 'liush99@foxmail.com'
}
}
}