本指南记录最终的 Remote Runtime v1 模型:远程执行统一走 websocket,SSH 固定在 helper 通道,运维在 direct-connect listener 和 reverse-connect machine-agent daemon 两种拓扑之间做选择。内容涵盖支持拓扑、旧机器记录迁移、验证策略、可观测性、守护进程安装、升级与回滚,以及分阶段 rollout 检查清单。
本指南中的术语:
direct_connect:控制面可以主动拨到机器。reverse_connect:机器守护进程可以反向拨回控制面。websocket:目标远程执行路径。- SSH 仅保留为引导、诊断和紧急修复 helper。
Remote Runtime v1 将远程机器行为拆成三个独立关注点:
- 拓扑:
direct_connect或reverse_connect - runtime 平面:统一 websocket
- helper 通道:可选的 SSH bootstrap 与 diagnostics
它们与机器存储字段和运行入口的映射如下:
| 拓扑 | 机器存储状态 | 运行入口 | 说明 |
|---|---|---|---|
| Direct-connect listener | reachability_mode=direct_connect、execution_mode=websocket |
控制面直接拨号到保存的 advertised_endpoint |
适用于 OpenASE 可以直接到达机器 |
| Reverse-connect daemon | reachability_mode=reverse_connect、execution_mode=websocket |
远端主机运行 openase machine-agent run 并保持 machine-channel 会话 |
适用于机器可以向外拨号但不应暴露入站 listener |
从仓库根目录运行聚焦的传输矩阵:
scripts/ci/remote_transport_matrix.sh当前快速矩阵覆盖:
| 场景 | 覆盖 |
|---|---|
| 监听与反向拓扑共享的统一 WebSocket runtime 契约 | TestUnifiedWebsocketRuntimeContractSuite |
| SSH 引导 + 反向 WebSocket 机器会话 | TestMachineConnectWebsocketPublishesActivityAndMetrics |
| 反向 WebSocket runtime 正常路径(含 hook 与产物同步) | TestRuntimeLauncherLaunchesWebsocketReverseRuntimeWithHooksAndArtifactSync |
| SSH 引导 helper 行为 | TestRunMachineSSHBootstrapUploadsBinaryEnvAndService |
| SSH 诊断 helper 行为 | TestRunMachineSSHDiagnosticsReportsBootstrapAndRegistrationIssues |
| SSH 引导 + 监听 WebSocket 运行时 | TestRuntimeLauncherLaunchesWebsocketListenerRuntimeWithHooksAndArtifactSync |
| 直接 SSH runtime 拒绝 | TestRuntimeLauncherRunTickRejectsSSHRuntimeExecution |
| 无反向会话时反向 WebSocket 启动不回退到 SSH | TestRuntimeLauncherDoesNotFallBackToSSHWhenWebsocketReverseTransportUnavailable |
| 远程二进制/预检失败 | TestRuntimeLauncherRecordsWebsocketPreflightFailureStageInActivityAndMetrics |
| 守护进程认证失败 | TestMachineConnectWebsocketAuthFailurePublishesActivityAndMetric |
每个正常路径运行时用例验证:
- 机器注册或可达性
- 工作空间准备
- Agent 进程启动
- 输出流或命令握手
- 清理或断开连接记账
按以下顺序使用验证层:
scripts/ci/remote_transport_matrix.sh- 对于具备 Linux + Docker Compose 的机器,运行
make remote-runtime-container或scripts/ci/remote_runtime_container_harness.sh ... - rollout 过程中结合
openase machine test <machine-uuid>与openase machine ssh-diagnostics <machine-uuid>做定向运维检查
设计意图是:
- 快速矩阵进入普通仓库和 PR 验证
- 容器 harness 负责本地专用或手动 / nightly 的 rollout 级检查
- 运维命令负责部署后的单机诊断
当你需要验证真实的守护进程启动、容器网络、远端文件系统权限、SSH 传输和进程执行,而不是只依赖进程内 fake 时,使用慢速的本地容器 harness:
make remote-runtime-container只跑指定 case 时可以直接执行:
scripts/ci/remote_runtime_container_harness.sh listener
scripts/ci/remote_runtime_container_harness.sh reverse ssh这套容器 harness:
- 不会进入普通 pull request CI
- 会把 case 日志和 compose 服务日志写到
.artifacts/remote-runtime-container/ - 需要 Linux 和 Docker Compose
- 使用
scripts/ci/remote_runtime_container.compose.yml - 提供独立的手动 / nightly workflow:
.github/workflows/remote-runtime-container.yml
当前容器 case:
| 场景 | 覆盖 |
|---|---|
| 通过真实 listener 容器验证 direct-connect websocket runtime | TestWebsocketListenerRuntimeContainerE2E |
| 通过真实 machine-agent 容器验证 reverse-connect websocket runtime | TestWebsocketReverseRuntimeContainerE2E |
| 通过真实 SSH 容器验证 SSH bootstrap + diagnostics helper | TestMachineSSHHelperContainerE2E |
runtime 契约本身现在由两种 WebSocket 拓扑共同验证:
- 监听 WebSocket 通过直接 listener 端点验证契约
- 反向 WebSocket 通过 machine-channel
runtime消息验证同一份契约
关于消息模型、版本兼容规则与错误分类,请参见 docs/zh/websocket-runtime-contract.md。
OpenASE 现在发出以下传输相关指标:
openase.machine_channel.active_sessions- 标签:
transport_mode
- 标签:
openase.machine_channel.websocket_reconnect_total- 标签:
transport_mode
- 标签:
openase.machine_channel.events_total- 标签:
event、transport_mode
- 标签:
openase.runtime.launch_failures_total- 标签:
failure_stage、transport_mode
- 标签:
推荐告警:
openase.machine_channel.websocket_reconnect_total的重连速率飙升openase.runtime.launch_failures_total中failure_stage in {workspace_transport, openase_preflight, agent_cli_preflight, process_start}持续非零openase.machine_channel.active_sessions意外下降或波动
传输相关日志在已知时应包含以下关联字段:
machine_idsession_idtransport_modeworkspace_rootfailure_stageticket_idrun_idagent_id
运行时启动器现在在启动失败时记录 failure-stage 元数据,WebSocket 守护进程注册日志携带机器和会话标识符。
项目活动现在记录:
machine.connectedmachine.reconnectedmachine.disconnectedmachine.daemon_auth_failedagent.failed- 在启动期间失败时包含
failure_stage、transport_mode、machine_id和workspace_root
- 在启动期间失败时包含
结合项目活动和日志来回答:
- 哪台机器丢失或替换了 WebSocket 会话?
- 守护进程是认证失败还是仅重连?
- 运行时在传输设置、工作空间准备、二进制预检还是进程启动时失败?
- 机器守护进程通过
--control-plane-url接受控制面板基础 URL、API 基础 URL 或直接 WebSocket 端点。 - 生产环境中,优先使用具有有效 DNS 和 TLS 的稳定 HTTPS 源,然后将该源传递给守护进程。
- 反向 WebSocket 需要从远程机器到控制面板的出站可达性。
- 监听 WebSocket 需要从控制面板到机器公布的 WebSocket 端点的入站可达性。
- 如果 TLS 终止在 OpenASE 前面,确保公布的主机名与监听证书匹配,且 WebSocket 升级头能通过代理。
反向 WebSocket:
- 最适合机器可以向外拨号但无法暴露入站监听器的场景
- 需要机器通道令牌
- 仅当运维需要 helper 引导或诊断时才需要在机器记录上保留 SSH 凭证
监听 WebSocket:
- 最适合控制面板可以直接到达机器的场景
- 需要机器公布的 WebSocket 端点
- 如需直接修复入口,可保留 SSH 凭证用于 helper 引导或诊断
SSH 兼容路径:
- 不再是受支持的 runtime 回退路径
- 应被视为遗留记录状态加 helper 基础设施,而不是远程执行模型
先列出机器,识别缺少 websocket 拓扑必填字段的记录:
openase machine list当控制面可以直接拨号到机器时使用此路径:
- 保存
reachability_mode=direct_connect。 - 保存
execution_mode=websocket。 - 保存有效的
advertised_endpoint。 - 重新保存机器,并确认 direct-connect listener endpoint 仍然存在。
- 运行:
openase machine test <machine-uuid>只有在仍需 helper 引导或诊断时才保留 SSH 凭证。
当机器应主动回拨控制面时使用此路径:
- 保存
reachability_mode=reverse_connect。 - 保存
execution_mode=websocket。 - 保存有效的
workspace_root。 - 签发专用 machine channel token:
openase machine issue-channel-token \
--machine-id <machine-uuid> \
--ttl 24h \
--format shell- 在远端主机粘贴导出的
OPENASE_MACHINE_*变量,并启动:
openase machine-agent run- 确认守护进程会话和机器检查:
openase machine test <machine-uuid>
openase machine ssh-diagnostics <machine-uuid>如果已经保留 SSH helper 访问,则应优先使用 openase machine ssh-bootstrap <machine-uuid> 上传当前二进制并安装或刷新与拓扑匹配的服务:
reverse_connect + websocket:安装或刷新反向 daemon 服务direct_connect + websocket:安装或刷新远端 websocket listener 服务
迁移完成后,运维需要默认接受以下前提:
- 两种远程拓扑的工单执行都固定在 websocket 上
- direct-connect 故障首先按 listener 可达性问题排查,而不是去找 SSH fallback
- reverse-connect 故障首先按 daemon 注册或会话健康问题排查
- SSH 命令负责引导或修复远程访问,但不属于 runtime 执行平面
从源码构建当前二进制文件:
make build-web在启动守护进程之前,确保机器记录有:
- 预期的可达性与执行组合:
reverse_connect + websocketdirect_connect + websocket
- 有效的
workspace_root - 只有在仍需引导、诊断或紧急修复时才保留 SSH helper 凭证
- 远程 CLI 无法从
PATH发现时的agent_cli_path
在控制面板主机上:
./bin/openase machine issue-channel-token \
--machine-id <machine-uuid> \
--ttl 24h \
--format shell这会打印以下 shell 导出:
OPENASE_MACHINE_IDOPENASE_MACHINE_CHANNEL_TOKENOPENASE_MACHINE_CONTROL_PLANE_URL
如果控制面已经可以通过 SSH 到达机器,可以直接使用 helper 流而不必手工拷贝文件:
./bin/openase machine ssh-bootstrap <machine-uuid>它会上传当前 openase 二进制、写入拓扑环境文件、安装用户级服务并重启。
对于 reverse_connect + websocket,helper 会安装 openase machine-agent run。
对于 direct_connect + websocket,helper 会安装 openase machine-agent listen,并要求机器记录已经保存控制面要拨入的 advertised_endpoint。
不使用 helper 的运维手工方式如下:
远程机器上的 reverse-connect 手工方式:
export OPENASE_MACHINE_ID=<machine-uuid>
export OPENASE_MACHINE_CHANNEL_TOKEN=<issued-token>
export OPENASE_MACHINE_CONTROL_PLANE_URL=https://openase.example.com
/usr/local/bin/openase machine-agent run \
--agent-cli-path /usr/local/bin/codex \
--openase-binary-path /usr/local/bin/openase远程机器上的 remote-listener 手工方式:
export OPENASE_MACHINE_LISTENER_ADDRESS=0.0.0.0:19837
export OPENASE_MACHINE_LISTENER_PATH=/openase/runtime
export OPENASE_MACHINE_LISTENER_BEARER_TOKEN=<listener-token>
/usr/local/bin/openase machine-agent listen推荐的 systemd --user 单元:
[Unit]
Description=OpenASE machine-agent
After=network-online.target
Wants=network-online.target
[Service]
ExecStart=/usr/local/bin/openase machine-agent run --agent-cli-path /usr/local/bin/codex --openase-binary-path /usr/local/bin/openase
Restart=always
RestartSec=5
Environment=OPENASE_MACHINE_ID=<machine-uuid>
Environment=OPENASE_MACHINE_CHANNEL_TOKEN=<issued-token>
Environment=OPENASE_MACHINE_CONTROL_PLANE_URL=https://openase.example.com
[Install]
WantedBy=default.target对于监听 WebSocket 模式,先部署监听端点,然后在机器记录上保存公布的 WebSocket URL,并验证控制面板可以拨号到该端点。
- 构建目标
openase二进制文件。 - 在远程机器上,将新二进制文件安装在当前二进制文件旁边。
- 重启
machine-agent服务。 - 确认:
- 出现
machine.connected或machine.reconnected活动 openase.machine_channel.active_sessions恢复到预期水平- 金丝雀运行时启动期间
openase.runtime.launch_failures_total保持平稳
- 出现
- 停止守护进程服务。
- 恢复之前的二进制文件。
- 重启守护进程。
- 如果 WebSocket 启动仍不稳定,使用
openase machine ssh-diagnostics <machine-uuid>和openase machine ssh-bootstrap <machine-uuid>修复守护进程配置,再决定是否继续扩大部署。
| 症状 | 可能信号 | 检查内容 |
|---|---|---|
| 守护进程从未注册 | machine.daemon_auth_failed,auth_failed 指标 |
令牌已撤销、令牌已过期、错误的机器 ID、错误的控制面板 URL |
| 频繁重连 | machine.reconnected,重连计数器 |
控制面板重启、网络抖动、代理空闲超时、心跳间隔不匹配 |
| 运行时启动前失败 | agent.failed 带 failure_stage |
查看阶段是 workspace_transport、workspace_root、repo_auth、openase_preflight、agent_cli_preflight 还是 process_start |
| 监听 WebSocket 无法拨号 | 启动器日志带 failure_stage=workspace_transport 或 preflight_transport |
DNS 解析、TLS 链、公布端点正确性、防火墙可达性 |
| 远程二进制缺失 | failure_stage=openase_preflight |
.openase/bin/openase 存在于已准备的工作空间中且可以解析 OPENASE_REAL_BIN 或 PATH |
| Git 克隆失败 | failure_stage=repo_auth |
仓库凭证投射、GH_TOKEN、部署密钥或远程 git 传输策略 |
| 工作空间根目录无效 | failure_stage=workspace_root |
保存的机器 workspace_root、权限、挂载的文件系统可用性 |
当你需要快速确认工作空间权限、远程二进制是否存在、服务状态或最近日志时,使用 openase machine ssh-diagnostics <machine-uuid> 获取 helper-only 诊断输出。
- 运行
scripts/ci/remote_transport_matrix.sh - 确认直接 SSH runtime 会被拒绝
- 确认反向 WebSocket 启动失败不会回退到 SSH
- 确认 WebSocket 预检失败被分类为
failure_stage
- 在小规模机器子集上启用
ws_reverse - 只在运维需要 helper 引导或诊断的机器上保留 SSH 凭证
- 每个 rollout 批次至少跑一次反向 WebSocket 正常路径 runtime
- 验证守护进程重启下的
machine.connected和重连行为 - 确认强制 WebSocket 传输失败仍被归类为 WebSocket 侧启动错误
- 仅在反向 WebSocket 金丝雀稳定后启用
ws_listener - 在每次监听部署前验证 DNS、TLS 和控制面板直接可达性
- 每批部署运行至少一个监听运行时正常路径
- 在部署窗口期间不要把 SSH 当作 runtime 执行计划的一部分
- 保持以下仪表盘视图:
- 按
transport_mode的启动成功率 - 重连恢复
- 孤立或卡住的运行时计数
- 活跃 WebSocket 机器会话
- 按
- 运行时启动成功率在连续两个部署窗口中保持在 SSH 基线或以上
- 重连恢复在不需要运维操作的情况下为目标机器群恢复会话
openase.runtime.launch_failures_total保持在商定的错误预算以下,且主要由已知的、可操作的阶段主导- WebSocket 启用后孤立进程或卡住会话计数不增加
- 项目活动和日志足以在不登录机器的情况下识别机器、会话、传输和失败阶段