Debugging NodeJs in Node-RED Docker container

Hi folks,

My test system died yesterday, after a few desperate attempts to downgrade NodeJs. At the end I decided to start using Docker containers. And shortly afterwards I was up-and-running again. My compliments to the Node-RED chef and sous-chef for the nice Docker setup and tutorial!!!!!

Now I would like to start debugging my Node-RED server-side code again. But I'm not sure how to achieve with NodeJs running in a Docker container.

In a non-Docker setup that was very easy:

  • I needed to start NodeJs in debug mode:
    node --inspect=0.0.0.0:5858 /usr/lib/node_modules/node-red/red.js
  • And then I could connect with the Chrome debugger to port 5858

So I can forward port 5858 of my host system to port 5858 of the Docker container, but I'm not sure how to start NodeJs with the --inspect=0.0.0.0:5858 parameter.

Hopefully this doesn't mean I have to start creating (somehow) Docker images by myself?

Thanks a lot !!!
Bart

I 'think' I need to pass the NodeJs command line parameter as NODE_OPTIONS environment variable:

sudo docker run -it -p 1880:1880 -p 5858:5858 -v /home/pi/.node-red:/data -e NODE_OPTIONS="--inspect=0.0.0.0:5858" --name mynodered nodered/node-red:1.0.3-12-minimal-arm32v6

Then it indeed starts very promising, but it fails immediately afterwards:

When I use another port number (e.g. the default inspector port 9229) I get the same error ...
It looks like i tries to use the port twice now.

[EDIT] Could it be related to this somehow?

