No environment variable expansion or other processing is done on exec form CMD
(or ENTRYPOINT
or RUN
). Your application is getting invoked with literally the strings --spring.profiles.active=${profile}
and ${JAVA_OPTS}
, and you will see these including the ${...}
markers in your Java program's main()
function.
Docker's normal assumption here is that any expansion like this will be done in a shell, and shell form CMD
will wrap its string in /bin/sh -c '...'
so this happens. However, this setup isn't compatible with splitting ENTRYPOINT
and CMD
: due to the mechanics of how the two parts are combined neither part can be wrapped in a shell if you're using the "container as command" pattern where the CMD
is just an argument list.
The easiest way to handle this is to ignore ENTRYPOINT
entirely; put all of the command and arguments into CMD
; and use the shell form rather than the exec form.
ENV JAVA_OPTS="--XX:MinRAMPercentage=50.0 --XX:MaxRAMPercentage=80.0"
# no ENTRYPOINT; shell form of CMD
CMD java ${JAVA_OPTS} -jar /app/app.jar --spring.profiles.default=${profile}
If you docker run
a temporary debugging container on this image, it will see the environment variable but the command you provide will replace the image's CMD
.
docker run --rm your-image \
/bin/sh -c 'echo $JAVA_OPTS'
# prints the environment setting
Correspondingly if you run a separate java
, it won't see the options that are only provided in the image's CMD
. (Similarly try running java -XX:MaxRamPercentage=80.0
in one terminal window, and java -XX:+PrintFlagsFinal
with no other options in another window, and the second invocation won't see the JVM options from the first JVM; the same mechanics apply to Docker containers.)