如何通过 Google Cloud 调试在 Docker 容器中运行的 Nodejs 应用程序

Posted

技术标签:

【中文标题】如何通过 Google Cloud 调试在 Docker 容器中运行的 Nodejs 应用程序【英文标题】:How to debug Nodejs app running inside Docker container via Google Cloud 【发布时间】:2015-04-15 14:42:16 【问题描述】:

我发现 Google 提供了一些关于 how to run Nodejs on a custom runtime environment 的指南。一切似乎都很好,我正在设法在运行 gcloud preview app run . 的本地计算机上启动我的 Nodejs 应用程序。正如我所见,它可能创建了一个 Docker 容器并在其中运行 Nodejs 程序。我说“可能”,因为这是我第一次接触 Docker,但我是 2 年以上经验丰富的 Nodejs 开发人员。

所以我的问题是 如何在我的 Nodejs 程序在 Docker 容器内运行时调试(断点停止)? 使用 Chrome 开发人员工具或如何设置 Webstorm 调试配置以使其停止在断点上。是否可以配置 Docker 如何启动节点,甚至可以通过 Webstorm 内部的gcloud 启动 Docker 以确保调试正常工作?任何帮助或澄清表示赞赏。

请不要提供关于如何在 Docker 容器之外调试 Nodejs 应用程序的答案——我知道如何做到这一点。

【问题讨论】:

【参考方案1】:

不好意思,我只知道node-inspector的解决方法,希望对你有帮助:

您可以在容器中安装 node-inspector 包:https://github.com/node-inspector/node-inspector 在主机上映射容器的 8080 端口(使用参数 -p 8080:8080 运行容器)

在你的容器中运行它(使用 docker exec 或 docker-enter)

node-debug --web-host 0.0.0.0 yourScript.js

转到http://localhost:8080/debug?port=5858

【讨论】:

确认我能够在 chrome 中启动调试会话,使用 Docker for Mac,在我的 docker-compose 的端口部分使用 5858:5858。使用默认的 docker 网络模式。不需要 --net=host、SSH 转发或任何其他技巧。这就是 Docker 的本意(隔离)。此外,在我的配置中没有提到的--web-host 0.0.0.0 是我的配置中缺少的部分。没有节点调试启动,但没有任何东西能够从外部连接到它(连接被拒绝)。有了它“它就可以工作” 从节点检查器启动到文件加载到浏览器中的源代码之间存在相当长的延迟时间。知道这是为什么吗?【参考方案2】:

有一种更简单的方法,至少从 Docker 0.11 或其他版本开始。

仅在您的开发机器上运行带有 --net="host" 的 Docker。这使得 Docker 直接绑定到 localhost,而不是创建桥接网络适配器,因此 Docker 机器像您机器上的任何其他进程一样运行,并在本地接口上打开它所需的端口。

这样,您可以连接到您的调试端口,就好像 Node 没有在 Docker 中运行一样。

更多文档在这里:https://docs.docker.com/reference/run/

在 Docker 0.11 之前,除了使用 node-inspector 之外,您还有其他两种调试方式:

在 Docker 机器中运行 sshd 并设置 ssh 隧道,就像在远程机器上进行调试一样。 使用 ip 表“搞砸”以“恢复”本地端口的 Docker 映射。这里有一些东西Exposing a port on a live Docker container。

【讨论】:

【参考方案3】:

默认情况下,节点调试器将仅侦听同一主机 (127.0.0.1) 的连接。但在 Docker 中,您需要接受来自任何主机的连接 (0.0.0.0):

# inside Docker
node --inspect=0.0.0.0:9229 myapp.js

您还必须公开调试端口 (9229)。然后应用程序应该会被自动检测并在 Chrome 中的chrome://inspect/#devices 中列为远程目标(在 Chrome 67 中测试)。

示例

这是一个最小的例子。它在 Docker 中运行一个简单的 javascript 应用程序,并展示了如何将 Chrome 调试器附加到它:

$ cat example.js
setInterval(() => console.log('Hallo world'), 1000);

$ cat Dockerfile
FROM node
COPY example.js /
CMD node --inspect=0.0.0.0:9229 /example.js

运行:

$ docker build . -t myapp && docker run -p 9229:9229 --rm -it myapp
Sending build context to Docker daemon  3.072kB
Step 1/3 : FROM node
 ---> aa3e171e4e95
Step 2/3 : COPY example.js /
 ---> Using cache
 ---> 3ef6c0311da2
Step 3/3 : CMD node --inspect=0.0.0.0:9229 /example.js
 ---> Using cache
 ---> e760739c2802
Successfully built e760739c2802
Successfully tagged debug-docker:latest
Debugger listening on ws://0.0.0.0:9229/4177f6cc-85e4-44c6-9ba3-5d8e28e1b124
For help see https://nodejs.org/en/docs/inspector
Hallo world
Hallo world
Hallo world
...

打开 Chrome 并转到 chrome://inspect/#devices。它应该在应用程序启动后不久,检测它并列出它。

疑难解答

对于调试 Docker 网络问题,docker inspect 很有用:

$ docker ps
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                    NAMES
ae83d50e24c8        debug-docker        "/bin/sh -c 'node --…"   2 minutes ago       Up 2 minutes        0.0.0.0:9229->9229/tcp   blissful_sammet
$ docker inspect ae83d50e24c8
...
    "NetworkSettings": 
        "Bridge": "",
        "SandboxID": "682d3ac98b63d4077c5d66a516666b6615327cbea0de8b0a7a2d8caf5995b0ae",
        "HairpinMode": false,
        "LinkLocalIPv6Address": "",
        "LinkLocalIPv6PrefixLen": 0,
        "Ports": 
            "9229/tcp": [
                
                    "HostIp": "0.0.0.0",
                    "HostPort": "9229"
                
            ]
        ,
   ...

如果想查看 Docker 和 Chrome 之间发送的请求,ngrep 可以提供帮助:

$ sudo ngrep -d any port 9229
interface: any
filter: (ip or ip6) and ( port 9229 )
############################
T ::1:38366 -> ::1:9229 [AP]
  GET /json/version HTTP/1.1..Host: [::1]:9229....                            
#####
T ::1:38368 -> ::1:9229 [AP]
  GET /json HTTP/1.1..Host: [::1]:9229....                                    
##############
T 172.17.0.1:56782 -> 172.17.0.2:9229 [AP]
  GET /json HTTP/1.1..Host: [::1]:9229....                                    
#
T 172.17.0.1:56782 -> 172.17.0.2:9229 [AP]
  GET /json HTTP/1.1..Host: [::1]:9229....                                    
###
T 172.17.0.1:56784 -> 172.17.0.2:9229 [AP]
  GET /json/version HTTP/1.1..Host: [::1]:9229....                            
#
T 172.17.0.1:56784 -> 172.17.0.2:9229 [AP]
  GET /json/version HTTP/1.1..Host: [::1]:9229....                            
###
T 172.17.0.2:9229 -> 172.17.0.1:56782 [AP]
  HTTP/1.0 200 OK..Content-Type: application/json; charset=UTF-8..Cache-Contro
  l: no-cache..Content-Length: 465....                                        
#
T 172.17.0.2:9229 -> 172.17.0.1:56782 [AP]
  HTTP/1.0 200 OK..Content-Type: application/json; charset=UTF-8..Cache-Contro
  l: no-cache..Content-Length: 465....                                        
###
T 172.17.0.2:9229 -> 172.17.0.1:56782 [AP]
  [ .  "description": "node.js instance",.  "devtoolsFrontendUrl": "chrome-de
  vtools://devtools/bundled/inspector.html?experiments=true&v8only=true&ws=[::
  1]:9229/f29686f9-e92d-45f4-b7a2-f198ebfc7a8e",.  "faviconUrl": "https://node
  js.org/static/favicon.ico",.  "id": "f29686f9-e92d-45f4-b7a2-f198ebfc7a8e",.
    "title": "/example.js",.  "type": "node",.  "url": "file:///example.js",. 
   "webSocketDebuggerUrl": "ws://[::1]:9229/f29686f9-e92d-45f4-b7a2-f198ebfc7a
  8e". ]..                                                                   
#

【讨论】:

感谢@philipp-claßen 提供此信息。 0.0.0.0 部分至关重要,非常感谢。 :thumbs-up:【参考方案4】:

据我所知,您需要在启动时向节点提供参数 --debug-brk= - 这将启用调试。之后,访问 docker 容器上的指定端口。您可能必须公开它或隧道(使用 ssh)。

之后,将 Webstorm 远程调试器指向指定的端口,你就应该设置好了。

【讨论】:

【参考方案5】:

如果您为容器使用桥接网络,并且不想在与节点进程相同的容器中安装节点检查器,我发现这是一个方便的解决方案:

在主node.js容器中,将5858端口映射到主机 在启用调试的情况下运行主节点进程 使用单独的容器运行节点检查器 为节点检查器容器使用主机网络

也就是说,node-inspector 容器将连接到 localhost:5858,然后将端口映射到主节点容器。

如果您在公共 VM 上运行此程序,我建议:

确保端口 5900 没有公开(例如通过防火墙) 确保节点检查器端口(例如 8080)us 公开,以便您可以连接到它

我在这里写了一些关于它的更多细节:https://keylocation.sg/our-tech/debugging-nodejs-in-docker-using-node-inspector

【讨论】:

以上是关于如何通过 Google Cloud 调试在 Docker 容器中运行的 Nodejs 应用程序的主要内容,如果未能解决你的问题,请参考以下文章

从 Google Cloud Datalab 向 BigQuery 插入数据时如何调试解析错误?

如何在 Google Cloud App Engine 上使用 PubSub 创建订阅者,该订阅者通过 Publisher 从 Google Cloud App Engine Flex 收听消息?

如何通过服务帐户通过 Google BigQuery External Table 访问 Google Sheets Doc

如何使用工作负载身份通过 Google Cloud .NET SDK 访问 Google Kubernetes Engine 中的 ESP?

如何通过 terraform 使用服务帐户创建 google cloud pubsub pull 订阅?

如何通过 Exposed 连接到 Google Cloud SQL