百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 技术分析 > 正文

一文告诉你如何调试运行在Docker容器中的远程Node.js应用程序

liebian365 2024-11-08 13:58 19 浏览 0 评论

作者 | Terence Shin

翻译 | 天道酬勤,责编 | Carol

出品 | CSDN云计算(ID:CSDNcloud)


你知道吗?


如果你想要调试已运行在远程计算机上Docker容器内的Node.js应用程序,并且希望无需修改命令参数(启用调试模式),其实并不需要向全世界开放远程Node.js调试器代理端口来实现。

或许你原本不知道这真的可以实现,也不知道该如何实现。不过当你看完本文,就会Get 到一些新奇的知识点,话不多说,往下看吧!


TdodoMVC演示应用程序


作者将使用TodoMVC Node.js应用程序的一个Github分支(由Gleb Bahmutov创建)作为本文的演示应用程序,可以随意克隆并使用此代码库:https://github.com/alexei-led/todomvc-express。

下面是添加的用于TodoMVC应用程序的Dockerfile,它允许在Docker容器中运行TodoMVC应用程序。

FROM alpine:3.5
# install node
RUN apk add --no-cache nodejs-current tini
RUN mkdir -p /usr/src/app
WORKDIR /usr/src/app
# Build time argument to set NODE_ENV (‘production’’ bydefault)
ARG NODE_ENV
ENV NODE_ENV ${NODE_ENV:-production}
# install npm packages: clean obsolete files
COPY package.json /usr/src/app/
RUN npm config set depth 0 && \
    npm install && \
    npm cache clean && \
    rm -rf /tmp/*
# copy source files
COPY . /usr/src/app
EXPOSE 3000
# Set tini as entrypoint
ENTRYPOINT [“/sbin/tini”, “--“]
CMD [ “npm”, “start” ]
# add VCS labels for code sync and nice reports
ARG VCS_REF=”local”
LABEL org.label-schema.vcs-ref=$VCS_REF \
     org.label-schema.vcs-url="https://github.com/alexei-led/todomvc-express.git"


在Docker容器中构建和运行TodoMVC

要为TodoMVC应用程序构建新的Docker映像,请运行docker build命令。

$ # build Docker image; set VCS_REF tocurrent HEAD commit (short)
$ docker build -t local/todomvc --build-argVCS_REF=`git rev-parse ---short HEAD` .
$ # run TodoMVC in a Docker container
$ docker run -d -p 3000:3000 --name todomvclocal/todomvc node src/start.js


计划

最终目标:作者希望能够将Node.js调试器添加到AWS云中的远程主机上Docker容器中已经启动并运行的Node.js应用程序上,而无需修改应用程序、容器、容器配置或使用其他调试标志重新启动它。


想象一下,该应用程序正在运行,但是现在发生了一些问题。作者想使用调试器连接到该应用程序并开始查看问题。

因此,作者需要一个计划一个逐步的流程,这将有助于实现最终目标。下面让我们来探索操作流程。

在服务器(AWS EC2 VM)机器上,有一个运行在Docker容器中的Node.js应用程序。在客户端(笔记本电脑)上,使用一个IDE(Visual Studio Code),Node.js应用程序代码(git pull /clone)和一个Node.js调试器。下面是计划清单:


  • 将已经运行的应用程序设置为调试模式
  • 公开一个新的Node.js调试器代理端口,以安全的方式启用远程调试
  • 同步客户端-服务器代码:两者都应在git树中的相同的提交上
  • 将本地Node.js调试器添加到远程服务器上的Node.js调试器代理端口,并以安全的方式进行
  • 如果一切正常,应该能够执行常规的调试任务,例如设置断点、检查变量和暂停执行等。


步骤1:将已经运行的Node.js应用程序设置为调试模式


通过使用debug命令行标志启动Node或使用SIGUSR1通知现有的Node进程,可以启用和访问V8调试器。(Node API文档)

因此,为了打开Node调试器代理,只需要将SIGUSR1信号发送到TodoMVC应用程序的Node.js进程。注意它运行在Docker容器中。我们可以使用什么命令将过程信号发送到在Docker容器中运行的应用程序呢?

作者选择docker killcommand,该命令实际上并没有杀死在Docker容器中运行的PID 1进程,而是向其发送Unix信号(默认情况下,它会发送SIGKILL)。

1)将TodoMVC设置为调试模式


下面要做的就是将SIGUSR1发送到在todomvcDocker容器中运行的TodoMVC应用程序。有两种方法可以做到这一点:


  • 使用docker kill --signal命令将SIGUSR1发送到在Docker容器中运行的PID 1进程,如果它是正确的(正确完成信号转发)初始化应用程序(如tini),那么它将起作用;
  • 或者在已经运行的Docker容器中执行kill -s SIGUSR1,将SIGUSR1信号发送到主Node.js进程。
$ # send SIGUSR1 with docker kill (if usingproper init process)
$ docker kill --signal SIGUSR1 todomvc
$ # OR run kill command for node processinside todomvc container
$ docker exec -it todomvc sh -c ‘kill -sSIGUSR1 $(pidof -s node)’

让我们确认Node应用程序已设置为调试模式。

$ docker logs todomvcTodoMVC server listening athttp://:::3000

emitting 2 todos server has new 2 todos

GET / 200 31.439 ms — 3241

GET /app.css 304 4.907 ms

— —

Starting debugger agent.

Debugger listening on 127.0.0.1:5858

如上所示,Node.js调试器代理已启动,但它只能接受来自本地主机的连接,请参见最后输出行:Debugger listening 127.0.0.1:5858

步骤2:公开节点调试端口

为了将远程Node.js调试器添加到以调试模式运行的Node应用程序中,需要以下操作:

  • 允许从任何(或特定)IP(或IP范围)连接到调试器代理
  • 公开Docker容器外部的Node.js调试器代理的端口

当应用程序已经在Docker容器中运行并且Node.js调试器代理准备与运行在同一台机器上的Node.js调试器进行通信而无法从Node.js调试器代理端口访问时,该如何在Docker容器之外访问呢?


可以使用暴露的调试器端口启动每个Node.js Docker容器并允许来自任何IP的连接(使用特殊的--debug-port和--debug Node.js标志),但是我们并不是在寻找很简单的方法。

从安全的角度来看,这不是一个好主意(允许不受保护地访问Node.js调试器)。另外,如果我们使用调试标志重新启动一个已经在运行的应用程序,那么我们将失去当前的执行上下文,并且可能无法重现要调试的问题。那么我们需要一个更好的解决方案。

很不幸,Docker不允许为已经运行的Docker容器公开其他端口。因此,我们需要以某种方式连接到正在运行的容器网络,并为Node.js调试器代理公开一个新端口。

同样,当Node.js进程已经启动时,也无法告诉Node.js调试器代理接受来自不同IP地址的连接。

借助名为socat(SOcketCAT)的小型Linux实用程序,可以解决上述两个问题。就像netcat一样,但考虑到安全性(例如它支持chrooting),并且可以在各种协议并通过文件、管道、设备、TCP套接字、Unix套接字、OCKS4的客户端、代理CONNECT或SSL等工作。

socat手册页上描述如下:

socat是基于命令行的实用程序,可建立两个双向字节流并在它们之间传输数据。因为可以从大量不同类型的数据接收器和源(请参阅地址类型)中构造流,并且由于可以将大量地址选项应用于流,所以socat可以用于许多不同的目的。

这个socat正是我需要的。因此,计划如下:我将在板载socat实用程序的情况下运行一个新的Docker容器,并为TodoMVC容器配置Node.js调试器端口映射。

socat.Dockerfile如下:

FROM alpine:3.5
RUN apk add --no-cache socat
CMD socat -h

1)构建socat Docker容器

$ docker build -t local/socat — <socat.Dockerfile

2)允许从任何IP连接到Node debugger代理

需要在与todomvc容器相同的网络名称空间中运行“ sidecar” socat容器,并定义端口映射。

$ # define local port forwarding
$ docker run -d --name socat-nip--network=container:todomvc \
local/socat socat TCP-LISTEN:4848,forkTCP:127.0.0.

现在,到达4848端口的所有流量都将被路由到监听127.0.0.1:5858的Node.js调试器代理。 4848端口可以接受来自任何IP的流量。还可以使用IP范围来限制到socat侦听端口的连接,添加range = <ANY IP RANGE>选项。

3)公开Docker容器的Node.js调试器端口

在大多数情况下,我们都想调试在远程计算机(例如,AWS EC2实例)上运行的应用程序。我们也不想将不受保护的Node.js调试器代理端口公开给全世界。一种可行且可行的解决方案是使用SSH隧道访问此端口。

$ # Open SSH Tunnel to gain access to serversport 5858.
$ # Set `SSH_KEY_FILE` to ssh key location oradd it to ssh-agent
$ #
$ # open an ssh tunnel, send it to the bg, andwait 20 seconds
$ # for connections, once all connections areclosed
$ # after 20 seconds then close the tunnel
$ ssh -i ${SSH_KEY_FILE} -f -oExitOnForwardFailure=yes \
-L 5858:127.0.0.1:5858ec2_user@some.ec2.host.com s

现在,所有到localhost:5858的流量都将通过SSH隧道传输到远程Docker主机,并经过一些socat转发到运行在todomvc容器中的Node.js调试器代理上。



步骤3:同步相同的代码提交

为了能够调试远程应用程序,你需要确保在IDE中使用的代码与在远程服务器上运行的代码相同。作者也将尝试使这一步骤自动化,还记得在TodoMVC Dockerfile中使用过的LABEL命令吗?这些标签可帮助我们识别git存储库并提交应用程序Docker映像:


  • org.label-schema.vcs-ref——包含用于HEAD提交的短SHA
  • org.label-schema.vcs-url——包含一个应用程序git存储库URL(可在git clone/pull中使用)


作者使用的是(标签架构约定)[http://label-schema.org/rc1/],因为它很有用,你也可以选择其他任何约定。


这种方法可以为每个正确标记的Docker映像标识应用程序代码存储库以及创建该存储库的提交。


$ # get git repository url form Docker image
$ GIT_URL=$(docker inspect local/todomvc
| jq -r‘.[].ContainerConfig.Labels.”org.label-schema.vcs-url”’)
$ # get git commit from Docker image
$ GIT_COMMIT=$(docker inspect local/todomvc
| jq -r ‘.[].ContainerConfig.Labels.”org.label-schema.vcs-ref”’)
$
$ # clone git repository, if needed
$ git clone $GIT_URL
$ # set HEAD to same commit as server
$ git checkout $GIT_COMMIT


现在,本地开发环境和远程应用程序都在同一个git commit上了,我们可以开始调试代码了。

步骤4:将本地Node.js调试器添加到调试器代理端口

需要配置IDE才能开始调试,作者使用的是Visual Studio Code,这里需要添加一个新的Launch配置。

此启动配置指定远程调试器服务器和要添加的端口以及应用程序源文件的远程位置,这些位置应与本地文件同步(请参见上一步)。

$ # get git repository url form Docker image
$ GIT_URL=$(docker inspect local/todomvc
| jq -r‘.[].ContainerConfig.Labels.”org.label-schema.vcs-url”’)
$ # get git commit from Docker image
$ GIT_COMMIT=$(docker inspect local/todomvc
| jq -r ‘.[].ContainerConfig.Labels.”org.label-schema.vcs-ref”’)
$
$ # clone git repository, if needed
$ git clone $GIT_URL
$ # set HEAD to same commit as server
$ git checkout $GIT_COMMIT

总结


通过以上步骤可以实现计划的目标:可以将Node.js调试器添加到已经在远程计算机上的Docker容器中运行的Node.js应用程序。找到合适的解决方案需要很长时间,但是在找到合适的解决方案之后,该过程看起来并不复杂。

弄清楚之后,一旦在环境中遇到新问题,就可以轻松地将Node.js调试器添加到正在运行的应用程序,并开始研究该问题,这样非常方便。

作者录制了一部短片,只是为了证明所演示的步骤与本文中所描述的所有步骤一样都很顺利。

希望这篇文章对你有用,欢迎评论区和我们讨论!

相关推荐

“版本末期”了?下周平衡补丁!国服最强5套牌!上分首选

明天,酒馆战棋就将迎来大更新,也聊了很多天战棋相关的内容了,趁此机会,给兄弟们穿插一篇构筑模式的卡组推荐!老规矩,我们先来看10职业胜率。目前10职业胜率排名与一周前基本类似,没有太多的变化。平衡补丁...

VS2017 C++ 程序报错“error C2065:“M_PI”: 未声明的标识符&quot;

首先,程序中头文件的选择,要选择头文件,在文件中是没有对M_PI的定义的。选择:项目——>”XXX属性"——>配置属性——>C/C++——>预处理器——>预处理器定义,...

东营交警实名曝光一批酒驾人员名单 88人受处罚

齐鲁网·闪电新闻5月24日讯酒后驾驶是对自己和他人生命安全极不负责的行为,为守护大家的平安出行路,东营交警一直将酒驾作为重点打击对象。5月23日,东营交警公布最新一批饮酒、醉酒名单。对以下驾驶人醉酒...

Qt界面——搭配QCustomPlot(qt platform)

这是我第一个使用QCustomPlot控件的上位机,通过串口精确的5ms发送一次数据,再将读取的数据绘制到图表中。界面方面,尝试卡片式设计,外加QSS简单的配了个色。QCustomPlot官网:Qt...

大话西游2分享赢取种族坐骑手办!PK趣闻录由你书写

老友相聚,仗剑江湖!《大话西游2》2021全民PK季4月激燃打响,各PK玩法鏖战齐开,零门槛参与热情高涨。PK季期间,不仅各种玩法奖励丰厚,参与PK趣闻录活动,投稿自己在PK季遇到的趣事,还有机会带走...

测试谷歌VS Code AI 编程插件 Gemini Code Assist

用ClaudeSonnet3.7的天气测试编码,让谷歌VSCodeAI编程插件GeminiCodeAssist自动编程。生成的文件在浏览器中的效果如下:(附源代码)VSCode...

顾爷想知道第4.5期 国服便利性到底需优化啥?

前段时间DNF国服推出了名为“阿拉德B计划”的系列改版计划,截至目前我们已经看到了两项实装。不过关于便利性上,国服似乎还有很多路要走。自从顾爷回归DNF以来,几乎每天都在跟我抱怨关于DNF里面各种各样...

掌握Visual Studio项目配置【基础篇】

1.前言VisualStudio是Windows上最常用的C++集成开发环境之一,简称VS。VS功能十分强大,对应的,其配置系统较为复杂。不管是对于初学者还是有一定开发经验的开发者来说,捋清楚VS...

还嫌LED驱动设计套路深?那就来看看这篇文章吧

随着LED在各个领域的不同应用需求,LED驱动电路也在不断进步和发展。本文从LED的特性入手,推导出适合LED的电源驱动类型,再进一步介绍各类LED驱动设计。设计必读:LED四个关键特性特性一:非线...

Visual Studio Community 2022(VS2022)安装图文方法

直接上步骤:1,首先可以下载安装一个VisualStudio安装器,叫做VisualStudioinstaller。这个安装文件很小,很快就安装完成了。2,打开VisualStudioins...

Qt添加MSVC构建套件的方法(qt添加c++11)

前言有些时候,在Windows下因为某些需求需要使用MSVC编译器对程序进行编译,假设我们安装Qt的时候又只是安装了MingW构建套件,那么此时我们该如何给现有的Qt添加一个MSVC构建套件呢?本文以...

Qt为什么站稳c++GUI的top1(qt c)

为什么现在QT越来越成为c++界面编程的第一选择,从事QT编程多年,在这之前做C++界面都是基于MFC。当时为什么会从MFC转到QT?主要原因是MFC开发界面想做得好看一些十分困难,引用第三方基于MF...

qt开发IDE应该选择VS还是qt creator

如果一个公司选择了qt来开发自己的产品,在面临IDE的选择时会出现vs或者qtcreator,选择qt的IDE需要结合产品需求、部署平台、项目定位、程序猿本身和公司战略,因为大的软件产品需要明确IDE...

Qt 5.14.2超详细安装教程,不会来打我

Qt简介Qt(官方发音[kju:t],音同cute)是一个跨平台的C++开库,主要用来开发图形用户界面(GraphicalUserInterface,GUI)程序。Qt是纯C++开...

Cygwin配置与使用(四)——VI字体和颜色的配置

简介:VI的操作模式,基本上VI可以分为三种状态,分别是命令模式(commandmode)、插入模式(Insertmode)和底行模式(lastlinemode),各模式的功能区分如下:1)...

取消回复欢迎 发表评论: