DEV Community

Cover image for Mastering Docker: Defining Health Checks in Docker Compose
juan jose orjuela
juan jose orjuela

Posted on

Mastering Docker: Defining Health Checks in Docker Compose

In this article, we will explore an important aspect of Docker Compose, specifically focusing on health checks, an essential tool for ensuring the reliability and robustness of containerized services. We will cover everything from the basics of what they are and why they are important, to how to practically implement them in your Docker Compose definitions.

Context on Docker and Docker Compose

In the dynamic world of information technology, virtualization and containerization have revolutionized the way we deploy and manage applications. Docker emerges as a leading solution, enabling developers and system administrators to package, distribute, and manage applications efficiently. Docker encapsulates applications in containers, lightweight and portable environments that ensure consistency across different development, testing, and production environments.

Docker Compose, a tool within the Docker ecosystem, simplifies the process of defining and sharing multi-container applications. With Docker Compose, you can define all the services that make up your application in a single docker-compose.yml file. This tool facilitates the orchestration of multiple containers, allowing them to work together harmoniously to form complex applications.

Basic Concepts

What are Health Checks?

In the context of containerization and Docker, health checks are periodic tests or verifications used to determine whether a container is functioning correctly. Essentially, a health check is a way to automatically monitor the health status of a service or application within a container. If a service fails or stops responding, the health check can detect it and take appropriate actions, such as restarting the container or alerting the operations team.

Health checks are essential in production and development environments because they ensure that applications continue to function optimally and reliably. In an environment with multiple services and containers, health checks provide an additional layer of security by ensuring that each individual service is functioning as expected.

How They Work in Docker

Docker incorporates a health check system that allows users to define commands or instructions to check the status of a container. These commands can be as simple as an HTTP request to an application endpoint or a script that checks the availability of an internal service.

When a health check fails, Docker marks the container as unhealthy. This information can be used by orchestration and monitoring tools to make automated decisions, such as restarting the container or redistributing load among healthy containers.

Docker's health checks offer flexibility in terms of configuration, allowing users to define intervals between checks, the number of attempts before considering a service unhealthy, and the maximum time a check should take before being considered failed.

This functionality is crucial for maintaining high availability and reliability of applications, especially in microservices environments where multiple interdependent services must operate in sync.

In the next section, we will delve into how health checks are integrated and configured in Docker Compose, providing practical examples for their implementation.

Health Checks in Docker Compose

Integration with Docker Compose

Docker Compose, a tool for defining and running multi-container Docker applications, natively integrates the concept of health checks into its configurations. Through docker-compose.yml files, Docker Compose enables developers and system administrators to specify how the health check for each service in their environment should be performed.

The integration of health checks in Docker Compose is crucial for automating the monitoring and management of service health. In complex environments with multiple containers, health checks become a vital tool to ensure that each service is operating correctly and to facilitate automatic recovery in case of failures.

Configuration Parameters

In a docker-compose.yml file, the configuration of a health check is done within the definition of each service. The key parameters include:

  • test: The command that will be executed to check the status of the service. It can be a string or a list. For example, ["CMD", "curl", "-f", "http://localhost/health"] for a web application.
  • interval: The time between each check. For example, 30s indicates that the health check is performed every 30 seconds.
  • timeout: The maximum time a health check can take before being considered failed. For example, 10s.
  • retries: The number of times a failed health check will be attempted before marking the service as unhealthy.
  • start_period: An initial period during which the results of failed health checks are not counted towards the maximum number of retries. This is useful for applications that require time to start.

These parameters allow for detailed configuration tailored to the specific needs of each service, providing precise control over how and when a service should be considered unhealthy.

Example:



 service1:
    build: ./web-server
    environment:
      - PORT=3000
    ports:
      - "3000:3000"
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost:3000/ping"]
      interval: 2s
      timeout: 60s
      retries: 20


Enter fullscreen mode Exit fullscreen mode

This Docker Compose example illustrates the configuration of a health check for a service named service1, which represents a web server. The health check definition is made in the docker-compose.yml file and is composed of several key components:

Health Check Test (test):

  • ["CMD", "curl", "-f", "http://localhost:3004/ping"]: This line defines the command that will be executed for the health check. It uses curl to make an HTTP GET request to the /ping path on port 3004 of localhost. The -f option causes curl to fail if the HTTP status code is 400 or higher, which is useful for detecting errors. This command checks if the web service is responding correctly.

Interval (interval):

  • 2s: This specifies that the health check will be executed every 2 seconds. That is, every 2 seconds, Docker Compose will execute the curl command to check the status of the service.

Timeout (timeout):

  • 60s: This is the maximum time Docker will wait for the health check command to complete. If the curl command does not respond within 60 seconds, it will be considered a health check failure.

Retries (retries):

  • 20: Indicates the number of times Docker will retry the health check before marking the service as unhealthy. In this case, if the health check fails 20 consecutive times, Docker will consider the service1 service to be unhealthy.

Example of a Service Dependent on Another:



service2:
    build: ./web-server
    environment:
      - PORT=3001
    ports:
      - "3001:3001"
    depends_on:
      service1:
        condition: service_healthy
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost:3001/ping"]
      interval: 2s
      timeout: 60s
      retries: 20


Enter fullscreen mode Exit fullscreen mode

In this Docker Compose example, we have two services: service1 and service2. Both are configured with health checks, but the interesting aspect here is the dependency of service2 on the health status of service1, indicated by the depends_on clause.

Health Check-Based Dependency (depends_on):

  • service2 uses the depends_on option to establish a dependency on service1.
  • condition: service_healthy: This line specifies that service2 should only start after service1 has been considered "healthy" by Docker.

Operation of service1's Health Check in Relation to service2:

  • Starting of service1: When the set of services is initiated with Docker Compose, service1 begins its initialization process.
  • Execution of service1 Health Check: While service1 is running, Docker performs health checks at intervals of 2 seconds (as per its configuration). If the service successfully responds to the health check command (in this case, a curl to http://localhost:3000/ping), it continues operating normally. If it fails, Docker will retry the health check up to 20 times, with a 60-second timeout per attempt.
  • Health Status of service1 and Its Effect on service2: If service1 passes the health check and is marked as healthy, then Docker proceeds to start service2. If service1 fails its health checks and is marked as unhealthy, service2 will not start until service1 is considered healthy.

Example of Starting Up When Service1 is Healthy:

service 1 healthy

Example of Starting Up When Service1 is Unhealthy:

Service 2 Unhealthy

This health-based dependency model is crucial in environments where services need to interact with each other and where the availability of one service depends on the state of another. It ensures that service2 will not attempt to operate until service1, on which it depends, is fully functional and ready to handle requests or interact with other services. This improves the stability and reliability of the overall application deployment.

In this repository, you will find the example ready to be deployed with Terraform. Feel free to download and try it out.

References:

If you liked this article, don't hesitate to give it a 👏 and ⭐ the repository.

🤔 Follow me on social media!

Thank you!

Top comments (1)

Collapse
 
glours profile image
Guillaume

Hey 👋
Just to let you know that the official documentation link you provided at the end of the post refers to an old file format version.
Compose is now following the Compose specification and the link to the health check section is the following one docs.docker.com/compose/compose-fi...