I'm certain you have searched Bart but in case you missed this one, thought I'd post it (sorry I've only small experience of docker and even less when it comes to remote debugging)

Hey Steve,

Thanks for joining!
I'm not experienced with this stuff, but in the package.json file of the node-red-docker repository, I see this:

"scripts": {
    "start": "node $NODE_OPTIONS node_modules/node-red/red.js $FLOWS"
},

So I 'assume' this will be called by NPM:

image
And from the link in my previous post you can see this:

image

So I think that first the port is being used by NPM, and afterwards by NodeJS (which will fail because the port is already in use...)? But I don't know how that guy his solution could be implemented in the Node-RED docker container :pleading_face:

Unfortunately this stuff is not my cup of tea ...

1 Like

In the link I added above, somebody has provided a solution:

image

Could that perhaps be used in the Node-RED Dockerfile.alpine file, by adding the $NODE_OPTIONS in the entrypoint:

image

And then remove the $NODE_OPTIONS from the nodeJs start command in the package.json file:

image

Or is that complete bull what I'm saying here?
Can I perhaps change my local Docker image to test this theory??

To be able to fix this, I have been reading a bit more about this topic.
And it seems (e.g. here) that I have to solve it in another way:

  1. I started creating my own Node-RED Docker image, as explained very well in this tutorial. Again my compliments to the Node-RED chef and his sous-chef!

  2. Then I only have added a "debug" script line to the package.json file:

    "scripts": {
         "start": "node $NODE_OPTIONS node_modules/node-red/red.js $FLOWS",
         "debug": "node --inspect=0.0.0.0:9229 $NODE_OPTIONS node_modules/node-red/red.js $FLOWS"
    },
    

    The "debug" script is almost identical to the "start" script, except it starts NodeJs in debug mode (with the default debug port number 9229). By adding such a second script, I have no impact on production containers!

  3. Then I have build my Docker image (named "testing:node-red-build").

  4. Once the build was completed, I have started a container (from my custom Docker image) via this command:

    docker run -it -p 1880:1880 -p 9229:9229 --entrypoint npm testing:node-red-build run debug -- --userDir /data
    

    Remark: I have explained below all the details of this command...

  5. Then I have specified (once) the IP address and port 9229 in my Chrome debugger, and it immediately allows me to start debugging the server-side code (which is running inside the Docker container!):

    image

So it works fine, and I don't think there is impact on non-debug environments.

So now I only need to have the approval of @knolleary and @dceejay, whether this solution is good enough to create a pull request (to add the "debug" script line to the package.json file)? It would be great if I could do all my developments and debugging on Docker containers, since that allows me to setup very easily new clean test environments (e.g. with various NodeJs versions)...

Question: Is it also ok if I add a third script to the package.json file:

"debug_brk": "node --inspect=0.0.0.0:9229 --inspect-brk $NODE_OPTIONS node_modules/node-red/red.js $FLOWS"

The extra " -- inspect - brk" flag will cause Node-RED to break already on the first line of its application code. This allows developers to debug the startup code, which might be useful sometimes ...

Thanks for reading!!!
Bart

Here the details of the command to start the Node-RED Docker container in debug mode, for people that want to have more background information:

  • "Docker run" starts a container.

  • "-it" (Optional) tells Docker to attach your terminal to the container, so you can see that NodeJs indeed has been started in debug mode:

    image

  • "-p 1880:1880": Tell Docker that port 1880 of the host system (e.g. Raspberry) should be forwarded to port 1880 of this Docker container. That way you access your Node-RED web-server (which is running inside the Docker container), like you used to do without Docker...

  • "-p 9229:9229": Tell Docker that port 9229 of the host system (e.g. Raspberry) should be forwarded to port 9229 of this Docker container. That way your debugger (e.g. Chrome, Visual Code, ...) can communicate with NodeJs to do remote debugging.

  • "--entrypoint npm testing:node-red-build run debug": The Node-RED DockerFile contains the following entrypoint:

    ENTRYPOINT ["npm", "start", "--", "--userDir", "/data"]
    

    This way Docker knows that - when the container is started - he has to execute the command "npm start -- --userDir /data" (which is equal to "npm run start -- --userDir /data"). Which means npm will run the "start" script from the package.json file. But since we want to run our "debug" script instead, we will have to overwrite that endpoint by our own endpoint.
    CAUTION: Docker expects the format --entrypoint <executable> <container name> <executable arguments>, which is very confusing (with the container name between the executable 'npm' and his arguments)!

  • "--" This npm argument tells npm that the next argument won't be an npm argument but that it needs to be passed as an argument to the "debug" script.

  • "--userDir /data": npm will pass this argument to the "debug" script, which means it becomes an argument for Node-RED. This way Node-RED knows that his data folder (with flow, credentials, ... files) will be the /data folder (in the Docker container filesystem). In the Node-RED documentation, you can see that you can use this folder as a mount point for e.g. the /home/pi/.node-red folder on your host system (i.e. a Raspberry for example).

6 Likes

Excellent work Bart.

Hi Bart,
now that looks like a better solution. Happy if you want to fire up a PR pointed at the dev branch of the node-red-docker project. Even better if it included a section for the docs !

1 Like

Hey Dave,
Very glad to hear that a PR is allowed. Thanks!
And also good to know (in front) that I need to target the 'dev' branch!!!!

Do you mean the readme file of the node-red-docker project itself:

image

Yes - somewhere in the README that makes sense.

1 Like

Hey Dave,
the pull-request has been created, inclusive some documentation :champagne:. This means you can publish it in Dockerhub around 2024 :zipper_mouth_face:

To avoid mistakes, I have build a new local docker image which now also contains the second script ("debug_brk").

When I start the docker container using that second script:

docker run -it -p 1880:1880 -p 9229:9229 --entrypoint npm testing:node-red-build run debug_brk -- --userDir /data

Then you will see in the log that NodeJs nicely starts listening to the debug port, and then it breaks automatically:

NodeJs will wait at the first statement of Node-RED until you connect with a debugger to port 9229:

image

From here on you can start debugging the entire Node-RED startup code, or the startup code of each contribution node ...

Have fun with it !!!
Bart

1 Like

you're VERY optimistic aren't you :slight_smile:
maybe by 20:24 tonight

1 Like

Haha!
Please don't hurry. I have now my own private debuggable container which fits my needs until you have time to publish it...

Just out of curiosity: do you need to build the image manually on various types of hardware? Because initially I had accidentally started an AMD build on my Raspberry, which failed. Afterwards I had started an ARM build, which runned fine.

Before this weekend, I wasn't even aware that there were multiple builds for a single image. Had always thought that Docker images where hardware independent :relaxed:

Thanks to the great work by @RaymondMouthaan we have travis build it for multiple version across multiple platforms.

1 Like

For everybody following this discussion. I have added a wiki page to the node-red-docker repository, which explains how to debug Node-RED (server-side code) via Chrome Developer tools. Note that this also works when Node-RED is running without Docker ...
As usual, all 'constructive' feedback is more than welcome!

1 Like

Great work for figuring out remote debugging! Thanks!

Later this week I will have a look to get remote debugging feature as part of the official Node-RED images. My idea is to have an environment variable "remote-debug", which can be set to true or false and is false by default. In case it's true, the "script" you provided will be loaded and node-red runs in debug, so a connection from Chrome can be established. This way it's easy for users to toggle between normal and remote debug mode, without building custom images or load specific scripts.

Greets,
Raymond

1 Like

meanwhile I have taken the PR as-is and pushed it to https://hub.docker.com/r/nodered/node-red-dev to make it easier to test

...and dev will be merged to stable in 2024...

You should be a politician @dceejay :laughing:

Is that a request...? We can make that the plan of record if you like...

3 Likes

Hi, this is great work!

I wonder how I can start the debug from my docker-compose.yml, instead of docker run. I am running different containers in my RPI and node-red is one of them. I am no expert in this.

Cheers