# PRD — Docker 容器化巡检环境隔离问题

> 版本：1.0 ｜ 日期：2026-07-29 ｜ 作者：czj

---

## 1. 问题描述

当前服务监测模块已通过 Docker 容器化部署，巡检脚本在容器内执行。这导致以下问题：

### 1.1 本级巡检（本地目标）问题

| 问题 | 说明 |
|------|------|
| **系统信息不真实** | `uname -a`、`/proc/*` 读取的是容器内核信息，非宿主机 |
| **CPU/内存数据错误** | 容器有资源限制，读取的 `/proc/cpuinfo`、`/proc/meminfo` 与宿主机不同 |
| **磁盘信息偏差** | 容器文件系统是挂载的 volume，`df` 看到的是容器视角 |
| **进程列表不完整** | 容器内 `ps aux` 只能看到容器内进程 |
| **网络信息不真实** | 容器有自己的网络命名空间，`ip addr`、`netstat` 是容器网络 |

### 1.2 远程 SSH 巡检

远程巡检通过 SSH 连接目标服务器执行脚本，**理论上不受影响**。但需要验证：
- SSH 连接从容器内发起是否正常
- SSH 密钥/密码在容器内是否可用

---

## 2. 需求目标

### 方案选择

| 方案 | 优点 | 缺点 |
|------|------|------|
| **A. 宿主机部署** | 本级巡检真实、简单直接 | 需要回退到 systemd/nohup 方式，丢失 Docker 隔离优势 |
| **B. 容器特权模式 + 挂载** | 保留 Docker 部署，本级巡检真实 | 安全风险大，容器逃逸风险，配置复杂 |
| **C. 本级巡检走 SSH 到宿主机** | 保留 Docker 部署，本级数据真实 | 需要配置容器到宿主机的 SSH，略复杂 |
| **D. 本级巡检禁用/标记** | 最简单，避免误导用户 | 功能缺失 |

### 推荐方案：**C. 本级巡检走 SSH 到宿主机**

**实现思路**：
1. 本级目标（`host_local`）的巡检，通过 SSH 连接到宿主机执行
2. 宿主机需要配置 SSH 服务，容器通过 SSH 访问
3. 容器内存储宿主机的 SSH 凭据（或使用 SSH 密钥挂载）

---

## 3. 功能规格

### 3.1 本级目标自动检测

当创建 `host_local` 类型目标时，系统自动识别为"本级巡检"，并：
- 提示用户配置宿主机 SSH 连接信息
- 或自动使用 Docker 宿主机 IP（通过 `host.docker.internal` 或网关 IP）

### 3.2 巡检执行逻辑调整

```python
def execute_check(target):
    if target.get('host') == 'localhost' or target.get('type') == 'local':
        # 本级巡检 → SSH 到宿主机执行
        host_ip = get_docker_host_ip()  # 获取宿主机 IP
        ssh_to_host_and_execute(host_ip, scripts)
    else:
        # 远程巡检 → 正常 SSH 执行
        ssh_to_target_and_execute(target['host'], scripts)
```

### 3.3 宿主机 IP 获取方式

**方式一**：Docker 网关 IP（Linux）
```bash
# 容器内执行
ip route | grep default | awk '{print $3}'
# 返回如 172.17.0.1（Docker 网关）
```

**方式二**：`host.docker.internal`（Docker Desktop / 部分环境）
```bash
# 需要容器启动时添加参数
docker run --add-host=host.docker.internal:host-gateway ...
```

### 3.4 宿主机 SSH 配置

需要在宿主机上：
1. 确保 SSH 服务运行（`sshd`）
2. 创建巡检专用用户或使用现有用户
3. 配置 sudo 免密执行巡检脚本（可选）

---

## 4. 后端实现

### 4.1 修改目标服务

**文件**：`skill/code/web/service_monitor/services/target_service.py`

```python
def create_target(data):
    # 自动检测本级目标
    if data.get('host') in ('localhost', '127.0.0.1', '::1'):
        data['type'] = 'local'
        data['requires_host_ssh'] = True  # 标记需要宿主机 SSH
```

### 4.2 修改执行器

**文件**：`skill/code/web/service_monitor/utils/executor.py`

```python
class LocalExecutor:
    """本级巡检执行器 - 通过 SSH 到宿主机"""
    
    def __init__(self):
        self.host_ip = self._get_docker_host_ip()
        self.ssh_client = None
    
    def _get_docker_host_ip(self):
        """获取 Docker 宿主机 IP"""
        import subprocess
        result = subprocess.run(
            ['ip', 'route'],
            capture_output=True, text=True
        )
        for line in result.stdout.split('\n'):
            if 'default' in line:
                return line.split()[2]  # 网关 IP
        return 'host.docker.internal'
    
    def execute(self, script_path):
        """通过 SSH 到宿主机执行脚本"""
        return ssh_execute(
            host=self.host_ip,
            username='monitor',  # 宿主机巡检用户
            key_or_password=...,  # 从目标配置或环境变量读取
            script=script_path
        )
```

### 4.3 环境变量配置

在 `.env` 中添加：

```
# 本级巡检宿主机 SSH 配置
LOCAL_SSH_HOST=172.17.0.1  # 或 host.docker.internal
LOCAL_SSH_USER=monitor
LOCAL_SSH_KEY=/app/keys/host_key  # 挂载的 SSH 密钥
```

---

## 5. 前端调整

### 5.1 目标创建页面提示

当用户填写 `localhost` 或 `127.0.0.1` 时，显示提示：

> 检测到本级目标，巡检将通过 SSH 连接到宿主机执行。请确保：
> 1. 宿主机 SSH 服务已启动
> 2. 已配置 SSH 凭据（见环境变量 LOCAL_SSH_*）

### 5.2 目标列表标识

本级目标显示特殊图标或标签，区分"本级（宿主机）"和"远程"。

---

## 6. 部署调整

### 6.1 Docker 启动参数

```bash
docker run -d --name troubleshoot \
  --add-host=host.docker.internal:host-gateway \  # 添加宿主机映射
  -v /path/to/ssh_key:/app/keys/host_key:ro \     # 挂载 SSH 密钥
  ...
```

### 6.2 宿主机配置脚本

提供一键配置脚本，在宿主机上：
- 创建巡检用户 `monitor`
- 配置 sudo 免密执行
- 生成 SSH 密钥对

---

## 7. 临时方案（快速修复）

如果暂时不做完整改造，建议：

1. **禁用本级目标创建**：前端隐藏本级目标选项
2. **目标列表标记**：已存在的本级目标显示警告："容器化部署下本级巡检数据可能不准确"
3. **巡检报告提示**：本级巡检报告中添加说明

---

## 8. 实施优先级

| 优先级 | 任务 | 工作量 |
|--------|------|--------|
| **P0** | 本级目标标记 + 警告提示 | 0.5 天 |
| **P1** | 本级巡检 SSH 到宿主机 | 1 天 |
| **P2** | 前端优化 + 一键配置脚本 | 0.5 天 |
| **P3** | 文档更新 + 测试验证 | 0.5 天 |
