# 方案 C：100 主机 Dubbo 开发代理（不影响 K8s 集群）

> 适用场景：本地 IDE 已通过 **VPN** 接入 `192.168.20.0/24`，需要调用 100 上 GBS Dubbo 服务进行开发联调。  
> 脚本目录：`docs/gbs/scripts/dubbo-dev-proxy/`  
> **本文档为唯一实施指南**，可独立指导任意新会话从零搭建整套方案。

---

## 0. 新会话快速实施清单

按顺序执行，已完成的步骤可跳过。

| 步骤 | 动作 | 验收标准 |
|------|------|----------|
| 0 | 确认 VPN 连通 `192.168.20.100` | `Test-NetConnection 192.168.20.100 -Port 30140` 成功 |
| 1 | 检查 100 是否已装代理（见 **4.0**） | `dubbo-proxy-status.sh` 显示 `running` |
| 2 | 未安装则执行 **4.2** 或 `deploy_plan_c.py` | `32080`、`32084` 端口 LISTEN |
| 3 | 确认本项目代码改动已就位（见 **5.7**） | `bootstrap.yml` / `application-local.yml` / Dubbo Client 已配置 |
| 4 | IDEA 设置 `local` profile + VM Options（见 **5.4**） | 启动无 Nacos 报错 |
| 5 | 启动本地服务，检查 Dubbo 日志 | 连接 `192.168.20.100:32080`，**无** `10.244.*` 超时 |
| 6 | 功能验证 | 用户同步、短信等依赖 GBS 的接口正常 |

**关键端口速记（safety-eval 常用）**：

| Facade / 服务 | GBS 服务名 | 代理端口 |
|---------------|-----------|----------|
| **UserFacade** | jjb-saas-**system** | **32080** |
| **MessageFacade** | jjb-saas-**message** | **32084** |
| user 服务（非 UserFacade） | jjb-saas-user | 32088 |

> 易错点：`UserFacade` 在 **system（32080）**，不是 user（32088）。

---

## 1. 方案原理

### 1.1 要解决的问题

| 现象 | 原因 |
|------|------|
| 本地连 Nacos 后 Dubbo 调用失败 | Nacos 返回 Provider 地址为 `10.244.x.x:20880`（Pod 网段） |
| VPN 能访问 100，但仍调不通 Dubbo | VPN 通常只路由 `192.168.20.0/24`，不包含 Pod 网段 `10.244.0.0/16` |

### 1.2 方案 C 做法

在 **192.168.20.100 主机** 上运行 `socat` TCP 代理：

```text
本地 IDE  --VPN-->  192.168.20.100:32080  --socat-->  10.244.x.x:20880 (system Pod)
                         固定端口                         当前 Pod IP（动态刷新）
```

### 1.3 与已废弃「NodePort + 改注册」方案 A 的区别

| 对比项 | 已废弃方案 A | **方案 C（本文）** |
|--------|-------------|-------------------|
| 创建 K8s `*-dubbo` Service | 是 | **否** |
| 修改 `DUBBO_IP_TO_REGISTRY` | 是 | **否** |
| 修改 Nacos 注册地址 | 是 | **否** |
| 影响集群内服务互调 | 是 | **否** |
| 本地可通过固定端口访问 Dubbo | 是 | **是** |

**结论：方案 C 只在 100 主机做端口转发，K8s 内部仍保持 Pod IP 注册与 ClusterIP 通讯。禁止重新执行方案 A。**

---

## 2. 架构图

```mermaid
flowchart LR
    subgraph local [本地开发机 VPN]
        IDE[IDE / 本地 Java]
    end

    subgraph host100 [192.168.20.100 主机]
        Socat[socat 32080-32100]
        FW[firewalld]
    end

    subgraph k8s [jjb-dragon 集群内 - 不变]
        PodSystem[system Pod 10.244.x.x:20880]
        PodMessage[message Pod 10.244.x.x:20880]
        Nacos[prod-nacos:8848]
    end

    IDE -->|192.168.20.100:32080 UserFacade| FW
    IDE -->|192.168.20.100:32084 MessageFacade| FW
    FW --> Socat
    Socat --> PodSystem
    Socat --> PodMessage
    PodSystem --> Nacos
    PodMessage --> Nacos
```

