核心是容器运行--inspect服务且vscode正确映射路径;推荐用remote-containers扩展启动dev container,自动挂载代码并监听0.0.0.0:9229,避免端口与路径配置错误。

VSCode 调试 Docker 中的 Node 容器,核心就两件事:容器里得跑着 --inspect 服务,且 VSCode 能把本地代码路径和容器内路径对上。用 Remote-Containers 扩展开整个开发环境最稳;直接 attach 到已有容器也行,但容易卡在路径映射或端口绑定上。
用 Dev Containers 启动带调试能力的 Node 容器
这是目前最可靠、副作用最少的方式。它不是“连进去”,而是让整个 VSCode 工作区(终端、调试器、扩展)都在容器里运行,天然规避路径错位问题。
- 确保已安装
Remote - Containers扩展,并能执行docker info和docker run --rm hello-world - 打开项目根目录,在命令面板中运行
Dev Containers: Add Development Container Configuration Files...,选Node.js模板 - 检查生成的
.devcontainer/devcontainer.json,确认"forwardPorts"包含9229(例如[3000, 9229]) - 关键:修改
Dockerfile中的启动命令,把CMD ["npm", "start"]换成CMD ["npm", "run", "debug"],并在package.json里加脚本:"debug": "node --inspect=0.0.0.0:9229 server.js" - 运行
Dev Containers: Reopen in Container—— 此时容器内已监听0.0.0.0:9229,无需额外-p映射,VSCode 内置调试器可直连
attach 到已有 Node 容器时 port 和 address 必须匹配
如果你已有运行中的容器(比如用 docker-compose up 启的),想临时 attach 调试,launch.json 里的 port 和 address 得跟容器内真实监听值一致,否则连接直接超时。
在 Linux 上通过 Docker 运行 OpenClaw,并使用 Tailscale 实现远程访问。⚠️ 涉及 sudo、Docker、Tailscale和凭证挂载——请先查阅安全章节...
- 先确认容器内 Node 进程是否真在监听外部:进容器执行
netstat -tuln | grep 9229或lsof -i :9229,输出必须含0.0.0.0:9229,不是127.0.0.1:9229 - 启动容器时必须带
-p 9229:9229,且应用启动参数为--inspect=0.0.0.0:9229(漏掉=0.0.0.0是最高频错误) -
launch.json配置中"address": "localhost"是对的(指宿主机 localhost),但"port": 9229必须和容器-p映射的**宿主机端口**一致 - 别信
type: "docker"自动识别——它常把remoteRoot错判成/workspace,实际你挂载的是/app,手动写死"remoteRoot": "/app"更安全
sourceFileMap 或 pathMappings 写错,断点永远不命中
VSCode 断点依赖源码路径一对一映射。容器里报错显示 /app/server.js:12,你就得告诉 VSCode:“这个 /app 对应我本地的 ${workspaceFolder}”,差一个字符都不行。
- 对于
Dev Containers模式,devcontainer.json默认已将工作区挂载到/workspace,所以launch.json中"localRoot": "${workspaceFolder}"和"remoteRoot": "/workspace"通常就能对上 - 如果用了
-v ${PWD}:/app挂载,那remoteRoot必须是/app,且不能多一层路径,比如"/app/src"—— 即使代码真在/app/src,只要入口文件是/app/server.js,映射就得从/app开始 - Node.js 的
require()路径解析会影响调试器定位,若用ts-node或esbuild,需额外配置outFiles指向生成的 JS 文件目录
最易被忽略的是用户权限和网络模式:docker run --network host 会绕过端口映射逻辑,导致 localhost:9229 实际连的是宿主机而非容器;而用非 root 用户启动容器时,--inspect 可能因权限被拒绝静默失败,建议初期先用默认 root 用户验证通路。










