基于Docker+Jenkins+Git的CI/CD实战
与上一篇随笔:基于 Jenkins+Docker+Git 的CI流程初探 有所不同,该内容更偏向于实际业务的基础需求。
有几点需要注意:
- 该实战中没有涉及到镜像仓库,所以略去了镜像推送阶段,可以参考基于 Jenkins+Docker+Git 的CI流程初探。
- 与上一篇对比,该实战是基于外网服务器进行的,所以加入了Jenkins自动触发拉取代码以及发送构建报告功能。
- 实战中的Jenkins也是基于docker运行,对于Jenkins数据持久化是通过VOLUME实现的。
- 不再进行自建git代码仓库,选择使用Gitee管理代码。
- 实验环境均已提前准备完毕。
1、Jenkins启动
docker run \ -u root \ -d \ -p 8080:8080 \ -p 50000:50000 \ -v jenkins-data:/var/jenkins_home \ -v /etc/localtime:/etc/localtime:ro \ -v /var/run/docker.sock:/var/run/docker.sock \ --restart=always \ jenkinsci/blueocean
启动后设置用户与密码
2、新建item
名称:java-devops-demo
创建流水线
选择保存
Jenkins流水线工作流程:
先定义一个流水线项目,指定项目的git位置
流水线启动
a.先去git位置自动拉取代码
b.解析拉取代码里面的Jenkinsfile文件
c.按照Jenkinsfile指定的流水线开始加工项目
Jenkins重要的点
1) jenkins的家目录 /var/jenkins_home 已经被我们docker外部挂载了/var/lib/docker/volumes/jenkins-data/_data
2)WORKSPACE(工作空间)=/var/jenkins_home/workspace/java-devops-demo每一个流水线项目,占用一个文件夹位置
3)BUILD_NUMBER=5;当前第几次构建
4)WORKSPACE_TMP(临时目录)=/var/jenkins_home/workspace/java-devops-demo@tmp
3、定义Jenkinsfile与Dockerfile具体内容
Jenkinsfile部分是逐步测试,按阶段写成。
pipeline{ //全部的CI/CD流程都需要在这里定义 //任何一个代理可用就可以执行 agent any //定义一些环境信息 environment { WS = "${WORKSPACE}" } //定义流水线的加工流程 stages{ stage('环境检查'){ steps { sh 'printenv' echo "正在检测基本信息" sh 'java -version' sh 'git --version' sh 'docker version' sh 'pwd && ls -alh' } } //1、编译 "abc" stage('maven编译'){ agent { docker { image 'maven:3-alpine' args '-v /var/jenkins_home/appconfig/maven/.m2:/root/.m2' //docker run -v /var/jenkins_home/appconfig/maven/.m2:/root/.m2 } } //要做的所有事情 //jenkins不配置任何环境的情况下, 仅适用docker兼容所有场景 steps{ echo "编译..." sh 'pwd && ls -alh' sh 'cd ${WS} && mvn clean package -s "/var/jenkins_home/appconfig/maven/settings.xml" -Dmaven.test.skip=true' } } //2、打包 stage('生成镜像'){ steps{ sh 'pwd && ls -alh' sh 'docker version' sh 'docker build -t java-devops-demo .' } } //3、部署 stage('部署'){ steps{ echo "部署..." sh 'docker rm -f java-devops-demo-dev' sh 'docker run -d -p 80:8080 --name java-devops-demo-dev java-devops-demo' } } //4、推送报告 stage("发送报告"){ steps { //短信通知,购买api接口即可 // sh 'curl -i -k -X POST 'https://gyytz.market.alicloudapi.com/sms/smsSend?mobile=mobile¶m=**code**%3A12345%2C**minute**%3A5&smsSignId=2e65b1bb3d054466b82f0c9d125465e2&templateId=908e94ccf08b4476ba6c876d13f084ad' -H 'Authorization:APPCODE dddddddd'' //REST API 所有都行 // sh 'curl ' echo '准备发送报告' emailext body: '''<!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"> <h3>本邮件由系统自动发出,请勿回复!</h3> <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> <ul> <hr size="2" width="100%" /> ${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>''', subject: '${ENV, var="JOB_NAME"}-第${BUILD_NUMBER}次构建日志', to: 'xxxxx@163.com' } } } //后置处理过程 post { failure { echo "这个阶段 完蛋了.... $currentBuild.result" } success { echo "这个阶段 成了.... $currentBuild.result" } } }
Dockerfile:
#这个也得有 FROM openjdk:8-jre-alpine LABEL maintainer="xxxxxxx@qq.com" #复制打好的jar包 COPY target/*.jar /app.jar RUN apk add -U tzdata; \ ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime; \ echo 'Asia/Shanghai' >/etc/timezone; \ touch /app.jar; ENV JAVA_OPTS="" ENV PARAMS="" EXPOSE 8080 ENTRYPOINT [ "sh", "-c", "java -Djava.security.egd=file:/dev/./urandom $JAVA_OPTS -jar /app.jar $PARAMS" ]
Jenkinsfile与Dockerfile均位于java-devops-jemo目录下,由Jenkins从git仓库拉取。
4、远程构建触发
期望效果: 远程的github代码提交了,jenkins流水线自动触发构建。
实现条件:
- 保证jenkins所在主机能被远程访问。
- jenkins中远程触发需要权限,我们应该使用用户进行授权。
- 配置gitee,webhook进行触发。
实现过程:
1)进入流水线配置页,填入身份验证令牌
2)远程构建即使配置了gitee/github 的webhook,默认会403。我们应该使用用户进行授权
a.创建一个用户 (主界面>管理Jenkins>管理user>新建用户)
b.新建用户后一定要重新登陆激活一次,进入用户列表>点击当前用户名>设置
c.生成一个apitoken (生成后立即复制,只出现一次)
3)码云端配置WebHooks,进入码云对应代码仓库-配置-WebHooks-添加WebHook
URL配置格式:http://dk:用户dk的apitoken@主机的公网ip:8080/job/java-devops-demo/build?token=身份验证令牌
添加成功后可测试与Jenkins主机的连通性。
至此,当本地修改代码,git push提交到gitee/github后,Jenkins就能够自动构建,构建成功即可查看前端页面的变化。
5、配置maven环境
(使用自定义agent的方式引入maven环境,利用多阶段构建不同场景下的复杂环境)
1)安装docker pipeline插件
2)自定义agent(在stages内部)
3)配置maven加速(配置国内阿里云)
把Maven的配置文件放在jenkins-data里面的某个位置。默认所有的可变配置项都推荐放在jenkins-home的位置,增强移植性。
4)缓存必要jar包,下次构建无需下载
agent { docker { image 'maven:3-alpine' //用完就会杀掉 args '-v /var/jenkins_home/appconfig/maven/.m2:/root/.m2' // 将jar包映射到宿主机上/var/jenkins_home/appconfig/maven/.m2目录中 // 也可以将jar包以数据卷方式挂载到宿主机 } }注:jenkins不配置任何环境的情况下, 仅适用docker兼容所有场景。
- 临时容器导致的问题(每个stage都会回到默认workspace,临时容器产生的打包数据不能被利用)
- 第一次检出代码,默认在 /var/jenkins_home/workspace/【java-devops-demo】
- 使用docker临时agent的时候,每一个临时容器运行又分配临时目录 /var/jenkins_home/workspace/java-devops-demo@2;默认就是workspace/java-devops-demo 的内容
- 在临时容器里面 运行的mvn package命令,会在 /var/jenkins_home/workspace/java-devops-demo@2 进行工作
- package到了 /var/jenkins_home/workspace/java-devops-demo@2 位置
- 进入下一步(stage)进行打包镜像,又会回到 /var/jenkins_home/workspace/【java-devops-demo】(默认workspace)这个位置
- 这个位置没有运行过 mvn clean package ,所以没有target。 默认的 工作目录 没有 target
解决方法:在临时容器内部切换到Jenkins的默认工作目录,再进行maven打包。
6、邮件推送
使用邮件扩展插件:Email Extension Plugin-2.71 (对于每个stage执行的任务成功与否可以通过后置执行post来进行感知)
系统管理>系统配置>配置管理员邮箱(系统管理员邮件地址)、SMTP服务相关及其他
下图Use SMTP Authentication部分在高版本插件中已不再支持
填写完毕,可以通过发送测试邮件进行测试。
上图的邮件用户的授权码需要配置邮件发送的认证权限信息
- 登录自己邮箱,开启POP3/SMTP邮件服务
- 获取到自己的授权码(tlqhksolsmeodjad)
- 配置并测试好邮件发送即可
邮件模板内容见Jenkinsfile中报告推送阶段。
至此,开发提交代码后,将自动触发构建过程,构建结束后发送此次构建邮件报告如下: