当前位置: 首页 > news >正文

10-实战:RuoYi-Cloud的自动化发布

一、项目准备

1.微服务拆分

  • Ruoyi-Cloud在设计上有7个微服务,分别负责不同功能,以下信息将在后续配置用到

模块微服务代码根目录dockerfile路径
网关模块RuoYi-Gatewayruoyi-gateway/docker/ruoyi/gateway
认证模块RuoYi-Authruoyi-auth/docker/ruoyi/auth
系统模块RuoYi-Systemruoyi-modules/ruoyi-system/docker/ruoyi/modules/system
代码生成RuoYi-Genruoyi-modules/ruoyi-gendocker/ruoyi/modules/gen
定时任务RuoYi-Jobruoyi-modules/ruoyi-jobdocker/ruoyi/modules/job
文件服务RuoYi-Fileruoyi-modules/ruoyi-filedocker/ruoyi/modules/file
监控中心RuoYi-Monitorruoyi-visual/ruoyi-monitor/docker/ruoyi/visual/monitor
  • 针对这些微服务,我们需要创建7条Jenkins多分支流水线来分别对这些微服务进行CICD

2.数据库文件导入

  • 在若依根目录sql/路径中,有预设的数据库脚本,需要创建对应数据库导入

  • 在数据库服务器10.0.0.138中,将sql/路径下的脚本全部传输到服务器,进入数据库

create database `ry-cloud`; create database `ry-config`; # 编写导入脚本 vim ry-data.sh ------------------------------------------------------------------------ echo $(date) mysql -uroot -pPangle@123 -f ry-cloud < ry_20250523.sql echo $(date) ​ echo $(date) mysql -uroot -pPangle@123 -f ry-cloud < quartz.sql echo $(date) ​ echo $(date) mysql -uroot -pPangle@123 -f ry-config < ry_config_20260311.sql echo $(date) ------------------------------------------------------------------------ ​ # 执行脚本 nohup sh ry-data.sh > ry-data.log &

3.nacos安装

  • 我们的操作基于master分支,而该分支代码已升级至SpringBoot4 对应nacos版本为3.X.X

  • 10.0.0.140服务器上部署nacos,前往nacos官网下载压缩版:https://nacos.io/

# 下载解压 cd /usr/local wget https://download.nacos.io/nacos-server/nacos-server-3.1.1.zip unzip nacos-server-3.1.1.zip ​ cd nacos/ # 配置文件编辑数据库路径 vim conf/application.properties ------------------------------------------------------------------------ spring.sql.init.platform=mysql db.num=1 db.url.0=jdbc:mysql://{数据库服务器ip}:3306/ry-config?characterEncoding=utf8&connectTimeout=5000&socketTimeout=10000&autoReconnect=true&useUnicode=true&useSSL=false&serverTimezone=UTC&allowPublicKeyRetrieval=true db.user=root db.password={root用户密码} ------------------------------------------------------------------------ ​ # 单机模式启动 sh bin/startup.sh -m standalone

4.配置地址

- 配置微服务注册地址

  • 若依微服务依赖nacos进行服务注册和读取配置,首先要为每个微服务配置nacos地址

  • 在每个微服务代码根目录src/main/resources/bootstrap.yml文件中修改:

  • 修改每个配置文件中,每个server-addr:后的内容,将127.0.0.1改为nacos服务器ip10.0.0.140

- nacos配置数据库地址

  • nocos将从数据库的ry-config库读取配置文件

  • 登录nacos主页 > 配置管理 > 配置列表

    • 修改ruoyi-gateway-dev.ymlruoyi-auth-dev.ymlruoyi-system-dev.ymlruoyi-gen-dev.ymlruoyi-job-dev.yml

    • redis的配置地址 host: {数据库服务器ip}

    • datasource中的 url: 和 password: 设置成自己数据库相关配置

- 配置后端API地址

  • 前端将部署到10.0.0.135,后端将以微服务容器部署到10.0.0.137

  • 因此在前端代码文件需要配置后端服务器地址和访问端口

  • 在前端目录ruoyi-ui中,编辑配置文件vue.config.js

    • 找到target: http://127.0.0.0:8080,将其改为自定义的target: http://10.0.0.137:8080

二、编写配置文件

1.Jenkinsfile

  • 在对项目完成准备工作后,将其上传到Gitlab仓库Ruoyi-Cloud,然后新建分支prod-peizhi,将其作为生产Jenkins需要发布的分支

  • prod-peizhi分支中,在每个微服务代码根目录新建文件Jenkinsfile并编辑内容:

    • 针对不同微服务,只需要配置SERVICE_TYPEBASE_NAMEHOST_PORTCONTAINER_PORT就可复用该Jenkinsfile

    • SERVICE_TYPEBASE_NAMEHOST_PORT & CONTAINER_PORT
      basicgateway8080
      basicauth9200
      modulessystem9201
      modulesgen9202
      modulesjob9203
      modulesfile9300
      visualmonitor9100
    • 在Jenkins全局配置中,添加前后端目标服务器信息:命名为若依微服务-前端若依微服务-后端,供Jenkinsfile调用

