使用 WebTTY 在浏览器中登录边缘容器

解读

面试官想确认三件事:

  1. 你是否真的在弱网、低算力、无 SSH 客户端的边缘场景里交付过容器;
  2. 能否把“浏览器 ⇄ WebTTY ⇄ 容器 Shell”这条链路与 Docker 安全、网络、镜像规范打通;
  3. 遇到端口冲突、Token 泄露、TTY 断连、容器重启后会话丢失等中国特色现场问题,有没有成体系的定位与加固套路。
    回答时要体现“边缘场景优先、安全合规兜底、可运维可回滚”的落地思维,而不是简单抛命令。

知识点

  • 边缘容器三大约束:CPU<1 核、内存<512 MiB、带宽<2 Mbps,镜像必须多阶段裁剪到 50 MiB 以内。
  • WebTTY 主流实现:ttyd、gotty、wetty,均通过 WebSocket 暴露 /p/:id 路径;国内公网需额外过阿里云/腾讯云七层 CLB,必须支持 WSS。
  • Docker 安全基线:镜像内预装 tini 或 dumb-init,ENTRYPOINT 以非 root UID≥1000启动;通过 --cap-drop ALL --security-opt no-new-privileges 关闭提权。
  • 一次性 Token 机制:ttyd 的 -c 参数一次生效,边缘场景用边缘节点本地 Redis 5 秒 TTL 缓存 Token,防止浏览器缓存泄露。
  • 断连自愈:容器内安装 reptyr 或 tmux,WebTTY 仅作为 WebSocket→PTY 的转发层,会话由 tmux 保持,容器重启后通过preStop hook 自动 detach。
  • 国内合规:若容器运行在省级工业互联网平台,必须满足 GB/T 22239-2019 三级要求,WebTTY 流量需走国密 TLS 双证书,镜像仓库开启镜像签名与 cosign 验签

答案

现场我会分五步落地:

  1. 镜像侧:Dockerfile 采用多阶段构建, alpine:3.18 基础镜像仅保留 bash、curl、tmux、tini,最终镜像 38 MiB;创建用户 webtty(uid=1001),ENTRYPOINT ["tini","--","su","-","webtty"]。
  2. 启动参数:
    docker run -d --name edge-app
    --cap-drop ALL --security-opt no-new-privileges
    -p 127.0.0.1:7681:7681
    -v /etc/localtime:/etc/localtime:ro
    --restart unless-stopped
    myreg.cn/edge/app:1.4.0
    ttyd -p 7681 -c webtty:$(uuidgen) tmux new -A -s debug
    解释:端口仅监听本地环回,通过边缘节点 Nginx Stream 转发实现 WSS;Token 每次容器重启自动刷新,防止历史链接重放。
  3. 浏览器访问:
    边缘节点已预置国密双证书,Nginx 配置 proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade"; 路径 /terminal/ 反向代理到 127.0.0.1:7681。
    用户打开 https://edge-node-id.region.iot.company.cn/terminal/,输入**一次性 Token** 后即可获得 tmux 会话;F12 看不到 Token,因通过 HttpOnly Cookie 下发。
  4. 故障排查:
    • 若页面空白,优先在边缘节点tcpdump -i any port 7681 确认 WebSocket 握手是否 403,一般是 Token 过期,查看 docker logs 中 uuidgen 与浏览器 Cookie 是否一致;
    • 若中文乱码,exec 进容器 export LANG=C.UTF-8,并在 ttyd 启动参数加 -t fontSize=14,fontFamily=Monaco,locale=zh_CN.UTF-8;
    • 容器重启后会话丢失,通过preStop hook 脚本 tmux detach-client -a 保证 tmux 仍在后台,重启后 ttyd 自动 attach 原会话。
  5. 安全加固:
    每周通过镜像扫描工具 trivy 检查 ttyd 二进制 CVE;
    使用OPA Gatekeeper 策略强制容器必须加 --cap-drop ALL,否则拒绝调度到边缘节点;
    浏览器侧开启Content-Security-Policy: default-src 'self' wss:,阻断 XSS 注入。

拓展思考

如果边缘节点位于5G 专网且无外网 IP,可以把 WebTTY 与KubeEdge EdgeMesh 结合:

  • EdgeMesh 在节点间建立P2P 隧道,浏览器只需访问云端统一入口 cloudcore:10003,由 EdgeMesh 把流量透传到节点 Pod 7681 端口,实现零公网暴露
  • 此时 Token 由 cloudcore 的MetaServer 统一签发,JWT 里携带节点名、Pod IP、过期时间,边缘侧轻量级 OPA 代理验签后再启动 ttyd,防止横向移动;
  • 最后把整个过程固化成Helm Chart,一键安装到任意边缘 K8s 集群,实现“浏览器即运维入口”的标准化交付。