10

How does ENTRYPOINT to a Docker container work exactly? I have a base docker image which has an ENTRYPOINT script and I am building another image on top of that which has one more ENTRYPOINT script.

When I run the image will both the ENTRYPOINT scripts run?

3 Answers 3

16

If the parent image contains a line:

ENTRYPOINT ["/entrypoint-parent.sh"]

and you want to add the following to your child image:

ENTRYPOINT ["/entrypoint-child.sh"]

Then the value of ENTRYPOINT in the resulting image is replaced with /entrypoint-child.sh, in other words, there is only a single value for ENTRYPOINT. Docker will only call a single process to start your container, though that process can spawn child processes. There are a couple techniques to extend entrypoints.

Option A: Call your entrypoint, and then run the parent entrypoint at the end, e.g. /entrypoint-child.sh could look like:

#!/bin/sh

echo Running child entrypoint initialization steps here
# ...

exec /entrypoint-parent.sh "$@"

The exec part is important, it replaces the current shell by the /entrypoint-parent.sh shell or process, which removes issues with signal handling. The result is you run the first bit of initialization in the child entrypoint, and then delegate to the original parent entrypoint. This does require that you keep track of the name of the parent entrypoint, would could change between versions of your base image.

Option B: Run the parent entrypoint in the background. This is less than ideal since you will no longer have error handling on the parent process unless you take some extra steps. At the simplest, this looks like the following in your /entrypoint-child.sh:

#!/bin/sh

# other initialization steps

/entrypoint-parent.sh "$@" &

# potentially wait for parent to be running by polling

# run something new in the foreground, that may depend on parent processes
exec /child-process.bin

Note, the "$@" notation I keep using is passing through the value of CMD as arguments to the parent entrypoint.

Option C: Switch to a tool like supervisord. I'm not a huge fan of this since it implies running multiple daemons inside your container, and you are usually best to split that into multiple containers. You need to decide what the proper response is when a single child process keeps failing.

Option D: Similar to Options A and B, I often create a directory of entrypoint scripts that can be extended at different levels of the image build. The entrypoint itself is unchanged, I just add new files into a directory that gets called sequentially based on the filename. In my scenarios, these scripts are all run in the foreground, and I exec the CMD at the end. You can see an example of this in my base image repo, in particular the entrypoint.d directory and bin/entrypointd.sh script which includes the section:

# ...

for ep in /etc/entrypoint.d/*; do
  ext="${ep##*.}"
  if [ "${ext}" = "env" -a -f "${ep}" ]; then
    # source files ending in ".env"
    echo "Sourcing: ${ep}"
    set -a && . "${ep}" && set +a
  elif [ "${ext}" = "sh" -a -x "${ep}" ]; then
    # run scripts ending in ".sh"
    echo "Running: ${ep}"
    "${ep}"
  fi
done

# ...

# run command with exec to pass control
echo "Running CMD: $@"
exec "$@"
4
  • 1
    Any idea why in my case "$@" isn't working (exited with code 0), but when I manually pass "mysqld" as parameter enstead of "$@" container starts just fine? CMD["mysqld"] after the ENTRYPOINT command doesn't help... Apr 23, 2021 at 2:45
  • @TechNomad please open a new question that includes details of your scenario.
    – BMitch
    Apr 23, 2021 at 12:02
  • Option A would be perfect, but I get an "/usr/local/bin/docker-entrypoint.sh: line 4: $1: unbound variable". I imagine that I should forward the arguments when executing the parent entrypoint Mar 10, 2022 at 17:13
  • I have hardcoded the variable when executing the parent process and it worked. I'd prefer I could just forward it, but this will work for me now: exec /usr/local/bin/docker-entrypoint.sh php-fpm "$@" (What I added was the php-fpm parameter) Mar 10, 2022 at 17:18
1

No, there is a single entry point, so your script will replace the one defined in the parent image. But your script can call(*) or borrow code from the script used by the parent image.

(*) Only if this the last step of course. Note that in a well-designed container, you should exec the last command of your script, so that this becomes the container's main process. If you fail to do so, signals sent to terminate the container gracefully (SIGINT/SIGTERM) will be sent to your script (which won't do anything with them) instead of being sent to the container "real" process. Thois will 1) make the container slow to stop and 2) will prevent graceful exit: docker stop will send a SIGTERM, and if the container doesn't terminate in a timely manner (10 seconds) it will use a SIGKILL. If you exec a script which itself exec's a command then the command will become the main process and everything will be fine, too.

0

As mentioned in previous answers:

  1. Your entrypoint spec will replace the previous entrypoint.
  2. If you write an entrypoint and call the original entrypoint you should use 'exec' to make sure that the original entrypoint runs as a seperate process, not as a function within your entrypoint.
  3. Pass original parameters to the original entrypoint: "#@"

A better solution might be, if the image spec is host on a git platform, to fork the git repository, modify the entrypoint as required, then build the image using the build from git feature in docker build from this new fork.

1
  • As it’s currently written, your answer is unclear. Please edit to add additional details that will help others understand how this addresses the question asked. You can find more information on how to write good answers in the help center.
    – Community Bot
    Mar 25, 2022 at 4:02

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .