How to debug Nodejs app running inside Docker container via Google Cloud - node.js

I have found Google provides some guidelines on how to run Nodejs on a custom runtime environment. Everything seems fine and I am managing to start my Nodejs app on local machine running gcloud preview app run ..As I can see, it probably creates a Docker container and runs Nodejs program in there. I am saying "probably", because it is my first experience with Docker, however I am 2+ years experienced Nodejs developer.
So my question is how to debug (with breakpoint stops) my Nodejs program when it is running inside Docker container? Using Chrome Developer Tools or how can I set up Webstorm debug configuration to make it stop on breakpoints. Is it possible to configure Docker on how it starts node or even start Docker via gcloud inside Webstorm to assure debugging is working? Any help or clarifications are appreciated.
Please don't provide answers on how to debug Nodejs app outside of Docker container – I know how to do that very well.

I'm sorry, but I only know a solution with node-inspector, I hope it can help you:
You can install node-inspector package inside your container: https://github.com/node-inspector/node-inspector
Map the port 8080 of your container on your host (run you container with parameter -p 8080:8080)
Run this inside your container (with docker exec, or docker-enter)
node-debug --web-host 0.0.0.0 yourScript.js
Go to http://localhost:8080/debug?port=5858

There is an easier way, at least from Docker 0.11 or something.
Run, on your development machine only, Docker with --net="host". This makes Docker bind to the localhost directly, and not creating a bridging network adapter, so the Docker machine runs like any other process on your machine and opens the ports it needs on the local interface.
This way, you can connect to your debug port as if Node was not running inside Docker.
More documentation here : https://docs.docker.com/reference/run/
Before Docker 0.11 you have other two ways of debugging, apart from using node-inspector :
Run sshd inside your Docker machine and setup an ssh tunnel, as if you were to debug on a remote machine.
"Mess up" with ip-tables to "revert" the Docker mapping of local ports. There is something about it here Exposing a port on a live Docker container .

By default, the node debugger will listen only for connections for the same host (127.0.0.1). But in Docker, you need to accept connections from any host (0.0.0.0):
# inside Docker
node --inspect=0.0.0.0:9229 myapp.js
Also you have to expose the debug port (9229). Then the application should be automatically detected and listed as a Remote Target in chrome://inspect/#devices in Chrome (tested in Chrome 67).
Example
Here is a minimal example. It runs a simple JavaScript application in Docker and shows how to attach the Chrome debugger to it:
$ 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
Run with:
$ 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
...
Open Chrome and go to chrome://inspect/#devices. It should soon after the start of the application, detect it and list it.
Troubleshooting
For debugging Docker network issues, docker inspect is useful:
$ 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"
}
]
},
...
If want to see the requests sent between Docker and Chrome, ngrep can help:
$ 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".} ]..
#

As far as I can see, you need to provide the parameter --debug-brk= to node upon startup - this will enable debugging. After that, access the specified port on your docker container. You probably have to expose it or tunnel (using ssh).
After that, point the Webstorm remote debugger at the specified port, and you should be set.

If you are using bridge networking for your containers, and you don't want to install node-inspector inside the same container as your node process, I've found this to be a convenient solution:
In the main node.js container, map port 5858 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
This say, the node-inspector container will connect to localhost:5858 which will then be port mapped through to the main node container.
If you're running this on a public VM, I'd then recommend:
Make sure port 5900 is not exposed publicly (e.g. by the firewall)
Make sure the node inspector port (e.g. 8080) us exposed publicly, so you can connect to it
I wrote a few more details about it here: https://keylocation.sg/our-tech/debugging-nodejs-in-docker-using-node-inspector

Related

Azure container App fails to start with Julia image

