基于Springboot以及Gitee的Jenkins自动化部署
本次教程环境准备:
- 主要在centOS的Minimal版本下完成,需要下载vmware以及[镜像文件](链接:https://pan.baidu.com/s/13VoGLwBwHQI8EbdaPxfQbg
提取码:cg8q[)。- ssh工具(本文使用finalShell),官网下载地址:http://www.hostbuf.com/t/988.html
- jdk下载、解压并配置环境变量(本文使用jdk1.8),通过java -version查看版本,官网下载地址:https://www.oracle.com/java/technologies/javase/javase-jdk8-downloads.html
- maven下载、解压并配置环境变量(本文使用maven3.8.2),通过mvn -version查看版本,官网下载地址:https://maven.apache.org/download.cgi
- git下载,yum install -y git
Jenkins安装
Jenkins安装可通过yum、rpm、docker等方式进行安装,本文采用rpm安装,官网下载地址:https://pkg.jenkins.io/redhat/ ,也可通过我的百度云下载地址进行下载:链接:https://pan.baidu.com/s/1GfA_rZg32saGGdXlUTjw4w 提取码:cg8q。完成下载后会得到一个jenkins-2.174-1.1.noarch.rpm文件。
- 创建文件夹放入rpm文件
- 文件安装,通过
rpm -ivh jenkins-2.174-1.1.roarch.rpm
命令安装jenkins。
- 安装完成之后通过
whereis jenkins
查看jenkins安装目录。
- jenkins需要配置jdk路径,进入
/etc/init.d
目录下的jenkins文件去通过vim jenkins
添加jdk路径。
- 进入jenkins安装目录通过
service jenkins start
启动jenkins(也可通过/etc/profile
修改环境变量后直接通过命令启动)
由于上一步修改了文件,若未重载修改文件时启动会出现提示,需再执行以下systemctl daemon-reload重新加载文件即可
- 当出现以上提示则代表jenkins启动成功了,我们可通过ip:端口直接访问(默认端口为8080,需保证当前端口未被占用),本机访问地址为(192.168.159.138:8080)。
- 此时我们需要输入管理员密码,即初始化密码,当前密码存在于
/var/lib/jenkins/secrets/initialAdminPassword
中,输入即可
- 输入之后出现以下界面,不清楚自己需求的情况下直接选择安装推荐的插件,社区推荐的插件也挺丰富的。
- 设置管理员用户的用户名和密码
- 主界面
对于插件下载失败问题
一是被墙了,二是网络问题,三是jenkins版本过低。
解决一:系统管理->插件管理->高级->升级站点URL改为:
-
http://mirror.esuni.jp/jenkins/updates/update-center.json
-
https://mirrors.tuna.tsinghua.edu.cn/jenkins/updates/current/update-center.json(备用)
解决二:升级jenkins版本
在系统管理找到
可选择自动升级,如果无此按钮可通过下载war文件后到指定目录中替换原有文件
通过系统管理->系统信息中查到需替换文件的路径
替换完成之后重启jenkins
- 当前url访问/restart路由,本机为192.168.159.138:8080/restart
- 通过
whereis jenkins
查询jenkins安装目录后,执行命令service jenkins reload
解决三:手动上传安装插件(不推荐,因为太多了,一个一个安装太慢,但最有效)
官网地址:https://plugins.jenkins.io,在搜索框查询需要的插件名称选择版本进行下载后,在jenkins中系统管理->管理插件->高级->上传插件,完成上传即可
Jenkins自动化部署配置
- Jenkins->系统管理->全局工具配置来设置jdk、maven、git的路径,可通过jenkins的Install automatically选择安装版本(本文手动安装了jdk、maven、git,无需通过jenkins自动安装)
- Jenkins->插件管理中下载Maven Integration plugin插件
- 虽然jdk、maven、git路径配置完成,但是jenkins默认会读取的是/usr/bin目录下的命令,如果不配置的话就会造成java、mvn命令找不到的问题
我们可以通过软连接和硬连接的方式来使jenkins能读取命令(当前采用的是软连接方式,具体软连接和硬连接的区别自行上网查看)
ln -s /usr/local/apache-maven-1.3.8/bin/mvn /usr/bin/mvn
ln -s /usr/jdk1.8.0_261/bin/java /usr/bin/java
创建一个Springboot项目
- 定义一个简单的springboot项目,定义一个get请求的api以及存放Pipeline语法文件的位置
- 以下是Pipeline的语法结构
- credentialsId可通过Jenkins设置-> 凭证管理->更新->ID得到
- Jenkinsfile文件通过shell命令执行指定路径下的文件并传递所给的参数,默认jar会存在/var/lib/jenkins/workspace/jenkins-demo/target下,sshpass命令需要通过
yum install sshpass
进行安装
- 上图的stop和start执行sh文件在linux中定义如图,本项目存于/data/app/sh目录下
新建Item
- 采用Pipeline声明式语法构建项目
- 这里我们不做任何其他配置
- 需要自定义Pipeline脚本,可通过流水线语法去完成脚本编辑
- 两种方式在定义Pipleline脚本,一是直接在Jenkins上定义Item的流水线语法,二是通过源代码管理仓库获取流水线,即代码中编写流水线脚本并通过指定路径区访问编写的流水线语法(当前示例采用的是Pipeline script from SCM)
- 选择SCM源(当前示例采用的是Git控制)
- 填写具体信息后点击保存
- 当前即为你新建的Item启动项
-
部署启动成功
-
访问API
可能出现的问题
-
springboot项目的jdk版本和jenkins设置的jdk版本不一样导致出现发行版本不同的问题而无法启动项目,需要统一jdk版本问题
-
无法找到mvn、java命令->jenkins默认找的是/usr/bin目录下的命令,需要通过软连接方式链接到/usr/bin目录下
-
权限问题,可能存在jar移动到其他目录而导致的权限问题,最粗暴的方式是chmod 777,直接给该文件或文件夹设置成最高权限,或者指定文件或文件夹某一个权限。
-
编译太慢,可能是maven仓库问题,特别是第一次部署项目时需要从仓库中拉依赖,在没有镜像设置的情况下极其慢,我们需要设置以下镜像(如阿里云镜像)
-
Host key verification failed.
运行Jenkins的用户是程序用户jenkins,但是程序用户jenkins是非正常用户
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-U1t7jJAL-1630597523895)(C:\Users\win10\Desktop\jenkins\Jenkins自动化部署.assets\image-20210828170934437.png)]
非正常主要体现在登陆shell异常 如下非正常主要体现在登陆shell异常 如下
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-1PW54qFq-1630597523896)(C:\Users\win10\Desktop\jenkins\Jenkins自动化部署.assets\image-20210828171035189.png)]
解决方法
(1)改变jenkins用户的登陆shell,使用
vim /etc/passwd
修改文件[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-cDMGHY5a-1630597523897)(C:\Users\win10\Desktop\jenkins\Jenkins自动化部署.assets\image-20210828171237941.png)]
(2)切换jenkins用户 测试
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-JO0Npti8-1630597523899)(C:\Users\win10\Desktop\jenkins\Jenkins自动化部署.assets\image-20210828171353584.png)]
(3)重新定义jenkins用户的命令提示符,
cd
返回根目录通过vim .bash_profile
执行指令后再尾部添加export PS1='[\u@\h \W]\$ '
,source .bash_profile
重载文件。[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-n5olF4gX-1630597523900)(C:\Users\win10\Desktop\jenkins\Jenkins自动化部署.assets\image-20210828171651725.png)]
(4)再次切换到jenkins用户测试
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-uyZXBMwB-1630597523902)(C:\Users\win10\Desktop\jenkins\Jenkins自动化部署.assets\image-20210828172209719.png)]
(5)jenkins用户对目标主机做免密登陆,其命令包含
su jenkins
和ssh-keygen
和ssh-copy-id -i ~/.ssh/id_rsa.pub root@你的ip
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-NmgzgOpU-1630597523904)(C:\Users\win10\Desktop\jenkins\Jenkins自动化部署.assets\image-20210828172345849.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-hi0lNJmW-1630597523905)(C:\Users\win10\Desktop\jenkins\Jenkins自动化部署.assets\image-20210828172956001.png)]
-
无法访问问题
大部分原因在于防火墙拦截,端口未开放
解决方法:
1、 关闭防火墙(不推荐),systemctl stop firewalld
2、开放指定端口
(1)linux 防火墙查询开放的端口号
firewall-cmd --query-port=端口号/tcp
(2)linux 防火墙开放指定端口号
firewall-cmd --add-port=端口号/tcp --permanent
关于本项目中的Jenkins文件以及sh文件讲解
Jenkins:
文件定义其实就是Pipeline的语法
什么是Pipeline?
Jenkins Pipeline是一组插件,支持在Jenkins上实现和集成持续交付的管道。Pipeline这个单词是水管的意思。我以后可能会翻译成管道或者流水线,我建议大家不要翻译,就写Pipeline。这里持续集成(CI)和持续交付(CD),我们在DevOps基础扫盲篇介绍过,以后多经常用到这两个单词缩写。 Jenkins为了更好支持CI和CD,通过Groovy语言这么DSL(动态描述语言)来开发Pipeline组件。在Jenkins中有一句话,Pipeline as code,Pipeline是Jenkins中最优雅的存在。之前Jenkins上UI操作动作,都可以在Pipeline中代码实现,主要你对Jenkins和Groovy语言有足够多掌握。 以后我们经常说CI Pipeline和CD Pipeline,你现在大致可以理解为,要实现CD,先要实现CI。CD Pipeline就是一个代码文件,里面把你项目业务场景都通过Groovy代码和Pipeline语法实现,一个一个业务串联起来,全部实现自动化,从代码仓库到生产环境完成部署的自动化流水线。这个过程就是一个典型的CD Pipeline 官网建议我们把Pipeline代码放在一个名称为Jenkinsfile的文本文件中,并且把这个文件放在你项目代码的根目录,采用版本管理工具管理。Jenkinsfile我后面会具体例子来介绍。当然,我们也可以把Pipeline代码用一个Hello.groovy这样的文件去保存在代码库,这也是没问题的。
Pipeline关键字解释
pipeline 这个单词是小写,可以看作是Pipeline语法中的一个关键字。以后一个groovy文件或者一个Jenkinsfile文件中不光只有Pipeline代码,例如还有其他的工具类方法等。通过pipeline { Pipeline代码},这个关键字就是告诉Jenkins接下来{}中的代码就是pipeline代码,和普通的函数或者方法隔离出来。 node 关键字node就是用来区分,Jenkins环境中不同的节点环境。例如一个Jenkins环境包括master节点,也就是主节点,还包括N多个从节点,这些从节点在添加到主节点的向导页面中有一个参数,好像是label,就是给这个从节点取一个名称。在Pipeline代码中可以通过node这个关键字告诉Jenkins去用哪一台节点机器去执行代码。 stage 关键字stage,就是一段代码块,一般个stage包含一个业务场景的自动化,例如build是一个stage, test是第二个stage,deploy是第三个stage。通过stage隔离,让Pipeline代码读写非常直观。到后面你还会学习stages这个关键字,一个stages包含多个stage。 step 关键字step就是一个简单步骤,一般就是几行代码或者调用外部一个模块类的具体功能。这里step是写在stage的大括号里的。
本项目Jenkins文件讲解
pipeline { //一 agent any //二 options { //三 timeout(time: 2, unit: 'HOURS') //运行超时时间为两小时 } stages { //四 stage('Package') { //五 该时期名称定义为Package steps { //六 sh 'mvn clean install -Dmaven.test.skip=true' //shell命令执行maven的clean和install操作,中间跳过test } } stage('Deliver for dev') { //该时期名称定义为Deliver for dev steps { //具体steps内部引用参照https://www.jenkins.io/doc/pipeline/steps/ withCredentials([usernamePassword(credentialsId: 'cheyinbo', passwordVariable: 'password', usernameVariable: 'username')]) { //shell命令执行文件deploy.sh文件并根据顺序传入参数 sh "bash scripts/deploy/deploy.sh 192.168.159.138 root root jenkins-demo" } } } } }
一:整个大的代码块,表明该文件是一个Pipeline语法文件,内部语法必须遵从pipeline语法
二:agent部分指定整个Pipeline或特定阶段将在Jenkins环境中执行的位置,具体取决于该agent 部分的放置位置。该部分必须在pipeline块内的顶层定义。
any none label node docker 在任何可用的agent 上执行Pipeline或stage 当在pipeline块的顶层使用none时,将不会为整个Pipeline运行分配全局agent ,每个stage部分将需要包含其自己的agent部分 agent { node { label ‘labelName’ } },等同于 agent { label ‘labelName’ },但node允许其他选项(如customWorkspace)。 使用提供的label标签,在Jenkins环境中可用的代理上执行Pipeline或stage。例如:agent { label ‘my-defined-label’ } 定义此参数时,执行Pipeline或stage时会动态供应一个docker节点去接受Docker-based的Pipelines。 docker还可以接受一个args,直接传递给docker run调用。例如:agent { docker ‘maven:3-alpine’ }或docker
agent {
docker {
image 'maven:3-alpine’
label 'my-defined-label’
args ‘-v /tmp:/tmp’
}
}三:options指令允许在Pipeline本身内配置Pipeline专用选项。Pipeline本身提供了许多选项,例如buildDiscarder,但它们也可能由插件提供,例如 timestamps。
可用选项
buildDiscarderpipeline保持构建的最大个数。例如:options { buildDiscarder(logRotator(numToKeepStr: ‘1’)) }
disableConcurrentBuilds
不允许并行执行Pipeline,可用于防止同时访问共享资源等。例如:options { disableConcurrentBuilds() }
skipDefaultCheckout
默认跳过来自源代码控制的代码。例如:options { skipDefaultCheckout() }
skipStagesAfterUnstable
一旦构建状态进入了“Unstable”状态,就跳过此stage。例如:options { skipStagesAfterUnstable() }
timeout
设置Pipeline运行的超时时间。例如:options { timeout(time: 1, unit: ‘HOURS’) }
retry
失败后,重试整个Pipeline的次数。例如:options { retry(3) }
timestamps
预定义由Pipeline生成的所有控制台输出时间。例如:options { timestamps() }
四—五:Stages 是 Pipeline 中最主要的组成部分,Jenkins 将会按照 Stages 中描述的顺序从上往下的执行。Stages 中可以包括任意多个 Stage,而 Stage 与 Stages 又能互相嵌套,除此以外还有
parallel
指令可以让内部的 Stage 并行运行。实际上可以把 Stage 当作最小单元,Stages 指定的是顺序运行,而 parallel 指定的是并行运行。六:steps 是 Pipeline 中最核心的部分,每个 Stage 都需要指定 Steps。Steps 内部可以执行一系列的操作,任意操作执行出错都会返回错误。
jenkins-demo.sh文件讲解
APP_NAME=jenkins-demo USER_DIR=/data/app/java APP_JAR=${APP_NAME}.jar JAR_FILE=$USER_DIR/${APP_NAME}.jar PID_FILE=$USER_DIR/${APP_NAME}.pid #--logging.config=$USER_DIR/logback.xml \ //开始进程的语法 start() { //1>/dev/null:表示标准输出重定向到空设备文件,也就是不输出任何信息到终端,不显示任何信息。 //2>&1:表示标准错误输出重定向等同于标准输出,因为之前标准输出已经重定向到了空设备文件,所以标准错误输出也重定向到空设备文件。 nohup java -Xmx512M -jar $JAR_FILE > /dev/null 2>&1 & //后台运行jar包 //$!表示获取做个一个生成进程的pid, 本语句译为将当前执行进程的pid存入到指定目录下的指定文件名称.pid文件里并输出当前生成的进程pid echo $! > $USER_DIR/$APP_NAME.pid & //输出当前jar的路径 echo $JAR_FILE //休眠1秒 sleep 1 //输出当前应用执行完毕的标识 echo "Start $APP_NAME done." //结束 exit 0 } //结束进程方法 stop() { //获取生成pid文件中的pid PID=`cat ${PID_FILE}` //结束指定pid的进程 kill $PID //循环 for i in {1..30} do //查询当前pid进程是否还存在 process=`ps aux | grep ${PID} | grep -v grep` if [[ $process ]]; then //输出等待指定应用的进程结束的标识 echo "Wait process ${APP_NAME} exit..." //休眠1秒 sleep 1 else //输出指定应用的进程已结束的标识 echo "Process ${APP_NAME} exited." //删除之前保存的pid文件 rm -rf $PID_FILE //结束 exit 0 fi done echo 'Force kill' //若进程依旧未被结束,在执行一次结束进程的命令 kill -KILL $PID //删除之前生成的pid文件 rm -rf $PID_FILE } case $1 in start) start ;; stop) stop ;; esac
//输出指定应用的进程已结束的标识 echo "Process ${APP_NAME} exited." //删除之前保存的pid文件 rm -rf $PID_FILE //结束 exit 0 fi done echo 'Force kill' //若进程依旧未被结束,在执行一次结束进程的命令 kill -KILL $PID //删除之前生成的pid文件 rm -rf $PID_FILE
}
case $1 in
start)
start
;;
stop)
stop
;;
esac