Similar to #1136.
I want to be able to say CMD [ "$CATALINA_HOME/bin/catalina.sh", "run"]
Have you tried this way?
CMD [ "${CATALINA_HOME}/bin/catalina.sh", "run"]
Yes. It doesn't work: docker run -P -i -t tomcat
gives me:
2014/04/30 17:52:12 exec: "${CATALINA_HOME}/bin/catalina.sh": stat ${CATALINA_HOME}/bin/catalina.sh: no such file or directory
I can confirm this. Using a Dockerfile with this
ENV MY_HOME /opt
CMD ["echo", "$MY_HOME"]
And it doesn't work on the build of the image. However, it work when you enter through /bin/bash (docker run [image] /bin/bash) and type:
echo $MY_HOME
Will print:
/opt
I have also tried:
CMD ["echo", "${MY_HOME}"]
CMD ["echo", "MY_HOME"]
CMD ["echo $MY_HOME"]
CMD ["echo ${MY_HOME}"]
With no luck.
I'll keep trying to work around this issue
Try CMD echo ${MY_HOME}
or CMD ["sh", "-c", "echo ${MY_HOME}"]
and you should have more luck.
The explanation is that the shell is responsible for expanding environment variables, not Docker. When you use the JSON syntax, you're explicitly requesting that your command bypass the shell and be execed directly.
Confirmed that the form CMD ["sh", "-c", "echo ${MY_HOME}"]
works as expected. I'm assuming the other form will as well.
Might be nice to add a note about this to the documentation.
And based on @sfitts logic, as CMD is passed to the ENTRYPOINT as an argument, the following is possible:
Dockerfile:
FROM ubuntu:16.04
env MY_HOME /opt
ADD start.sh /start.sh
ENTRYPOINT ["/start.sh"]
CMD ["echo", "${MY_HOME}"]
start.sh
#!/bin/bash
/bin/bash -l -c "$*"
I'd like this issue to be reopened.
The "answer" as provided above is merely a workaround, punting the expansion of ENV variables to the shell. I can immediately think of several scenarios in which this workaround is insufficient.
EDIT: Please see issue #34772, which I just created as a correlation for ARG directives. The use cases I mention there have possible overlap with the issues with ENV.
+1 to @dejayc
In case this may be useful for anyone, I wrote a small Go script to achieve this. Wrapping with shell script works but does not forward OS signals to the process.
+1 many of us are using the ENTRYPOINT ["docker-entrypoint.sh"] CMD ["something", "${VARIABLE"] pattern where this fails. The last line of docker-entrypoint.sh is typically exec $@
which will not expand variables. The current proposed work-around does not handle OS signal forwarding gracefully.
@akravetz I recall on DockerConf it was said multiple times avoid using docker-entrypoint.sh, they grow massively.
@holms thank you, this is good info. Is there a place where best practices like that are documented for those of us who don't attend DockerConf? It's a bit confusing considering numerous high profile projects on docker hub (memcached, postgres, redis, etc) use the docker-entrypoint.sh pattern.
@akravetz same for me actually :) Docs has some best practises: https://docs.docker.com/develop/develop-images/dockerfile_best-practices/
Also there's case studies: https://www.docker.com/products/resources/case-studies
Also success stories: https://success.docker.com
Also I'm reading a lot of Docker blog: https://blog.docker.com
Regarding entrypoint.sh I might be wrong but I clearly remember that some features appeared because of long entrypoint.sh, personally trying not to use them at all, because everything possible to do better most of the time, by using docker provided features.
Another workaround is to move the command into the script. And in there you'll get variable expansion.
ENV
var doesn't work using scratch
image, any idea how to fix it?
I've tried
FROM scratch
ENV CONFIG=config/dev.json
COPY --from=builder /config /config
COPY --from=builder /rush-rbac /rush-rbac
ENTRYPOINT [ "/rush-rbac","--config=${CONFIG}" ] # or
# CMD [ "/rush-rbac --config=${CONFIG}"]
@andho Yes. I tried it a couple weeks ago and the env vars are always available within the app. I've been trying to remember what I was getting stuck on and can't. It for sure would have been a 3rd party binary I was trying to build into a container, so maybe it was just doing something odd and I didn't notice.
I'm curious how the app ends up with access to the expanded env vars if the shell is responsible for expanding them. Is that a Go specific thing? When I tested it I noticed that if I use exec.Command(...).Run()
to run another Go binary it also gets access to the env vars.
@ryanjaeb The apps will have access to the environment variables in the environment it's run within. The shell is also an app, which is used to call other apps. So the apps called from within the shell also has access to env vars. But most apps take input/config through arguments instead of env vars, and that's where variable expansion is needed. Hope the explanation is clear.
Write the command without use the args array: ie CMD gunicorn --bind 0.0.0.0:$PORT wsgi:app
Just write this in your docker file.
This example runs a node js app.
ARG ENV
node server.js $ENV
Most helpful comment
Confirmed that the form
CMD ["sh", "-c", "echo ${MY_HOME}"]
works as expected. I'm assuming the other form will as well.Might be nice to add a note about this to the documentation.