---

## 3. 端口映射表

沿用历史开发端口，便于本地配置复用（见 `dubbo-proxy.map`）：

| 本地固定端口 | GBS 服务 | Pod 标签 | Dubbo 端口 |
|-------------|----------|----------|------------|
| **32080** | **jjb-saas-system** | jjb-saas-system-pod | 20880 |
| 32081 | jjb-saas-auth | jjb-saas-auth-pod | 20880 |
| 32082 | jjb-saas-events | jjb-saas-events-pod | 20880 |
| 32083 | jjb-saas-security | jjb-saas-security-pod | 20880 |
| **32084** | **jjb-saas-message** | jjb-saas-message-pod | 20880 |
| 32085 | jjb-saas-login | jjb-saas-login-pod | 20880 |
| 32086 | jjb-saas-base | jjb-saas-base-pod | 20880 |
| 32087 | jjb-saas-process-layout | jjb-saas-process-layout-pod | 20880 |
| 32088 | jjb-saas-user | jjb-saas-user-pod | 20880 |
| 32089 | jjb-saas-official | jjb-saas-official-pod | 20880 |
| 32090 | jjb-saas-facade | jjb-saas-facade-pod | 20880 |
| 32091 | jjb-saas-open-platform | jjb-saas-open-platform-pod | 20880 |
| 32092 | jjb-saas-application | jjb-saas-application-pod | 20880 |
| 32093 | jjb-saas-attachment | jjb-saas-attachment-pod | 20880 |
| 32094 | jjb-saas-formily-design | jjb-saas-formily-design-pod | 20880 |
| 32095 | jjb-saas-desk | jjb-saas-desk-pod | 20880 |
| 32096 | jjb-saas-config | jjb-saas-config-pod | 20880 |
| 32097 | jjb-saas-document | jjb-saas-document-pod | 20880 |
| 32098 | jjb-saas-component-design | jjb-saas-component-design-pod | 20880 |
| 32099 | jjb-saas-view | jjb-saas-view-pod | 20880 |
| 32100 | jjb-saas-gateway | jjb-saas-gateway-pod | 20880 |

---

## 4. 100 服务器需要做什么

### 4.0 判断是否已安装（先执行，可跳过安装）

在 100 上执行：

```bash
# 目录与 systemd 是否存在
ls /opt/dubbo-dev-proxy/dubbo-proxy-status.sh
systemctl is-active dubbo-dev-proxy.timer

# 代理是否在跑
/opt/dubbo-dev-proxy/dubbo-proxy-status.sh

# 关键端口是否在监听
ss -lntp | grep -E ':32080|:32084'
```

**已安装且 running** → 跳到 **4.3** 日常运维，或直接进入本文 **第 5 节** 配置本地。

**未安装或 stopped** → 执行 **4.2** 安装。

从开发机远程一键检查（需 Python + paramiko）：

```bash
python docs/gbs/scripts/dubbo-dev-proxy/debug_plan_c.py
```

### 4.1 前置条件

| 项 | 要求 |
|----|------|
| 主机 | `192.168.20.100`（K8s Master） |
| 权限 | `root` SSH |
| 工具 | `kubectl` 可用、`socat`（脚本自动安装） |
| K8s | 命名空间 `jjb-dragon` 内目标 Pod 为 Running |
| 网络 | 100 主机能访问 Pod IP（`10.244.0.0/16`） |

### 4.2 一次性安装

**方式 A：在 100 上手动安装**

```bash
ssh root@192.168.20.100
cd /path/to/safety-eval-service/docs/gbs/scripts/dubbo-dev-proxy
chmod +x *.sh
sudo ./dubbo-proxy-install.sh
```

