基于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)进入流水线配置页,填入身份验证令牌
远程构建即使配置了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中报告推送阶段。
至此,开发提交代码后,将自动触发构建过程,构建结束后发送此次构建邮件报告如下: