Effective Docker Healthchecks For Node.js

Writing effective healthchecks will make your services running in Kubernetes or Docker Swarm more reliable

When I first started writing healthcheck’s for Node.js, they were pretty naive. They also followed the commonly suggested wisdom of the internet. Just install curl and hit your API!


But, turns out it’s not so great.

For one, many of my services do not have API endpoints over HTTP. Most of my internal services use AMQP. I ended up adding on lightweight APIs and installing curl in my production containers just for healthchecks!

Adding more complexity to a service is a never a great solution.

Additionally, just because curl can hit your API, doesn’t mean it’s working correctly.

Maybe your API is responding but your service can’t connect to your database, or queue, or whatever other dependency it needs to be fully operational.

I really wanted to be able to TRUST my healthcheck. If it says healthy, I want to know that the ability to connect to it’s dependencies was part of that state’s computation.

In celebration of Node.js 10’s LTS release, I’ll show you how to create a custom healthcheck for your service, and it’s dependencies, by writing a simple ES6 module with .mjs!

Let’s imagine a service.

We still want our healthcheck to be relatively lightweight, and for my purposes, just checking that all of the dependencies are working and that I’m able to connect with them would be loads better than a curl to a endpoint that just says ‘ok’.

In my example, I’m using two libraries servicebus and sourced. These libraries are dependent on rabbitmq, mongodb, and redis.

If our service is unable to connect to any of these three, it is definitely not healthy.

Seems how these libraries can be passed a configuration with their connection options, and that’s how our application is using them internally, no need to do anything extra fancy or reinvent the wheel.

Here’s the healthcheck example. I store it in ./bin/healthcheck.mjs.

And that’s it!

This first line executes /bin/sh to call node with the experimental modules flag.

This way, we can just run the file without trying to figure out how to modify our calling code to know or expect to need to use the --experimental-modules flag.

Next, we have our imports, and then define the exit function.

This is so we can call exit and say what we mean, instead of trying to remember whether we want exit code 0 or 1.

Our actual healthcheck function then just returns an array of promises that need to be resolved for the service to be considered healthy:

Notice that I’m able to reuse the same config that my application uses.

Lastly, we call check, and provide a success and a failure function.

Now, to use the healthcheck easily, we are going to do two things.

  1. Set up the bin section of package.json to expose our healthcheck command.
  2. npm link to be able to call the healthcheck


Now when we npm link our project, the commands defined in bin will be available via our CLI.

This doesn’t make a ton of sense to do in our local machine, but it does inside of our container.

Here’s an example multi-stage Dockerfile which does so:

Notice the command RUN npm link in the second stage (second FROM defines second stage).

This makes the command healthcheck in that container, execute the healthcheck we’ve defined.

This can also be used by Kubernetes livenessProbes and readinessProbes!

Check out the probes above, and then check out the /bin folder for the healthcheck example!

Happy Hacking!

Interested in hearing my DevOps story? Read it on HackerNoon now!

If you’ve found this helpful, and would like to help me, the best way to do so is “clapping” for this article (press and hold) up to 50 times, and sharing it on social media! :)

I make things for the internet, that scale, look nice, and make money!