**方式 B：从开发机 SSH 自动部署（推荐新会话使用）**

```bash
# 需 pip install paramiko
python docs/gbs/scripts/dubbo-dev-proxy/deploy_plan_c.py
```

脚本会上传 `*.sh` 与 `dubbo-proxy.map` 到 100 的 `/opt/dubbo-dev-proxy-src/`，再执行 `dubbo-proxy-install.sh`。

安装脚本会：

1. 安装 `socat`
2. 复制配置到 `/opt/dubbo-dev-proxy/`
3. 开放防火墙 `32080-32100/tcp`
4. 注册 systemd 服务 + 定时器（每 3 分钟自动刷新 Pod IP）

### 4.3 日常运维命令

```bash
# 查看代理状态
/opt/dubbo-dev-proxy/dubbo-proxy-status.sh

# Pod 重启/漂移后手动刷新
/opt/dubbo-dev-proxy/dubbo-proxy-refresh.sh

# 停止全部开发代理（下班/不需要本地联调时）
/opt/dubbo-dev-proxy/dubbo-proxy-stop.sh

# 重新启用
systemctl start dubbo-dev-proxy.service
systemctl start dubbo-dev-proxy.timer
```

### 4.4 验证（在 100 上）

```bash
# 1. 代理进程
/opt/dubbo-dev-proxy/dubbo-proxy-status.sh

# 2. 端口监听
ss -lntp | grep -E '3208[0-9]|32100'

# 3. 本机探测 safety-eval 常用代理
nc -zv 127.0.0.1 32080   # system / UserFacade
nc -zv 127.0.0.1 32084   # message / MessageFacade

# 4. 确认 K8s 未被改动（方案 A 残留检查）
kubectl get svc -n jjb-dragon | grep dubbo          # 应无 *-dubbo
kubectl get deploy -n jjb-dragon -o yaml | grep DUBBO_IP_TO_REGISTRY  # 应无输出
```

### 4.5 100 服务器清单（汇总）

| 类别 | 路径/端口 | 说明 |
|------|-----------|------|
| 安装目录 | `/opt/dubbo-dev-proxy/` | 脚本与 map 配置 |
| 上传暂存 | `/opt/dubbo-dev-proxy-src/` | `deploy_plan_c.py` 上传位置 |
| PID 目录 | `/var/run/dubbo-dev-proxy/` | socat 进程 PID |
| 日志 | `/var/log/dubbo-dev-proxy/` | 按端口分日志 |
| systemd | `dubbo-dev-proxy.service` | 刷新代理 |
| systemd timer | `dubbo-dev-proxy.timer` | 每 3 分钟自动刷新 |
| 防火墙 | `32080-32100/tcp` | 仅开发代理端口 |
| **不改** | K8s Deployment/Service | 无 env、无 NodePort Service |
| **不改** | Nacos 注册信息 | Provider 仍为 Pod IP |

---

## 5. 本地开发机需要做什么

### 5.1 前置条件

| 项 | 要求 |
|----|------|
| VPN | 已连接，能访问 `192.168.20.100` |
| JDK | 1.8（与项目一致） |
| IDE | IntelliJ IDEA / 其他支持 Spring Boot |

### 5.2 基础连通性自检

在本地 PowerShell / Git Bash 执行：

```powershell
# VPN + 网关
curl -s -o /dev/null -w "gateway:%{http_code}\n" http://192.168.20.100:30140/

# Nacos
curl -s -o /dev/null -w "nacos:%{http_code}\n" http://192.168.20.100:30290/nacos/

# Dubbo 代理（safety-eval 常用端口）
Test-NetConnection 192.168.20.100 -Port 32080   # UserFacade
Test-NetConnection 192.168.20.100 -Port 32084   # MessageFacade
```

### 5.3 本地配置原则

