Home Interests DevOps

How to Add a Health Check to Your Docker Container

howchoo   (467)
September 15, 2023
12 minutes

Share

Interests
Posted in these interests:
devops • 3 guides
docker • 4 guides

This guide will cover Docker health checks. First, we’ll talk about what health checks are and why they’re valuable, then will talk about implementation. I’ll be cover the material in the form of a tutorial, so feel free to grab a shell and follow along.

1 – What is a health check?

Health checks are exactly what they sound like – a way of checking the health of some resource. In the case of Docker, a health check is a command used to determine the health of a running container.

When a health check command is specified, it tells Docker how to test the container to see if it’s working. With no health check specified, Docker has no way of knowing whether or not the services running within your container are actually up or not.

In Docker, health checks can be specified in the Dockerfile as well as in a compose file. I’ll cover both implementations in a later step.

2 – An example using Flask

Let’s see how health checks work by building a simple Flask app.

Before we begin, note that all of this code is available in a Github repository: Howchoo/docker-flask.

Let’s start with the requirements.txt:

Flask==0.12.2

And the Dockerfile:

FROM python:3.6-alpine

COPY . /app

WORKDIR /app

RUN pip install -r requirements.txt

CMD ["python", "app.py"]

And finally, app.py:

from flask import Flask

app = Flask(__name__)


@app.route('/')
def hello_world():
    return 'Hello world'


if __name__ == '__main__':
    app.run(host='0.0.0.0')

Now let’s build the container:

docker build -t docker-flask .

This should build pretty quickly. Then we’ll run the container.

docker run --rm --name docker-flask -p 5000:5000 docker-flask

Now test by opening up your browser to localhost:5000. You should see “Hello world”.

3 – Why do we need a health check?

Well, to be honest, in our case it may not make that much of a difference because we’re just running the development server, but in a production environment we’d probably be running a few different processes. We’d probably serve our Flask app using nginx and uwsgi, possibly using supervisor.

In this case, we could theoretically lose our Flask app, but the container would still be running. So the normal state of the container would be “running” even though we are no longer serving traffic.

If we’re running this service in a swarm, the swarm will still think everything is OK because the container is running. But actually, we’d prefer the swarm to know that things aren’t healthy and restart the container so we can serve traffic again.

4 – Add a health check to the Dockerfile

Since the goal of our container is to serve traffic on port 5000, our health check should make sure that is happening.

A health check is configured in the Dockerfile using the HEALTHCHECK instruction. There are two ways to use the HEALTHCHECK instruction:

HEALTHCHECK [OPTIONS] CMD command

or if you want to disable a health check from a parent image:

HEALTHCHECK NONE

So we’re obviously going to use the first. So let’s add the HEALTHCHECK instruction, and we’ll use curl to ensure that our app is serving traffic on port 5000.

So add this line to the Dockerfile right before the last line (CMD).

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

In this case, we are using the default options, which are interval 30s, timeout 30s, start-period 0s, and retries 3. Read the health check instruction reference for more information on the options.

5 – See the health status

Let’s rebuild and run our container.

docker build -t docker-flask .
docker run --rm --name docker-flask -p 5000:5000 docker-flask

Now let’s take a look at the health status. Notice we have the –name option to the above command so we can easily inspect the container.

docker inspect --format='{{json .State.Health}}' docker-flask 

If you run this immediately after the container starts, you’ll see Status is starting.

{"Status":"starting","FailingStreak":0,"Log":[]}

And after the health check runs (after the default interval of 30s):

{"Status":"healthy","FailingStreak":0,"Log":[{"Start":"2017-07-21T06:10:51.809087707Z","End":"2017-07-21T06:10:51.868940223Z","ExitCode":0,"Output":"Hello world"}]}

We have a little more information here. We see the Status is healthy as well as some details about the health check.

We can also see the health status by running docker ps.

docker ps

You’ll see the following:

CONTAINER ID        IMAGE                  COMMAND                  CREATED             STATUS                   PORTS                    NAMES
9f89662fc56a        howchoo/docker-flask   "python app.py"          2 minutes ago       Up 2 minutes (healthy)   0.0.0.0:5555->5000/tcp   docker-flask

Notice under STATUS, the status is Up with (healthy) next to it. The health status appears only when a health check is configured.

6 – Configure the health check using a compose file

We can also configure the health check using a compose file. Let’s make a file called docker-compose.yml.

version: '3.1'

services:
  web:
    image: docker-flask
    ports:
      - '5000:5000'

And we deploy our stack to a swarm using:

docker stack deploy --compose-file docker-compose.yml flask

Now, the health check was specified in the Dockerfile, but we can also specify (or override) the health check settings in our compose file.

version: '3.1'

services:
  web:
    image: docker-flask
    ports:
      - '5000:5000'
    healthcheck:
      test: curl --fail -s http://localhost:5000/ || exit 1
      interval: 1m30s
      timeout: 10s
      retries: 3

7 – In conclusion

Hopefully you have a better understanding of Docker health checks and how to implement them. If you have any questions or would like to suggest improvements to this guide, please comment below.

NEXT UP

Secure Your Sensitive Data with Kubernetes Secrets

Learn how to create and use Kubernetes secrets.
howchoo   (467)
November 26, 2023

Kubernetes secrets are objects that store and manage sensitive data inside your Kubernetes cluster. One mistake developers often make is storing sensitive information like database passwords, API credentials, etc in a settings file in their codebase. This is very bad practice (hopefully for obvious reasons). Most developers know this, but still choose the option because it’s easy.

Continue Reading

howchoo

 467 guides

Introducing Howchoo, an enigmatic author whose unique pen name reflects their boundless curiosity and limitless creativity. Mysterious and multifaceted, Howchoo has emerged as a captivating storyteller, leaving readers mesmerized by the uncharted realms they craft with their words. With an insatiable appetite for knowledge and a love for exploration, Howchoo's writing transcends conventional genres, blurring the lines between fantasy, science fiction, and the surreal. Their narratives are a kaleidoscope of ideas, weaving together intricate plots, unforgettable characters, and thought-provoking themes that challenge the boundaries of imagination.

Discover interesting things!

Explore Howchoo's most popular interests.

Explore