dockerdockerfiledocker-run

Variable passed by 'docker run' to CMD of Dockerfile is not resolved


Can anyone explain why is the environment variable passed by

docker run --rm -it -e APP_PORT=80 -p 8080:80 my_container <image-id> 

to CMD in Dockerfile is not resolved in following cases:

...
ARG APP_PORT
ENV APP_PORT=${APP_PORT}
...
CMD ['gunicorn', "-b", "0.0.0.0:${APP_PORT}", "main:app"]  # DOES NOT WORK!
CMD ['gunicorn', "-b", "0.0.0.0:$APP_PORT", "main:app"]    # DOES NOT WORK!

CMD ["sh", "-c", "echo 0.0.0.0:$APP_PORT"]                 # WORKS!

CMD gunicorn -b 0.0.0.0:$APP_PORT main:app                 # WORKS!

DOES NOT WORK! means I get the error: Container log - Error: '$APP_PORT' is not a valid port number.


Solution

  • There are 2 forms of the CMD statement, like you show.

    One is the exec form, which is the one that doesn't work. It's usually preferred because it doesn't start a shell first to run the command, so it uses a little less resources.

    The other is the shell form, which is the one that works. The reason that it works is that you need a shell to replace environment variables in a command. The shell form starts up a shell, that then executes your command.

    As you've seen in your echo example, you can also make the exec form work by running the shell manually.

    You can read more about the 2 forms here: https://docs.docker.com/engine/reference/builder/#cmd

    In short, the examples that don't work, don't work because there's no shell to insert the value of the environment variable in the command.