Docker: healthcheck and depends_on

Introduction

This post mainly covers the mechanisms and syntax of Docker healthcheck and Docker Compose’s depends_on. This post can be viewd as a cheat sheet.

healthcheck Mechanism

When a container has a healthcheck specified, it has a health status in addition to its normal status. This status is initially starting. Whenever a health check passes, it becomes healthy (whatever state it was previously in). After a certain number of consecutive failures, it becomes unhealthy.

healthcheck has the following parameters:

Parameter Default Description
--interval=DURATION 30s Interval between healthchecks.
--timeout=DURATION 30s How long to wait for the healthcheck to complete. If it exceeds this time, it’s considered a failure.
--retries=N 3 After retries consecutive failures, the container status changes to unhealthy.
--start-period=DURATION 0s Failures during this period are not counted towards the retries limit. However, once a healthcheck succeeds, the container is considered started and the start period ends automatically.
--start-interval=DURATION 5s Interval between healthchecks during the start period.

After the container starts, it is in the starting state, i.e., the start period. During the start period, the container can only become healthy, not unhealthy.

healthcheck Syntax

Syntax

This post focuses on the syntax in Compose, not in Dockerfile or CLI.

A healthcheck in Compose will override the one in Dockerfile.

An Example:

1
2
3
4
5
6
7
healthcheck:
test: curl -f https://localhost || exit 1
interval: 1m30s
timeout: 10s
retries: 3
start_period: 40s
start_interval: 5s

test defines the command Compose runs to check container health. It can be either a string or a list.

If it’s a list, the first item must be either NONE, CMD or CMD-SHELL.

If it’s a string, it’s equivalent to specifying CMD-SHELL followed by that string.

The following two forms are equivalent:

1
test: ["CMD-SHELL", "curl -f http://localhost || exit 1"]
1
test: curl -f https://localhost || exit 1

Clearly, the second form is more convenient.

Debugging test Command

Common test command templates can be found in the previous post. How to debug our test command? Use docker inspect. Healthcheck information is in State.Health, and we can get it with the following command:

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

An example:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
{
"Status": "healthy",
"FailingStreak": 0,
"Log": [
{
"Start": "2024-06-02T13:45:22.110841425+08:00",
"End": "2024-06-02T13:45:22.178282083+08:00",
"ExitCode": 0,
"Output": "mysqladmin: [Warning] Using a password on the command line interface can be insecure.\nmysqld is alive\n"
},
{
"Start": "2024-06-02T13:45:27.208737778+08:00",
"End": "2024-06-02T13:45:27.261481813+08:00",
"ExitCode": 0,
"Output": "mysqladmin: [Warning] Using a password on the command line interface can be insecure.\nmysqld is alive\n"
}
]
}

Attributes of the Log element:

  • Output: The output of the command, used for debugging.
  • Exitcode: 0 indicates the container is healthy, 1 indicates it is unhealthy.

Disabling healthcheck

1
2
healthcheck:
disable: true

depends_on Mechanism

You can control the order of service startup and shutdown with the depends_on attribute. Compose always starts and stops containers in dependency order.

It is useful if services are closely coupled, and the startup sequence impacts the application’s functionality.

Note that depends_on only indicates startup order and does not guarantee the container starting earlier is ready.

On startup, Compose does not wait until a container is “ready”, only until it’s running.

By setting the condition attribute of depends_on, you can specify when container B, which is dependent on container A, will start. This attribute has the following values:

Value Description
service_started Default value, B starts after A starts.
service_healthy B starts after A is healthy.
service_completed_successfully B starts after A successfully completes its command. Here, A typically executes a command/script and stops after completion. A successful exit is indicated by exit code 0. Check this specific example.

Therefore, to achieve truly ordered startup of multiple containers as services in Compose, use the healthcheck mechanism and set condition to service_healthy.


Note that using depends_on is only effective when using docker compose up|start. If the container’s restart policy is set to unless-stopped or always, these containers will not restart in depends_on order after the server restarts.

depends_on Syntax

Simple Configuration

1
2
3
4
5
6
7
8
9
10
services:
web:
build: .
depends_on:
- db
- redis
redis:
image: redis
db:
image: postgres

Here, the condition defaults to service_started.

Detailed Configuration

This kind of configuration allows specifying the condition.

1
2
3
4
5
6
7
8
9
10
11
12
services:
web:
build: .
depends_on:
db:
condition: service_healthy
redis:
condition: service_started
redis:
image: redis
db:
image: postgres

References