Files
aiops/docs/terminal-architecture.md
T
LoganandClaude 76ec9387f0 feat(rdp): 新增 RDP 远程桌面/SMB/账单同步能力 + 清理编译产物
主要变更:
- RDP 远程桌面:新增 backend/pkg/rdp(RDP 引擎 + credssp/display/rle/trace)、
  backend/controller/rdp*(连接/凭证/文件/会话/实时)、frontend RDP 组件与 API
- Windows SMB 文件传输:backend/pkg/winsmb
- 云账单同步:backend/pkg/billingsync + billing_sync/aliyun_billing,前端账单详情
- Agent CLI Kubernetes 工具:kubernetes_action/get、pod_execute/logs
- 服务器导入助手:server_import_helpers、ImportCredentialSettings
- 国际化与组件重构(cloud/deploy/monitor/server/system 等多模块)
- 清理编译产物二进制:移除 backend/server、backend/agent/bin/aiops-agent-*
- .gitignore:新增 backend/agent/ 与 .cache/(避免 334MB go-build 缓存误入库)

Co-Authored-By: Claude <noreply@anthropic.com>
2026-07-04 01:50:36 +08:00

525 lines
14 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# AIOps 终端与远程桌面设计说明
> 更新:2026-07-03
> 范围:SSH WebShell、Windows RDP、Kubernetes Pod exec、kubectl 集群终端、流水线 Workspace 终端、审计实时查看与历史回放。
> 本文用于记录当前实现、设计取舍与后续重构方向。// Logan.Li
---
## 1. 总体目标
AIOps 的终端体系不是单一功能,而是一组共享基础能力:
1. **实时交互**:浏览器通过 WebSocket 与后端建立交互式会话。
2. **尺寸自适应**:前端终端容器变化后执行 `fit()`,并同步 `cols/rows` 到远端 PTY。
3. **审计留痕**:会话起止、用户、资产、输入动作、命令、输出大小、录制数据可追溯。
4. **历史回放**:SSH 终端使用文本流回放,RDP 使用 Canvas 图形帧回放。
5. **统一体验**:SSH、Pod、kubectl、Workspace 终端共享 xterm.js 适配策略;RDP 使用 Canvas 独立渲染策略。
核心原则:
- 终端输入只走实时链路,审计只记录有价值的离散事件。
- `mousemove` 等高频低价值事件不持久化。
- RDP 历史回放采用节流图形帧,不保存每个实时帧,避免存储爆炸。
- 前端终端窗口不手写分散 resize 逻辑,统一走 `frontend/src/lib/xterm-utils.ts`。// Logan.Li
---
## 2. 统一链路
### 2.1 SSH / Pod / kubectl / Workspace
```
Browser xterm.js
├─ onData → WebSocket JSON {status:0,data}
├─ ResizeObserver + FitAddon
└─ resize → WebSocket JSON {status:1,cols,rows}
│
▼
Backend WebSocket Handler
├─ SSH: ssh.Session + PTY
├─ Pod exec: Kubernetes channel.k8s.io WebSocket
├─ kubectl: local kubectl process + PTY
└─ Workspace: pipeline workspace shell + PTY
│
▼
Audit / Recording
├─ terminal session metadata
├─ asciicast text stream
└─ command records
```
### 2.2 Windows RDP
```
Browser Canvas
├─ mouse/key/clipboard input → WebSocket JSON
└─ bitmap frames ← WebSocket binary RDPR
│
▼
controller/rdp.go
├─ load RDP credential
├─ create RDPSession
├─ start Engine.Run()
├─ broadcast live audit frames
└─ throttle snapshot frames for replay
│
▼
pkg/rdp Engine
└─ AIOps RDP protocol engine
```
RDP 与 xterm 终端不同:它没有 PTY 的 `cols/rows` 概念,主要优化点是输入事件合并、图形帧编码、Canvas 绘制和录屏抽样。// Logan.Li
---
## 3. 前端终端窗口适配
公共工具:`frontend/src/lib/xterm-utils.ts`
| 方法 | 作用 |
|------|------|
| `fitTerminal()` | 调用 FitAddon,并在 WebSocket 打开时发送 `{status:1,cols,rows}` |
| `mountXterm()` | 等容器渲染完成后挂载 xterm,延迟多次 fit,减少右侧黑边 |
| `attachTerminalResize()` | 通过 ResizeObserver 监听容器尺寸,节流 fit 和 resize 同步 |
已接入或应接入的组件:
| 组件 | 类型 | 说明 |
|------|------|------|
| `TerminalDialog.tsx` | SSH 单会话终端 | 资产列表打开 SSH |
| `WebShell.tsx` | SSH 多标签终端 | WebShell 页面 |
| `PodExecTerminal.tsx` | Pod exec | K8s Pod 容器终端 |
| `KubectlTerminal.tsx` | kubectl | 集群级 kubectl shell |
| `WorkspaceTermDialog.tsx` | Workspace shell | 流水线构建目录终端 |
| `LiveMonitorDialog.tsx` | SSH 实时审计 | 只读 xterm |
| `ReplayDialog.tsx` | SSH 历史回放 | asciicast 回放 |
终端容器统一使用:
```tsx
<div ref={containerRef} className="xterm-terminal-host" />
```
全局样式位置:`frontend/src/index.css`
```css
.xterm-terminal-host {
width: 100%;
overflow: hidden;
background: #0a0e14;
}
.xterm-terminal-host .xterm {
height: 100%;
}
```
注意事项:
- Dialog 动画会影响 xterm 首次测量,因此终端弹框禁用过渡。
- `fit()` 后必须同步后端 PTY 尺寸,否则只是前端铺满,远端程序仍按旧尺寸输出。
- `term.open()` 只能对同一个 xterm 实例执行一次,复用场景需要检查 `term.element`。// Logan.Li
---
## 4. SSH 终端实现
主要文件:
| 文件 | 说明 |
|------|------|
| `backend/controller/webshell.go` | SSH WebSocket、PTY、录制、命令审计 |
| `backend/model/terminal_session.go` | SSH 会话模型 |
| `backend/model/session_command.go` | 命令审计模型 |
| `frontend/src/components/server/TerminalDialog.tsx` | 单资产 SSH 终端 |
| `frontend/src/components/server/WebShell.tsx` | 多标签 SSH 终端 |
协议:
```json
{ "status": 0, "data": "ls -la\n" }
{ "status": 1, "cols": 120, "rows": 34 }
```
审计策略:
- 会话记录:开始时间、结束时间、用户、资产、状态、录制大小。
- 录制数据:asciicast 文本流。
- 命令记录:按回车提交后提取命令,不记录每个按键。
- 输出统计:下一条命令前累计 stdout 字节数写入上一条命令。
优化方向:
- 命令列表按会话聚合展示,减少碎片行。
- 对连续输入、粘贴、多行脚本增加摘要视图。
- 高危命令识别只用于展示和告警,不阻塞正常录制。// Logan.Li
---
## 5. Kubernetes Pod Exec
主要文件:
| 文件 | 说明 |
|------|------|
| `backend/controller/k8s_pod.go` | Pod exec WebSocket 代理 |
| `frontend/src/components/kubernetes/PodExecTerminal.tsx` | Pod 终端 UI |
链路:
```
xterm.js
└─ WebSocket JSON
└─ backend
└─ Kubernetes API WebSocket channel.k8s.io
```
K8s channel 映射:
| Channel | 方向 | 说明 |
|---------|------|------|
| 0 | client → pod | stdin |
| 1 | pod → client | stdout |
| 2 | pod → client | stderr |
| 3 | pod → client | error/status |
| 4 | client → pod | resize |
前端 resize JSON:
```json
{ "status": 1, "cols": 120, "rows": 34 }
```
后端转换为 K8s resize frame:
```json
{ "Width": 120, "Height": 34 }
```
注意事项:
- Pod exec 不应进入 SSH 命令审计表,除非未来设计 K8s 独立审计模型。
- 容器切换、shell 切换会重连 WebSocket。
- ESC 必须传给终端,Dialog 不能用 ESC 自动关闭。// Logan.Li
---
## 6. kubectl 集群终端
主要文件:
| 文件 | 说明 |
|------|------|
| `backend/controller/kubectl_shell.go` | kubectl shell WebSocket |
| `frontend/src/components/kubernetes/KubectlTerminal.tsx` | kubectl 终端 UI |
设计目标:
- 给运维提供集群级 kubectl shell。
- 使用与 SSH 相同的 xterm 自适应策略。
- 后端负责 kubeconfig/集群上下文隔离。
风险点:
- kubectl shell 权限大,必须依赖 RBAC、审计和操作权限控制。
- 后续应对危险命令做二次确认或审计标记。
- 多集群切换时不能复用旧进程上下文。// Logan.Li
---
## 7. Workspace 终端
主要文件:
| 文件 | 说明 |
|------|------|
| `backend/controller/workspace_files.go` | 流水线工作区文件/终端入口 |
| `frontend/src/components/deploy/WorkspaceTermDialog.tsx` | 工作区终端 UI |
用途:
- 进入流水线构建目录查看文件。
- 辅助排查构建产物、日志、临时文件。
设计约束:
- 默认目录必须限制在 pipeline workspace 内。
- 后端不能允许用户通过路径逃逸进入任意系统目录。
- 终端尺寸适配与 SSH 共用 `xterm-utils`。// Logan.Li
---
## 8. RDP 实现
主要文件:
| 文件 | 说明 |
|------|------|
| `backend/controller/rdp.go` | RDP WebSocket、会话、审计、实时帧推送 |
| `backend/controller/rdp_live.go` | RDP 实时审计广播 |
| `backend/controller/rdp_session.go` | RDP 会话列表、录制、终止 API |
| `backend/pkg/rdp/engine.go` | 引擎选择 |
| `backend/pkg/rdp/session_engine.go` | 自研 RDP 引擎主循环 |
| `frontend/src/components/server/RdpDialog.tsx` | RDP 实时操作窗口 |
| `frontend/src/components/system/RdpAuditViewer.tsx` | RDP 实时审计与历史回放 |
### 8.1 自研 RDP 引擎策略
当前后端固定使用自研 `SessionEngine`,不再通过 `RDP_ENGINE` 切换第三方兜底。已删除的 grdp 目录备份到:
```text
/opt/rdp/third-party/grdp-aiops-backup-20260703
```
仓内 `backend/third_party` 已清理,Dockerfile 不再复制本地 replace 模块。// Logan.Li
### 8.2 WebSocket 帧协议
服务端到浏览器:
```json
{ "type": "session", "message": "123", "width": 1024, "height": 800 }
{ "type": "status", "message": "正在连接 RDP ..." }
{ "type": "error", "message": "..." }
```
图像帧优先走二进制:
```text
RDPR + x:uint32 + y:uint32 + width:uint32 + height:uint32 + rgba:[]
```
历史回放帧走节流 PNG:
```json
{ "type": "bitmap", "x": 0, "y": 0, "width": 300, "height": 200, "image": "data:image/png;base64,..." }
```
浏览器到服务端:
```json
{ "type": "mouse_move", "x": 100, "y": 200 }
{ "type": "mouse_down", "x": 100, "y": 200, "button": 0 }
{ "type": "mouse_up", "x": 100, "y": 200, "button": 0 }
{ "type": "wheel", "x": 100, "y": 200, "delta_y": -120 }
{ "type": "key", "code": "KeyA", "key": "a", "down": true }
{ "type": "clipboard", "text": "..." }
```
### 8.3 输入优化
- 前端 `mousemove` 16ms 合并,只保留最新坐标。
- `mouse_down`、`mouse_up` 前先 flush 最新坐标,保证拖拽起止准确。
- 后端输入队列满时丢弃移动事件,关键事件优先。
- RDP 引擎处理输入时不打印每个 `mousemove`,避免日志拖慢实时操作。
### 8.4 图形优化
- 实时图形帧使用 RGBA 二进制直传,历史回放使用节流 PNG 快照。
- 前端 Canvas 使用 `putImageData()` 绘制二进制帧。
- 右下角帧统计节流刷新,避免每帧 React 重渲染。
- RDP 录屏只保存节流快照,不保存每个实时帧。
### 8.5 审计策略
持久化:
- 会话元数据:用户、资产、开始/结束时间、状态、录制大小。
- 离散操作:点击、滚轮、剪贴板、文件上传下载、输入摘要。
- 历史回放:节流图形快照。
不持久化:
- 高频 `mousemove`。
- 每个实时 RGBA 帧。
- 无业务含义的连续坐标变化。
拖拽建议记录:
```text
[RDP拖拽] button=left start=(x1,y1) end=(x2,y2) duration=850ms
```
普通点击建议记录:
```text
[RDP点击] button=left x=100 y=200
```
键盘输入建议合并:
```text
[RDP输入] abc*** # 敏感字段后续可脱敏
```
---
## 9. 审计页设计
当前菜单:`/audit/terminal`
建议子页签:
| 页签 | 内容 |
|------|------|
| 在线会话 | SSH 在线会话 + RDP 在线会话 |
| 历史会话 | SSH 历史 asciicast 回放 + RDP Canvas 回放 |
| 会话命令 | SSH 命令 + RDP 操作摘要,按会话聚合展示 |
### 9.1 在线会话
SSH:
- 使用 `LiveMonitorDialog`
- 后端 `/ws/audit/:sessionId`
- 只读 xterm
RDP:
- 使用 `RdpAuditViewer mode="live"`
- 后端 `/ws/rdp-audit/:sessionId`
- 只读 Canvas
### 9.2 历史会话
SSH:
- 使用 `ReplayDialog`
- 数据源:`terminalSessionApi.getRecord()`
- 格式:asciicast 文本
RDP:
- 使用 `RdpAuditViewer mode="replay"`
- 数据源:`rdpSessionApi.getRecord()`
- 格式:节流 PNG bitmap JSON
### 9.3 会话命令 / 操作摘要
问题:
- SSH 命令记录适合逐条展示。
- RDP 如果按键、点击、剪贴板都逐条展示,会出现大量低价值行。
建议:
1. 后端写入时尽量合并:
- 连续键盘输入合并为 `[RDP输入] ...`
- 拖拽只记录开始/结束。
- 点击和滚轮按短时间窗口合并。
2. 前端展示时按会话聚合:
- 默认展示会话摘要。
- 展开后看详细事件。
- 高危动作、文件传输、剪贴板单独标记。
---
## 10. 当前架构质量评估
### 10.1 做得好的地方
- `backend/pkg/rdp/domain` 定义了引擎接口,控制器不直接依赖协议细节。
- `transport/`、`credssp/`、`rle/`、`display/` 已经有基础分层。
- RDP 依赖已收敛到自研协议栈,构建不再需要 `backend/third_party`。
- xterm 终端已抽出公共适配工具,后续维护成本低。
- RDP 实时帧和历史回放帧开始分离,避免审计存储被实时帧撑爆。
### 10.2 需要优化的地方
| 文件 | 问题 | 建议 |
|------|------|------|
| `backend/pkg/rdp/mcs_probe.go` | 1664 行,严重超过红线 | 拆成 `mcs_connect.go`、`gcc_caps.go`、`confirm_active.go`、`client_info.go`、`probe.go` |
| `backend/controller/rdp.go` | 约 460 行,承担会话、审计、帧编码、快照 | 拆出 `rdp_sink.go`、`rdp_audit.go`、`rdp_input_audit.go` |
| `RdpDialog.tsx` | 实时渲染、输入、工具面板入口集中 | 后续拆出 `useRdpSocket()`、`useRdpCanvas()`、`useRdpInput()` |
| `PodExecTerminal.tsx` | 连接、UI、resize 混合 | 可抽 `useXtermWebSocket()` |
| `KubectlTerminal.tsx` | 与 Pod exec 重复 | 与 Pod/Workspace 共用 hook |
### 10.3 建议目标结构
后端 RDP:
```text
backend/pkg/rdp/
├── domain/
├── engine.go
├── session_engine.go
├── input/
│ ├── fastpath.go
│ └── keymap.go
├── graphics/
│ ├── framebuffer.go
│ ├── codec.go
│ └── rle/
├── mcs/
│ ├── connect.go
│ ├── gcc.go
│ ├── caps.go
│ └── active.go
├── credssp/
└── transport/
```
控制器:
```text
backend/controller/
├── rdp.go # 路由入口和会话编排
├── rdp_sink.go # WebSocket frame sink
├── rdp_live.go # 实时审计广播
├── rdp_input_audit.go # 点击/拖拽/输入摘要
├── rdp_session.go # 会话 REST API
├── rdp_file.go
└── rdp_cred.go
```
前端:
```text
frontend/src/components/terminal/
├── useXtermSocket.ts
├── XtermDialogShell.tsx
└── terminalTheme.ts
frontend/src/components/rdp/
├── useRdpSocket.ts
├── useRdpCanvas.ts
├── useRdpInput.ts
├── RdpDialog.tsx
└── RdpAuditViewer.tsx
```
---
## 11. 验证清单
终端类修改后建议验证:
```bash
cd frontend
npx tsc --noEmit
npm run build
```
后端修改后建议验证:
```bash
cd backend
go build -o aiops .
```
端到端:
```bash
./run.sh docker up
python3 tests/integration_test.py --host localhost --port 8080
```
手动检查:
- SSH 终端打开、缩放、全屏、输入、回放。
- Pod exec 打开、切 shell、缩放、全屏。
- kubectl 终端打开、缩放、全屏。
- Workspace 终端打开、缩放、全屏。
- RDP 打开、拖动窗口、文件夹拖拽、实时审计、历史回放。
- 会话命令页筛选、导出、从命令跳转回放。// Logan.Li