Skip to content

Compose healthcheck example might not work as expected #14113

Closed

Description

@mbentley

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

  1. docker-robott commented on Dec 6, 2022

    @docker-robott
    Collaborator

    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 stale comment.
    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 frozen comment.

    /lifecycle stale

  2. docker-robott commented on Jan 19, 2023

    @docker-robott
    Collaborator

    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

  3. locked and limited conversation to collaborators on Jan 19, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions