From 6ffc06ed1fdc5f08946b5558c6931274ea71b2e6 Mon Sep 17 00:00:00 2001 From: lyon Date: Tue, 5 May 2026 12:32:39 +0800 Subject: [PATCH] docs: capture compute ssh passthrough lessons --- docs/reference/provider-gateway.md | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/docs/reference/provider-gateway.md b/docs/reference/provider-gateway.md index 158d8d27..a41f6f4d 100644 --- a/docs/reference/provider-gateway.md +++ b/docs/reference/provider-gateway.md @@ -16,6 +16,8 @@ Provider Gateway 是计算节点侧容器。它只主动连出到主 server 暴 新增或重建 provider-gateway 时,Docker socket、远程升级和 SSH 透传必须作为同一个部署包验收,不能只让 provider 在线就认为完成。节点侧应先启动目标宿主或 WSL 的 sshd,把维护公钥写入目标用户 `authorized_keys`,再用只读目录挂载私钥到 provider-gateway 容器内 `/run/host-ssh`;provider-gateway 环境变量必须包含 `HOST_SSH_HOST`、`HOST_SSH_PORT`、`HOST_SSH_USER`、`HOST_SSH_KEY` 和 `HOST_REMOTE_CWD`。注册成功后,主 server 看到的 labels 必须同时满足 `hostSshConfigured=true`、`hostSshKeyPresent=true`、`hostSshTarget` 指向目标 sshd,且 `unideskCapabilities` 包含 `host.ssh`。 +计算节点镜像必须包含 `ssh` 客户端,否则 provider 虽然可以在线并执行 Docker 任务,但 `host.ssh` 调度会在节点侧失败。标准 `src/components/provider-gateway/Dockerfile` 已安装 `openssh-client`;如果节点使用本地兜底镜像或复制 Bun/Docker CLI 的自定义镜像,也必须同时安装或复制可用的 OpenSSH client,并在容器内通过 `ssh -V`、`test -r /run/host-ssh/id_ed25519`、`ssh -i /run/host-ssh/id_ed25519 ... hostname` 做本地烟测后再接入主 server。 + SSH 透传只作为维护桥,不作为普通计算任务和自动升级的执行通道。普通任务、Docker 状态采集和 `provider.upgrade` 仍必须走本地 Docker socket;SSH 透传用于节点诊断、人工修复和验证 WSL/宿主维护入口是否可达。 ## WSL Compute Node Deployment @@ -34,7 +36,7 @@ WSL 本身会在没有前台进程时被 Windows 回收;如果该节点要作 标准镜像构建路径使用 `src/components/provider-gateway/Dockerfile`,基础镜像为 `oven/bun:1-alpine`,并在镜像内安装 Bun、Docker CLI、Compose plugin、`df` 和 provider-gateway 源码。WSL 或 Docker Desktop 环境中的 registry mirror、DNS 或代理配置可能导致 `oven/bun` 元数据拉取失败;此时不要修改 provider ingress 协议或服务端配置,应改用节点侧镜像交付兜底。 -可复用的兜底方式是使用本机已存在的 Debian/Node 基础镜像,复制 WSL 本地 `bun`、`docker` 和 `docker-compose` plugin 到镜像内,再复制 `src/components/provider-gateway/src` 与 `src/components/shared/src`。该镜像必须能在容器内执行 `bun --version`、`docker version`、`docker compose version`,并通过挂载的 `/var/run/docker.sock` 执行 `docker info` 和 `docker ps`;只有这些命令通过后才能作为 `unidesk_provider-gateway:` 运行。该兜底镜像只改变节点侧交付方式,不改变 `PROVIDER_SERVER_URL`、token、heartbeat、labels、Docker socket 挂载和服务端验收标准。 +可复用的兜底方式是使用本机已存在的 Debian/Node 基础镜像,复制 WSL 本地 `bun`、`docker` 和 `docker-compose` plugin 到镜像内,再复制 `src/components/provider-gateway/src` 与 `src/components/shared/src`。该镜像必须能在容器内执行 `bun --version`、`docker version`、`docker compose version`、`ssh -V`,并通过挂载的 `/var/run/docker.sock` 执行 `docker info` 和 `docker ps`;只有这些命令通过后才能作为 `unidesk_provider-gateway:` 运行。该兜底镜像只改变节点侧交付方式,不改变 `PROVIDER_SERVER_URL`、token、heartbeat、labels、Docker socket、SSH 私钥只读挂载和服务端验收标准。 ## Deployment Verification @@ -88,8 +90,10 @@ backend-core 可以通过真实 WebSocket 调度向在线 provider 下发 `provi 宿主 SSH / WSL SSH 转发是 provider-gateway 部署的必备维护能力,但只作为应急维护辅助路径,不用于自动计算任务调度。实现参考 `../web-terminal` 的经验:容器内使用只读挂载的私钥,主动连接宿主或 WSL sshd,并设置 `BatchMode=yes`、`StrictHostKeyChecking=accept-new`、`ServerAliveInterval=20` 和 `ServerAliveCountMax=3`。主 server Compose 会把 `config.json` 的 `sshForwarding.keyDir` 只读挂载为 `/run/host-ssh`,provider 标签会上报 `hostSshConfigured`、`hostSshKeyPresent` 和 `hostSshTarget`,便于在前端节点清单确认维护桥是否具备条件。 +WSL 计算节点使用 Docker Desktop daemon 时,provider-gateway 容器通常应连接 `host.docker.internal:22`,目标是当前 WSL 发行版里的 sshd,而不是给节点开放公网 SSH。节点侧必须确认 sshd 监听 `22`、目标用户可用维护公钥免密登录、`authorized_keys` 与挂载到 `/run/host-ssh/id_ed25519` 的私钥匹配;如果容器内直连 `host.docker.internal` 都失败,先修复 WSL sshd、Docker Desktop host gateway 或密钥权限,再排查 UniDesk WebSocket 透传。 + 维护桥通过真实 WebSocket dispatch 暴露为 `host.ssh` 命令。默认 payload 使用 `mode: "probe"`,远端只执行一个短命令并返回 `UNIDESK_SSH_TEST user=... host=... bridge=host.ssh cwd=...`;需要人工诊断时可以显式使用 `mode: "exec"` 与 `command` 字段执行有界命令。所有 `host.ssh` 执行都必须有超时,stdout/stderr 在 task result 中截断展示;自动升级和普通任务仍必须使用 Docker socket 与 `provider.upgrade`,不得把 WSL SSH 维护桥当成调度通道。 面向人的终端入口是 `bun scripts/cli.ts ssh [ssh-like args...]`。无后续参数时打开远端登录 shell,有后续参数时执行远端命令并返回远端 exit code;该入口走 backend-core 内网 `/ws/ssh` broker 和 provider 既有 WebSocket,不新增公网 core 端口。传统 ssh 传输参数由 provider-gateway 环境变量统一控制,CLI 只负责把 Provider ID 后的远端命令和终端 stdin/stdout/stderr 透传过去。 -验证 WSL SSH 桥时,先在目标 WSL 中启动 sshd 并确保维护公钥写入目标用户的 `authorized_keys`,再确认目标 provider 注册 labels 中 `unideskCapabilities` 包含 `host.ssh`。运行 `bun scripts/cli.ts debug dispatch host.ssh --wait-ms 15000` 后,结果应在 `debug task latest` 或前端任务历史中显示 `status: succeeded`、`probeLine` 含 `UNIDESK_SSH_TEST`、`exitCode: 0`,并且目标节点 labels 中 `hostSshKeyPresent` 为 true;随后运行 `bun scripts/cli.ts ssh hostname` 验证近似原生 ssh 的远端命令体验。在计算节点本机自测时,使用 remote CLI 透传同一组命令:`bun scripts/cli.ts --main-server-ip 74.48.78.17 debug dispatch host.ssh --wait-ms 15000` 和 `bun scripts/cli.ts --main-server-ip 74.48.78.17 ssh hostname`。如果 D518 这类 WSL 节点没有公网 SSH 入口,也必须通过这个 provider-gateway 自连维护桥完成验证,而不是要求主 server 直接连节点公网 22 端口;旧版 provider 未声明 `host.ssh` 时必须先升级 provider-gateway,否则 core 会拒绝 SSH 透传。 +验证 WSL SSH 桥时,先在目标 WSL 中启动 sshd 并确保维护公钥写入目标用户的 `authorized_keys`,再确认目标 provider 注册 labels 中 `unideskCapabilities` 包含 `host.ssh`。运行 `bun scripts/cli.ts debug dispatch host.ssh --wait-ms 15000` 后,结果应在 `debug task latest` 或前端任务历史中显示 `status: succeeded`、`probeLine` 含 `UNIDESK_SSH_TEST`、`exitCode: 0`,并且目标节点 labels 中 `hostSshKeyPresent` 为 true;随后运行 `bun scripts/cli.ts ssh hostname` 验证近似原生 ssh 的远端命令体验。在计算节点本机自测时,使用 remote CLI 透传同一组命令:`bun scripts/cli.ts --main-server-ip 74.48.78.17 debug health`、`bun scripts/cli.ts --main-server-ip 74.48.78.17 debug dispatch host.ssh --wait-ms 15000` 和 `bun scripts/cli.ts --main-server-ip 74.48.78.17 ssh hostname`;默认 remote CLI 走公网 frontend 登录态,不需要主 server SSH key。健康检查必须能看到该 Provider 在线、`hostSshConfigured=true`、`hostSshKeyPresent=true`、`hostSshTarget` 正确、`unideskCapabilities` 包含 `host.ssh`,probe 必须返回 `UNIDESK_SSH_TEST`,`ssh hostname` 必须输出目标 WSL/宿主 hostname 且 exit code 为 0。如果 D518 这类 WSL 节点没有公网 SSH 入口,也必须通过这个 provider-gateway 自连维护桥完成验证,而不是要求主 server 直接连节点公网 22 端口;旧版 provider 未声明 `host.ssh` 时必须先升级 provider-gateway,否则 core 会拒绝 SSH 透传。