How to Use Docker’s Health Check Command

In this guide, we are going to see what a Docker health check is and how to configure it for your Docker containers.

What is a Health Check?

A Health Check means to check the health of any resource to determine whether that resource is operating normally. Here, it is about checking the health of Docker containers. 

If you’ve been using docker containers in production, you might have noticed that docker checks the status of a container by using the status of the process (PID) launched from the Docker file command. If the process is running successfully, the container is considered healthy.

Although it works, there are certain situations where we need more information about the containers. For example, sometimes our application crashes but the process itself is still running. In that scenario, we might not know the exact status of the container. 

Let’s say you are running a Node.js container with a simple express application:

const express = require("express");
const app = express();
app.get("/health", (req, res) => {
  res.send({ success: true, message: "It is working" });
});
app.get("/", (req, res) => {
  // consider that this route crashes the entire application 
});
const PORT = process.env.PORT || 3000;
app.listen(PORT, () => {
  console.log(`Server is running on PORT ${PORT}`);
});


Now, consider that you have a router that crashes your application in the container. Here, I have a base router that does not return a response.

Here’s the simple Dockerfile to run the Node Container:

FROM node:alpine
WORKDIR /usr/src/app
COPY package*.json ./
RUN npm install
COPY . .
EXPOSE 3000
CMD ["node","app.js"]

Now we build the docker container using the command:

docker build -t docker-healthcheck .
docker run -d -p 3000:3000 docker-healthcheck:latest

After that, if you check the status of the container using docker ps . it will return something like:

undefined


You will notice the status as 
Up <time> , but when you try to run your application it will crash your whole application because there is an issue in the application code.

There comes the need for a Docker Health Check which helps us to find the exact status of the docker container.

Docker Health Check Example

To configure the health check in a Docker container, you need to configure it using the command HEALTHCHECK in the Dockerfile.

There are two different ways to configure the HEALTHCHECK in docker. They are: 

HEALTHCHECK [OPTIONS] CMD command

which will execute the specified command to check the status of the application in the container. In this guide, we will use curl for health check which pings the server and returns a response. Or the other option:

HEALTHCHECK NONE

In this guide, we are going to use the former way to configure health checks for the container. If you look carefully, there is a way to add OPTIONS to the health check command. We will cover the customization qualities in Health Check a bit later.

Here’s an example of implementing Health Check in Docker container, add HEALTHCHECK instruction into Dockerfile.

FROM node:alpine
WORKDIR /usr/src/app
COPY package*.json ./
RUN npm install
COPY . .
EXPOSE 3000


HEALTHCHECK CMD curl --fail http://localhost:3000 || exit 1   


CMD ["node","app.js"]

The curl command checks whether the application is running or not making a request to localhost:3000. If the request returns a 200, it will return exit code 0; if the application crashes, it will return exit code 1. These exit codes are how Docker's HEALTHCHECK determines the health of the container. Based on that, we can check the status of the application in the container.

undefined

Initially, it will take some time to start the health check and update, whether the application is healthy or not.

undefined

If the application crashes or has exited, it will change the status to unhealthy. You can use docker ps to check the status.

undefined

How to Write a Custom Health Check

There are several ways in which we can create a health check in docker. Any command that can be executed in the container and return the appropriate exit code can be used. Using curl or wget is common for containers running webservers.

curl command

Like we discussed before, curl is a primary way to check the status of an application container. It makes a request to the application server and checks the status of it based on the response status code.

HEALTHCHECK CMD curl --fail http://localhost:3000 || exit 1     

wget command

This can be used in two kinds of situations: one is replacing the curl command to check the http server application in the container.

HEALTHCHECK  --interval=5m --timeout=3s \
  CMD wget --no-verbose --tries=1 --spider http://localhost/ || exit 1

The other way is to health check the container, like nginx, which helps to check the status by serving a file in it.

FROM nginx:1.17.7

RUN apt-get update && apt-get install -y wget

HEALTHCHECK CMD wget -q --method=HEAD localhost/system-status.txt

Writing a Custom Health Check in Nodejs

As mentioned earlier, the command used for the HEALTHCHECK can be anything that can be executed in the container and return the correct exits codes.

Let’s take our Node.js application container and build a custom health check for it. First, create a healthcheck.js file and add it to the root directory.

var http = require("http");
var options = {
  host: "localhost",
  port: "3000",
  timeout: 2000,
};
var request = http.request(options, (res) => {
  console.log(`STATUS: ${res.statusCode}`);
  if (res.statusCode == 200) {
    process.exit(0);
  } else {
    process.exit(1);
  }
});
request.on("error", function (err) {
  console.log("ERROR");
  process.exit(1);
});
request.end();

This code checks if our application is running on port 3000 using the http library provided with Nodejs. If the server returns a status 200, it will exit with exit 0, otherwise, it will exit 1.

After that, we need to add this custom health check into our Dockerfile.

FROM node:alpine
WORKDIR /usr/src/app
COPY package*.json ./
RUN npm install
COPY . .
EXPOSE 3000

HEALTHCHECK --interval=12s --timeout=12s --start-period=30s \  
    CMD node healthcheck.js

CMD ["node","app.js"]

Here, we have some options to customize the health check configuration. It checks the status every 12 seconds which starts from 30 seconds (start-period) after booting up.

Once we configure it, we can build and run the docker image to see it in action.

undefined

undefined

Health Check Configuration

To finish off, let's discuss the HEALTHCHECK options available. 

There are a few options that we can use to customize our HEALTHCHECK instruction:

Interval - specifies the time between the health check for the application container. it waits for the specified time from one check to another.

Timeout - specifies the time that the health check waits for a response to consider the status of the container. For example, if we define 30 seconds and our server doesn’t respond within 30 seconds, then it’s considered as failed.

Start-period - specifies the number of seconds the container needs to start; health check will wait for that time to start.

Retries - specifies the number of consecutive health check failures required to declare the container status as unhealthy. Health check will only try up to the specified retry number. If the server fails consecutively up to the specified times, it is then considered unhealthy.