ruoyi-vue-pro 开发指南 ruoyi-vue-pro 开发指南
  • 萌新必读
  • 后端手册
  • 中间件手册
  • 工作流手册
  • 报表与大屏手册
  • 支付手册
  • 会员手册
  • 商城手册
  • ERP 手册
  • CRM 手册
  • MES 手册
  • WMS 手册
  • HRM 手册
  • FMS 手册
  • PMS 手册
  • OA 手册
  • IM 即时通讯手册
  • AI 大模型手册
  • IoT 物联网手册
  • 公众号手册
  • 系统手册
  • 运维手册
  • 前端手册 Vue 3.x
  • 前端手册 Vben 5.x
  • 前端手册 Vue 2.x
  • 前端手册 Admin Uniapp
  • 工作流手册
  • 报表与大屏手册
  • 支付手册
  • 会员手册
  • 商城手册
  • ERP 手册
  • CRM 手册
  • MES 手册
  • WMS 手册
  • HRM 手册
  • FMS 手册
  • PMS 手册
  • OA 手册
  • IM 即时通讯手册
  • AI 大模型手册
  • IoT 物联网手册
  • 公众号手册
  • 系统手册
视频教程
  • Vue3 + element-plus (opens new window)
  • Vue3 + vben5(ant-design-vue、element-plus) (opens new window)
  • Vue2 + element-ui (opens new window)
微服务版 (opens new window)
作者博客 (opens new window)
GitHub (opens new window)
  • 萌新必读
  • 后端手册
  • 中间件手册
  • 工作流手册
  • 报表与大屏手册
  • 支付手册
  • 会员手册
  • 商城手册
  • ERP 手册
  • CRM 手册
  • MES 手册
  • WMS 手册
  • HRM 手册
  • FMS 手册
  • PMS 手册
  • OA 手册
  • IM 即时通讯手册
  • AI 大模型手册
  • IoT 物联网手册
  • 公众号手册
  • 系统手册
  • 运维手册
  • 前端手册 Vue 3.x
  • 前端手册 Vben 5.x
  • 前端手册 Vue 2.x
  • 前端手册 Admin Uniapp
  • 工作流手册
  • 报表与大屏手册
  • 支付手册
  • 会员手册
  • 商城手册
  • ERP 手册
  • CRM 手册
  • MES 手册
  • WMS 手册
  • HRM 手册
  • FMS 手册
  • PMS 手册
  • OA 手册
  • IM 即时通讯手册
  • AI 大模型手册
  • IoT 物联网手册
  • 公众号手册
  • 系统手册
视频教程
  • Vue3 + element-plus (opens new window)
  • Vue3 + vben5(ant-design-vue、element-plus) (opens new window)
  • Vue2 + element-ui (opens new window)
微服务版 (opens new window)
作者博客 (opens new window)
GitHub (opens new window)
  • 萌新必读

    • 简介
    • 交流群
    • 视频教程
    • 功能列表
    • 快速启动(后端项目)
    • 快速启动(前端项目)
    • 接口文档
    • 技术选型
    • 项目结构
    • 代码热加载
    • 一键改包
    • 迁移模块(适合新项目)
    • 删除功能(以租户为例)
    • 表结构变更(版本升级)
    • 国产信创数据库(DM 达梦、大金、OpenGauss、瀚高、OceanBase、TiDB、GaussDB、PolarDB、神通、Vastbase、MogDB、TongRDS、CacheDB)
    • 如何去除 Redis 缓存
    • 面试题、简历模版、简历优化
    • 项目外包
    • 文档 MCP
  • 后端手册

    • 新建模块
    • 代码生成【单表】(新增功能)
    • 代码生成【主子表】
    • 代码生成(树表)
    • 代码生成(移动端)
    • 功能权限
    • 数据权限
    • 用户体系
    • 三方登录
    • OAuth 2.0(SSO 单点登录)
    • SaaS 多租户【字段隔离】
    • SaaS 多租户【数据库隔离】
    • WebSocket 实时通信
    • 异常处理(错误码)
    • 参数校验、时间传参
    • 分页实现
    • VO 对象转换、数据翻译
    • 文件存储(上传下载)
    • Excel 导入导出
    • 操作日志、访问日志、异常日志
    • MyBatis 数据库
    • MyBatis 联表&分页查询
    • 多数据源(读写分离)、事务
    • Redis 缓存
    • 本地缓存
    • 异步任务
    • 分布式锁
    • 幂等性(防重复提交)
    • 请求限流(RateLimiter)
    • HTTP 接口签名(防篡改)
    • HTTP 接口加解密
    • 单元测试
    • 验证码
    • 工具类 Util
    • 配置管理
    • 数据库文档
  • 中间件手册

    • 定时任务
    • 消息队列(内存)
    • 消息队列(Redis)
    • 消息队列(RocketMQ)
    • 消息队列(RabbitMQ)
    • 消息队列(Kafka)
    • 限流熔断
    • 分库分表
    • 分布式事务
  • 工作流手册

    • 工作流演示
    • 功能开启
    • 工作流(达梦适配)
    • 审批接入(流程表单)
    • 审批接入(业务表单)
    • 流程设计器(BPMN)
    • 流程设计器(钉钉、飞书)
    • 选择审批人、发起人自选
    • 会签、或签、依次审批
    • 流程发起、取消、重新发起
    • 审批通过、不通过、驳回
    • 审批加签、减签
    • 审批转办、委派、抄送
    • 执行监听器、任务监听器
    • 流程表达式
    • 流程审批通知
    • 移动端审批
  • 报表与大屏手册

    • 功能总览
    • UReport2 报表
    • 积木报表与仪表盘
    • GoView 大屏
  • 支付手册

    • 功能开启
    • 支付宝支付接入
    • 微信公众号支付接入
    • 微信小程序支付接入
    • 支付宝、微信退款接入
    • 支付宝转账接入
    • 微信转账接入
    • 钱包充值、支付、退款
    • 模拟支付、退款
    • 移动端支付管理
  • 会员手册

    • 功能开启
    • 微信公众号登录
    • 微信小程序登录
    • 微信小程序订阅消息
    • 微信小程序码
    • 会员用户、标签、分组
    • 会员等级、积分、签到
    • 移动端会员管理
  • 商城手册

    • 商城演示
    • 功能开启
    • 商城装修
    • 在线客服
    • 【商品】商品分类
    • 【商品】商品属性
    • 【商品】商品 SPU 与 SKU
    • 【商品】商品评价
    • 【交易】购物车
    • 【交易】交易订单
    • 【交易】售后退款
    • 【交易】快递发货
    • 【交易】门店自提
    • 【交易】分销返佣
    • 【营销】优惠劵
    • 【营销】积分商城
    • 【营销】拼团活动
    • 【营销】秒杀活动
    • 【营销】砍价活动
    • 【营销】满减送活动
    • 【营销】限时折扣
    • 【营销】内容管理
    • 【统计】会员、商品、交易统计
    • 移动端商城管理
  • ERP手册

    • ERP 演示
    • 功能开启
    • 【产品】产品信息、分类、单位
    • 【库存】产品库存、库存明细
    • 【库存】其它入库、其它出库
    • 【库存】库存调拨、库存盘点
    • 【采购】采购订单、入库、退货
    • 【销售】销售订单、出库、退货
    • 【财务】采购付款、销售收款
    • 移动端 ERP
  • CRM手册

    • CRM 演示
    • 功能开启
    • 【线索】线索管理
    • 【客户】客户管理、公海客户
    • 【商机】商机管理、商机状态
    • 【合同】合同管理、合同提醒
    • 【回款】回款管理、回款计划
    • 【产品】产品管理、产品分类
    • 【通用】数据权限
    • 【通用】跟进记录、待办事项
    • 移动端 CRM
  • AI大模型手册

    • AI 大模型演示
    • 功能开启
    • AI 聊天对话
    • AI 绘画创作
    • AI 知识库(RAG)
    • AI 音乐创作
    • AI 写作助手
    • AI 思维导图
    • AI 工具(function calling)
    • AI 工作流
    • Dify 工作流
    • FastGPT 工作流
    • Coze 智能体
    • 推理模式(thinking)
    • 联网搜索
    • MCP Client 客户端
    • MCP Server 服务端
    • 请求日志与 Token 用量
    • 【模型接入】小米 MiMo
    • 【模型接入】Claude
    • 【模型接入】OpenAI
    • 【模型接入】通义千问
    • 【模型接入】DeepSeek
    • 【模型接入】字节豆包
    • 【模型接入】腾讯混元
    • 【模型接入】硅基流动
    • 【模型接入】MiniMax
    • 【模型接入】月之暗面
    • 【模型接入】百川智能
    • 【模型接入】文心一言
    • 【模型接入】LLAMA
    • 【模型接入】智谱 GLM
    • 【模型接入】讯飞星火
    • 【模型接入】微软 OpenAI
    • 【模型接入】谷歌 Gemini
    • 【模型接入】Stable Diffusion
    • 【模型接入】Midjourney
    • 【模型接入】Suno
    • 【模型接入】Grok
    • 【模型接入】阶跃星辰
    • 移动端 AI 大模型
  • IoT物联网手册

    • 功能开启
    • 产品管理
    • 设备管理
    • 物模型配置
    • 设备网关与子设备
    • 设备动态注册
    • 设备影子
    • 消息透传与数据解析
    • 设备接入(概述)
    • 设备接入(HTTP 协议)
    • 设备接入(MQTT 协议)
    • 设备接入(EMQX 协议)
    • 设备接入(TCP 协议)
    • 设备接入(UDP 协议)
    • 设备接入(WebSocket 协议)
    • 设备接入(CoAP 协议)
    • 设备接入(Modbus Client 模式)
    • 设备接入(Modbus Server 模式)
    • 设备接入(自定义协议)
    • 场景联动
    • 数据流转
    • 告警配置
    • OTA 固件升级
    • 移动端 IoT 物联网
    • 设备网关合并部署
  • MES手册

    • MES 演示
    • 功能开启
    • 【基础】物料产品、分类、计量单位
    • 【基础】客户管理、供应商管理
    • 【基础】车间设置、工作站设置
    • 【基础】编码规则
    • 【生产】工序设置、工艺流程
    • 【生产】生产工单
    • 【生产】生产排产、工序流转卡
    • 【生产】生产报工
    • 【生产】安灯配置、安灯呼叫
    • 【生产】工作记录
    • 【仓库】仓库与库区库位、条码赋码、SN码
    • 【仓库】批次管理、库存现有量、库存事务
    • 【仓库】到货通知、采购入库、采购退货
    • 【仓库】生产领料、生产退料、物料消耗
    • 【仓库】产品产出、产品入库
    • 【仓库】发货通知、销售出库、销售退货
    • 【仓库】外协发料、外协入库
    • 【仓库】其他入库、其他出库
    • 【仓库】调拨单、装箱管理
    • 【仓库】库存盘点
    • 【质量】检测项设置、常见缺陷
    • 【质量】质检方案
    • 【质量】来料检验(IQC)
    • 【质量】过程检验(IPQC)
    • 【质量】出货检验(OQC)
    • 【质量】退货检验(RQC)
    • 【质量】待检任务、检验结果、缺陷记录
    • 【设备】设备类型、设备台账
    • 【设备】点检保养项目、点检保养方案
    • 【设备】点检记录、保养记录、维修单
    • 【工具】工具类型、工装夹具台账
    • 【排班】班组设置、节假日设置
    • 【排班】排班计划、排班日历
    • 移动端 MES
  • WMS手册

    • WMS 演示
    • 功能开启
    • 【基础】仓库
    • 【基础】商品、SKU、分类、品牌
    • 【基础】往来企业(供应商、客户)
    • 【库存】库存记录、流水、统计
    • 【单据】入库
    • 【单据】出库
    • 【单据】移库
    • 【单据】盘库
    • 【其它】WMS、MES、ERP 对比
    • 移动端 WMS
  • HRM人力资源

    • HRM 演示
    • 功能开启
    • 【组织】工作台、组织架构
    • 【员工】员工管理
    • 【招聘】招聘管理
    • 【考勤】考勤管理
    • 【社保】社保管理
    • 【薪资】计薪设置、薪资档案
    • 【薪资】月度工资、工资条
    • 【绩效】绩效模板、绩效计划
    • 【绩效】绩效考核、绩效档案
    • 移动端 HRM
  • FMS财务管理

    • FMS 演示
    • 功能开启
    • 【设置】账套管理、财务参数、财务指标
    • 【设置】币别、科目、辅助核算、初始余额
    • 【设置】凭证字、常用摘要、凭证模板
    • 【凭证】凭证管理
    • 【账簿】账簿管理
    • 【报表】财务报表
    • 【结账】期末结账
    • 移动端 FMS
  • PMS项目管理

    • PMS 演示
    • 功能开启
    • 【项目中心】工作台与项目管理
    • 【项目中心】项目详情与迭代
    • 【项目中心】工作项与协作
    • 【知识中心】知识库管理
    • 【知识中心】文档与协作
    • 移动端 PMS
  • OA协同办公

    • OA 演示
    • 功能开启
    • 【协作】日程、任务、计划与汇报
    • 【协作】公告、讨论、通讯录与笔记
    • 【办公】企业邮箱
    • 【办公】企业云盘
    • 【行政】办公用品、用印管理
    • 【行政】会议室、车辆管理
    • 【流程】公文管理
    • 【流程】出差、费用报销
    • 【流程】考勤、请假、加班、转正与离职
    • 移动端 OA
  • IM即时通讯手册

    • IM 演示
    • 功能开启
    • 【好友】好友关系、好友申请
    • 【群聊】群组、群成员、入群申请
    • 【消息】私聊、群聊、频道消息
    • 【频道】频道、频道素材
    • 【内容】表情、敏感词
    • 【通话】语音通话、视频通话、共享屏幕
    • 【WebSocket】实时推送与离线消息
    • 移动端 IM 即时通讯
  • 公众号手册

    • 功能开启
    • 公众号接入
    • 公众号粉丝
    • 公众号标签
    • 公众号消息
    • 模版消息
    • 自动回复
    • 公众号菜单
    • 公众号素材
    • 公众号图文
    • 公众号统计
    • 移动端公众号管理
  • 系统手册

    • 短信配置
    • 邮件配置
    • 站内信配置
    • Webhook(钉钉、飞书、企微)
    • 数据脱敏、字段权限
    • 敏感词
    • 地区 & IP 库
  • 运维手册

    • 开发环境
    • Linux 部署
    • Docker 部署
    • Jenkins 部署
      • 1. 环境准备
        • 1.1 安装 Jenkins
        • 1.2 安装插件
        • 1.3 配置构建工具
        • 1.4 准备服务器
      • 2. 配置凭据
        • 2.1 SSH 私钥
        • 2.2 known_hosts
      • 3. 新建 Job
        • 3.1 构建参数
        • 3.2 固定配置
      • 4. 执行部署
        • 4.1 首次部署
        • 4.2 再次部署
        • 4.3 部署失败
      • 5. 验证
      • 6. 回滚
      • 7. 部署前端
        • 7.1 修改配置
        • 7.2 新增 Jenkinsfile
        • 7.3 新建 Job
      • 666. 更多说明
    • 宝塔部署
    • 1Panel 部署
    • Docker Compose 部署
    • Kubernetes 部署
    • HTTPS 证书
    • 服务监控
    • 生产环境安全
    • Tomcat WAR 部署
    • 东方通服务器部署(TongWeb、TongHttpServer)
    • 宝兰德服务器部署(BES AppServer)
    • 内网穿透
  • 前端手册 Vue 3.x

    • 开发规范
    • 菜单路由
    • Icon 图标
    • 字典数据
    • 系统组件
    • 通用方法
    • 配置读取
    • CRUD 组件
    • 国际化
    • IDE 调试
    • 代码格式化
  • 前端手册 Vben 5.x

    • 开发规范
    • 菜单路由
    • 图标、主题、国际化
    • 字典数据
    • 系统组件
    • 通用方法
    • 配置读取
    • IDE 调试
    • 代码格式化
  • 前端手册 Vue 2.x

    • 开发规范
    • 菜单路由
    • Icon 图标
    • 字典数据
    • 系统组件
    • 通用方法
    • 配置读取
  • 前端手册 Admin Uniapp

    • 开发规范
    • 菜单路由
    • 图标、主题、国际化
    • 字典数据
    • 系统组件
    • 通用方法
    • IDE 调试
    • 代码格式化
    • 运行发布
  • 更新日志

    • 【v2026-11】
    • 【v2026-10】
    • 【v2026-09】
    • 【v2026-08】
    • 【v2026-07】
    • 【v2026-06】
    • 【v2026-05】
    • 【v2026-04】
    • 【v2026-03】
    • 【v2026-01】
    • 【v2025-12】
    • 【v2025-11】
    • 【v2025-10】
    • 【v2025-09】
    • 【v2025-08】
  • 开发指南
  • 运维手册
