11 KiB
Provider Gateway Reference
Provider Gateway 是计算节点侧容器。它只主动连出到主 server 暴露的 provider ingress WebSocket,不要求计算节点有公网 IP,适合 NAT、内网和防火墙后的机器。
Main Server Self Provider
当前主 server 也运行一个 provider-gateway,providerId 固定来自 config.json 的 providerGateway.id。这让单机环境也能验证完整的分布式调度闭环:frontend 发起任务,core 写数据库并通过 provider ingress WebSocket 下发,provider gateway 执行后回传状态。
Deployment Method
当前主 server 公网 IP 是 74.48.78.17,config.json 中的 network.publicHost 必须保持为该地址;公网 frontend 入口是 http://74.48.78.17:18081/,provider gateway 对外接入入口是 ws://74.48.78.17:18082/ws/provider,provider ingress 健康检查是 http://74.48.78.17:18082/health。主 server 本机 provider 由根目录 docker-compose.yml 的 provider-gateway 服务启动,容器内使用 Docker 内网地址 ws://backend-core:8081/ws/provider 自接入;外部计算节点部署 provider-gateway 时必须改用公网 provider ingress URL,并复用 config.json / .state/docker-compose.env 中的 provider token、心跳间隔和重连参数。
计算节点部署 provider-gateway 的最小方法是:准备可运行 unidesk_provider-gateway 镜像的 Docker 环境,为节点分配唯一 PROVIDER_ID 与可读 PROVIDER_NAME,设置 PROVIDER_SERVER_URL=ws://74.48.78.17:18082/ws/provider、PROVIDER_TOKEN、PROVIDER_LABELS_JSON、HEARTBEAT_INTERVAL_MS、RECONNECT_BASE_MS 和 RECONNECT_MAX_MS,并挂载 /var/run/docker.sock:/var/run/docker.sock 作为 Docker 状态采集、任务执行和远程升级的唯一自动化通道。需要支持 provider.upgrade 的节点还必须设置 PROVIDER_UPGRADE_* 环境变量,把节点上的 UniDesk 仓库只读挂载到 PROVIDER_UPGRADE_WORKSPACE_PATH,并确保升级命令只重建 provider-gateway service,不影响 database、backend-core、frontend。
WSL Compute Node Deployment
WSL 计算节点和普通外部计算节点使用同一套 provider ingress 协议:节点不暴露入站端口,只需要从 WSL 主动连出到 ws://74.48.78.17:18082/ws/provider。已验证的 WSL 节点命名口径是短设备编号,例如 PROVIDER_ID=D601 与 PROVIDER_NAME=D601 保持一致;新增 WSL 节点必须替换为唯一 ID,避免把旧节点状态覆盖到同一条 unidesk_nodes.provider_id 记录。
WSL 节点应优先使用 WSL 内部原生 Docker Engine 和 /var/run/docker.sock,让资源采样、Docker 状态和任务执行都反映 WSL 计算环境本身,而不是 Windows 或 Docker Desktop 的代理上下文。如果当前 Docker CLI 实际连接 Docker Desktop daemon,也可以先作为可用计算节点接入,但必须在 PROVIDER_LABELS_JSON 中显式标注 dockerContext=docker-desktop 或等价标签,避免在 frontend 中把 Docker Desktop 资源误判为 WSL 原生资源。UniDesk 仓库建议放在 WSL 原生文件系统,例如 /home/ubuntu/unidesk,再按需从 Windows 工作区同步源码;长期运行和升级挂载应使用 WSL 原生路径只读挂到容器内 /workspace,减少 /mnt/c 权限、性能和路径转换问题。
WSL provider 的最小环境文件应放在节点本地私有路径,例如 /home/ubuntu/unidesk/.state/provider-<ID>.env,并由 docker run --env-file 读取。PROVIDER_LABELS_JSON 在 Docker env-file 中可以写成单行 JSON;如果临时用 shell source 方式调试,必须对整段 JSON 加引号,否则 shell 会按 {} 和逗号拆分导致 JSON 解析失败。WSL 节点建议至少包含这些 labels:host、role=wsl-provider、wsl=true、distro、docker=true;运行时 provider-gateway 会自动追加 runtime、dockerSocketPresent 和 gatewayUptimeSeconds。.state/provider-<ID>.env、logs/provider-<ID>/ 和容器日志属于节点本地运行态,必须保持在 .gitignore 覆盖范围内,不能提交 provider token、登录态或运行日志。
长期运行推荐用 systemd 管理 provider-gateway 容器,而不是只在交互 shell 中运行 Bun 进程。systemd unit 的稳定形态是:ExecStartPre=-docker rm -f unidesk-provider-gateway-<ID> 清理同名旧容器,ExecStart=docker run --name unidesk-provider-gateway-<ID> --env-file ... -v /var/run/docker.sock:/var/run/docker.sock -v /home/ubuntu/unidesk:/workspace:ro -v /home/ubuntu/unidesk/logs/provider-<ID>:/var/log/unidesk unidesk_provider-gateway:<id>,ExecStop=docker stop unidesk-provider-gateway-<ID>,并设置 Restart=always。临时部署可以直接使用 docker run -d --restart unless-stopped,但仍要保证容器名、env 文件、日志目录和镜像 tag 都带上节点 ID,便于 frontend、Docker 状态和本地排障互相对应。临时或一次性外部 WSL 节点如果没有完整远程升级回滚方案,应设置 PROVIDER_UPGRADE_ENABLED=false,保留 provider.upgrade 预检能力但禁止远端 schedule 自升级。
WSL 本身会在没有前台进程时被 Windows 回收;如果该节点要作为长期在线算力,必须通过 Windows 启动项、计划任务或后台 wsl.exe -d <distro> -u root -- bash -lc "systemctl start docker unidesk-provider-gateway-<ID>.service; exec sleep infinity" 这类 keepalive 进程保持发行版运行。仅启用 WSL 内 systemd service 不等价于 Windows 层面的常驻守护。
WSL Image Build Fallback
标准镜像构建路径使用 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-id> 运行。该兜底镜像只改变节点侧交付方式,不改变 PROVIDER_SERVER_URL、token、heartbeat、labels、Docker socket 挂载和服务端验收标准。
Deployment Verification
provider-gateway 部署是否成功必须以 UniDesk frontend 中可见的 Provider 信息为准,不能只看节点容器 running。验证时访问 http://74.48.78.17:18081/,使用配置中的账号密码登录,进入 资源节点 / 节点清单,确认目标 PROVIDER_ID、PROVIDER_NAME、online 状态、lastHeartbeat 和 labels 可见;点击该节点的 查看原始JSON,确认 raw payload 中的 providerId、name、status、labels 与部署环境变量一致。随后进入 资源节点 / 资源监控,确认该 Provider 有 CPU、实际内存和硬盘采样曲线;进入 资源节点 / Docker 状态,确认 Docker daemon、containers、images、volumes、networks 已渲染出来,且 dockerSocketPresent 或 Docker ready 状态与预期一致。只有这些前端信息都能通过 UniDesk 正常读取,才说明 provider-gateway 已经真正挂载到主 server。
WSL 节点还应补充一次真实调度验证:向该 PROVIDER_ID 下发 docker.ps,任务必须从 dispatched 进入 succeeded,并在结果中看到 WSL Docker daemon 返回的容器列表;对于容器化运行的 provider-gateway,列表中通常应包含 unidesk-provider-gateway-<PROVIDER_ID>。这一步可以同时证明 provider WebSocket、服务端任务路由、节点侧 Docker socket 和结果回传链路都已贯通。
自动化验证必须使用 Playwright 访问公网 frontend,而不是在容器内直接调 core API 代替浏览器验收。标准命令是 bun scripts/cli.ts e2e run;该命令会让 Playwright 打开公网 http://74.48.78.17:18081/、登录、抓取页面中的 Provider 信息和 查看原始JSON 内容,并检查 Provider 自接入、资源指标、Docker 状态和 provider.upgrade 预检。外部新增节点的人工验收应复用同一套前端路径:先确认 Provider 信息出现在节点清单,再确认资源监控和 Docker 状态页面有该节点的数据,最后通过任务调度向该 Provider 下发 echo 或 docker.ps 并在任务历史中查看耗时、状态和失败原因。
Provider Ingress
provider ingress 是唯一允许公网暴露的 provider 连接接口,当前由 backend-core 容器的独立端口提供 /ws/provider 和 /health。backend-core REST API 仍只在 Docker 内网开放,外部计算节点只应连接 provider ingress。
Docker Socket Path
自动任务执行只允许走本地 Docker socket。Compose 将 /var/run/docker.sock 挂入 provider-gateway,provider 标签会报告 dockerSocketPresent,docker.ps 调试任务会通过该 socket 查询宿主 Docker 容器。
Docker Status Telemetry
provider-gateway 连接成功后必须周期性上报 Docker daemon 状态,数据来源是本地 Docker socket 上的 docker info、docker ps -a、docker images、docker volume ls 和 docker network ls。backend-core 将最新快照保存到 unidesk_node_docker_status,frontend 的资源节点 Docker 状态 子标签用该快照渲染 Docker Desktop 风格视图;该能力仍然只通过 provider 主动上报,不要求主 server 反向连接计算节点。
System Status Telemetry
provider-gateway 连接成功后必须周期性上报节点 CPU、内存和硬盘用量。采集来源是节点本地 /proc/stat、/proc/loadavg、/proc/meminfo 与 df -PB1,backend-core 将最新快照保存到 unidesk_node_system_status,并将历史采样保存到 unidesk_node_metric_samples 供 frontend 绘制任务管理器风格曲线。内存使用量采用实际占用口径:MemTotal - MemFree - Buffers - Cached - SReclaimable + Shmem,也就是不把 Linux page cache / buffer 计入占用;上报中同时保留 cacheBytes 便于排查。该链路仍然由 provider 主动上报,主 server 不反向探测计算节点。
Remote Provider Upgrade
backend-core 可以通过真实 WebSocket 调度向在线 provider 下发 provider.upgrade。mode: "plan" 只返回升级计划,用于 E2E 和人工预检;mode: "schedule" 会要求 provider-gateway 通过本地 Docker socket 启动一个 detached updater 容器,由 updater 在节点本地执行 docker compose up -d --no-deps --build provider-gateway。--no-deps 是强制要求,升级 provider-gateway 时不得重建或停止 database、backend-core、frontend。升级执行路径使用 Docker socket 和只读仓库挂载,不使用 Host SSH 维护桥作为自动调度通道。
Host SSH Maintenance Bridge
宿主 SSH 转发只作为应急维护辅助路径,不用于自动任务调度。实现参考 ../web-terminal 的经验:容器内使用只读挂载的私钥,通过 ssh -tt 主动连接宿主 sshd,并设置 StrictHostKeyChecking=accept-new、ServerAliveInterval 和 ServerAliveCountMax。本仓库保留 src/components/provider-gateway/scripts/host-ssh-shell.sh 作为维护桥接脚本,默认 Compose 不挂载私钥,避免把 SSH 路径误用为调度通道。