12

I am planning the workflow for typical dev on a nodejs app. I presume most of you would:

git clone [appcode] + (Dockerfile with volume mapping to local path) > docker-compose build > docker-compose up

Then I edit some code, preferably using an IDE like Webstorm or text editor Sublime etc. Then terminal Ctrl+C to kill current process > docker-compose up (or configure your container to use nodemon to watch for code changes) and refresh browser to see latest local code running.

Does all the above look pretty standard?

My main question is does anyone debug either with an IDE or node-inspect into the container?

I've tried exposing ports etc.. Connection Refused. I believe because node.js will only allow debug on 127.0.0.1:5858

BMW
  • 42,880
  • 12
  • 99
  • 116
Steve Pascoe
  • 306
  • 3
  • 10

4 Answers4

24

I managed to make it run here. I wish I could run node-inspector as a sidekick container, it would be so clean(EDIT: It is possible, see end of answer). Unfortunately, looking into node-inspector sources, it is not possible to run node-inspector remotely(because node-inspector needs to access files so it can display them) so even container linking is out the window. Maybe it will support it at some point.

Here's is my solution:

In Dockerfile, install node-inspector. I decided to make it global so I can use the same container to debug all my apps.

RUN npm install -g node-inspector

Instead of lunching node in the CMD command, use a bash script that will let you launch more than a single process. This is not the Docker way but as I stated, limit in node-inspector prevent us from using sidekick container. You could also use a more robust solution for process management like supervisor but for debugging a simple script is enough in my opinion.

CMD ["/bin/bash", "start.sh"]

This script checks for the presence of a DEBUG environment variable to launch node and enable debug.

#!/bin/bash

if [ -z ${DEBUG+x} ]; then
  node server.js
else
  node-inspector --web-port 9080 &
  node --debug server.js
fi

I guess you could use the same trick to install or not node-inspector. You can even have conditional statement in RUN command if you want to skip the script for installation.

Then when you want to debug a container, launch it like so:

docker run -d -P -p 9080:9080 --env DEBUG=1 --name my_service \
    -v /home/docker/sources/.../:/usr/src/app custom-node

Now you just need to hit the docker daemon ip for debugging since we exposed the debug port specified in the script(9080) on the docker run command. My Dockerfile already exposes my main port so I used -P for that.

If your container runs on a local VM and you are setup behind a proxy, make sure it either support local addresses or that you disable it before debugging.


EDIT: now works with sidekick container

Here's is the content of my node-debug container Dockerfile

FROM node:4.2.1

EXPOSE 9080

RUN npm install -g node-inspector

CMD ["node-inspector", "--web-port", "9080"]

Docker provides us 2 features to make it as if node-inspector was running locally with the node process.

  1. Even though node-inspector seems to imply you can connect to remote machine by telling you to connect to 127.0.0.1:8080/?ws=127.0.0.1&port=5858, I couldn't find any code that was parsing the ws parameter so I used docker net config option to pop the node-debug container in the same network stack as my debugged process: --net=container:mysvc. This way, node-inspector can open the websocket connection to localhost:5858.

  2. By using the same mount point as your debugged process, you can fake file locality to the node-inspector process.

Now to make it a little more convenient, I would suggest to use data container for your app sources.

If you want the possibility to start node in debug or not, continue to use the start.sh script(remove the node inspector command though). I wonder if we could use a signal with docker though, that would remove the dependency on start.sh entirely.

if [ -z ${DEBUG+x} ]; then
  node server.js
else
  node --debug server.js
fi

So create the data container:

docker create -v /home/docker/sources/.../:/usr/src/app  \
    --name my_service-src custom-node /bin/true

Launch node app and expose node-inspector debug port:

docker run -d -P -p 9080:9080 --env DEBUG=1 --name my_service \
    --volumes-from my_service-src custom-node

Launch node-debug container:

docker run -d --net=container:my_service --volumes-from my_service-src \
    --name node-debug node-debug

This way, you can quickly spawn node-debug container on the fly to debug a node process.

Connect to docker ip and enjoy your debugging session !

Community
  • 1
  • 1
Eric Fortin
  • 7,533
  • 2
  • 25
  • 33
5

After struggling for a while to get this to work, I found that adding:

--inspect-brk=0.0.0.0:9229

instead of just the usual inspect-brk

made things work.

You'll also need to map your ports correctly in your docker run command:

-p 9229:9229

Full example:

docker run -ti -p 3000:3000 -p 9229:9229 -v `pwd`:/app/ myImage bash

node --inspect-brk=0.0.0.0:9229 /app/index.js

Then go to chrome://inspect

And hit "Open dedicated DevTools for Node" and it should all work :)

tnrich
  • 8,006
  • 8
  • 38
  • 59
0

Using two different images for debugger (node-debug) and app server (custom-node) has no sense in this case. As custom-node container needs node-inspector binaries to be installed too. Otherwise a Cannot find module '/usr/lib/node_modules/node-inspector/lib/InjectorServer.js' error is pushed into node-inspector client-side console and nothing is being debugged as well.

guta
  • 1
0

I have an alternative solution that's similar to Eric's above but uses host rather than container networking.

  • In the main node.js container, map port 5900 to the host
  • Run the main node process with debug enabled
  • Use a separate container for running node-inspector
  • Use host networking for the node-inspector container

I wrote a few more details about it here: https://keylocation.sg/our-tech/debugging-nodejs-in-docker-using-node-inspector

rgareth
  • 3,377
  • 5
  • 23
  • 35