芋道源码
2022-04-15
目录

Jenkins 部署

本小节,讲解如何使用项目自带的 script/jenkins/Jenkinsfile (opens new window),通过 Jenkins Pipeline 将后端打包成 Jar 包,再使用 SSH 部署到一台 Linux 服务器上。整体流程如下:

Git 仓库(master-jdk17 分支)
    │ ① checkout scm 拉取代码
    ↓
Jenkins Pipeline
    │ ② mvn package 打包出 yudao-server.jar(JDK 17),并归档到 Jenkins
    │ ③ ssh 检查服务器 => scp 上传 Jar 包 => ssh 备份、停止、替换、启动,并检查启动结果
    ↓
Linux 服务器的 /work/projects/yudao-server 目录
    ├── yudao-server.jar        # 正在运行的 Jar 包
    ├── app.env                 # 运行时配置(数据库、Redis 的地址与密码),只保存在服务器上
    ├── backup/                 # 每次部署前的备份,保留最近 5 个
    ├── upload/                 # 上传中的新 Jar 包
    └── nohup.out               # 控制台日志

注意:服务器的 IP 地址。

  • 外网 IP:139.9.196.247

下属所有涉及到 IP 的配置,需要替换成你自己的。

友情提示:

  • 本文部署出来的结果,和 《Linux 部署》 一样,都是 java -jar + Nginx 的方式,只是把“编译、上传、重启”交给 Jenkins 自动完成。
  • 前端使用独立的 Jenkins Job 部署,见「7. 部署前端」小节。
  • 如果希望使用 Docker 部署,可参考 《Docker Compose 部署》 文档。

注意:目前只有 `master-jdk17` 分支提供本文使用的 `script/jenkins/Jenkinsfile`!

其它分支的 script/jenkins 目录尚未同步,请以对应分支的实际内容为准,不要直接套用本文。

# 1. 环境准备

# 1.1 安装 Jenkins

参考 Jenkins 官方的 《Installing Jenkins》 (opens new window) 文档,安装 LTS 版本的 Jenkins。需要特别注意 Java 版本:

用途 Java 版本 说明
运行 Jenkins 本身(Controller、Agent) 21 或 25 Jenkins 已经不再支持 Java 17,使用不支持的 Java 版本,Jenkins 无法启动
编译项目(Jenkinsfile 中的 mvn 命令) 17 与 Jenkins 自身的 Java 版本无关,在「1.3 配置构建工具」中单独指定

具体可见 Jenkins 官方的 《Java Support Policy》 (opens new window) 文档。

注意:请使用「Pipeline(流水线)」类型的 Job,不要使用「构建一个 Maven 项目」(Maven Integration 插件)类型!

Maven Integration 插件可能要求编译使用的 JDK 不低于 Jenkins 自身的 Java 版本(21 或 25),与项目的 JDK 17 冲突。本文在 Pipeline 的 sh 步骤中直接执行 mvn 命令,没有这个限制。

# 1.2 安装插件

在 [Manage Jenkins -> Plugins] 菜单中,确认已经安装如下插件:

插件 用途
Pipeline (opens new window) 执行 Jenkinsfile
Git (opens new window) 拉取代码
Credentials Binding (opens new window) 读取 known_hosts 文件凭据
SSH Agent (opens new window) 使用 SSH 私钥凭据,执行 ssh、scp 命令

前 3 个属于安装 Jenkins 时的“推荐插件”,一般已经安装;SSH Agent 插件需要手动安装。

# 1.3 配置构建工具

在 [Manage Jenkins -> Tools] 菜单中,新增如下两个工具,名字必须与 Jenkinsfile 中 tools 的配置一致:

类型 名字 说明
JDK jdk17 JDK 17 的安装目录,即 JAVA_HOME
Maven maven3 Maven 3.9.x 的安装目录

执行构建的机器(Jenkins 内置节点或 Agent),需要是 Linux 系统,并安装 git,以及 ssh、scp、ssh-agent 命令(一般在 openssh-clients 或 openssh-client 软件包中)。生产环境建议使用独立的 Agent 执行构建,而不是 Jenkins 内置节点。

# 1.4 准备服务器

① 参考 《Linux 部署》 的「1. 环境准备」小节,安装 MySQL、Redis、Nginx,并导入 sql/mysql/ruoyi-vue-pro.sql 脚本。另外:

  • 还需要导入 sql/mysql/quartz.sql 脚本:application-dev.yaml 开启了 Quartz 定时任务,并使用数据库存储,缺少 QRTZ_ 开头的表时,后端会启动失败。
  • JDK 需要 17 或以上的版本,例如说执行 yum install -y java-17-openjdk 命令安装,而不是《Linux 部署》中的 JDK 8。
  • 需要有 bash、curl、pgrep、ss 命令,大部分 Linux 发行版默认自带。其中,ss 用于检查本机所有地址上的端口监听情况,没有时,CentOS / RHEL 执行 yum install -y iproute,Debian / Ubuntu 执行 apt-get install -y iproute2 安装。部署脚本还会读取 /proc/<进程号>/cmdline 识别进程,所以只支持 Linux 服务器。

② 执行如下命令,创建部署目录与运行时配置 app.env:

mkdir -p /work/projects/yudao-server
vi /work/projects/yudao-server/app.env
chmod 600 /work/projects/yudao-server/app.env

app.env 的内容如下,按照你的环境修改:

## 必填:Spring Profile,对应 Jar 包中的 application-dev.yaml
SPRING_PROFILES_ACTIVE=dev
## 可选:JVM 参数,不填时为 -Xms512m -Xmx512m
JAVA_OPTS='-Xms512m -Xmx512m'
## 可选:JDK 的安装目录,不填时使用 PATH 中的 java 命令
#JAVA_HOME=/usr/lib/jvm/jre-17

## MySQL:主库 master、从库 slave 都要设置,否则会使用 application-dev.yaml 中的地址
SPRING_DATASOURCE_DYNAMIC_DATASOURCE_MASTER_URL='jdbc:mysql://127.0.0.1:3306/ruoyi-vue-pro?useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true&rewriteBatchedStatements=true'
SPRING_DATASOURCE_DYNAMIC_DATASOURCE_MASTER_USERNAME=root
SPRING_DATASOURCE_DYNAMIC_DATASOURCE_MASTER_PASSWORD='请修改为你的密码'
SPRING_DATASOURCE_DYNAMIC_DATASOURCE_SLAVE_URL='jdbc:mysql://127.0.0.1:3306/ruoyi-vue-pro?useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true&rewriteBatchedStatements=true'
SPRING_DATASOURCE_DYNAMIC_DATASOURCE_SLAVE_USERNAME=root
SPRING_DATASOURCE_DYNAMIC_DATASOURCE_SLAVE_PASSWORD='请修改为你的密码'

## Redis:Redis 库索引沿用 application-dev.yaml 中的 1
SPRING_DATA_REDIS_HOST=127.0.0.1
SPRING_DATA_REDIS_PORT=6379
## Redis 设置了密码时,才取消下面这行的注释,并填写真实的密码。Redis 没有密码时,不要保留空值,否则会以空密码执行 AUTH,导致连接失败
#SPRING_DATA_REDIS_PASSWORD='请修改为你的密码'
  • 部署时,会以 set -a; . app.env; set +a 的方式加载它,所以只能写 KEY=VALUE 格式;值包含 &、空格等特殊字符时,使用单引号包裹。
  • 这些环境变量,会覆盖 Jar 包中 application-dev.yaml 的同名配置,例如说 SPRING_DATA_REDIS_HOST 对应 spring.data.redis.host。所以不需要为了修改地址、密码而修改源码。其它配置项同理,例如说 YUDAO_CAPTCHA_ENABLE=false 关闭登录验证码。
  • 如需修改后端端口,增加 SERVER_PORT=xxx 即可,启动检查也会使用它。
  • app.env 只保存在服务器上,不要提交到 Git 仓库,也不要放到 Jenkins 中。

③ 建议使用专用的部署用户(例如说 yudao),而不是 root。此时,需要执行 chown -R yudao:yudao /work/projects/yudao-server 命令,保证该用户对部署目录有读写权限。

# 2. 配置凭据

在 [Manage Jenkins -> Credentials] 菜单中,新建如下两个凭据。它们的 ID,需要与 Jenkinsfile 中的 SSH_CREDENTIAL_ID、KNOWN_HOSTS_CREDENTIAL_ID 一致。

# 2.1 SSH 私钥

① 在一台可信的机器上,执行如下命令,生成专门用于部署的密钥对:

ssh-keygen -t ed25519 -C jenkins-deploy -f ./jenkins-deploy

② 将公钥 jenkins-deploy.pub 的内容,追加到服务器上部署用户的 ~/.ssh/authorized_keys 文件中。

③ 在 Jenkins 中新建凭据:

  • Kind:SSH Username with private key
  • ID:yudao-deploy-ssh
  • Username:部署用户,例如说 root。仅作为说明,实际登录的用户以构建参数 DEPLOY_USER 为准
  • Private Key:选择 [Enter directly],粘贴私钥 jenkins-deploy 的内容。生成密钥时设置了密码的话,填写 Passphrase

④ 导入完成后,删除本地的私钥文件。

# 2.2 known_hosts

Jenkinsfile 使用 StrictHostKeyChecking=yes 连接服务器,只信任这个凭据中记录的服务器公钥,从而避免连接到伪造的服务器。

① 在 Jenkins 所在的机器上,执行如下命令,获取服务器的公钥,并查看它的指纹:

## SSH 端口不是 22 时,需要修改 -p 参数
ssh-keyscan -p 22 -t ed25519 139.9.196.247 > known_hosts
ssh-keygen -lf known_hosts

② 通过云厂商的控制台等可信方式登录服务器,执行如下命令,查看服务器真实的公钥指纹:

ssh-keygen -lf /etc/ssh/ssh_host_ed25519_key.pub

③ 确认两个 SHA256:xxx 指纹完全一致后,在 Jenkins 中新建凭据:

  • Kind:Secret file
  • ID:yudao-deploy-known-hosts
  • File:上传第 ① 步生成的 known_hosts 文件

注意:不要使用 `StrictHostKeyChecking=no` 跳过服务器公钥的校验!

ssh-keyscan 不会校验获取到的公钥是否可信,所以一定要执行第 ② 步比对指纹。

服务器重装系统、更换 SSH 主机密钥后,部署会报 Host key verification failed. 错误,需要重新执行上述步骤,更新凭据。部署到多台服务器时,把它们的 ssh-keyscan 结果合并到同一个 known_hosts 文件即可。

友情提示:

能修改 Jenkinsfile 的人,就能使用这两个凭据登录服务器。请限制 Git 仓库的写权限,以及 Jenkins 中 Job 的配置权限。

# 3. 新建 Job

① 在 Jenkins 首页,点击 [New Item] 按钮,名字填写 yudao-server(不要包含空格),类型选择 [Pipeline]。

② 在 [Pipeline] 部分,填写如下配置,然后保存:

配置项 值
Definition Pipeline script from SCM
SCM Git
Repository URL 你的后端仓库地址,例如说 https://github.com/YunaiV/ruoyi-vue-pro.git。私有仓库需要选择 Credentials
Branch Specifier */master-jdk17
Script Path script/jenkins/Jenkinsfile

③ 点击 [Build Now] 按钮,执行一次构建。第一次构建会在「检查参数」阶段失败,提示 DEPLOY_HOST 必填,这是正常的:Jenkins 需要先执行一次 Jenkinsfile,才能读取到其中的参数定义。之后,[Build Now] 按钮会变成 [Build with Parameters]。

# 3.1 构建参数

参数 默认值 说明
DEPLOY_HOST 空 必填,服务器的 IPv4 地址或域名,例如说 139.9.196.247
DEPLOY_USER root SSH 登录的用户
DEPLOY_SSH_PORT 22 SSH 端口
DEPLOY_BASE_DIR /work/projects 部署根目录,实际部署到 /work/projects/yudao-server

参数会拼接到 ssh、scp 命令中,所以「检查参数」阶段会严格校验格式,不允许包含空格、引号、; 等字符,避免命令注入。

# 3.2 固定配置

如下配置写在 Jenkinsfile 中,如需修改,修改 Jenkinsfile 后提交到 Git 仓库即可:

配置 值 说明
APP_NAME yudao-server 服务器上的目录名、Jar 包名
APP_MODULE yudao-server Maven 模块
APP_JAR yudao-server/target/yudao-server.jar 打包出的 Jar 包
APP_PORT 48080 启动检查使用的端口。app.env 中设置了 SERVER_PORT 时,以它为准
SSH_CREDENTIAL_ID yudao-deploy-ssh 见「2.1 SSH 私钥」
KNOWN_HOSTS_CREDENTIAL_ID yudao-deploy-known-hosts 见「2.2 known_hosts」
tools jdk17、maven3 见「1.3 配置构建工具」
stop_timeout、start_timeout、backup_keep 60、180、5 在 REMOTE_SCRIPT 的开头:停止的最长等待秒数、启动检查的最长等待秒数、保留的备份个数

# 4. 执行部署

点击 [Build with Parameters] 按钮,填写 DEPLOY_HOST 等参数,再点击 [Build] 按钮。Pipeline 会依次执行如下阶段:

阶段 说明
拉取代码 执行 checkout scm,拉取 Job 中配置的仓库与分支
检查参数 校验构建参数的格式
编译 执行 mvn -B -ntp clean package -pl yudao-server -am -Dmaven.test.skip=true 命令,只编译 yudao-server 及其依赖的模块
归档 将 yudao-server.jar 归档到 Jenkins,保留最近 5 次构建的 Jar 包
部署 通过 SSH 部署到服务器,见下文

「部署」阶段,会依次执行:

  • ① 检查服务器:部署目录、app.env、Java、curl、pgrep 是否就绪,并创建 upload、backup 目录。如果 yudao-server 没有运行,但 48080 端口已经被其它进程占用,直接失败。
  • ② 上传:使用 scp 命令,将 Jar 包上传到 upload/yudao-server.jar。
  • ③ 部署:备份当前的 Jar 包到 backup 目录 => kill -15 停止旧进程(60 秒未停止时 kill -9),确认进程已经退出 => 确认端口已经空闲 => 替换 Jar 包 => 加载 app.env 后,使用 nohup java -jar 启动 => 启动检查。

① 和 ③ 在服务器上执行的脚本,直接写在 Jenkinsfile 的 REMOTE_SCRIPT 变量中,每次部署时,通过 ssh ... bash -s 传给服务器执行,所以服务器上不需要额外放置 deploy.sh 脚本。

疑问:旧进程是怎么找到的?

只停止 java 进程中,-jar 后面的参数与 /work/projects/yudao-server/yudao-server.jar 完全一致的进程:逐个比较 /proc/<进程号>/cmdline 中的参数,而不是使用 pgrep -f 的正则匹配,所以不会误停同目录下其它 Jar 包的进程。

进程在 kill -9 后仍然没有退出时(例如说属于其它用户,没有权限停止),部署会直接失败,不会替换 Jar 包。

疑问:启动检查是怎么判断的?

在启动新进程之前,先使用 ss 确认端口在本机所有地址上都没有被任何进程监听,避免把其它进程的响应误认为启动成功。启动后,在 180 秒内,新进程没有退出,并且 http://127.0.0.1:48080/ 返回了 HTTP 状态码(小于 500),就认为启动完成。

项目默认没有引入 spring-boot-starter-actuator 依赖,所以没有使用 /actuator/health 接口。它只能说明服务已经启动、端口可以访问,不代表业务健康,业务是否正常,还需要参考「5. 验证」小节。

