How can I make my Docker compose "wait-for-it" script invoke the original container ENTRYPOINT or CMD?
Asked Answered
R

1

28

According to Controlling startup order in Compose, one can control the order in which Docker Compose starts containers by using a "wait-for-it" script. Script wait-for-it.sh expects both a host:port argument as well as the command that the script should execute when the port is available. The documentation recommends that Docker Compose invoke this script using the entrypoint: option. However, if one uses this option, the container will no longer run its default ENTRYPOINT or CMD because entrypoint: overrides the default.

How might one provide this default command to wait-for-it.sh so that the script can invoke the default ENTRYPOINT or CMD when the condition for which it waits is satisfied?

In my case, I've implemented a script wait-for-file.sh that polls waiting for a file to exist:

#!/bin/bash

set -e

waitFile="$1"
shift
cmd="$@"

until test -e $waitFile
do
  >&2 echo "Waiting for file [$waitFile]."
  sleep 1
done

>&2 echo "Found file [$waitFile]."
exec $cmd

Docker Compose invokes wait-for-file.sh as the entry-point to a slightly custom container derived from tomcat:8-jre8:

  platinum-oms:
    image: opes/platinum-oms
    ports:
      - "8080:8080"
    volumes_from:
      - liquibase
    links:
      - postgres:postgres
      - activemq:activemq
    depends_on:
      - liquibase
      - activemq
    entrypoint: /wait-for-file.sh /var/run/liquibase/done

Before it exits successfully, another custom container liquibase creates /var/run/liquibase/done and so platinum-oms effectively waits for container liquibase to complete.

Once container liquibase creates file /var/run/liquibase/done, wait-for-file.sh prints Found file [/var/run/liquibase/done]., but fails to invoke default command catalina.sh run in base container tomcat:8-jre8. Why?

Test Scenario

I created a simplified test scenario docker-compose-wait-for-file to demonstrate my problem. Container ubuntu-wait-for-file waits for container ubuntu-create-file to create file /wait/done and then I expect container ubuntu-wait-for-file to invoke the default ubuntu container command /bin/bash, but instead, it exits. Why doesn't it work as I expect?

Rashid answered 12/5, 2016 at 18:25 Comment(0)
B
12

However, if one uses this option, the container will no longer run its default ENTRYPOINT or CMD command because entrypoint: overrides the default.

That is expected, which is why the wait-for-it is presented as a wrapper script.
It does allow to execute a "subcommand" though:

wait-for-it.sh host:port [-s] [-t timeout] [-- command args]
                                               ^^^^^^^^^^^^

The subcommand will be executed regardless if the service is up or not.
If you wish to execute the subcommand only if the service is up, add the --strict argument.

That means the CMD part of your image can be used for your actual container command, as its parameters will passed in parameters to the ENTRYPOINT command:

entrypoint: wait-for-it.sh host:port --
cmd: mycmd myargs

This should work... except for docker-compose issue 3140 (mentioned by the OP Derek Mahar in the comments)

entrypoint defined in docker-compose.yml wipes out CMD defined in Dockerfile

That issue suggests (Jan. 2021)

If you have a custom image you can add a startscript to the build and call it inside the dockerfile and in the docker-compose you can call it again.
Thats a way to avoid duplicate for more complicated entrypoints.

