SpringCloud(CI/CD-Nexus+Gitea+Jenkins)
前面聊了SpringCloud-Netflix这一套,聊的同时,我自己搭建了一个一套SpringCloud-Netflix框架,其中包含了7个微服务,这还是我没有任何业务支撑的情况下。很显然,随着微服务数量的增加。像传统的那样打包jar,复制jar,并且发布jar(nohup java -jar ${APP_NAME} > ***.log 2>&1 &)到服务器上绝对不是一个好的办法。本篇,我将对我的微服务项目使用【Nexus(maven私服)+Gitea(代码托管工具)+Jenkins(持续集成)】进行部署,首先聊他们的搭建,然后结合我们的代码,最终完成自动化部署。
搭建Nexus私服环境
因为是多个微服务组成的一个项目,而且可能有多个项目组同时依赖某一个jar,那我们就需要把这个jar放在一个统一的地方进行管理。所以这里使用【nexus】进行一个中央仓库的搭建。
搭建步骤:
- 和咱们前面搭建jenkins一样,确保maven和jdk都已经安装
- 下载地址:【https://sonatype-download.global.ssl.fastly.net/repository/downloads-prod-group/3/nexus-3.37.3-02-unix.tar.gz】,下载速度特别慢,有需要可以找我拿
- 解压:tar -zxvf nexus-3.37.3-02-unix.tar.gz
- 启动:进入到${NEXUS_HOME}\bin目录,执行【./nexus start】
输入 http://192.168.43.3:8081/ 我是本地搭建的虚拟机,大家写自己的ip,但是默认端口是8081
- 登录默认用户名admin,密码在/data/program/sonatypework/nexus3/admin.password文件中
tips:
- 如果想配置 nexus 的应用在本地启动的 JVM参数,可以在 nexus.vmoptions
- 如果想改变 nexus 的 端口号,可以在 nexus-default.properties,默认是8081
- 他的日志在sonatype-work/nexus3/log,启动后去查询一下nexus是否启动,我启动的时候就是因为linux的root磁盘接近饱和,nexus要求最少有4096MB的磁盘空间,后面不得不去对磁盘从新扩容,查询磁盘大小命令【df -h】
功能介绍:
进入Nexus控制台的Browse菜单,可以看到四种仓库类型:
- maven-central: maven中央库,默认从https://repo1.maven.org/maven2/拉取jar
- maven-releases: 私库发行版jar
- maven-snapshots:私库快照(调试版本)jar
- maven-public: 仓库分组,把上面三个仓库组合在一起对外提供服务,在本地maven基 础配置settings.xml中使用。
Nexus设置成系统服务
- 修改${NEXUS_HOME}\bin\nexus这个脚本,增加【INSTALL4J_JAVA_HOME_OVERRIDE=/data/program/jdk1.8.0_241】
- 设置软链接 ln -s /data/program/nexus-3.37.0-01/bin/nexus /etc/init.d/nexus
- 通过chkconfig方式配置系统服务:
- cd /etc/init.d sudo chkconfig --add nexus #添加nexus服务 sudo chkconfig --levels 345 nexus on #设置开启自启动
- 启动和停止服务
- sudo service nexus start #开启服务 service nexus status #查看服务状态
搭建Gitea环境
【普通版本】:首先必须要有git环境,之前我的虚拟机上已经有了,这里就不带搭建搭建了。按照官方给的文档就行( https://docs.gitea.io/zh-cn/install-from-binary/)
【设置系统服务】:
- 创建Git用户 注:git需放到 :/bin/git ,并且需要创建软连接【 ln -s /usr/local/git/bin/git /bin/git 】
View Codesudo useradd \ --system \ --shell /bin/bash \ --comment 'Git Version Control' \ --create-home \ --home /home/git \ git- 下载二进制文件【wget -O gitea https://dl.gitea.io/gitea/1.15.7/gitea-1.15.7-linux-amd64】
- 把下载的文件移动到/usr/local/bin目录(官方建议,因为我们的gitea.service中写的就是这个路径,并且下面我们也会为这个路径分配权限)
- 【sudo mv /data/program/gitea /usr/local/bin】
- 让二进制文件可以执行【chmod +x /usr/local/bin/gitea】
- 按照命令创建必要目录并设置权限
View Codesudo mkdir -p /var/lib/gitea/{custom,data,indexers,public,log} sudo mkdir -p /var/lib/gitea/{custom,data,indexers,public,log} sudo chown git: /var/lib/gitea/{data,indexers,custom,public,log} sudo chmod 750 /var/lib/gitea/{data,indexers,log} sudo mkdir /etc/gitea sudo chown root:git /etc/gitea sudo chmod 770 /etc/gitea
- 在/etc/systemd/system/中创建gitea.service文件,内容为
View Code[Unit] Description=Gitea (Git with a cup of tea) After=syslog.target After=network.target [Service] RestartSec=2s Type=simple User=git Group=git WorkingDirectory=/var/lib/gitea/ ExecStart=/usr/local/bin/gitea/gitea web --config /etc/gitea/app.ini Restart=always Environment=USER=git HOME=/home/git GITEA_WORK_DIR=/var/lib/gitea [Install] WantedBy=multi-user.target
- 设置自动启动
- systemctl enable
- gitea systemctl start gitea
- jenkins 实际上就是一个war,下载下来我们用命令启动就行(自行百度),我们关于它的一些内容我们之前聊过,这里不赘述了,
- tips:
- 第一个输入地址后,会让你对服务器地址等的填写,这里最好填写。如果没有填写,那可以通过修改app.ini文件进行修改(如果不修改这个的话,我们创建的项目ssh或或者http地址就是localhost,这样的话别人就无法访问了!!!)。在我们启动gitea的时候,这个文件地址则会被打印出来。相关配置请看 【https://docs.gitea.io/zh-cn/config-cheat-sheet/#server-server】
项目中配置私服
在maven的setting文件中,写上我们的nexus的服务器地址和端口,以及相关配置
View Code<mirrors> <mirror> <id>nexus</id> <mirrorOf>maven-public</mirrorOf> <url>http://192.168.43.3:8081/repository/maven-public/</url> </mirror> </mirrors> <profiles> <profile> <id>nexusRep</id> <repositories> <repository> <id>nexus</id> <url>http://192.168.43.3:8081/repository/maven-public/</url> <layout>default</layout> <releases> <enabled>true</enabled> <updatePolicy>always</updatePolicy> </releases> </repository> </repositories> <pluginRepositories> <pluginRepository> <!--插件地址--> <id>nexus</id> <url>http://192.168.43.3:8081/repository/maven-public/</url> <snapshots> <enabled>true</enabled> </snapshots> <releases> <enabled>true</enabled> </releases> </pluginRepository> </pluginRepositories> </profile> </profiles> <activeProfiles> <activeProfile>nexusRep</activeProfile> </activeProfiles>在springCloud的父项目中写上我们nexus的仓库地址
View Code<distributionManagement> <snapshotRepository> <id>snapshots</id> <name>Nexus Snapshot Repository</name> <url>http://192.168.43.3:8081/repository/maven-snapshots/</url> </snapshotRepository> <repository> <id>releases</id> <name>Nexus Release Repository</name> <url>http://192.168.43.3:8081/repository/maven-releases/</url> </repository> </distributionManagement>重启idea后,我们的所有的jar则会同步到我们nexus上的中央仓库中,当然我们也可以自己配置aliyun仓库。
注意:我们这个时候deploy的时候,可能有【Return code is: 401, ReasonPhrase: Unauthorized.】这样的错误, 这是因为我们权限,我们需要把nexus的密码和用户名维护在maven中的setting.xml中的servers标签中,并且pom中的id和我们maven中维护账号密码的id需要一致!
View Code<server> <id>releases</id> <username>admin</username> <password>123456</password> </server> <server> <id>snapshots</id> <username>admin</username> <password>123456</password> </server>然后我们使用maven进行deploy,则发现这些jar就发布到了nexus上SNAPSHOT中,但是release中没有,这是因为我们的pom中写version中写的都是
<version>0.0.1-SNAPSHOT</version>
配置Jenkins的环境变量
在jenkins的【系统管理】中的【全局工具配置】中,配置maven,jdk,git
在【系统配置】中的【插件管理】中 安装gitea、Git Parameter、Publish Over SSH、Maven Integration这些插件
在全局配置中配置gitea的地址
和配置发布目标服务器的地址
构建项目
创建一个maven项目,并且填写上我们的gitea中项目的地址,和gitea的账号和密码
指定我们需要打包的pom,并且执行maven命令,对项目进行清理、打包、跳过检测,我们这里的root pom的名称的来由是从jenkins的工作目录下的项目中来的
配置需要接收的目标服务器地址和目录,并且我们需要编写需要执行的脚本
【 jenkins上的执行脚本】注意,脚本中我直接使用微服务的名称作为jar的名称,这是因为我在项目中的pom中的finalName标签中写了微服务的名称
- 停止项目
- 备份老的文件
- 把转移传递过来的ja转移到和执行脚本在一起的目录
- 执行启动脚本
- 删除备份了5次以上的备份文件
View Code#! bin/sh -e export JAVA_HOME=/usr/local/jdk/jdk1.8.0_291 export JRE_HOME=/usr/local/jdk/jdk1.8.0_291/jre export CLASSPATH=.:$JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar:$JRE_HOME/lib:$CLASSPATH export PATH=$JAVA_HOME/bin:$PATH source /etc/profile # define property JAR_PATH='/app/service/marking-service' TEMP_PATH='/app/service/temp' BACKUP_PATH='/app/service/backup' JAR_NAME=marking-service.jar FILE_NAME=marking-service # stop target service cd ${JAR_PATH} sh run-marking-service.sh stop sleep 2 rm -rf $FILE_NAME.log # backup old jar if there is not the path then create a path BACKUP_DATE=$(date +%Y%m%d_%H%M) if [ ! -d $JAR_PATH/backup/$FILE_NAME ];then mkdir -p $JAR_PATH/backup/$FILE_NAME fi # enter into the path if there is a jar then move the jar to back path to backup cd ${JAR_PATH} pwd if [ -f $JAR_NAME ];then mv -f ./$JAR_NAME ./backup/$FILE_NAME/$JAR_NAME$BACKUP_DATE sleep 1 fi # start jar BUILD_ID=dontKillMe cd ${TEMP_PATH} mv -f $JAR_NAME $JAR_PATH cd ${JAR_PATH} # run the script to restart sh run-marking-service.sh restart # clear old backup cd ${JAR_PATH}/backup/$FILE_NAME ls -lt|awk 'NR>5{print $NF}' |xargs rm -rf ps -ef|grep java echo "=============deploy success========" #首先进入/app/service/marking-service #执行sh文件停止,并且睡2s,同时删除marking-service.log 文件 #备份老的文件 如果不存在/app/service/marking-service/backup/marking-service这个文件,则创建一个文件 #进入到/app/service/marking-service中,如果存在marking-service.jar,则把这个文件转移到./backup/marking-service/marking-service.jar$BACKUP_DATE中 #进入到/app/service/temp中,把marking-service.jar转移到/app/service/marking-service中 #进入到/app/service/marking-service中, #执行启动方法 #进入到/app/service/marking-service/backup/marking-service中,删除一下备份文件 #打印java的jar目标服务器的执行脚本
View Code# 表示当前脚本采用/bin路径的bash程序来解释执行 #!/bin/bash # 执行的jar包 APP_NAME=marking-service.jar usage() { echo "执行操作命令 [start|stop|restart|status]" exit 1 } #判断当前应用是否存在 if_exist() { pid=`ps -ef|grep $APP_NAME|grep -v grep|awk '{print $2}'` #判断进程是否为空 if [ -z "${pid}" ]; then return 1 else return 0 fi } #启动 start() { #判断是否启动 if_exist #已经启动 if [ $? -eq 0 ]; then #打印 echo "${APP_NAME} already running . pid=${pid}" else #进行启动 nohup java -jar ${APP_NAME} > marking-service.log 2>&1 & #启动后的pid npid=`ps -ef|grep $APP_NAME|grep -v grep|awk '{print $2}'` #打印 echo "start ${APP_NAME} success, pid=${npid}" fi } #停止 stop() { if_exist #如果存在 if [ $? -eq 0 ]; then #停止 kill -9 $pid #打印 echo "stop $pid success". else #打印 echo "${APP_NAME} is not running" fi } #查询状态 status() { if_exist if [ $? -eq 0 ]; then echo "${APP_NAME} is running. pid is ${pid}" else echo "${APP_NAME} is not running " fi } #重启 restart() { stop #休眠5s sleep 5 start } case "$1" in "start") start ;; "stop") stop ;; "status") status ;; "restart") restart ;; *) #提示 usage ;; esac进行构建
整体流程
- 从我们的gitea上拉取代码
- 开始去nexus上拉取jar
- maven打包结束
- 发布jar到目标服务器
- 目标服务器已经可以看见jar
并且通过日志查砍项目自己启动完成
当项目推送到gitea的时候进行自动构建解决方案
我们有时候希望当我们某个分支有代码发布后,自动构建,那我们就可以采用webhook进行处理。
安装Generic Webhook Trigger到jenkins中
在项目配置中选择构建触发器,并且填写我们的token,他会给我们生成一个地址,我们需要把这个地址填写到我们gitea中
这个时候我们我们提交一个代码给gitea,注意这个时候我们jenkins上是没有任何构建的任务的!!
gitea上已经有我们的代码了
Jenkins正在构建项目
gitea上显示构建成功
代码也已经传递到目标服务器中,并且启动成功
我们后面的模块就可以按照这种方式进行构建,当新建一个构建项目的时候,jenkins提供复制功能,这可以为我们省去很多时间
至此,nexus+Gitea+Jenkins自动化部署完成!