疑问:-Dmaven.test.skip=true 是什么意思?

跳过单元测试的执行。如果你项目的单元测试写的不错,可以修改 Jenkinsfile,去掉该参数,保证交付的质量。

# 4.1 首次部署

首次部署时,服务器上还没有 Jar 包,不需要备份和停止。日志如下(Java 版本以实际为准):

[check] Java:openjdk version "17.0.12" 2024-07-16
[check] Profile:dev,端口:48080
[check] 首次部署:/work/projects/yudao-server/yudao-server.jar 不存在,无需备份
[backup] 首次部署,无需备份
[stop] yudao-server 未运行,无需停止
[start] 启动 /work/projects/yudao-server/yudao-server.jar,Profile:dev
[start] 进程号:12345
[start] http://127.0.0.1:48080/ 已响应,启动完成
[deploy] 部署成功:yudao-server

如果之前按照 《Linux 部署》 在 /work/projects/yudao-server 目录启动过 yudao-server.jar,并且启动命令中使用的是 -jar /work/projects/yudao-server/yudao-server.jar 这个完整路径,Jenkins 会找到并停止它。注意,部署用户需要有权限停止该进程。

# 4.2 再次部署

再次部署时,会先备份当前的 Jar 包,再停止旧进程。日志如下:

[check] 已存在 /work/projects/yudao-server/yudao-server.jar,部署前会先备份
[backup] 已备份到 /work/projects/yudao-server/backup/yudao-server-20261025103000.jar
[stop] 停止进程:12345
[stop] 已停止
[start] 启动 /work/projects/yudao-server/yudao-server.jar,Profile:dev
[start] 进程号:12346
[start] http://127.0.0.1:48080/ 已响应,启动完成
[deploy] 部署成功:yudao-server

部署成功后,backup 目录只保留最近 5 个备份(按文件名中的时间戳判断新旧)。旧备份没有权限删除时,会输出警告并继续,此时备份可能超过 5 个,需要检查权限后手动清理。

# 4.3 部署失败

任一步骤失败时,构建会被标记为失败。常见的错误如下:

日志 原因与解决
DEPLOY_HOST 必填,只能是 IPv4 地址或域名 构建参数没有填写,或者格式不正确
does not have an install of "jdk17" 没有完成「1.3 配置构建工具」,或者名字不一致
找不到 yudao-deploy-ssh、yudao-deploy-known-hosts 凭据 没有完成「2. 配置凭据」,或者 ID 不一致
Host key verification failed. known_hosts 中没有该服务器(注意 IP 与端口,要和 DEPLOY_HOST、DEPLOY_SSH_PORT 一致),或者服务器公钥发生了变化。按照「2.2 known_hosts」重新生成
Permission denied (publickey...) 公钥没有加入 DEPLOY_USER 用户的 ~/.ssh/authorized_keys 文件
[deploy] 失败:目录 ... 不存在、[deploy] 失败:缺少运行时配置 .../app.env 首次部署前,没有完成「1.4 准备服务器」
[deploy] 失败:找不到 Java:java 服务器 PATH 中没有 java 命令,在 app.env 中设置 JAVA_HOME 即可
[deploy] 失败:端口 48080 已被其它进程占用、[deploy] 失败:停止 yudao-server 后,端口 48080 仍被其它进程占用 有其它进程监听该端口,此时新 Jar 包没有被替换。注意,第二种情况下,旧的 yudao-server 进程已经被停止(例如说 app.env 中修改了 SERVER_PORT,而新端口被占用),并且不会自动恢复。执行 ss -ltnp 找到并处理占用端口的进程(或者改回 SERVER_PORT)后,重新构建;也可以先执行「6. 回滚」代码块开头的 cd 与 JAR=... 两行,再执行第 ④、⑥、⑦ 步,手动启动当前的 Jar 包
[deploy] 失败:进程 ... 无法停止 旧进程在 kill -9 后仍然存在,常见原因是它属于其它用户,此时 Jar 包没有被替换。使用该进程所属的用户停止它后,重新构建
[start] 进程已退出、[start] 等待 180 秒后,... 仍未响应 后面会打印 nohup.out 的最后 100 行,常见原因是数据库、Redis 的地址或密码错误,内存不足等。修改 app.env 后,重新构建即可

注意:部署中途失败时,旧版本可能已经被停止!

「停止后端口仍被占用」与「启动检查失败」这两种失败,发生在旧进程停止之后,服务会中断。Jenkins 不会自动回滚,也不会自动恢复旧进程:

  • 停止后端口仍被占用:新 Jar 包没有被替换。处理端口占用后重新构建,或者手动启动当前的 Jar 包即可。
  • 启动检查失败:新 Jar 包已经替换,日志中会打印备份 Jar 包的路径。由你确认原因后,参考「6. 回滚」小节手动回滚。

# 5. 验证

① 在服务器上,执行如下命令,确认后端可以访问:

curl http://127.0.0.1:48080/admin-api/

返回 {"code":401,"data":null,"msg":"账号未登录"} 即可。

② 执行如下命令,验证 后端 => MySQL 正常,并且 SQL 已经初始化:

curl -G --data-urlencode "name=芋道源码" http://127.0.0.1:48080/admin-api/system/tenant/get-id-by-name

返回 {"code":0,"data":1,"msg":""},说明从数据库中查询到了默认租户。

③ 参考 《Linux 部署》 的「4. 配置 Nginx 转发」小节,配置 Nginx。只需要配置一次,Jenkins 部署不会修改 Nginx 的配置。

④ 部署前端后(见「7. 部署前端」小节),请求 http://139.9.196.247 (opens new window) 地址(“需要换成你的外网 IP”),使用默认账号 admin、密码 admin123 登录。

⑤ 查看日志:

tail -f /work/projects/yudao-server/nohup.out  ## 控制台日志
tail -f ~/logs/yudao-server.log                ## 应用日志文件,位于部署用户的 home 目录下

# 6. 回滚

在服务器上,使用 bash 执行如下命令,回滚到某个备份的 Jar 包:

cd /work/projects/yudao-server
JAR=/work/projects/yudao-server/yudao-server.jar

## ① 查看备份,选择要回滚的版本。文件名中的时间戳就是备份的时间(文件的修改时间是原 Jar 包的时间,不要以它为准)
ls -1 backup/

## ② 找到 java 进程中,-jar 后面的参数与 Jar 路径完全一致的进程,并确认输出的进程号
PIDS=$(for p in $(pgrep -x java); do tr '\0' '\n' < /proc/$p/cmdline 2> /dev/null | grep -A1 -xF -- -jar | grep -qxF -- "$JAR" && echo $p; done)
echo "$PIDS"

## ③ 停止这些进程,并等待它们退出。超过 60 秒仍未退出时,按 Ctrl+C 中断,执行 kill -9 $PIDS 后,再重新执行 for 循环
kill -15 $PIDS
for p in $PIDS; do while [ -e /proc/$p ]; do sleep 1; done; done

## ④ 确认端口已经空闲:它会列出本机所有地址上监听该端口的 TCP 套接字,只输出表头、没有 LISTEN 行时,才能继续。app.env 中设置了 SERVER_PORT 时,替换为该端口
ss -ltn 'sport = :48080'

## ⑤ 恢复备份的 Jar 包。文件名,需要换成第 ① 步选择的
cp -p backup/yudao-server-20261025103000.jar "$JAR"

## ⑥ 加载 app.env 后启动,与 Jenkins 的启动方式一致
(set -a; . ./app.env; set +a; nohup "${JAVA_HOME:+$JAVA_HOME/bin/}java" ${JAVA_OPTS:--Xms512m -Xmx512m} -jar "$JAR" > nohup.out 2>&1 < /dev/null &)

## ⑦ 查看启动日志
tail -f nohup.out
  • 第 ② 步没有输出进程号时,说明服务没有运行,跳过第 ③ 步即可。
  • 备份被清理时,也可以在 Jenkins 历史构建的 [Build Artifacts] 中,下载对应版本的 yudao-server.jar,上传到服务器的 backup 目录,并按照备份的格式命名,时间戳使用上传时的时间,例如说 /work/projects/yudao-server/backup/yudao-server-20261025120000.jar。不要直接覆盖正在运行的 yudao-server.jar。然后,从第 ② 步开始执行,第 ⑤ 步的源文件使用这个文件名。
  • 回滚只会替换 Jar 包,不会回滚数据库。如果新版本执行过升级 SQL,请先确认旧版本能否兼容。

# 7. 部署前端

前端与后端分开构建、分开部署:在 Jenkins 中为前端单独新建一个 Job,它的 Jenkinsfile 放在你自己的前端仓库中(后端仓库不包含前端代码)。最终,前端打包出的静态文件,部署到服务器的 /work/projects/yudao-ui-admin 目录,与 《Linux 部署》 一致。

# 7.1 修改配置

