Contents

Debug in VSCode: Attach Debugger To Containers

We all need to debug node program from time to time. If you are using VSCode as your IDE, it’s pretty straightforward.

Debugging with local files is even more comfortable. However, when you need to debug node program in a container, there are a few caveats need to notice.

Let’s start with a few js lines and Dockerfiles. (You can also clone this repo).

Or, skip to TL; DR :)

Get Started

index.js

1
2
3
4
5
6
const sleep = seconds => new Promise(resolve => setTimeout(resolve, seconds * 1000));

sleep(10)
  .then(() => {
    console.log("The waiting is over!");
  });

Dockerfile

1
2
3
4
5
6
FROM node:12-alpine
WORKDIR /app
RUN apk add --no-cache tini
COPY package.json index.js ./
ENTRYPOINT ["/sbin/tini", "--"]
CMD node index.js

Dockefile_node5

1
2
3
4
FROM node:5
WORKDIR /app
COPY package.json index.js ./
CMD node index.js

What you can see here, are two different versions of node. If you are going to debug with older node versions, you will have to change the protocol and the port.

The following launch.json will let VSCode how to attach to the code in the container properly.

launch.json

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
{
  "version": "0.2.0",
  "configurations": [
    {
      "name": "Docker: Attach to Node Version >= 7.7",
      "type": "node",
      "request": "attach",
      "localRoot": "${workspaceRoot}",
      "remoteRoot": "/app",
      "protocol": "auto",
      "port": 9229
    }
  ]
}

Build images and run containers

Now we have 2 Dockerfiles with different node versions; we need to build these images before we can run it.

1
2
$ docker build -t debug-demo . # Build image with Dockerfile
$ docker build -t debug-demo:node5 . -f Dockerfile_node5 # Build image with Dockerfile_node5

Let try node 12 first, copy the launch.json above into your configuration. And set breaking point at line 5.

/img/2019/09/brk-point.png

Then start the container:

1
$ docker run --rm -p 9229:9229 debug-demo node --inspect=0.0.0.0 index.js

And start debug session with the green arrow:

/img/2019/09/debug_ui.png

When the bottom bar turns to orange, then it’s successfully attached to the container.

/img/2019/09/attached.png

A few seconds later, you will see that line 5 has been highlighted. Seems familiar right?

/img/2019/09/stopped.png

But do we need to make the program to wait for a while before we can attach them?

No, of course. That’s where another useful argument --inspect-brk comes in. Let’s change the --inspect to --inspect-brk:

1
$ docker run --rm -p 9229:9229 debug-demo node --inspect-brk=0.0.0.0 index.js

And start the session again:

/img/2019/09/inspect-brk.png

The program now stopped at the very beginning. After VSCode attached to it, you can go to any point you want.

What if I am still using an older node version (<= 7.6)?

Then you need to have some configurations changed. Remember that the protocol and the port mentioned above? That’s what we need to modify.

1
2
3
4
5
6
7
8
9
{
  "name": "Docker: Attach to Node Version <= 7.6",
  "type": "node",
  "request": "attach",
  "localRoot": "${workspaceRoot}",
  "remoteRoot": "/app",
  "protocol": "legacy", // specify legacy instead
  "port": 5858 // not 9229 anymore
}

Change the configuration:

/img/2019/09/node5_config.png

Start the container:

1
$ docker run --rm -p 5858:5858 debug-demo:node5 node --debug-brk index.js

Things to remember here:

  • When you are debugging using the old protocol, you need to expose different port 5858 instead of 9229.
  • The argument is --debug (or --debug-brk) instead of --inspect=0.0.0.0 (or --inspect-brk=0.0.0.0).

Finally, let’s debug! /img/2019/09/node5.png

TL; DR

Run your container

Node version <= 7.6

1
2
$ docker run --rm -p 5858:5858 <IMAGE> node --debug-brk <ENTRY_POINT>
$ docker run --rm -p 5858:5858 debug-demo:node5 node --debug-brk index.js # Example

Node version >= 7.7

1
2
$ docker run --rm -p 9229:9229 <IMAGE> node --inspect-brk=0.0.0.0 <ENTRY_POINT>
$ docker run --rm -p 9229:9229 debug-demo node --inspect-brk=0.0.0.0 index.js # Example

launch.json

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
{
  "version": "0.2.0",
  "configurations": [
    {
      "name": "Docker: Attach to Node Version >= 7.7",
      "type": "node",
      "request": "attach",
      "localRoot": "${workspaceRoot}", // make sure the path is correct
      "remoteRoot": "/app", // make sure the path is correct
    },
    {
      "name": "Docker: Attach to Node Version <= 7.6",
      "type": "node",
      "request": "attach",
      "localRoot": "${workspaceRoot}", // make sure the path is correct
      "remoteRoot": "/app", // make sure the path is correct
      "protocol": "legacy",
      "port": 5858
    }
  ]
}

Further readings