Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Docker ENTRYPOINT with ENV variable and optional arguments

I have a Dockerfile with an ENTRYPOINT that uses an ENV variable. I can't get the ENTRYPOINT structured so the container can also accept additional command line arguments. Here is the relevant part of the Dockerfile:

ARG MODULE_NAME
ENV MODULE_NAME=$MODULE_NAME
ENTRYPOINT /usr/bin/python3 -m ${MODULE_NAME}

That works fine if I just want to launch the container without additional arguments:

docker run my-image

But I need to be able to pass additional command line arguments (e.g., a "--debug" flag) to the python process like this:

docker run my-image --debug

With the form of ENTRYPOINT above, the "--debug" arg is not passed to the python process. I've tried both the exec form and the shell form of ENTRYPOINT but can't get it to work with both the ENV variable and command line args. A few other forms I tried:

This runs but doesn't accept additional args:

ENTRYPOINT ["/bin/bash", "-c", "/usr/bin/python3 -m ${MODULE_NAME}"]

This gives "/usr/bin/python3: No module named ${MODULE_NAME}":

ENTRYPOINT ["/usr/bin/python3", "-m ${MODULE_NAME}"]

This gives "/usr/bin/python3: No module named ${MODULE_NAME}":

ENTRYPOINT ["/usr/bin/python3", "-m", "${MODULE_NAME}"]
like image 872
bogatron Avatar asked Mar 06 '18 14:03

bogatron


1 Answers

It appears it isn't possible to create an ENTRYPOINT that directly supports both variable expansion and additional command line arguments. While the shell form of ENTRYPOINT will expand ENV variables at run time, it does not accept additional (appended) arguments from the docker run command. While the exec form of ENTRYPOINT does support additional command line arguments, it does not create a shell environment by default so ENV variables are not expanded.

To get around this, bash can be called explicitly in the exec form to execute a script that then expands ENV variables and passes command line args to the python process. Here is an example Dockerfile that does this:

FROM ubuntu:16.04
ARG MODULE_NAME=foo
ENV MODULE_NAME=${MODULE_NAME}

RUN apt-get update -y && apt-get install -y python3.5

# Create the module to be run
RUN echo "import sys; print('Args are', sys.argv)" > /foo.py

# Create a script to pass command line args to python
RUN echo "/usr/bin/python3.5 -m $MODULE_NAME \$@" > /run_module.sh

ENTRYPOINT ["/bin/bash", "/run_module.sh"]

Output from the docker image:

$ docker run my-image
Args are ['/foo.py']

$ docker run my-image a b c
Args are ['/foo.py', 'a', 'b', 'c']

Note that variable expansion occurs during the RUN commands (since they are using shell form) so the contents of run_script.py in the image are:

/usr/bin/python3.5 -m foo $@

If the final RUN command is replaced with this:

    RUN echo "/usr/bin/python3.5 -m \$MODULE_NAME \$@" > /run_module.sh

then the run_script.sh would contain

/usr/bin/python3.5 -m $MODULE_NAME $@

But output from the running container would be the same since variable expansion will occur at run time. A potential benefit of the second version is that one could override the module to be run at run time without replacing the ENTRYPOINT.

like image 187
bogatron Avatar answered Oct 31 '22 00:10

bogatron