Skip to content

Comparing methods to launch Node.js applications in a Docker environment

License

Notifications You must be signed in to change notification settings

jonfairbanks/docker-node-init

Repository files navigation

docker-node-init

GitHub Workflow Status GitHub top language Docker Pulls GitHub last commit Lines of code License

PM2 is a very popular application used to launch Node.js (and other scripts) in a production fashion.

Although PM2 does a good job of launching process on bare-metal, it is not ideal in a Docker environment.

What's wrong with PM2 & Docker?

When a Node.js process exits, it exits with a particular process event:

  • SIGINT
  • SIGTERM
  • SIGKILL

If the Node script is started with npm start for example, these events may not be properly exposed to the parent process(es) allowing error handling to take place.

Similar scenarios may take place when using pm2 start index.js within a Docker container. If a SIG* event is thrown, the event may be swallowed by npm or pm2.

PM2 does offer a method for Docker, however there's a better way. Read on!

So what should I use instead?

👉 tini 👈

From the repo:

All Tini does is spawn a single child (Tini is meant to be run in a container), and wait for it to exit all the while reaping zombies and performing signal forwarding.

Example Dockerfiles

In this repository are a few sample Dockerfiles --

  • Dockerfile: A barebones Dockerfile which supports exposing a Node.js app; common in online tutorials
  • Dockerfile-pm2: An advanced Dockerfile with environments and security scans, but is using pm2
  • Dockerfile-tini: A production-ready Dockerfile with environments, security scans and proper SIG* handling

Running with Docker

Three versions of this image are available to test each scenario:

Base Docker image:

docker run -d -p 8080:8080 --name docker-node-init-base jonfairbanks/docker-node-init:latest --restart=always

PM2 Docker image:

docker run -d -p 8080:8080 --name docker-node-init-pm2 jonfairbanks/docker-node-init:latest-pm2 --restart=always

Tini Docker image:

docker run -d -p 8080:8080 --name docker-node-init-tini jonfairbanks/docker-node-init:latest-tini --restart=always

Using the App

To test how a theoretical Node.js app runs in these scenarios, this app exposes a few endpoints to test with:

  • /: Landing page
  • /sigint: Sends the app process a SIGINT signal after X seconds
  • /sigkill: Sends the app process a SIGKILL signal after X seconds
  • /sigterm: Sends the app process a SIGTERM signal after X seconds

Configuration Options

The following process.env options are supported:

  • PORT - Override the application port (Default: 8080)
  • SECS - Override seconds before process signals are sent (Default: 2)

Resources