Home > Software design >  Append argument to ENTRYPOINT in Docker run where some args are already defined
Append argument to ENTRYPOINT in Docker run where some args are already defined

Time:09-28

I'm using ENTRYPOINT to pass in an argument when running docker run but I cannot get the runtime argument to surface in my script as an argument.

Dockerfile

FROM debian:latest

ENV a="my arg in Dockerfile"

COPY . .
RUN chmod  x myscript.sh

ENTRYPOINT ["/bin/bash", "-c", "/myscript.sh ${a}"]

with myscript.sh

#!/bin/bash

echo "From script: $@"

When I run docker build -t my_image . then docker run -it --rm my_image I get the result as expected: From script: my arg in Dockerfile

But when I run docker run -it --rm my_image from_run I get the same result: From script: my arg in Dockerfile so the "from_run" is not being passed down to the script through ENTRYPOINT.

I read that arguments passed after the image name is appended to the ENTRYPOINT but clearly I'm not understanding something here.

Same result when using the exec form as opposed to JSON form:

ENTRYPOINT /myscript.sh ${a}

https://docs.docker.com/engine/reference/run/#entrypoint-default-command-to-execute-at-runtime

CodePudding user response:

Bash is Bash, see bash manual how -c pases arguments. The following:

/bin/bash -c "/myscript.sh ${a}" from_run

passes only one argument to myscript.sh and that is unquoted $a, so $a undergoes word splitting and filename expansion. And the argument from_run is assigned to $0. I would do:

ENTRYPOINT ["/bin/bash", "-c", "./myscript.sh \"$a\" \"$@\"", "--"]

Note that it's typical to use upper case (and unique names) for environment variables $a.

CodePudding user response:

The main container command is made up of two parts. The string you pass after the docker run image-name replaces the Dockerfile CMD, and it's appended to the Dockerfile ENTRYPOINT.

For your docker run command to work, you need to provide the command you want to run as ENTRYPOINT and its arguments as CMD. You do not need an environment variable here. However, it is important that both parts use JSON-array syntax and that neither invokes a shell. If ENTRYPOINT includes a shell then things get syntactically complex (see @KamilCuk's answer); if CMD includes a shell then it won't get invoked but the command will be invoked with /bin/sh and -c as parameters instead.

FROM debian:latest
COPY myscript.sh /usr/local/bin/myscript # preserves execute permissions
ENTRYPOINT ["myscript"]                  # in a $PATH directory
CMD ["my", "arg", "in", "Dockerfile"]
docker run --rm the-image
docker run --rm the-image my arg from command line

If you want the initial set of command-line arguments to be included and the docker run arguments to be appended, you can move them into the ENTRYPOINT line; note that the docker run --entrypoint is syntactically awkward if you ever do decide you need to remove some of the options.

ENTRYPOINT ["myscript", "--first-default", "--second-default"]
# CMD []
docker run --rm the-image
docker run --rm the-image --user-option
docker run --entrypoint myscript the-image --first-default --no-second-default

If you can update your application to accept options as environment variables in addition to command-line settings, this makes all of this syntactically easier.

ENV FIRST_DEFAULT=yes
ENV SECOND_DEFAULT=yes
CMD ["myscript"]
docker run --rm the-image
docker run --rm -e USER_OPTION=yes the-image
docker run --rm -e SECOND_DEFAULT=no the-image
  • Related