Bastard answered 12/5, 2016 at 18:54 Comment(26)
From where did you copy the quote about the --strict argument?Rashid
Yes, but how could Docker Compose or wait-for-it determine and run the original ENTRYPOINT or CMD in the container? Effectively, I want wait-for-it to delegate to the default container command after the test succeeds. How can wait-for-it do this if the container hides this command? At least in my scenario, it's not very useful for wait-for-it to wait for a condition before allowing the container to continue if the script cannot run the original container command.Rashid
@DerekMahar It does not: you need an image which has its command only in CMD (that part will be passed automatically to the new entrypoint). The original entrypoint will be overridden. Which not a big deal if its was the defaut sh -c.Bastard
VonC, in that case, I think my custom wait-for-file.sh script must not be working. I'll post it in my question and wait for someone to tear it apart. (No wait-for-it pun intended.)Rashid
(For some reason, StackOverflow prevents me from entering @VonC into a comment.)Rashid
To help me troubleshoot this issue, I will run a Docker Compose scenario using wait-for-file.sh and two basic containers.Rashid
@DerekMahar a basic container is likely to have a default entrypoint sh -c: that can be overridden without problem by wait-for-file.sh. The CMD part of that image will be passed as parameter to wait-for-file.sh, which is what you want.Bastard
Does github.com/tianon/docker-brew-ubuntu-core/blob/… qualify? Project github.com/derekmahar/docker-compose-wait-for-file is a test scenario, but container ubuntu-wait-for-file doesn't invoke default command /bin/bash.Rashid
@DerekMahar 1/ Yes, it does qualifies: no entrypoint means default entrypoint, which can then safely be overridden. 2/ It depends on what ubuntu-wait-for-file is. The original script you mention (github.com/vishnubob/wait-for-it) is supposed to execute the commands passed as parameters to it. Try it with a CMD being echo test. Try it with commands wrapped in a sh -c 'my commands'. See in both instances if there are passed to and executed by the wait-for-it.sh script.Bastard
VonC, but absent any command argument, shouldn't wait-for-it (or wait-for-file) invoke the default command of the container?Rashid
Yes, it should. Your test dockerfile doesn't seem to have one though.Bastard
VonC, but image ubuntu, from which both of my container images derive, has default command github.com/tianon/docker-brew-ubuntu-core/blob/…. Shouldn't wait-for-file.sh invoke this command?Rashid
For your test, it is best to specify your own.Bastard
Okay, but that's not the scenario that I'm trying to represent. In my "real" case, my container, which has no default command, derives from tomcat:8-jre8 which has a default command catalina.sh run.Rashid
I agree, it should work. I would double-check the documentation around the exact syntax of entrypoint in docker-compose.yml.Bastard
If I append "echo You called?" to the entrypoint in docker-compose.yml it does print "You called?", but absent this command, container ubuntu-wait-for-file just exits.Rashid
Docker Compose documentation states that entrypoint overrides the default (see docs.docker.com/compose/compose-file/#entrypoint). However, I understand that a Dockerfile may effectively have at most one ENTRYPOINT and CMD entry. In the presence of ENTRYPOINT, CMD serves as arguments to ENTRYPOINT. Absent ENTRYPOINT, CMD behaves like ENTRYPOINT (see docs.docker.com/engine/reference/builder/#cmd and docs.docker.com/engine/reference/builder/#entrypoint).Rashid
So given these results, wait-for-it doesn't strike me as a very effective way for Docker Compose to control container startup order, or there is a bug in Docker Compose.Rashid
I'm guessing that under this scenario, derived containers don't correctly inherit the default CMD or ENTRYPOINT of the base container.Rashid
@DerekMahar Well spotted. I have included a reference to that issue in the answer for more visibility.Bastard
VonC, are you sure that this is how Docker Compose is supposed to work? Absent bug 3140, would wait-for-it even need the extra command parameter? After wait-for-it exits (or if it exits), couldn't Docker Compose just delegate directly to the default CMD in the container?Rashid
@DerekMahar Yes, I am sure. CMD is always passed to ENTRYPOINT. wait-for-it will execute the CMD found in the image.Bastard
VonC, I think you're probably right, but until Docker Compose fixes bug 3140, I can't prove it. Nevertheless, it makes sense that Docker Compose entrypoint should behave the same as Docker ENTRYPOINT.Rashid
@DerekMahar I agree. I will monitor issue 3140.Bastard
VonC, According to github.com/docker/compose/issues/3140#issuecomment-234267729, 3140 is actually a bug in the Docker Compose documentation. wait-for-it will not execute CMD in the image because Docker Engine clobbers the command which may be by design. This is certainly not the behaviour that I expected, though.Rashid
@DerekMahar Yes, github.com/docker/compose/pull/3764/files and github.com/docker/docker/pull/25012/files confirm this unfortunate design choice.Bastard

© 2022 - 2024 — McMap. All rights reserved.