前端和后端通过同一个 Nginx 同源访问,所以“后端地址”要填写 Nginx 的访问地址(例如说 http://139.9.196.247),修改后提交到你的前端仓库:

前端项目 配置文件 修改的配置项 打包命令 => 产物目录
yudao-ui-admin-vue3 .env.prod VITE_BASE_URL='http://139.9.196.247',VITE_API_URL=/admin-api 保持不变 pnpm build:prod => dist-prod
yudao-ui-admin-vben(ant-design-vue) apps/web-antd/.env.production VITE_BASE_URL=http://139.9.196.247,VITE_GLOB_API_URL=/admin-api pnpm build:antd => apps/web-antd/dist
yudao-ui-admin-vben(element-plus) apps/web-ele/.env.production 同上 pnpm build:ele => apps/web-ele/dist
  • 前端的 VITE_APP_CAPTCHA_ENABLE,要与后端的验证码开关一致,默认都是 true。
  • 执行构建的机器,需要安装 Node.js 与 pnpm:
    • yudao-ui-admin-vue3:Node.js 20.19.0 及以上,pnpm 9(已验证 9.15.9)。虽然它 package.json 的 engines 写的是 pnpm 8.6.0 及以上,但 pnpm-lock.yaml 是 v9 格式,使用 pnpm 8 执行 pnpm install --frozen-lockfile 会报 ERR_PNPM_LOCKFILE_BREAKING_CHANGE 错误。
    • yudao-ui-admin-vben:Node.js 22.18.0+ 或 24.12.0+,pnpm 11 及以上(packageManager 为 pnpm@11.16.0)。
    • 可以执行 corepack enable、corepack prepare pnpm@9.15.9 --activate 命令:没有声明 packageManager 的 yudao-ui-admin-vue3 使用 pnpm 9.15.9;yudao-ui-admin-vben 会按照自己声明的 packageManager,使用 pnpm 11.16.0。

# 7.2 新增 Jenkinsfile

在你的前端仓库根目录下,新建 Jenkinsfile 文件,内容如下:

#!groovy
// 前端的 Jenkins 部署流水线:pnpm 打包,再通过 SSH 部署到 Nginx 的静态文件目录

// 在服务器上执行的脚本:解压到新目录 => 备份旧目录 => 切换到新目录
def REMOTE_SCRIPT = '''
set -euo pipefail
dir="$1"
backup="$dir-backup/$(date +%Y%m%d%H%M%S)"
[ ! -e "$backup" ] || { echo "[deploy] 失败:$backup 已存在,请稍后重试" >&2; exit 1; }
rm -rf "$dir.new"
mkdir "$dir.new"
tar -xzf "$dir.tar.gz" -C "$dir.new"
[ -f "$dir.new/index.html" ] || { echo "[deploy] 失败:产物中没有 index.html" >&2; exit 1; }
mkdir -p "$dir-backup"
if [ -d "$dir" ]; then
    mv "$dir" "$backup"
    echo "[backup] 已备份到 $backup"
else
    echo "[backup] 首次部署,无需备份"
fi
mv "$dir.new" "$dir"
rm -f "$dir.tar.gz"
# 只保留最近 5 个备份:目录名是时间戳,按名称排序(C 语言环境)即为时间顺序。不使用修改时间,因为 mv 会保留原目录的修改时间
LC_ALL=C
backups=("$dir-backup"/[0-9]*)
if [ -e "${backups[0]}" ]; then
    for ((i = 0; i < ${#backups[@]} - 5; i++)); do
        rm -rf -- "${backups[i]}" || echo "[backup] 警告:无法删除旧备份 ${backups[i]},请检查权限后手动清理" >&2
    done
fi
echo "[deploy] 部署成功:$dir"
'''

pipeline {

    agent any

    options {
        skipDefaultCheckout()
        disableConcurrentBuilds()
        timeout(time: 30, unit: 'MINUTES')
        buildDiscarder(logRotator(numToKeepStr: '20'))
    }

    parameters {
        string(name: 'DEPLOY_HOST', defaultValue: '', trim: true, description: '目标服务器的 IP 或域名(必填)')
        string(name: 'DEPLOY_USER', defaultValue: 'root', trim: true, description: 'SSH 登录用户')
        string(name: 'DEPLOY_SSH_PORT', defaultValue: '22', trim: true, description: 'SSH 端口')
        string(name: 'DEPLOY_DIR', defaultValue: '/work/projects/yudao-ui-admin', trim: true, description: '前端部署目录,与 Nginx 的 root 一致')
    }

    environment {
        // 打包命令与产物目录,见「7.1 修改配置」的表格。例如说 yudao-ui-admin-vben 为 build:antd、apps/web-antd/dist
        BUILD_SCRIPT = 'build:prod'
        DIST_DIR = 'dist-prod'
        // Jenkins 凭据 ID,与后端共用
        SSH_CREDENTIAL_ID = 'yudao-deploy-ssh'
        KNOWN_HOSTS_CREDENTIAL_ID = 'yudao-deploy-known-hosts'
    }

    stages {
        stage('拉取代码') {
            steps {
                checkout scm
            }
        }

        stage('检查参数') {
            steps {
                script {
                    // 参数会拼接到 ssh、scp 命令中,必须严格校验,避免命令注入
                    if (!(params.DEPLOY_HOST ?: '').matches('[A-Za-z0-9]([A-Za-z0-9.-]*[A-Za-z0-9])?')) {
                        error('DEPLOY_HOST 必填,只能是 IPv4 地址或域名')
                    }
                    if (!(params.DEPLOY_USER ?: '').matches('[a-z_][a-z0-9_-]{0,31}')) {
                        error('DEPLOY_USER 不合法,只能包含小写字母、数字、下划线、中划线')
                    }
                    def port = params.DEPLOY_SSH_PORT ?: ''
                    if (!port.matches('[0-9]{1,5}') || port.toInteger() < 1 || port.toInteger() > 65535) {
                        error('DEPLOY_SSH_PORT 必须是 1 ~ 65535 的数字')
                    }
                    def dir = params.DEPLOY_DIR ?: ''
                    if (!dir.matches('/[A-Za-z0-9._/-]*[A-Za-z0-9_-]') || dir.contains('..') || dir.contains('//')) {
                        error('DEPLOY_DIR 必须是绝对路径,只能包含字母、数字和 . _ - /,不能以 / 结尾')
                    }
                }
            }
        }

        stage('编译') {
            steps {
                sh 'node -v && pnpm -v'
                sh 'pnpm install --frozen-lockfile'
                sh 'pnpm run "$BUILD_SCRIPT"'
                sh 'test -f "$DIST_DIR/index.html"'
                sh 'tar -czf dist.tar.gz -C "$DIST_DIR" .'
            }
        }

        stage('部署') {
            steps {
                writeFile file: '.jenkins-remote-deploy.sh', text: REMOTE_SCRIPT
                withCredentials([file(credentialsId: env.KNOWN_HOSTS_CREDENTIAL_ID, variable: 'KNOWN_HOSTS_FILE')]) {
                    sshagent(credentials: [env.SSH_CREDENTIAL_ID]) {
                        sh '''
                            set -eu
                            case "$KNOWN_HOSTS_FILE" in
                                *[[:space:]]*) echo "known_hosts 文件路径不能包含空白字符,请修改 Job 名称" >&2; exit 1 ;;
                            esac
                            scp -P "$DEPLOY_SSH_PORT" -o BatchMode=yes -o ConnectTimeout=10 -o StrictHostKeyChecking=yes -o GlobalKnownHostsFile=/dev/null -o "UserKnownHostsFile=$KNOWN_HOSTS_FILE" dist.tar.gz "$DEPLOY_USER@$DEPLOY_HOST:$DEPLOY_DIR.tar.gz"
                            ssh -p "$DEPLOY_SSH_PORT" -o BatchMode=yes -o ConnectTimeout=10 -o StrictHostKeyChecking=yes -o GlobalKnownHostsFile=/dev/null -o "UserKnownHostsFile=$KNOWN_HOSTS_FILE" "$DEPLOY_USER@$DEPLOY_HOST" bash -s -- "$DEPLOY_DIR" < .jenkins-remote-deploy.sh
                        '''
                    }
                }
            }
        }
    }
}

如果使用的是 yudao-ui-admin-vben,把 BUILD_SCRIPT、DIST_DIR 修改为 build:antd、apps/web-antd/dist(或者 build:ele、apps/web-ele/dist)即可。

# 7.3 新建 Job

① 首次部署前,在服务器上执行 mkdir -p /work/projects 命令,保证部署目录的上级目录存在,并且部署用户有写权限。

② 在 Jenkins 中新建一个 [Pipeline] 类型的 Job,名字例如说 yudao-ui-admin。配置与「3. 新建 Job」相同,只是 Repository URL 填写你的前端仓库地址,Branch Specifier 填写前端的分支(例如说 */master),Script Path 填写 Jenkinsfile。

③ 与后端相同,第一次构建会失败,之后使用 [Build with Parameters] 构建。构建参数为 DEPLOY_HOST、DEPLOY_USER、DEPLOY_SSH_PORT,以及 DEPLOY_DIR(默认 /work/projects/yudao-ui-admin)。

部署成功后,旧的前端文件会备份到 /work/projects/yudao-ui-admin-backup 目录,只保留最近 5 个。旧备份没有权限删除时,会输出警告并继续,此时备份可能超过 5 个,需要检查权限后手动清理。回滚时,执行如下命令即可(目录名需要换成你要回滚的版本):

cd /work/projects
ls -1 yudao-ui-admin-backup/                                   ## 目录名就是备份的时间,选择要回滚的版本
mv yudao-ui-admin "yudao-ui-admin-failed-$(date +%Y%m%d%H%M%S)"
mv yudao-ui-admin-backup/20261025103000 yudao-ui-admin

# 666. 更多说明

① Jenkins Pipeline 的更多用法,可见 Jenkins 官方的 《Using a Jenkinsfile》 (opens new window)、《Pipeline Syntax》 (opens new window) 文档,以及 SSH Agent 插件 (opens new window) 的说明。

② 部署到多台服务器时,每台服务器各执行一次构建(修改 DEPLOY_HOST 参数)即可,Jenkinsfile 一次只部署一台服务器。

③ 如果 Jenkins 构建结束后,后端进程也跟着被停止,检查服务器 /etc/systemd/logind.conf 中的 KillUserProcesses 配置,或者对部署用户执行 loginctl enable-linger 命令。

④ 如果需要 HTTPS 访问,可参考 《HTTPS 证书》 文档。

Docker 部署
宝塔部署

← Docker 部署 宝塔部署→

Theme by Vdoing | Copyright © 2019-2026 芋道源码 | MIT License
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式
×