1. **Nacos**：用 NodePort `30290` 拉配置，namespace `jjb-dragon`
2. **HTTP**：走网关 `http://192.168.20.100:30140`
3. **MySQL/Redis**：直连 `192.168.20.100:33080` / `6379`
4. **Dubbo**：**不要**依赖 Nacos 自动发现的 `10.244.*` 地址；对需要的接口使用 **显式 URL** `dubbo://192.168.20.100:32xxx`
5. **本地服务注册**：关闭 Nacos discovery，避免以线上同名注册到 `jjb-dragon`

### 5.4 safety-eval 本地 Profile 配置

**模板文件**（完整版，含数据源密码）：

```text
docs/gbs/scripts/dubbo-dev-proxy/application-local.example.yml
```

**本项目已提交的配置**（精简版，依赖 nacos 公共配置）：

```text
safety-eval-start/src/main/resources/application-local.yml
```

`bootstrap.yml` 已在 `local` profile 中 import `application-local.yml`，**无需额外改动 bootstrap**。

IDE VM Options 示例：

```text
-Dspring.profiles.active=local
-Dnacos.url=192.168.20.100:30290
-Dmysql.host=192.168.20.100
-Dmysql.port=33080
-Dmysql.username=root
-Dmysql.password=Mysql@zcloud33080
-DGBS_USER_FACADE_URL=dubbo://192.168.20.100:32080
-DGBS_MESSAGE_FACADE_URL=dubbo://192.168.20.100:32084
```

IDEA 环境变量（可选，与 VM Options 二选一）：

```text
GBS_USER_FACADE_URL=dubbo://192.168.20.100:32080
GBS_MESSAGE_FACADE_URL=dubbo://192.168.20.100:32084
```

### 5.5 Dubbo 依赖与端口对照

| 业务依赖 | GBS 服务 | 显式 URL |
|----------|----------|----------|
| 用户 Facade（**UserFacade**） | jjb-saas-system | `dubbo://192.168.20.100:32080` |
| 消息 Facade（**MessageFacade**） | jjb-saas-message | `dubbo://192.168.20.100:32084` |
| 认证 / 安全 | jjb-saas-auth / security | `32081` / `32083` |
| 附件 | jjb-saas-attachment | `dubbo://192.168.20.100:32093` |

更多端口见 `dubbo-reference-local.example.properties`。

### 5.6 本地清单（汇总）

| 类别 | 配置 | 值 |
|------|------|-----|
| Profile | `spring.profiles.active` | `local` |
| Nacos 配置中心 | `spring.cloud.nacos.config.server-addr` | `192.168.20.100:30290` |
| Nacos 命名空间 | `jjb-dragon` | 与线上一致（只读拉配置） |
| Nacos 服务注册 | `spring.cloud.nacos.discovery.enabled` | `false` |
| 网关 | `gateway.url` | `http://192.168.20.100:30140` |
| MySQL | host/port | `192.168.20.100:33080` |
| Redis | host/port | `192.168.20.100:6379` |
| Dubbo UserFacade | `GBS_USER_FACADE_URL` | `dubbo://192.168.20.100:32080` |
| Dubbo MessageFacade | `GBS_MESSAGE_FACADE_URL` | `dubbo://192.168.20.100:32084` |
| 本地服务端口 | `server.port` | `8095` |

### 5.7 本项目已改文件清单（新会话核对用）

| 文件 | 改动说明 |
|------|----------|
| `safety-eval-start/src/main/resources/bootstrap.yml` | `local` profile import `application-local.yml` |
| `safety-eval-start/src/main/resources/application-local.yml` | 关闭 discovery；配置 Dubbo 显式 URL |
| `safety-eval-infrastructure/.../GbsUserFacadeClient.java` | `@DubboReference(url = "${safety-eval.gbs-user-sync.user-facade-url:}")` |
| `safety-eval-infrastructure/.../SmsRemote.java` | `@DubboReference(url = "${safety-eval.dubbo.message-facade-url:}")` |

新增 Dubbo 依赖时，按同样模式在 `application-local.yml` 增加 URL 属性，并在对应 `@DubboReference` 绑定 `${...}` 占位符。

