故障排查
按症状查原因。每条都来自实际踩过的坑,处理办法是当时验证过的做法。
排查纪律(先读这一条,能省一半时间)
第一站永远是「我的应用 → 应用任务」。 安装/升级/卸载的步骤与日志是边跑边落库的,失败原因(含服务端异常文本)就在那条任务记录里,比翻服务端日志快得多。细节见 任务中心与日志。
第二条纪律:验证目录远程调用时,不要一边用 curl 手工打对端。 否则对端访问日志里那几条 GET /app/catalog/... 是你自己打的,你会把「我打成功了」当成「调用方链路通了」的证据。这个坑真实踩过。另外 HTTP 200 不等于成功,远程目录曾经出现过「返回 200 但 body 是错误信封」。
启动与加载
| 现象 | 原因 | 处理 |
|---|---|---|
启动直接失败,最后一句是 Result Maps collection already contains value | plugins-dist 里同一应用有两个版本的 jar 并存,MyBatis 解析了两份同样的 mapper XML。loader.path 会把目录下所有 jar 都挂上去,它不选版本 | 跑 scripts\prune-plugins.ps1(只按 active-plugins.txt 删同 appCode 下非当前生效版本的 jar),再启动。用 scripts\start-host.ps1 会自动先 prune |
| 插件完全没加载(运行时只打一条醒目告警) | 只在 yml 里改了 app-market.plugin-runtime.enabled。启动加载器在 Spring 之前执行,读不到 yml —— 结果是「启动器让路、运行时又没开」 | 必须用 JVM 参数:-Dapp-market.plugin-runtime.enabled=false(要退回旧行为时);正常启用不要改 |
插件控制器启动即报 expected single matching bean but found 2 | 宿主上下文里注册了与插件实现同类型的 bean,Spring 按类型注入把父子上下文的候选一起算 | 宿主侧不要注册插件实现类型(哪怕是转发代理)。宿主拿插件服务只走 PluginServiceProvider SPI 或 XxxServiceLocator.proxy(...) |
| 改了代码但行为没变 | 只跑了 mvn compile —— 它不会更新 ruoyi-admin.jar;你启动的还是旧代码 | mvn -pl ruoyi-admin -am -B install -DskipTests,然后重启。确认 jar 是新的:模块类在 fat jar 里是嵌套的(BOOT-INF/lib/ruoyi-<模块>.jar),在顶层找 org/dromara/...class 永远找不到,嵌套条目的时间戳也不可靠 —— 要把嵌套 jar 抽出来看里面那个 class |
改了注解/常量后行为没变,但构建是 BUILD SUCCESS | maven-compiler-plugin 按时间戳判断是否重编;源码与上次的 class 落在同一秒内会被判定「已是最新」,装进本地仓库的还是旧注解 | 验证前先 -pl <模块> clean install;下结论前用 javap -v 看 jar 里那个 class |
正在运行的服务突然抛 NoClassDefFoundError | 有人在对正在跑的 JVM 上执行了 mvn install —— compiler 插件会先清空输出目录再全编,而运行中的 JVM 按需懒解析类 | 不要在别人正在跑的 JVM 上 mvn install。需要并行时改工作副本或先停服务 |
-Dloader.path=plugins-dist 在 PowerShell 里报 ClassNotFoundException: /path=plugins-dist
-D 参数必须加引号,否则 PowerShell 会把 .path 当路径拆开:
java "-Dloader.path=plugins-dist" "-Dspring.profiles.active=prod" -jar ruoyi-admin\target\ruoyi-admin.jar安装与升级
| 现象 | 原因 | 处理 |
|---|---|---|
| 安装报「jar 不存在,还没部署」或「jar 已经存在但不在运行时 classpath 上」 | 市场里该版本没上传安装包,或 package_url 为空 | 去上架端「应用管理 → 版本管理」上传并点部署。仅上传不部署时产物不会落位 |
| 安装报「应用版本不存在」 | 目录集中模式下目录服务不可达、或两端数据不一致;也可能是本地目录里确实没有可用版本 | 看任务日志的具体报错;到目录服务的访问日志里找 GET /app/catalog/version |
| 安装报「应用包未签名」 | app-market.security.mode=enforce 下的预期行为:包内没有 signature.txt | 打包时带 -SigningKey;历史版本走「就地重签」,见 密钥与签名 |
| 安装报「签名校验失败」/「签名与包内容不匹配」 | 有签名但校验不过:包被改过,或不是用服务端配置的公钥对应的私钥签的 | 重新打包并签名;若是换钥之后的老包,全部需要重签(旧钥签过的包都作废) |
安装报「应用包带签名,但服务端未配置 public-key」 | 没配公钥就切了 enforce —— 此时所有包都会被拒,包括你自己签的 | 配 app-market.security.public-key,重建宿主并重启(公钥是启动期读入的) |
| 上传时就被拒,报「应用包安全检查未通过(app-market.security.mode=enforce):…」 | enforce 下上传与下载两处都校验,上传这处只是尽早告知发布方 | 修包重传。注意部署未签名的包同样会被拒,且不会落位任何文件(校验在落位之前) |
| 安装卡在「执行版本迁移脚本」 | 某个 .sql 报错。MySQL 的 DDL 是隐式提交的,失败没法整体回滚,所以任务会停在失败态 | 看任务日志里那条脚本的错误文本;app_schema_history 里 success='0' 那行也能看到。不要改同一个文件名 —— 修好后换一个新脚本名重新打包发布 |
| 升级报「迁移脚本 X 的内容已被修改(摘要与首次执行时不一致)…请改用新的脚本名」 | 已执行过的脚本内容被改过。后端按 (app_code, script) 比对 SHA-256,不一致直接拒绝 | 新增一个脚本(幂等)承载这次变更。若是「把 01 里的种子数据拆出去」这类结构性改动,存量部署要先跑 script/sql/update/app_market_app_seed_split_repair.sql(幂等)再升级 |
升级报 Duplicate entry '000000-xxx-1.0.1' for key 'uk_schema_history' | app_schema_history 的唯一键不是 (app_code, script)。老 DDL 写的是 (tenant_id, app_code, version),一个版本里只要有第二个迁移脚本就撞键 | 执行 script/sql/update/app_market_schema_history_fix.sql(幂等:先去重、再删旧键、再建新键)。不只是升级,全新部署安装多脚本应用同样会炸 |
| 升级成功了但表没变 / 页面还是旧版 | 迁移脚本没打进包(静默漏打包),或升级没重新落位 | 检查 zip 里有没有 migrations/*.sql;确认打包时子目录里的 .sql 会被告警跳过(只扫顶层)。升级路径一定会重新从市场拉包落位,不会沿用旧产物 |
| 存量部署上点「安装」报「非法的应用状态迁移」或「当前已是该版本」 | 迁移脚本回填的安装实例状态是 enabled,而状态机里 enabled → installing 非法,升级到同一版本也会被拒 | 两条路:上架端点「版本管理 → 部署」,或发布一个更高版本再升级。给客户交付时直接发 1.0.1,让「升级」成为自然路径 |
| 装完应用,页面全报「表不存在」 | 建表脚本没随包走(客户那台只导入了平台初始化 SQL),或「彻底删除」后重装时迁移记录没清掉 | 把建表脚本补进 plugins/<插件>/migrations/;确认「彻底删除」会删 app_schema_history(这正是重装能重建表的前提) |
| 应用装好了但页面标签是空的、下拉没数据 | 该应用的字典没随包(sys_dict_type / sys_dict_data),或站点配置没随包(sys_config) | 应用包里应有 0N-create-<app>-dictionaries.sql / 0N-create-<app>-website-config.sql;老包要补发版本 |
| 手工执行了字典 SQL,接口还是旧值 | 字典与参数走 Redis 缓存 | 迁移脚本执行后平台会自动失效缓存;手工执行时要自己清(/system/dict/type/refreshCache 或界面「刷新缓存」) |
菜单
菜单类问题有一半的排查时间花在「这是两类完全不同的故障」上。先按下面这张表分流。
| 现象 | 原因 | 处理 |
|---|---|---|
控制台报 [permission] 菜单「XXX」的 component 解析不出来,已跳过该路由:…(一条菜单只报一次) —— 情况①:这条菜单在 app_version_menu 里没有任何归属 | 平台初始化 SQL 留下的孤儿菜单。菜单同步只处理清单声明过的菜单,永远修不到它 | 手工清(参考 script/sql/update/fix_dead_mall_finance_menus.sql)。判断依据:归属映射里查不到它 |
| 同上 —— 情况②:有归属,但指向的页面不存在 | 该应用清单里的 component 目标写错了,或本机产物是旧的(菜单同步只在安装/升级时跑,回填式的安装实例从没跑过) | 让该应用升级一次(升级顺带跑菜单同步),或执行 script/sql/update/fix_app_menu_component_remote.sql(幂等)。判断依据:归属映射里能查到它 |
| 分不清是①还是② | —— | 跑 npm run audit:menus -- <菜单导出 SQL 的结果>,一次看全(含当前用户看不到的菜单);脚本头部有导出 SQL |
控制台一片 [Vue Router warn]: Record with path "/im/workbench" is either missing a "component(s)" or "children" property | 菜单在、页面不在:库里那条菜单的 component 还是抽离前的宿主路径(im/workbench/index),而 .vue 已经搬进插件了 | 同上:执行那条修复 SQL,或让该应用升级一次。前端现在会把这类路由跳过并打一条指明菜单与 component 的 error |
| 菜单点得开,但页面「裸奔」:没有顶栏、没有侧边栏 | 应用清单里声明了 routes。path 与宿主菜单生成的路径相同,loader 会把清单里的路由注册成顶级路由(没有 Layout),抢先匹配 | 清单里不要声明 routes,只留 menus |
| 点菜单进去 403 | 菜单的 perms 与接口上的 @SaCheckPermission 不一致 | 对齐两处:菜单管理里的权限标识 vs 代码注解。漏写按钮权限的表现就是「菜单看得见但点进去 403」 |
| 表格里的「新增 / 折叠 / 删除」按钮变成纯文字 | 模板里的 K* 组件没进该前端工程的 HOST_SDK_COMPONENTS 白名单 → Vue 当它是未知自定义元素:不报错、不白屏,只剩插槽文字 | 补白名单(先确认它在宿主 SHARED_COMPONENTS 里)后重新构建,再跑 npm run check:remote |
| 装完一个菜单都没有 | 库里的归属映射指向已删除的菜单 ID(残留的死映射被菜单同步复用了) | 服务端日志里搜 菜单归属指向已不存在的菜单行 告警。菜单同步现在会自愈(丢掉死映射并按新菜单重建),源头修复见本页「卸载」一节那条 |
| 「重新同步菜单」跑完菜单变成两套(数量暴涨) | 归属映射表为空时,AppMenuPlanner 会把清单里每个菜单都当新建,插出第二套菜单树 | 用 script/sql/update/cleanup_duplicate_app_menus.sql(幂等)清理。兜底认领现在按结构(从根 path 逐层用 path/perms 匹配、一行只认领一次),不看 remark |
应用菜单受保护,改不了也删不掉是设计如此
path / component / perms / menuType / parentId 的修改与删除都会被服务端拒绝(不只是页面禁用按钮)。改名称/图标/排序/显隐是放行的;想隐藏请用「停用」。原理见 菜单归属与保护。
前端远程应用
先记住这条:远程应用是独立构建的 ESM,它继承宿主源码但不继承宿主的构建配置。宿主里靠构建期魔法生效的东西(自动导入、组件解析器、指令),插件必须逐项复刻,否则静默失效。
| 现象 | 原因 | 处理 |
|---|---|---|
| 菜单点开是「远程视图不可用: exam/settings(应用 exam 未安装或入口地址未配置)」 | 宿主不知道该去哪儿拿那份 ESM | 看 GET /app/runtime/remote-apps 有没有这个应用:应用没装/没启用 → 正常没有;有 entry 但请求 404 → 静态目录没部署到 /remote-apps/<code>/。浏览器控制台里那句 [app-market] 远程应用入口(后端): + Network 里的 entry 请求 |
控制台报 [app-market] 按需装载失败: social ReferenceError: process is not defined | 产物里残留 process.env。echarts(内置 zrender)与 vue-types 会在模块顶层读它,浏览器没有 process | 给该工程的 vite.config.ts 补 define: { 'process.env.NODE_ENV': JSON.stringify('production') },重新构建,再跑 npm run check:remote |
控制台报 [app-market] 按需装载失败: im ReferenceError: useStorage is not defined(随后 远程视图不可用) | 产物里混着宿主源码(@/store/**、@/utils/** 按别名原样打进产物),而该插件工程的 AutoImport 少了 @vueuse/core —— 宿主 src/utils/auth.ts 的 useStorage 靠自动导入注入,在产物里成了裸全局 | 把该工程的 imports 对齐宿主的 vite/plugins/auto-import.ts,重新构建,再跑 npm run check:globals |
SyntaxError: The requested module '@dromara/request' does not provide an export named 'globalHeaders' | 运行期垫片少一个具名导出。产物把 vue / element-plus / @dromara/* external 掉了,靠 import map 指到 app-market-dist/app-runtime/*.js,少一个名字浏览器在链接期整块报错 | @dromara/* 是虚拟说明符、只能静态声明,加具名导出要同时改两处:scripts/gen-runtime-shims.mjs 的 staticNames 与 src/plugins/appmarket/runtime.ts 里对应 slot。改完跑 npm run gen:runtime + npm run check:runtime |
| 升级后页面还是老样子 | 浏览器缓存了旧的远程应用产物 | 远程入口带 ?v=<版本号> 破缓存;确认前端确实调了 GET /app/runtime/remote-apps 而不是走了静态清单 |
打开 /remote-apps/xxx 是 404 | 该应用没有前端产物;纯后端应用本来就不会出现在 remote-apps 清单里 | 部署/安装对应应用;确认落位目录 app-market.deploy.frontend-dir/<code>/ 里有 index.js |
| 页面完全不打开,只有链接期报错 | 运行期垫片与产物 import 的名字对不上 | 跑 npm run check:runtime(拿产物真正 import 的名字和垫片导出对账,有缺口就非零退出) |
别在插件里写「薄垫片」绕 SDK
自己复刻一份 src/utils/request.ts 并 import { getToken } from '@/utils/auth',正是把宿主源码拉进产物的那条路径。@/utils/request 直接指向 @dromara/request 就行(它已具名导出 globalHeaders / download / isRelogin),并且要正则精确匹配,否则会连 @/utils/requestCache 一起吃进去。
目录与版本形态
| 现象 | 原因 | 处理 |
|---|---|---|
| 用户版里点「应用上架」→ 403 | 设计如此。用户版没有上架端:它的上架端写的是本地库,而安装读的是远端目录,放开会导致「上架成功但安装毫无影响」这种最坏的失败(看着成功、实际无效)。回 404 则会让人去查路由和网络,方向全错 | 不用处理。菜单侧也整棵隐藏,手打 /appconsole/** 会被前端守卫送回首页 |
用户版启动就失败,报「必须配合 catalog.mode=remote」 | 形态与目录配置不自洽(edition: client + catalog.mode=local)。那个组合是「能起来但什么都装不了」(市场列表读本地空目录、安装报「应用版本不存在」),根因从报错里看不出来 | 改成 catalog.mode: remote 并配 base-url。启动期自检 MarketEditionStartupCheck 刻意直接拦住 |
| 用户版市场列表 500,报「目录接口令牌校验失败」 | 两端 token 不一致 | 把服务端与调用方的 app-market.catalog.token 配成同一个值。服务端留空表示不校验调用方 —— 内网自用可以,公网必须配 |
| 用户版市场页是空的 / 装不上 | 官方目录服务不可达,或令牌不一致 | 先确认网络与 base-url(只写到主机,路径前缀代码里拼),再对令牌;验证时按本页开头的纪律,不要手工 curl 对端 |
用户版 /app/console/signature-readiness 返回 403 | 设计如此:它读的是本地目录,用户版下没有意义;签名自检只在官方版做 | 去官方版上调这个接口 |
用户版 GET /app/category/list、GET /app/console/owned-menus 是 200 | 这是刻意的例外,不是漏挡 | 分类的读要留给市场页做筛选;owned-menus 要留给菜单管理页打归属标签。分类的写仍是 403 |
| 中文关键词搜索永远返回空,英文正常 | 远程调用的 URI 被二次编码:自己 encode 后再交给按模板展开的 uri(String),对端解出来是 %E5%9B%BE... 这种百分号字面量 | 这是代码问题(已按 UriComponentsBuilder + encode() + 传 URI 对象修掉);如果自建了类似的远程调用,注意不要手写 encode |
传了 audience 参数却一条都查不出来 | 空串参数不是「没传」:拼 ?audience= 时服务端拿到的是空字符串而不是 null,而可见范围判断是 audience != null → 去匹配 FIND_IN_SET('', audience) | 可选参数要整条丢掉,不要拼空值 |
为什么用户版报 403 而不是静默失效
静默失效会让「上架成功」看起来是真的成功了;404 会把人引向路由与网络排查。403 + 明确文案(写明是 app-market.edition=client 导致的)是唯一不会误导人的做法。
卸载
| 现象 | 原因 | 处理 |
|---|---|---|
| 「彻底删除」之后表没被删 | 应用包里没有 CREATE TABLE(或建表脚本没打进包)。删表清单完全来自迁移脚本里解析出的 CREATE TABLE 表名,平台不维护「应用 → 表」映射 | 任务日志里会写明「该应用没有声明任何数据表」。把建表语句补进 migrations/ 并发布新版本(旧版本已无法补救) |
| 「彻底删除」之后按钮还在,父菜单没了 | 按钮(menu_type='F')没写进 app.json 的 menus,归属映射里没有它。历史上按钮来自平台初始化 SQL | 现在的版本会按 parent_id 把后代一起删(AppMenuTreeExpander)。给已有部署补按钮时要配一条 seed SQL(把新 key 映射到既有按钮 ID),否则升级会建出一套重复按钮 |
| 菜单/表没被删,日志说「检测到还有 N 个租户装着该应用……已跳过删除」 | 设计如此:sys_menu 与数据表、本机产物都是一个部署内全局共享的。只要还有别的租户装着同一应用,全局性删除一律跳过,只清本租户的安装记录 | 不用处理。真要清理得先把其它租户的安装记录也卸掉 |
| 重装后页面全报「表不存在」 | 迁移记录没清(正常流程会清),或建表脚本没进包 | 彻底删除会删 app_schema_history,这正是重装能重新建表的前提;脚本没进包则无解,只能补包 |
| 应用显示已启用但一个菜单都没有 | 残留的旧版本归属映射指向已删除的菜单 ID,跨版本解析时被复用了:updateById 影响 0 行、映射照样写回 | 菜单同步现在会自愈(同步前丢掉指向不存在菜单行的映射并按新菜单重建并告警)。清映射按三条线索并行:menu_id ∪ menu_key ∪ version_id |
| 卸载后历史任务显示「(应用已删除)」 | 「彻底删除」会把安装记录一起删掉,而任务历史(app_install_task)刻意保留当审计线索,查不到应用名 | 设计取舍,不是 bug |
| 卸载时报「以下产物未能删除,可停服务后手工清理」 | Windows 上被运行中的 JVM 占用的 jar 无法删除 | 停服务后跑 scripts\prune-plugins.ps1 清理 |
| 「彻底删除」后重装,页面标签是旧值 | 字典与站点配置在旧版本里留成了孤儿,而重装时脚本用 WHERE NOT EXISTS / INSERT IGNORE 会沿用上次留下的旧值 | 现版本会按 dict_type LIKE '<app>_%' 与 config_category = <app> 一并删除并失效缓存;确认你用的是包含该修复的版本 |
卸载后调某应用的接口返回 code: 4610,提示「应用「X」已停用/未安装或已卸载」 | 不是 bug,是对症提示:应用卸载/停用后路由已摘除,宿主用路由墓碑认出这条 404 本该由它提供 | 去「我的应用」重新安装/启用即可。若提示是「已启用但后端产物未加载」→ 本机缺插件 jar,走「部署」补 |
| 应用已停用/卸载,前端 console 里还有它接口的 404 | 宿主页面在应用不可用时仍在发请求 | 用 plugins/appmarket/appAvailability.ts 的 isAppEnabled('<code>') 先守卫(数据源是 GET /app/runtime/enabled-apps) |
1Panel / Docker
| 现象 | 原因 | 处理 |
|---|---|---|
安装日志 拉取镜像 失败 … error from registry: denied,紧接着 镜像已存在,使用存量镜像 | 正常。1Panel 装应用时无条件先 docker pull 一遍 compose 里的每个镜像;ruoyi-vue-plus/xxx 会被解析成 docker.io/ruoyi-vue-plus/xxx,而 Docker Hub 上这个命名空间不是本项目的 | 不用处理,本地有镜像就会继续装。想省掉约一分钟的等待:安装抽屉 → 高级 → 取消勾选「拉取镜像」(面板的离线模式也会自动不勾)。多机部署/上架官方商店时必须推到自己的仓库并同步改 compose 的 image: |
| 拉取失败之后没有「镜像已存在」,安装失败 | 本机真的没有那个镜像 | 在宿主机 docker build 出对应 tag,或推到仓库后改 compose 的 image: |
| 中间件下拉是空的 / 只显示「去安装」 | 面板里还没装对应的官方应用 | 应用商店里先装 MySQL、Redis(RabbitMQ 可选),再回到安装抽屉 |
打开安装抽屉就报 服务错误: record not found(请求 /api/v2/apps/services/undefined) | data.yml 里 type: apps 的字段漏了外层 default,1Panel 前端拿 p.default 当服务类型 key 去查服务列表 | 补上 default: mysql。本仓库由 gen-appstore-data.mjs 生成、check-appstore-data.mjs 会拦住这类错误;改完在面板「本地应用」点同步再重试 |
[entry] !! 没有数据库地址 | 既没选服务也没填外部 | 按安装表单补上;改完 docker compose up -d --force-recreate backend |
[entry] !! 等待 MySQL 超时 | 地址/端口/账号密码不对,或该库不允许本机访问;也可能是装完后改了库名/账号 —— 面板只改容器的 .env,不会去改 MySQL 里的库名与用户 | 在宿主机先 mysql -h <host> -u <user> -p 连一次;检查该服务的「允许访问」设置。库名/账号是安装时 random: true 随机生成的,装完就别改:要改就两边都改,或换新库名重装 |
[entry] !! 初始化不完整(缺 N 张关键表) | 某条初始化 SQL 报错(导入日志里有 ERROR),或库被删过 | 看导入日志定位;修好后清表 + 重启重新导入。别只 DROP DATABASE —— 应用账号没有全局 CREATE 权限,库建不回来 |
后端起来了但接口 500 Table xxx doesn't exist | 平台表没建全,却被判为「已初始化」 | 同上:清表 + 重启(会重新导入) |
| 改了初始化 SQL,重装/重启后没有变化 | ① 已装实例用的是它自己那份 sql/files/(bind mount),不是资源目录那份;② 有 platform.init.version 标记时入口脚本直接跳过导入 | 更新实例目录里的 SQL → 清表 → 重启 |
| nginx 起不来 | 变量没渲染(模板位置不对) | 模板必须 COPY 到 /etc/nginx/templates/*.template(走 envsubst),不是 conf.d/ |
RabbitMQ 401 ACCESS_REFUSED | 面板不会把 RabbitMQ 的账号密码带进安装表单,用的是默认 rabbitmq/rabbitmq | 去「应用商店 → 已安装 → RabbitMQ → 参数」抄账号密码,填进(或改)本应用的「RabbitMQ 用户 / 密码」。应用不依赖它启动,只影响消息中心/站内信 |
| 监控中心打开弹登录框 / 401 | 它是 HTTP Basic 认证(上游行为) | 用安装时填的账号密码(默认账号 ruoyi);主应用那边的账号密码要一致,否则注册不上 |
打开 http://<主机>:9090/ 或 :8800/ 是 404(Whitelabel / Tomcat) | 这两个服务都有 context-path,根路径没有映射 | 用 http://<主机>:9090/admin(监控中心,登录页 /admin/login)、http://<主机>:8800/snail-job/(调度中心控制台) |
| 数据库 → MySQL 里找不到本应用的库 | 库名是随机生成的 ry-vue_xxxxxx | 按前缀 ry-vue_ 过滤。卸载应用不会删库(刻意的:卸载不该顺手删数据),要清就手工删库删用户 |
| 「Redis 服务密码」空着又必填 | 面板里那个 Redis 没设密码,所以没有值可带入 | 先给 Redis 设个密码(数据库 → Redis → 改密码),再回到安装抽屉 |
| 定时任务一条都不跑 | 主应用表单里「调度中心地址」留空了(= 不启用) | 填固定别名 snailjob-server;日志里有 [entry] 定时任务调度中心:snailjob-server:17888 才说明开了。任务定义还要在 SnailJob 控制台导入,否则有调度中心也没有任务 |
| 多套部署的任务互相乱跑 | 共用了同一个调度中心 + 同一个命名空间 | 主应用表单里把「调度中心命名空间」改成各自不同的名字,并在调度中心里建出来 |
排障入口
cd /opt/1panel/apps/local/ruoyi-vue-plus-server
docker compose ps
docker compose logs --tail=200 backend | grep -E '\[entry\]|ERROR'[entry] 前缀的行来自容器入口脚本,中间件地址解析、初始化结论、调度/监控注册都在这里。