Repository navigation
Compose healthcheck example might not work as expected #14113
Description
File: compose/compose-file/compose-file-v3.md
I came across this question on reddit where someone was asking about why an example for compose has || exit 1 and another doesn't. The doc it references is specifically the healthcheck section of https://docs.docker.com/compose/compose-file/compose-file-v3/#healthcheck
Here is the breakdown of why one example isn't good to use:
The reason why you would want to specify an exit code is for one reason and that is because there are very specific behaviors that occur based on the exit code with health checks. Here, I would just consider that one of these examples it not good because the format that uses a non-shell exec type format will not work. Here are the exit codes that Docker knows how to manage as a part of a health check:
- 0: success - the container is healthy and ready for use
- 1: unhealthy - the container is not working correctly
- 2: reserved - do not use this exit code
Source: https://docs.docker.com/engine/reference/builder/#healthcheck
Here are three examples of just containers ran to show this behavior:
$ docker ps -a --no-trunc --format 'table {{.Command}}\t{{.Status}}'
COMMAND STATUS
"curl -f https://localhost || exit 1" Exited (7) 5 minutes ago
"/bin/sh -c 'curl -f https://localhost || exit 1'" Exited (1) 6 minutes ago
"curl -f https://localhost" Exited (7) 6 minutes ago
And for each line (in order), here are the CMDs used:
CMD ["curl","-f","https://localhost","||","exit","1" ]
CMD curl -f https://localhost || exit 1
CMD ["curl","-f","https://localhost" ]
The first line fails on the command line because there is no shell to interpret how to use the || and curl actually interprets it as another URL to attempt to connect to:
$ docker run -it test
curl: (7) Failed to connect to localhost port 443 after 0 ms: Connection refused
curl: (6) Could not resolve host: ||
curl: (6) Could not resolve host: exit
curl: (7) Failed to connect to 0.0.0.1 port 80 after 2 ms: Connection refused
The second line works as expected because we force it to exit with a code of 1 on failure:
$ docker run -it test
curl: (7) Failed to connect to localhost port 443 after 0 ms: Connection refused
And the third line doesn't return the right exit code (curl returns an exit code of 7) for a health check:
$ docker run -it test
curl: (7) Failed to connect to localhost port 443 after 0 ms: Connection refused
When using curl, it might not always exit with a 1 on failure so forcing a non-zero exit code to have a specific exit code is important for a health check to actually function as expected. The example without || exit 1 does so because exec format has no idea how to do the "if this process exits with a non-zero exit code, return an exit code of 1" that "|| exit 1" does. That's a function of the shell, in this case, sh.
So the real answer to "Why do I need 'exit 1' in shell form?" is because of how health checks work and the other question not asked is "why does exec format not have || exit 1" and the answer is because it doesn't handle a || operator and will in fact not work properly for a health check.
Activity
docker-robott commentedon Dec 6, 2022
There hasn't been any activity on this issue for a long time.
If the problem is still relevant, mark the issue as fresh with a
/remove-lifecycle stalecomment.If not, this issue will be closed in 14 days. This helps our maintainers focus on the active issues.
Prevent issues from auto-closing with a
/lifecycle frozencomment./lifecycle stale
docker-robott commentedon Jan 19, 2023
Closed issues are locked after 30 days of inactivity.
This helps our team focus on active issues.
If you have found a problem that seems similar to this, please open a new issue.
/lifecycle locked