---

## 6. 完整操作流程（首次）

### Step 1：100 安装或确认代理

```bash
# 先检查（4.0），未安装则：
python docs/gbs/scripts/dubbo-dev-proxy/deploy_plan_c.py
# 或 SSH 到 100 手动执行 dubbo-proxy-install.sh
```

### Step 2：本地验证 VPN + 代理端口

```powershell
Test-NetConnection 192.168.20.100 -Port 32080
Test-NetConnection 192.168.20.100 -Port 32084
Test-NetConnection 192.168.20.100 -Port 30140
Test-NetConnection 192.168.20.100 -Port 30290
```

### Step 3：本地配置 IDE

1. 确认 `application-local.yml` 存在（或从 example 复制）
2. 设置 VM Options（见 5.4）
3. Active profiles 填 `local`

### Step 4：启动本地服务并验证

启动后检查日志：

- Nacos 配置拉取成功
- Dubbo 连接 `192.168.20.100:32080` / `32084` 成功
- **无** `10.244.x.x` 连接超时

### Step 5：功能验证

- 调用依赖 GBS 用户的接口（用户同步）
- 调用依赖短信的接口（MessageFacade）
- 通过网关 `30140` 访问前端页面（可选）

---

## 7. 故障排查

| 现象 | 排查 |
|------|------|
| 本地 `32080` / `32084` 连不上 | VPN 是否通；100 上 `dubbo-proxy-status.sh` 是否 running；防火墙是否开放 |
| Dubbo 仍连 `10.244.*` | 未走 `local` profile；未配置显式 URL；检查 `GbsUserFacadeClient` / `SmsRemote` |
| 代理 running 但调用失败 | Pod 已漂移，执行 `dubbo-proxy-refresh.sh` 或 `debug_plan_c.py` |
| 100 上某服务显示 skipped | 对应 Pod 非 Running，`kubectl get pods -n jjb-dragon` 检查 |
| 集群内服务异常 | 确认未改 Deployment env；`kubectl get svc -n jjb-dragon \| grep dubbo` 应为空 |
| UserFacade 调不通但 32088 通 | **端口配错**：UserFacade 用 `32080`（system），不是 `32088`（user） |

---

## 8. 安全与维护建议

1. **限制访问源**：若 VPN 网段固定，可将 `32080-32100` 仅对 VPN 网段开放（`firewall-cmd --add-rich-rule`）
2. **下班停止**：不需要联调时 `dubbo-proxy-stop.sh`，减少暴露面
3. **禁止方案 A**：不得创建 `*-dubbo` NodePort Service 或设置 `DUBBO_IP_TO_REGISTRY`
4. **Pod 大规模重启后**：手动执行一次 `dubbo-proxy-refresh.sh`
5. **定期核对**：`kubectl get svc -n jjb-dragon | grep dubbo` 应始终为空

---

## 9. 相关文档

- `docs/gbs/GBS底座服务手册v2.md` — 端口与 Nacos 外部访问说明
- `docs/本地JAR打包发布到100服务器完整流程.md` — K8s 部署流程（与本地开发并行）

---

## 10. 脚本文件说明

| 文件 | 用途 |
|------|------|
| `dubbo-proxy.map` | 端口 ↔ Pod 标签映射 |
| `dubbo-proxy-install.sh` | 100 一次性安装 |
| `dubbo-proxy-refresh.sh` | 刷新 socat 到当前 Pod IP |
| `dubbo-proxy-status.sh` | 查看运行状态 |
| `dubbo-proxy-stop.sh` | 停止全部代理 |
| `deploy_plan_c.py` | 从开发机 SSH 上传并安装（新会话推荐） |
| `debug_plan_c.py` | 远程诊断代理与 Pod 状态 |
| `application-local.example.yml` | 本地 IDE 完整配置模板 |
| `dubbo-reference-local.example.properties` | Dubbo 显式 URL 速查 |