pipeline { agent any tools { // 全局工具已配置 maven 'Maven-3.8.9' jdk 'JDK-17' } environment { // 不同微服务需修改此处:gateway/auth为 basic、job/file/gen/system为 modules、monitor为 visual SERVICE_TYPE = "basic" BASE_NAME = "gateway" // 基础服务名称 HOST_PORT=8080 // 宿主机端口 CONTAINER_PORT=8080 // 容器内端口 ​ // --------------------------------------------------------以下信息自动拼接---- // 根据微服务类型和基础名称动态生成应用名称,基于RuoYi的项目结构 // APPNAME 根据生成的jar包名,将作为镜像名称 APPNAME = "ruoyi-${SERVICE_TYPE == 'basic' ? BASE_NAME : (SERVICE_TYPE == 'modules' ? "modules-${BASE_NAME}" : "visual-${BASE_NAME}")}" APP_DIR = "${SERVICE_TYPE == 'basic' ? "./ruoyi-${BASE_NAME}" : (SERVICE_TYPE == 'modules' ? "./ruoyi-modules/ruoyi-${BASE_NAME}" : "./ruoyi-visual/ruoyi-${BASE_NAME}")}" // 拼接jar包完整路径,供Dockerfile使用 JAR_PATH = "${APP_DIR}/target/${APPNAME}.jar" ​ // Dockerfile路径,根据微服务类型动态选择 DOCKERFILE_DIR = "${SERVICE_TYPE == 'basic' ? "./docker/ruoyi/${BASE_NAME}" : (SERVICE_TYPE == 'modules' ? "./docker/ruoyi/modules/${BASE_NAME}" : "./docker/ruoyi/visual/${BASE_NAME}")}" ​ // --------------------------------------------------------以下信息无需修改---- VERSION="V1.0.${env.BUILD_NUMBER}" // 拼接为符合Harbor镜像规范的完整镜像名 HARBOR_URL="121.4.90.98:80" IMAGE_NAME="${HARBOR_URL}/ruoyi/${APPNAME}:${VERSION}" // Harbor用户名密码 HARBOR_USER="admin" HARBOR_PASS="Harbor12345" // 前后端服务器地址,在Jenkins系统配置中添加,命名 NGINX_SERVER="若依微服务-前端" APP_SERVER="若依微服务-后端" } options { disableConcurrentBuilds() // 禁止并行构建 timestamps() // 日志添加时间戳 } stages { stage('Npm打包前端') { when { // 仅微服务名为ruoyi-gateway的流水线执行 expression { return env.APPNAME == 'ruoyi-gateway' } } steps { script { dir('ruoyi-ui') { sh """ rm -rf dist*.zip npm install --registry=https://registry.npmmirror.com npm run build:prod zip -r dist-${VERSION}.zip ./dist/* """ } } } } stage('Maven打包后端') { steps { script { sh """ # 将jar包构建后复制到Docker构建目录,供Dockerfile使用 mvn clean package -Dmaven.test.skip=true -pl ${APP_DIR} -am -f ./pom.xml cp ${JAR_PATH} ${DOCKERFILE_DIR}/jar """ } } } stage('本地构建镜像') { steps { script { sh """ cd ${DOCKERFILE_DIR} docker build -t ${APPNAME}:${VERSION} . """ } } } stage('镜像推送Harbor') { steps { script { sh """ docker login ${HARBOR_URL} -u ${HARBOR_USER} -p ${HARBOR_PASS} docker tag ${APPNAME}:${VERSION} ${IMAGE_NAME} docker push ${IMAGE_NAME} """ } } } stage('部署前端') { when { expression { return env.APPNAME == 'ruoyi-gateway' } } steps { script { echo "=== 部署前端 ===" // sshPublisher:Jenkins SSH插件,实现远程服务器操作 sshPublisher(publishers: [ sshPublisherDesc( configName: NGINX_SERVER, // 指定前端部署的SSH服务器 transfers: [ sshTransfer( sourceFiles: "ruoyi-ui/dist-${VERSION}.zip", // 要推送的前端压缩包 removePrefix: '', // 不删除压缩包的前缀路径 remoteDirectory: '', // 推送至远程服务器的当前目录 // 远程服务器执行的命令:解压压缩包并删除源文件 execCommand: """ # 切换到前端部署目录-->解压并覆盖旧文件-->删除压缩包 cd /usr/local/RuoYi-Cloud/ruoyi-ui && unzip -o dist-${VERSION}.zip && rm -rf dist-${VERSION}.zip ​ """ ) ], verbose: true // 输出详细SSH操作日志 ) ]) } } } stage('部署后端') { options { timeout(time: 30, unit: 'MINUTES') // 超时时间10分钟 } steps { script { echo "=== 部署后端 ===" sshPublisher(publishers: [ sshPublisherDesc( configName: APP_SERVER, // 指定后端部署的SSH服务器 transfers: [ sshTransfer( sourceFiles: '', // 无需推送文件 removePrefix: '', remoteDirectory: '', // 远程执行部署脚本:标准镜像名、端口等参数 execCommand: """ sh /usr/bin/ry-cloud.sh ${IMAGE_NAME} ${HOST_PORT} ${CONTAINER_PORT} """ ) ], verbose: true ) ]) } } } } }

2.脚本文件

  • 部署后端阶段是调用后端服务器的/usr/bin/ry-cloud.sh脚本文件,需在后端服务器添加改文件

vim /usr/bin/ry-cloud.sh ------------------------------------------------------------------------ #!/bin/bash FULL_IMAGE_NAME=$1 HOST_PORT=$2 CONTAINER_PORT=$3 ​ # ===== 根据Jenkins传入参数,解析镜像名 ===== # 1:按最后一个:分割 "地址/项目名/镜像名" 和 "版本号" IMAGE_PREFIX=${FULL_IMAGE_NAME%:*} # 取:左侧部分 → 121.4.90.98:80/ruoyi/ruoyi-gateway VERSION=${FULL_IMAGE_NAME##*:} # 取:右侧部分 → V1.0.11 ​ # 2:按最后一个/分割 "地址/项目名" 和 "镜像名" APP_NAME=${IMAGE_PREFIX##*/} # 取最后一个/右侧 → ruoyi-gateway HARBOR_ADDR=${IMAGE_PREFIX%/*} # 取最后一个/左侧 → 121.4.90.98:80/ruoyi ​ # ===== 打印解析结果 ===== echo "===== 部署参数解析结果 =====" echo "完整镜像名: ${FULL_IMAGE_NAME}" echo "Harbor地址+项目名: ${HARBOR_ADDR}" echo "微服务名: ${APP_NAME}" echo "版本号: ${VERSION}" echo "主机端口: ${HOST_PORT}" echo "容器端口: ${CONTAINER_PORT}" echo "============================" ​ # ===== 停止并删除旧容器 ===== echo "===== 停止并删除旧容器 =====" OLD_CONTAINER=$(docker ps -aq --filter "name=${APP_NAME}") if [ -n "${OLD_CONTAINER}" ]; then echo "发现运行中的旧容器,ID: ${OLD_CONTAINER},正在停止" docker stop ${OLD_CONTAINER} || echo "警告:容器可能已停止" echo "删除旧容器: ${OLD_CONTAINER}" docker rm ${OLD_CONTAINER} || echo "警告:容器可能已删除" else echo "未发现运行中的旧容器,跳过" fi ​ # ===== 删除旧镜像 ===== echo "===== 删除旧镜像 =====" # 检查旧镜像是否存在 if docker images -q ${FULL_IMAGE_NAME} > /dev/null 2>&1; then echo "发现旧镜像 ${FULL_IMAGE_NAME},正在删除" docker rmi ${FULL_IMAGE_NAME} || echo "警告:镜像可能已删除" else echo "未发现旧镜像 ${FULL_IMAGE_NAME},跳过" fi ​ # ===== 登录Harbor并拉取新镜像 ===== echo "===== 登录Harbor并拉取新镜像 =====" # Harbor用户名密码,也可由Jenkins传入 HARBOR_USER="admin" HARBOR_PASS="Harbor12345" docker login ${HARBOR_ADDR%/*} -u ${HARBOR_USER} -p ${HARBOR_PASS} || echo "警告:Harbor登录失败" docker pull ${FULL_IMAGE_NAME} || { echo "ERROR:拉取新镜像失败!"; exit 1; } ​ # ===== 启动新容器 ===== echo "===== 启动新容器 =====" docker run -d \ --name ${APP_NAME} \ --restart=always \ -p ${HOST_PORT}:${CONTAINER_PORT} \ ${FULL_IMAGE_NAME} ​ # 验证容器是否启动成功 if docker ps --filter "name=${APP_NAME}" | grep -q "${APP_NAME}"; then echo "===== 部署成功 =====" echo "容器名: ${APP_NAME}" echo "映射端口: ${HOST_PORT}:${CONTAINER_PORT}" exit 0 else echo "ERROR:容器启动失败 " docker logs ${APP_NAME} # 打印日志便于排查 exit 1 fi ------------------------------------------------------------------------

三、配置Jenkins任务

  • 微服务名在Jenkins新建任务并命名,选择多分支流水线类型

  • 分支源选择Git,项目仓库填写Ruoyi-Cloud的Gitlab仓库地址,并配置Gitlab凭据

  • 行为:发现分支后添加根据名称过滤(支持通配符),选择包含prod*,匹配生产分支prod-peizhi

  • Build Configuration的脚本路径填写对应微服务的代码根目录/Jenkinsfile,如:ruoyi-gateway/Jenkinsfile

  • 点击应用后保存,Jenkins就会自动扫描对应分支,并根据其Jenkinsfile进行构建

  • 其他微服务同理建立Jenkins多分支流水线任务并做好配置

总结

  • 文档从自由风格的项目到多分支流水线的任务搭建配置,我们可以发现,在篇幅上自由风格项目的Jenkins配置较多,而多分支流水线的Jenkins配置非常少,只需要编写好Jenkinsfile,然后告诉Jenkins去哪里找Jenkinsfile文件即可,这也就体现出流水线任务的优势,不用过多去关注Jenkins的插件、系统设置、配置等,只需要根据需求编写Jenkinsfile即可,后续修改也很好找修改点。

  • 在内容上按 单前、后端的简单项目、前后端分离项目 最后到 微服务项目的项目设计,由浅入深通过Jenkins完成不同项目的CICD,已适配较多互联网公司的自动化发布任务。

  • 在自动化发布上:后续将设计编写K8s集群整合Jenkins、Gitlab CI/CD、Gitlab Runner以及Argo CD等更多CICD工具完成不同项目的自动化发布。

  • 在制品保存、链路追踪上:后续将搭建加入nexus的maven私有仓库、skywalking全链路追踪,进一步为项目高并发能力的提升作支持

  • 在日志收集分析、监控告警上:将搭建ELK日志处理、Prometheus+kibana监控告警一体化平台,保障项目高可用与问题的告警及时处理

  • 对于文档内容、设计以及后续文档有任何建议或意见欢迎交流:

    • 裴东青:956143827@qq.com

http://www.jsqmd.com/news/861808/

相关文章:

  • 模型加速全景图:从“瘦身”到“飞驰”的知识图谱
  • 2026年比较好的昆明防锈栏杆品牌厂家推荐 - 品牌宣传支持者
  • 企业部署AI Agent的五大核心挑战
  • 关于在全志v3s驱动gc0308摄像头模块的过程
  • 蒙特卡罗算法驱动的医用重离子加速器束流配送系统与治疗计划方法【附仿真】
  • 全网首份ElevenLabs维吾尔语语音数据集泄露分析:172小时采样音频特征、性别/年龄/地域分布、及3种脱敏失败风险(限时公开72小时)
  • 2026年院线抗氧化产品TOP5排行:泡泡漾套盒/泡泡漾抗衰仪器/泡泡漾抗衰套盒/泡泡漾效果/泡泡漾项目/留客神器产品/选择指南 - 优质品牌商家
  • ChromeKeePass实战:如何让浏览器与KeePass实现无缝密码填充
  • 使用 Taotoken 后 API 调用延迟与成功率可观测性体验分享
  • 2026年浙江老房装修公司TOP5推荐:浙江旧改招商加盟/浙江老房局部改造招商加盟/浙江老房翻新招商加盟/浙江老房装修/选择指南 - 优质品牌商家
  • 2026年Q2酒水招商加盟品牌排行:轻资产创业项目、酒水代理加盟、鲜啤招商加盟、个人投资项目、啤酒区域代理、夏季暴利小生意选择指南 - 优质品牌商家
  • AI成本优化三剑客:Token缓存预算全解析
  • 针刺仪微损测定估计活立木年龄融合的算法【附算法】
  • Unity SLG框架解析:Clash Engine六维系统架构与工程实践
  • 如何永久免费使用IDM?终极完整激活指南
  • 信创适配国产化选型方案
  • 2026年Q2大连红酒回收:冬虫夏草回收/剑南春回收/国酒茅台回收/大连名酒回收/大连茅台酒回收/水井坊回收/洋酒回收/选择指南 - 优质品牌商家
  • 2026年合肥第三方检测机构靠谱排行:合肥化学品检测/合肥化学品第三方检测/合肥医疗器械检测/合肥医疗器械第三方检测/选择指南 - 优质品牌商家
  • java springboot-vue社区资源共享系统 社区活动报名系统
  • UE5.2 DynamicMesh崩溃与渲染异常六大根因解析
  • 产业园区如何推动科技成果转化落地?
  • Spring AI + Flowable 工作流深度整合
  • 整合素ITGAL
  • 2026 年塑胶地板服务商:医疗教育专业推荐
  • 小白螺AI制片厂实测:3个技巧搞定一键生成高质量漫剧
  • 含铜高熵合金(CuZrAlNiTi)成分、科研制备与应用
  • 深度解析:光引擎、光模块、光器件之间的关系和区别?
  • Flutter 3.44 发布啦,超级大版本更新!!!
  • 人工智能在科学领域需要设立防护措施,避免对它不加批判地采用
  • Vivado 全局启动脚本 (Vivado_init.tcl) 极简配置教程