提交 b9201749 authored 作者: 陈泽健's avatar 陈泽健

docs: 更新 HANDOFF_服务监测 — 阶段十 SSH sudo 自动检测

记录 SSH sudo 自动检测 + Docker 权限适配 + 5.60 部署环境修复全过程
Co-Authored-By: 's avatarClaude <noreply@anthropic.com>
上级 437a1b7e
# HANDOFF_服务监测 — 服务监测模块:检测项丰富化移植 + 移动端响应式优化 + 功能增强(报告对比 + 连续异常告警)
# HANDOFF_服务监测 — 服务监测模块:检测项丰富化移植 + 移动端响应式优化 + 功能增强 + SSH sudo 自动检测
> 最后更新:2026-07-23(阶段九:报告对比功能 + 异常项趋势告警)| 分支:troubleshoot-ai-assistant | 负责人:czj
> 最后更新:2026-08-05(阶段十:SSH sudo 自动检测 + Docker 权限适配)| 分支:troubleshoot-ai-assistant | 负责人:czj
> 专属交接文档:聚焦服务监测模块(service_monitor)的全部历史与当前状态
---
......@@ -18,25 +18,32 @@
- **阶段六**:巡检防重复触发优化 + 数据备份检测超时修复
- **阶段七**:模块清理 + 5.44 验证 + 移动端响应式样式优化
- **阶段八**:移动端响应式深度优化 — 新增 480px 超小屏幕断点 + 修正布局溢出问题
- **阶段九(本次)**:功能增强 — 报告对比功能 + 异常项趋势告警
- **阶段十(本次)**:SSH sudo 自动检测 + Docker 权限适配 + 目标管理编辑功能补全
本轮会话完成了以下工作:
**P1:报告对比功能**
1. 新增 `compare_service.py` 对比服务,支持 5 类差异分类(新增异常/恢复正常/值变化/新增项/消失项)
2. 新增 API:`GET /api/service-monitor/reports/{id1}/compare/{id2}` 和导出接口
3. 新增 `compare.html` 对比结果页,差异按模块分组展示
4. `report.html` 新增"对比历史报告"按钮和报告选择弹窗
**P1:SSH sudo 自动检测**
1. `executor.py` — SSHExecutor 新增 `_detect_sudo_need()``_try_configure_passwordless_sudo()` 方法
2. 连接后自动检测:先测 `docker ps` 是否可直接执行 → 失败则测 `sudo -n docker ps` → 尝试自动配置免密 sudoers
3. 修复检测逻辑:从只测 `sudo -n whoami` 改为精确测试 docker 命令权限(避免用户在 docker 组外但可免密 sudo 的情况)
4. `target_service.py``make_executor()` 支持 `use_sudo` 字段
**P1:异常项趋势告警**
1. `report_service.py` 新增 `check_consecutive_abnormal()` 函数,检测连续异常
2. `runner_service.py` 集成连续异常告警,报告完成后自动检测并发送通知
3. `notification.html` 新增"连续异常告警"配置区(阈值/级别/渠道)
4. 冷却期机制:24 小时内同一检测项不重复告警
**P1:Docker 检测脚本 sudo 适配**
1. `20_docker_basic.sh` — 新增 `_detect_docker_sudo()` 函数,所有 docker 命令使用 `$DOCKER_CMD` 变量
2. 自动适配 `docker``sudo docker`,解决非 root 用户执行 docker 权限拒绝问题
> **检测项丰富化移植全部完成**:阶段一至五共新增 15 个检测模块,full 套件模块数 30 → 42(移除 58 后)
>
> **设计原则**:所有原版依赖 Windows 本地工具(pscp.exe/adb.exe)的模块,均改造为远程巡检检测(检测就绪状态/能力,不执行本地文件操作);所有修复类操作均改为只检测不修复
**P2:目标管理编辑功能补全**
1. `routes.py` — 新增 `GET /api/service-monitor/targets/<target_id>` API
2. `targets.html` — 补充 `openEdit()` 函数,通过 API 获取目标数据并回填表单
**P1:5.60 部署环境修复**
1. 端口冲突:Docker 容器与 systemd 服务抢占 8088,已禁用 systemd
2. 容器代码更新:重建 Docker 镜像,同步最新代码到容器内
3. 前端文件恢复:volume 挂载空目录覆盖 dist,已恢复
4. 搜索索引修复:`搜索索引.json` 被误创建为目录,已修复
5. 通知配置修复:重建后加密密钥变更导致解密失败,已清除旧密文
> **设计原则**:所有原版依赖 Windows 本地工具(pscp.exe/adb.exe)的模块,均改造为远程巡检检测(检测就绪状态/能力,不执行本地文件操作);所有修复类操作均改为只检测不修复;SSH 用户非 root 时自动检测并启用 sudo 提权
---
......@@ -621,14 +628,112 @@
**验证结果**:218 个测试全绿 ✅ **已部署到 5.60**
### 2.30 SSH sudo 自动检测 ✅
**问题来源**:用户在 9.89 服务器上执行巡检时,Docker 容器显示为"未运行",但实际有 12 个容器在运行。根本原因是 SSH 用户 `openkylin` 不在 docker 组,巡检脚本直接执行 `docker ps` 因权限拒绝失败。
**核心实现**
**1. `executor.py` — SSHExecutor sudo 自动检测**
- `_detect_sudo_need()` 方法:SSH 连接后自动检测
- 先执行 `whoami` 检查当前用户是否为 root
- 如果是 root → `use_sudo = False`
- 如果不是 root → 测试 `docker ps` 是否可直接执行
- 如果 `docker ps` 失败 → 测试 `sudo -n docker ps`
- 如果 `sudo -n docker ps` 成功 → `use_sudo = True`
- 如果 sudo 需要密码 → 调用 `_try_configure_passwordless_sudo()`
- `_try_configure_passwordless_sudo()` 方法:
- 用 SSH 密码通过 `sudo -S` 写入 `/etc/sudoers.d/<username>`
- 验证写入后免密 sudo 是否生效
- 失败时给出明确配置提示
- `_exec()` 方法:根据 `use_sudo` 自动用 `sudo bash -c` 包裹命令
- 修复关键 bug:初始检测逻辑只测 `sudo -n whoami`(用户免密 sudo),未检测 Docker 命令权限。修正为直接测试 `docker ps`
**2. `target_service.py` — use_sudo 字段支持**
- `make_executor()` 从 target 数据读取 `use_sudo` 字段
- `create_target()` / `update_target()` 支持 `use_sudo` 字段
- `list_targets()` / `_build_view()` 返回 `use_sudo` 状态
**验证结果**:直接测试 9.89 服务器,`sudo docker ps` 正常列出 12 个容器 ✅ 脚本逻辑在 9.89 上实测通过 ✅
### 2.31 Docker 检测脚本 sudo 适配 ✅
**核心实现**
**`20_docker_basic.sh` — 自动适配 sudo**
- 新增 `_detect_docker_sudo()` 函数:
- 先尝试 `docker ps`
- 失败则尝试 `sudo -n docker ps`
- 设置 `DOCKER_CMD``docker``sudo docker`
- 所有 docker 命令使用 `$DOCKER_CMD` 变量
- 每个检测函数开头增加 `if [ -z "$DOCKER_CMD" ]` 保护
- 修复初始 bug:`_detect_docker_sudo()``$DOCKER_CMD` 变量未初始化就被引用
**验证结果**:在 9.89 上用修复后脚本实际测试,输出 `DOCKER_SERVICE_STATUS:运行中``CONTAINER_TOTAL:12``CONTAINER_RUNNING:11`
### 2.32 目标管理编辑功能补全 ✅
**问题来源**:用户之前已新增目标但无法编辑,`openEdit()` 函数为空(仅 TODO 注释)。
**核心实现**
**1. `routes.py` — 新增 GET 单个目标 API**
- `GET /api/service-monitor/targets/<target_id>`:返回单个目标的对外视图(脱敏)
- 管理员权限校验
**2. `targets.html` — 完整编辑交互**
- `openEdit(id)` 函数:通过 API 获取目标数据并回填表单
- 密码字段不回填(留空表示不修改)
- `use_sudo` 复选框回填
- 保存时区分新增(POST)和编辑(PUT)
**验证结果**:API 语法检查通过 ✅ 前端逻辑完整 ✅
### 2.33 5.60 Docker 部署环境修复 ✅
**背景**:部署 SSH sudo 自动检测功能时,发现 5.60 服务存在多个问题,一一修复。
**修复内容**
| 问题 | 原因 | 修复 |
|------|------|------|
| systemd 服务不断重启(9300+次) | Docker 容器与 systemd 抢占 8088 端口 | `sudo systemctl stop/disable troubleshoot`,统一用 Docker 容器 |
| 容器内代码未更新 | 代码在镜像构建时 COPY,非 volume 挂载 | 重建 Docker 镜像:`docker compose up -d --build` |
| 前端 403 Forbidden | volume 空目录覆盖 dist | `cp -r frontend/dist/* /opt/troubleshoot/dist/` |
| 搜索索引文件错误 | `搜索索引.json` 被误创建为目录 | 删除目录,复制正确的 JSON 文件 |
| 通知 API 500 错误 | 重建后 MONITOR_ENC_KEY 变更,旧密文无法解密 | 清除 notifications.json 中无法解密的加密字段 |
| 搜索向量.json 挂载失败 | 宿主机文件为空,镜像内路径不存在 | 注释 docker-compose.yml 中搜索向量的 volume 挂载 |
**当前部署状态**
- 容器运行:健康(healthy)✅
- 前端:正常访问 ✅
- 通知 API:已修复,需重新配置钉钉 secret ✅
- 定时任务:2 个任务运行中 ✅
- 搜索模式:TF-IDF ✅
---
## 3. 当前卡在哪
**无卡点**。阶段一至全部完成。
**无卡点**。阶段一至全部完成。
**当前状态**
- 服务健康检查:status: ok, scheduler: running ✅
- 容器运行:健康(healthy)✅
- SSH sudo 自动检测已部署 ✅
- Docker 检测脚本 sudo 适配已部署 ✅
- 目标管理编辑功能完整 ✅
- 报告免登访问正常工作 ✅
- 统计模块正常工作 ✅
- 检测项趋势图表友好提示正常 ✅
- full 套件 42 个模块(原 30 + 新增 12)✅
- 218 个单元测试全绿 ✅
- **已部署到 5.60** ✅(全部阶段已部署)
- 5.60 Docker 部署环境已修复 ✅
**待处理**
- 通知凭据需重新配置(重建容器后加密密钥变更)
- `MONITOR_ENC_KEY` 建议设为固定值(当前未设置,每次重启可能变更)
- 报告免登访问正常工作 ✅
- 统计模块正常工作 ✅
- 检测项趋势图表友好提示正常 ✅
......@@ -680,6 +785,14 @@
| ~~P1~~ | ~~异常项趋势告警~~ | ✅ 已完成(阶段九) |
| ~~P2~~ | ~~导出 PDF/Excel 格式~~ | ✅ 已完成(阶段九) |
| 持续 | 更新 HANDOFF_服务监测文档 | 每次会话结束前更新进度 |
| **P1** | **验证 9.89 巡检** | 添加 9.89 目标(openkylin:Ubains@123),运行全量巡检,验证 Docker 容器检测 |
| **P2** | **验证定时任务执行** | 明天 08:30/09:00 检查定时任务是否自动执行 |
| **P3** | **重新配置通知凭据** | 进入通知配置页重新填写钉钉 secret |
| **P4** | **固定 MONITOR_ENC_KEY** | 在 docker-compose.yml 中设置固定值 |
| **P1** | **验证 9.89 巡检** | 在目标管理添加 9.89(openkylin:Ubains@123),运行全量巡检,验证 Docker 容器检测是否正常显示 12 个容器 |
| **P2** | **验证定时任务执行** | 明天 08:30/09:00 检查定时任务是否自动执行,巡检报告是否生成 |
| **P3** | **重新配置通知凭据** | 进入通知配置页面重新填写钉钉 secret(重建后加密密钥变更) |
| **P4** | **固定 MONITOR_ENC_KEY** | 在 docker-compose.yml 中设置固定值,避免重建后凭据解密失败 |
---
......@@ -837,12 +950,69 @@
- `run_id` 必须加入 uuid 或其他唯一标识(已修复:使用 `target_id[:4]` + uuid[:6]
- 并发执行场景必须确保资源隔离(工作目录、内存状态)
### 坑 12:Docker 容器与 systemd 服务端口冲突
**坑**:Docker 容器和 systemd 服务同时运行抢占 8088 端口,systemd 每 6 秒重启一次,累计重启 9300+ 次。定时任务因服务不稳定无法执行。
**原因**:部署脚本只更新宿主机文件并重启 systemd 服务,没检查 Docker 容器是否已在运行。
**避免方法**
```bash
# 部署前先检查
sudo docker ps | grep troubleshoot # 如果有容器在运行
sudo systemctl disable troubleshoot # 禁用 systemd
```
### 坑 13:Docker 镜像内代码未随部署更新
**坑**:部署脚本只更新宿主机 `/opt/troubleshoot/web/` 下的文件,但 Docker 镜像构建时 `COPY` 代码到容器内,容器内代码仍是旧版本。
**原因**:代码文件不在 volume 挂载范围内,必须重建镜像才能更新。
**避免方法**
```bash
# 代码更新后必须重建镜像
sudo rsync -av --delete /opt/troubleshoot/web/ /data/third_party/monitor-platform/skill/code/web/
cd /data/third_party/monitor-platform && sudo docker compose up -d --build
```
### 坑 14:volume 挂载文件类型不匹配导致容器启动失败
**坑**`搜索索引.json` 被误创建为目录,docker-compose 挂载时报错 `not a directory: Are you trying to mount a directory onto a file`
**原因**:宿主机上 `/opt/troubleshoot/data/搜索索引.json` 是目录,挂载到容器内也是目录,与镜像内期望的文件类型冲突。
**避免方法**
```bash
# 重建前检查挂载文件类型
sudo file /opt/troubleshoot/data/搜索索引.json # 应输出:JSON text data
sudo rm -rf /opt/troubleshoot/data/搜索索引.json # 如果是目录则删除
sudo cp /data/.../搜索索引.json /opt/troubleshoot/data/ # 复制正确的文件
```
### 坑 15:通知配置解密失败导致 API 500
**坑**`notifications.json` 中钉钉 secret 用旧密钥加密(`enc:gAAAAA...`),重建容器后 `MONITOR_ENC_KEY` 变更,解密失败导致通知 API 返回 500。
**原因**:Fernet 加密密钥每次容器启动可能不同(如果 `MONITOR_ENC_KEY` 未固定)。
**避免方法**:在 `docker-compose.yml` 中设置固定的 `MONITOR_ENC_KEY` 环境变量。
### 坑 16:sudo 检测逻辑只测用户权限没测命令权限
**坑**:最初只检测 `sudo -n whoami`(用户是否有免密 sudo),没检测 Docker 命令权限。9.89 上 openkylin 有免密 sudo 但不在 docker 组,`docker ps` 仍失败。
**原因**:想当然认为"有 sudo 权限就能执行所有命令"。
**避免方法**:检测要具体到命令本身。正确逻辑:先测 `docker ps`,失败再测 `sudo -n docker ps`
---
## 6. Git 提交记录
| 日期 | Commit | 说明 |
|------|--------|------|
| **2026-08-05** | `65b25c4d` | **feat(monitor): SSH sudo 自动检测 + Docker 权限适配** |
| 2026-07-24 | `3cb1cf62` | fix(service-monitor): 修复定时任务并发执行导致 run_id 冲突 |
| 2026-07-23 | `7b0e7dcd` | feat(service-monitor): 导出 PDF/Excel 格式 |
| 2026-07-23 | `069f9fa2` | feat(service-monitor): 报告对比功能 + 异常项趋势告警 |
......@@ -970,6 +1140,22 @@ feat(service-monitor): 新增安全合规/中间件检测模块并修复状态
| `service_monitor/routes.py` | api_export_report() 增加 pdf/excel 格式,重构避免重复代码 |
| `templates/service_monitor/report.html` | 导出菜单新增"导出 PDF"、"导出 Excel" |
### 本次修改文件(阶段十:SSH sudo 自动检测 + Docker 权限适配)
| 文件 | 改动 |
|------|------|
| `service_monitor/utils/executor.py` | SSHExecutor 新增 sudo 自动检测(+150 行):`_detect_sudo_need()` + `_try_configure_passwordless_sudo()` |
| `service_monitor/services/target_service.py` | `make_executor()` 等支持 `use_sudo` 字段(+10 行) |
| `service_monitor/routes.py` | 新增 `GET /api/service-monitor/targets/<target_id>` API(+12 行) |
| `service_monitor/assets/service/20_docker_basic.sh` | 新增 `_detect_docker_sudo()` 函数,所有 docker 命令使用 `$DOCKER_CMD` 变量(+69 行) |
| `templates/service_monitor/targets.html` | 补充编辑回填功能 + sudo 提权选项(+37 行) |
**5.60 部署环境修复**
| `docker-compose.yml` | 注释搜索向量 volume 挂载 |
| `/opt/troubleshoot/data/搜索索引.json` | 修复目录→文件 |
| `/opt/troubleshoot/data/notifications.json` | 清除无效加密字段 |
| `systemd` | 禁用 troubleshoot 服务,统一用 Docker 容器 |
### 新增文档
| 文件 | 说明 |
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论