- 支持 Windows Agent 构建、安装脚本和统一上报协议 - 增强 RDP 剪贴板、虚拟盘和文件传输能力 - 新增 AIOps 上下文工具、告警 RCA trace 落库和回放接口 - 重构 docs 模块文档并补充终端、堡垒机、监控、AI Agent 设计
12 KiB
12 KiB
AIOps 终端体系实现规格
更新:2026-07-05 目标:让另一个项目仅阅读本文档,也能实现 WebSSH、Pod exec、kubectl、Workspace 终端和审计回放。 范围:xterm.js 前端底座、WebSocket 协议、后端 PTY/SSH/K8s 代理、会话录像、命令审计、实时查看。
1. 终端类型和职责
| 类型 | 前端渲染 | 后端执行 | 典型入口 | 审计方式 |
|---|---|---|---|---|
| SSH WebShell | xterm.js | ssh.Session + PTY |
服务器管理、WebShell | asciicast + 命令 |
| Pod Terminal | xterm.js | K8s pods/exec WebSocket |
Pod 详情 | 预留 K8s 审计 |
| kubectl Terminal | xterm.js | 本地 kubectl 进程 + PTY |
集群管理 | 建议命令审计 |
| Workspace Terminal | xterm.js | 本地 shell + PTY,限制目录 | 流水线工作区 | 建议命令审计 |
| RDP | Canvas | RDP 协议引擎 | Windows 资产 | 独立图形录像 |
本文只定义字符终端。RDP 详见 RDP 实现规格。
2. 统一前端底座
2.1 组件结构
Terminal Dialog/Page
├── create Terminal()
├── load FitAddon
├── mount into .xterm-terminal-host
├── open WebSocket
├── onData → ws.send({ status: 0, data })
├── ResizeObserver → fit() → ws.send({ status: 1, cols, rows })
└── ws.onmessage → terminal.write(data)
公共工具应提供:
| 方法 | 职责 |
|---|---|
mountXterm() |
延迟挂载、打开 terminal、执行多次初始 fit |
fitTerminal() |
调用 FitAddon,返回 cols/rows |
attachTerminalResize() |
监听容器 resize,节流 fit 并同步后端 |
disposeTerminal() |
关闭 WebSocket、移除 observer、销毁 xterm |
2.2 DOM 和样式要求
<div className="xterm-terminal-host" ref={containerRef} />
.xterm-terminal-host {
width: 100%;
height: 100%;
overflow: hidden;
background: #0a0e14;
}
.xterm-terminal-host .xterm {
height: 100%;
}
要求:
- 终端容器必须有稳定高度,不能依赖内容撑开。
- Dialog 动画会影响 xterm 测量,终端弹窗建议禁用打开/关闭缩放动画。
term.open()同一实例只能调用一次。fit()后必须把cols/rows发给后端,否则远端 PTY 仍按旧尺寸输出。
2.3 推荐 xterm 配置
const terminalOptions = {
cursorBlink: true,
convertEol: true,
fontFamily: 'Menlo, Monaco, Consolas, monospace',
fontSize: 13,
lineHeight: 1.15,
scrollback: 5000,
theme: {
background: '#0a0e14',
foreground: '#d8dee9',
cursor: '#f8fafc',
},
};
交互要求:
- ESC、Ctrl+C、Ctrl+D 必须传给终端,不应被 Dialog 或页面快捷键抢走。
- 粘贴走 xterm 默认粘贴或
navigator.clipboard.readText()后写入 WebSocket。 - 多标签终端切换时,不要销毁非当前标签的 WebSocket,除非用户主动关闭。
3. WebSocket 协议
3.1 通用 JSON 协议
浏览器到后端:
{ "status": 0, "data": "ls -la\n" }
{ "status": 1, "cols": 120, "rows": 34 }
后端到浏览器:
{ "status": 0, "data": "total 8\r\n" }
{ "status": 2, "message": "connected" }
{ "status": -1, "message": "connection failed" }
字段语义:
| 字段 | 方向 | 说明 |
|---|---|---|
status=0 |
双向 | stdin/stdout 数据 |
status=1 |
浏览器到后端 | resize,包含 cols/rows |
status=2 |
后端到浏览器 | 状态提示,可选 |
status=-1 |
后端到浏览器 | 错误提示 |
实现要求:
- 后端读取 WebSocket 后按
status分流。 - stdout/stderr 可以合并写回
status=0,也可以扩展stream字段。 - 输入数据必须原样写入 PTY,不要按行缓存,否则 vim/top 等交互程序不可用。
- resize 事件必须节流,建议 100-200ms。
3.2 鉴权
WebSocket 无法稳定设置自定义 Header,因此支持两种方式:
/ws/terminal/:serverId?token=<JWT>
/ws/pod/exec?...&token=<JWT>
要求:
- 后端优先读
Authorization,其次读?token=。 - 鉴权通过后仍要做资源权限校验。
- token 不能写入审计命令和终端录制。
4. SSH WebShell
4.1 后端流程
GET /ws/terminal/:serverId
→ JWTAuth
→ load server asset
→ load credential
→ ssh.Dial
→ session.RequestPty(term, rows, cols, modes)
→ session.Shell()
→ create sys_terminal_sessions
→ goroutine: ws input → ssh stdin
→ goroutine: ssh stdout/stderr → ws output + recorder + audit hub
→ on close: update duration, status, record_data, record_size
PTY 参数:
ssh.TerminalModes{
ssh.ECHO: 1,
ssh.TTY_OP_ISPEED: 14400,
ssh.TTY_OP_OSPEED: 14400,
}
4.2 命令审计
基础策略:
- 按回车提取命令。
- 不记录每个按键。
- 下一条命令出现前,统计上一条命令后的输出字节数。
- 粘贴多行脚本应合并或标记为多行命令。
命令表:
sys_session_commands
session_id
session_type = terminal
user_id / username
server_id / server_name
command
output_size
timestamp
敏感信息建议:
- 对
password=...、token=...、AKIA...、私钥片段做脱敏。 - 命令审计保存脱敏结果,原始录制可按安全策略决定是否保存。
5. asciicast 录制和回放
5.1 录制格式
使用 asciicast v2:
{"version":2,"width":120,"height":34,"timestamp":1783131042,"env":{"TERM":"xterm-256color"}}
[0.120,"o","Last login: ...\r\n"]
[0.450,"o","$ "]
[1.200,"o","ls -la\r\n"]
实现要求:
- 第一行是 header。
- 后续每行是
[timeOffset, "o", output]。 - 只录制后端输出,不录制用户输入的独立事件,避免重复。
RecordData建议限制大小,超过上限后截断并标记。
5.2 回放
前端回放流程:
GET /api/v1/terminal-sessions/:id/record
→ parse asciicast
→ create read-only xterm
→ 按 timeOffset 调度 terminal.write()
→ 支持播放、暂停、倍速、拖动进度
验收:
- 回放画面和原终端输出顺序一致。
- 支持命令书签跳转。
- 删除会话后录制不可访问。
6. Pod Exec
6.1 后端链路
Browser xterm
→ AIOps backend WebSocket
→ Kubernetes API /api/v1/namespaces/{ns}/pods/{pod}/exec
→ channel.k8s.io WebSocket
→ container shell
K8s channel:
| Channel | 方向 | 内容 |
|---|---|---|
| 0 | client to pod | stdin |
| 1 | pod to client | stdout |
| 2 | pod to client | stderr |
| 3 | pod to client | error/status |
| 4 | client to pod | resize |
resize frame:
{ "Width": 120, "Height": 34 }
实现要求:
- shell 可选
/bin/bash、/bin/sh。 - namespace、pod、container 必须做权限校验。
- 容器切换时必须重连。
- Pod exec 不应写入 SSH 的
sys_terminal_sessions,建议后续建 K8s 独立会话表。
7. kubectl 终端
7.1 后端链路
GET /ws/kubectl?cluster_id=1
→ JWTAuth + cluster permission
→ create temp kubeconfig
→ exec kubectl with PTY
→ ws input/output bridge
→ cleanup temp kubeconfig and process
安全要求:
- kubeconfig 必须按用户和集群隔离。
- 临时文件使用随机名,关闭后删除。
- 禁止复用上一次集群上下文。
- kubectl 权限由 AIOps RBAC 和集群 RBAC 双重约束。
建议审计:
- 记录输入命令。
- 标记
delete、scale、rollout restart、patch、apply为高风险。 - 后续接入审批或二次确认。
8. Workspace 终端
8.1 后端链路
GET /ws/workspace/:pipelineRunId/terminal
→ JWTAuth + pipeline permission
→ resolve workspace dir
→ ensure dir is under workspace root
→ start shell with PTY
→ ws input/output bridge
路径安全:
- 所有路径必须
filepath.Clean。 realpath后必须仍位于 workspace root 下。- 禁止用户通过
../../进入任意系统目录。 - Shell 的工作目录固定为本次 pipeline workspace。
9. 实时审计
9.1 SSH 实时查看
active SSH session
→ AuditHub broadcast output
→ /ws/audit/:sessionId
→ LiveMonitorDialog read-only xterm
要求:
- 审计端只读,不允许发送 stdin。
- 审计连接不能影响主会话性能。
- 活动会话结束后,审计连接收到关闭提示。
9.2 统一审计页
建议页面分区:
| 页签 | 内容 |
|---|---|
| 在线会话 | SSH active + RDP active |
| 历史会话 | SSH asciicast + RDP bitmap replay |
| 会话命令 | SSH 命令 + RDP 操作摘要 |
10. 数据模型
10.1 SSH 会话
sys_terminal_sessions
id
user_id / username
server_id / server_name / server_ip / server_port
client_ip
status: active | closed | failed
duration
record_data
record_size
start_time / end_time
10.2 命令审计
sys_session_commands
id
session_id
session_type: terminal | rdp
user_id / username
server_id / server_name
command
output_size
timestamp
10.3 策略配置
sys_audit_settings
retention_days
record_all
session_watermark_enabled
session_record_enabled
command_policy_enabled
approval_required
字符终端第一版至少需要:
record_allsession_record_enabledsession_watermark_enabledretention_days
11. 错误处理
| 场景 | 前端表现 | 后端处理 |
|---|---|---|
| 鉴权失败 | 显示未登录或无权限 | 关闭 WebSocket |
| 凭据错误 | 显示连接失败 | 会话状态 failed,保存错误 |
| SSH 超时 | 显示超时 | 释放 session/client |
| PTY resize 失败 | 显示警告或忽略 | 继续会话 |
| WebSocket 断开 | 显示已断开 | 关闭远端 session |
| 用户关闭窗口 | 清理资源 | 更新 end_time、duration |
实现要求:
- 任何退出路径都必须关闭 PTY、进程、SSH client、WebSocket。
- 后端 goroutine 需要 context 取消,避免泄露。
- 会话状态更新要放在
defer中兜底执行。
12. 验收清单
12.1 WebSSH
- 打开服务器 SSH 终端成功。
ls、top、vim、Ctrl+C、Ctrl+D 可用。- 拖动窗口或最大化后,远端
stty size与前端一致。 - 会话关闭后
sys_terminal_sessions状态为closed。 - 回放可播放完整输出。
- 命令审计能看到命令和输出大小。
12.2 Pod Exec
- 选择 namespace/pod/container 后能进入 shell。
- stdout/stderr 都能显示。
- resize 后
stty size正确。 - 容器切换会重连。
- 无权限 namespace 无法连接。
12.3 kubectl
- 打开指定集群 kubectl 终端。
kubectl get pods -A输出正常。- 切换集群不会复用旧上下文。
- 关闭窗口后后端 kubectl 进程退出。
12.4 Workspace
- 打开流水线工作区终端。
- 默认目录在 workspace root。
pwd、ls正常。- 不能通过路径逃逸访问系统目录。
12.5 审计回放
- 在线会话能实时只读查看。
- 历史会话能按时间播放。
- 删除会话后录制和命令记录按策略处理。
- 关闭录制策略后不写
record_data。
13. 常见问题
| 问题 | 原因 | 处理 |
|---|---|---|
| 终端右侧黑边 | 初始 fit 太早 | mount 后延迟多次 fit |
| resize 后远端仍旧宽度 | 只 fit 前端,未发 cols/rows | WebSocket 发送 status=1 |
| Ctrl+C 不生效 | 页面快捷键拦截 | xterm 容器 focus 后透传 |
| vim 显示错乱 | PTY 类型或 resize 不正确 | 使用 xterm-256color 并同步尺寸 |
| 回放速度不对 | time offset 解析错误 | 按 asciicast v2 第一列调度 |
| WebSocket 断开后进程残留 | 后端未 cancel context | close handler 统一清理 |
| Pod exec 没输出 | K8s channel 未拆分 | 按 channel 1/2 读取 stdout/stderr |