In a previous series of posts, I described how I set up Node.js in a Docker container for development on my macBook. It’s quite a lot of steps!

Well, there is a much simpler way - introducing Appsody.

Setup

Here’s what I did to download Appsody from GitHub and create my first project test1:

mkdir Appsody
cd Appsody
curl -GL -o appsody-homebrew-0.4.2.tar.gz "https://github.com/appsody/appsody/releases/download/0.4.2/appsody-homebrew-0.4.2.tar.gz"
tar -xvf appsody-homebrew-0.4.2.tar.gz
mkdir test1
cd test1
../appsody init nodejs-express

Not sure why but at the the time of writing, appsody-0.4.2-darwin-amd64.tar did not include appsody-controller, so I used the homebrew package instead.

In this example, I used the nodejs-express template. To get a list of templates, run ../appsody list. Choose your poison: Spring Boot, Python Flask, Swift, Vert.x, etc.

The output of the init command is:

Running appsody init...
Downloading nodejs-express template project from https://github.com/appsody/stacks/releases/download/nodejs-express-v0.2.5/incubator.nodejs-express.templates.simple.tar.gz
Download complete. Extracting files from nodejs-express.tar.gz
Setting up the development environment
Running command: docker[pull appsody/nodejs-express:0.2]
Running command: docker[run --rm --entrypoint /bin/bash appsody/nodejs-express:0.2 -c find /project -type f -name .appsody-init.sh]
Successfully initialized Appsody project

You’ll also have to edit the Docker Preferences.. > File Sharing to add your working folder and the .appsody hidden folder:

Docker File Sharing Setup for Appsody folders

Debugging

Now, execute ../appsody debug (or ../appsody run if you don’t intend to attach Visual Studio Code as the debugger):

Running debug environment
Running command: docker[pull appsody/nodejs-express:0.2]
Running docker command: docker[run --rm -p 3000:3000 -p 9229:9229 --name t1-dev -v /Users/usr/Work/Appsody/t1/:/project/user-app -v t1-deps:/project/user-app/node_modules -v /Users/usr/.appsody/appsody-controller:/appsody/appsody-controller -t --entrypoint /appsody/appsody-controller appsody/nodejs-express:0.2 --mode=debug]
[Container] Running Install: npm install --prefix user-app && npm audit fix --prefix user-app
[Container] [..................] | rollbackFailedOptional: verb npm-session e295audited 295 packages in 1.677s
[Container] found 0 vulnerabilities
[Container] 
[Container] [..................] | rollbackFailedOptional: timing audit body Comup to date in 0.919s
[Container] fixed 0 of 0 vulnerabilities in 295 scanned packages
[Container] 
[Container] 
[Container]    ╭────────────────────────────────────────────────────────────────╮
[Container]    │                                                                │
[Container]    │      New minor version of npm available! 6.9.0 -> 6.11.3       │
[Container]    │   Changelog: https://github.com/npm/cli/releases/tag/v6.11.3   │
[Container]    │               Run npm install -g npm to update!                │
[Container]    │                                                                │
[Container]    ╰────────────────────────────────────────────────────────────────╯
[Container] 
[Container] Running: npm run debug
[Container] 
[Container] > nodejs-express@0.2.5 debug /project
[Container] > node --inspect=0.0.0.0 server.js
[Container] 
[Container] Debugger listening on ws://0.0.0.0:9229/54413382-182a-4b5f-b2d1-626b1f5340ae
[Container] For help, see: https://nodejs.org/en/docs/inspector
[Container] [Wed Sep  4 16:36:34 2019] com.ibm.diagnostics.healthcenter.loader INFO: Node Application Metrics 5.0.3.201908230949 (Agent Core 4.0.3)
[Container] [Wed Sep  4 16:36:34 2019] com.ibm.diagnostics.healthcenter.mqtt INFO: Connecting to broker localhost:1883
[Container] App started on PORT 3000

Now, you can check out these routes:

  • The app itself, on http://localhost:3000/
  • The health check endpoint, http://localhost:3000/health, which returns {"status":"UP","checks":[]} if all is good.
  • For Prometheus metrics, http://localhost:3000/metrics
  • And an Application Metrics dashboard during debugging http://localhost:3000/health

Open Visual Studio Code and drag the entire test1 folder into it. Apsody already has created a hidden .vscode folder and configured launch.json for debugging! Just hit Debug > Start Debugging:

Visual Studio Debugging the Appsody generated code running in a Docker container

Add a breakpoint on app.js, e.g. on the line res.send("Hello from Appsody!"); and open your browser to http://localhost:3000 - you’ll see the message Hello from Appsody!

const app = require('express')()
app.get('/', (req, res) => {
  res.send("Hello from Appsody!");
});
module.exports.app = app;

Make a change to the file, e.g. res.send("Greets from Appsody!");, save it, re-start debugging, refresh your browser... viola!

Other

BTW, to stop the container, hit Ctrl-C.

And to “connect” to a container and inspect its contents or run commands within:

docker exec -it test1-dev bash

Here’s a screenshot of the Application Metrics dashboard http://localhost:3000/health including a flame graph during profiling:

Application Metrics Dashboard for Node.js Application Metrics Dashboard during profiling

Conclusion

Check out my previous post Setting up Node.js in a Docker container. I shared the individual docker commands to pull an image, then inject files, run interactive commands in the container to do more setup, and commit the new image.

Then, run the container with arguments to mount a Host folder and expose ports for the output and debugging. Ultimately, you’ll notice the docker command that is called during appsody debug is pretty similar to what I previously used:

docker run -it --rm -v $PWD:/code -p 8080:8080 -p 127.0.0.1:9229:9229 nodemondev bash -c "cd /code && nodemon --inspect=0.0.0.0:9229 hello.js"

And, finally, I previously described the manual steps to setup Visual Studio Code for debugging!

Appsody automates all that automagically and really makes my last post a colossal waste of effort. Life is that bit easier!

BTW Appsody is a piece of the Kabanero.io project, which according to this blog, “brings together open source projects Knative, Istio, and Tekton, with new open projects Codewind, Appsody, and Razee into an end-to-end solution for you to architect, build, deploy, and manage the lifecycle of Kubernetes-based applications.”