I am trying to run Julia code in azure container app, but it fails for some reason.
docker file is pretty simple:
FROM julia:1.7-bullseye
COPY . /
EXPOSE 8080
RUN julia --project='/' -e 'using Pkg; Pkg.build()'
ENTRYPOINT julia --project='/' main.jl "0.0.0.0" "8080"
"0.0.0.0" and "8080" there is the host and port on which HTTP is served:
HTTP.serve(GENERAL_ROUTER, host, port_restful_api)
The app supposed to run a simple HTTP server that is served over port 8080, GET to / is the health check that returns simple "Up"
When I run that same image locally with docker run -p 8080:8080 my-test:latest it works fine and hitting localhost:8080 gives me my expected response
But when I have it in container app - revision fails to be provisioned (and no extra errors provided). In the ingress I added availability to accept traffic from anywhere and target port is 8080...
What I am missing?
UPDATE
At the same time in log analytics I can see my output to console that should indicate that the app is supposedly running fine, e.g.
[ Info: API handler service: Running on thread 1
In Julia those are done with
#info "API Server: Running on thread $(Threads.threadid())"
But in logs those are in stderr stream. Could it be that the ACA treats any output to stderr as startup error?
UPDATE 2:
The very same code works without any issues or changes on Azure Container Instance and in Azure Kubernetes Service...
So for now I stopped investigating and decided to use ACI.
You should verify if any process inside the julia image needs root privileges as ACA do not support running privileged containers based on the docs:
Azure Container Apps can't run privileged containers. If your program
attempts to run a process that requires root access, the application
inside the container experiences a runtime error.
Did you specify 8080 as your target port when configuring the HTTP ingress of your Container App? https://learn.microsoft.com/en-us/azure/container-apps/ingress?tabs=bash
The platform will try to ping your app at the specified port due to the default health probes. If it receives no response, it will restart your app: https://learn.microsoft.com/en-us/azure/container-apps/health-probes?tabs=arm-template

Node web server not visible externally, but Python is (MacOS)

I'm just starting to build an Ionic 2 app, but I can't get it working on my mobile device.
Python (works)
To demonstrate that the phone can see the host, I tried a Python server:
$ python -m SimpleHTTPServer 8000
Serving HTTP on 0.0.0.0 port 8000 ...
If I go to http://192.168.8.101:8000 on my phone, it connects fine and displays the directory listing.
Node (fails)
However, when I start Ionic:
$ ionic serve -p 8000
[...]
[INFO] Development server running
Local: http://localhost:8000
External: http://192.168.8.101:8000
I can load it in my host's web browser, but I can't see it from my phone nor another computer (it times out). I also tried a basic node server:
$ npm install http-server -g
$ http-server -p 8000
Starting up http-server, serving ./
Available on:
http://127.0.0.1:8000
http://192.168.8.101:8000
With the same result as Ionic: accessible from the host, but not from the phone.
Is there something blocking the request? Or is there some Node configuration I'm missing? I'm new to both Mac OS and Node, so I don't know where to look.
Embarrasingly, this turned out to be a firewall issue. In System Preferences > Security & Privacy > Firewall > Firewall Options, Node was explicitly set to deny incoming connections:
Changing it to Allow has fixed it. Phew!
Just execute ionic address and you'll get an IP address in your command line. Try with that ipaddress:port number from your mobile which will enable you to access your site from your phone.
Just incase if the ionic address command doesn't return anything, you need to execute the below command to point it to your ip,
ionic serve --address YOUR_IP_ADDRESS
Hope this helps!

Can't connect to Node.js inspector on exposed Docker container port

Running the command docker run -p 9222:9229 --name node-inspect-test -d node:alpine node --inspect-brk -e 'console.log("hello world")' should expose the node.js inspector on port 9222 on the Docker host.
Running curl http://localhost:9222/json results in curl: (56) Recv failure: Connection reset by peer.
Requesting the same endpoint from within the container with docker exec -it node-inspect-test wget -qO- http://localhost:9229/json succeeds.
Why does the exposed port 9222 not get forwarded to the internal port 9229 successfully?
I'm running Docker version 17.06.0-ce, build 02c1d87 on Ubuntu 16.04.2.
By default node inspector listens on the loopback interface. The --inspect-brk flag has the option of specifying host and port. In order to have the debugger listen on all interfaces so that it is accessible via the Docker host, use the flag --inspect-brk=0.0.0.0:9229.

Debug a NodeJS application inside Docker

I'm moving my NodeJS application to docker, and the last problem that I have encountered is debugging the application.
My setup: OSx, boot2docker, docker (based on centos), WebStorm as IDE and debugger.
Here's what I have by now:
Forward 5858 from docker to boot2docker:
docker run -p 5858:5858 ...
Forward 5858 port from boot2docker to host:
VBoxManage controlvm boot2docker-vm natpf1 "boot2docker5858,tcp,127.0.0.1,5858,,5858"
This same setup works to foreword my application ports to host machine.
Port 5858 on the other hand, doesn't seem to react if accessed from outside the docker container.
Inside the docker container it works just fine.
Any idea what can be done to make this work?
Well, I have finally figured it out.
As it seems, node listens only on 127.0.0.1:5858.
To make it listen on all ports, I installed HAProxy on the docker, that forwards the requests from 0.0.0.0:5859 to 127.0.0.1:5858.
Here's the HAProxy configuration if anybody ever needs:
listen l1 0.0.0.0:5859
mode tcp
timeout client 180000
timeout server 180000
timeout connect 4000
server srv1 127.0.0.1:5858
And than add to your Dockerfile:
COPY haproxy.conf haproxy.conf
RUN haproxy -D -f /haproxy.conf

Remotely debugging my node app that is hosted on AWS

I would like to connect to my node server running in debug mode on AWS (node --debug app.js) from my development machine, and be able to debug my app remotely.
Two questions:
Can I do this with node-inspector? I wish I could, but node-inspector fails to install on my AWS instance.
Any alternatives that will allow me to do this?
And with the help of tepez's answer, the following worked for me (Node Inspector v0.12.2):
On my machine:
ssh -L 8080:127.0.0.1:8080 <username>#<host> -N
On the remote server:
node-debug --cli <appname>
And enter the following address in the browser:
127.0.0.1:8080/?ws=127.0.0.1:8080&port=5858
Forward remote debugger port with ssh from your dev machine
ssh -L 5858:127.0.0.1:5858 ubuntu#some.ec2.host.com
And now you can start node-inspector as if the debugger is running locally.
Allow me to present an alternative using node --inspect. I had the same need, although in a Windows environment, I believe this should work for you.
Remote machine (tested with Node 6.10.2, Windows Server 2012)
node --inspect=0.0.0.0:9229 <appname>.js
Local Machine (tested with Win 10, Chrome 60.0.3112.90)
In Chrome DevTools - Click the vertical ellipsis menu in top right:
Go to: More Tools -> Remote Devices
Under Network targets Click Add address
Enter <remote-ip>:9229
Once you enter address and remote target is connected you'll see Node.JS Icon on Top Left of DevTools
Click NodeJS Logo to launch DevTools Node Debugger
Screenshots of Steps 1,3,4 below.
One more option to use 0.0.0.0 to listen to request from outside:
node-debug --web-host=0.0.0.0 --cli app.js
and visit this address to debug:
http://<the-domain>:8080/?port=5858
it would be better if HTTP/2 is available since there are lots of small files.
You can use node --inspect too in your remote machine.
Start your node with node --inspect myapp.js
Then locally ssh -L 9229:127.0.0.1:9229 myuser#myserver -N
Search for an string like this at the log head and copy it
chrome-devtools://devtools/remote/serve_file/#60cd6e859b9ff284980/inspector.html?experiments=true&v8only=true&ws=127.0.0.1:9229/bef2ae68
Paste it in your chrome browser
Enjoy :)
If you are using pm2 just add this on your ecosystem.js
"apps": [{
"name": "myapp",
"script": "index.js",
"node_args": ["--inspect"],
...
Also you can specify --web-host argument.
node-inspector --web-host host.amazonaws.com
This is what worked for me:
Start node-inspector on server.
Start debugee on remote server with --debug flag.
Note the port that the debugger listens on, i.e. Debugger listening on port DEBUG_PORT message.
Create an ssh tunnel for port 8080, not the DEBUG_PORT as Andrey Sidorov's answer suggests.
Open SERVER_API:8080/debug?ws=127.0.0.1:8080&port=DEBUG_PORT in browser an voilà.
Node Inspector v0.10.1

Resources