Dockerfile placeholders not replaced during build - docker

Using Docker for Windows, Community version 17.06.0-ce-win19 (12801), Windows 10
Dockerfile
FROM frolvlad/alpine-oraclejdk8:slim
ARG APP_NAME=client-default
RUN mkdir -p /client/
ADD build/libs/$APP_NAME.jar /client/$APP_NAME.jar
ENTRYPOINT ["java", "-jar", "/client/$APP_NAME.jar"]
Running
docker build --build-arg APP_NAME=client-1 -t test/client-1 .
Placeholders not replaced after build (tried ${APP_NAME}, %APP_NAME%)

ARG and ENV are not replaced by Docker in an ENTRYPOINT or a CMD when you use the EXEC form inside []. If the ENTRYPOINT or CMD use the shell form (string, not an array) the shell will be able to do the variable substitution for you.
ARG and ENV variables will be available in RUN commands in the container as environment variables.
Docker will also replace $VARIABLES in the Dockerfile in the following instructions:
ADD
COPY
ENV
EXPOSE
FROM
LABEL
STOPSIGNAL
USER
VOLUME
WORKDIR
Only ENV variables will become available in a CMD or ENTRYPOINT, only in the environment of the running container:
Using ARG
FROM frolvlad/alpine-oraclejdk8:slim
ARG APP_NAME=client-default
ENV APP_NAME=$APP_NAME
RUN mkdir -p /client/
ADD build/libs/$APP_NAME.jar /client/$APP_NAME.jar
ENTRYPOINT ["sh", "-c", "java -jar /client/$APP_NAME.jar"]
or with only ENV
FROM frolvlad/alpine-oraclejdk8:slim
ENV APP_NAME=client-default
RUN mkdir -p /client/
ADD build/libs/$APP_NAME.jar /client/$APP_NAME.jar
ENTRYPOINT ["sh", "-c", "java -jar /client/$APP_NAME.jar"]

Environment variables in Dockerfile are declared with the ENV statement.
In your case:
FROM frolvlad/alpine-oraclejdk8:slim
ENV APP_NAME client-default
RUN mkdir -p /client/
ADD build/libs/${APP_NAME}.jar /client/${APP_NAME}.jar
ENTRYPOINT ["java", "-jar", "/client/${APP_NAME}.jar"]

ARG is only available during the build of a Docker image (RUN etc), not after the image is created and containers are started from it (ENTRYPOINT OR CMD)
ARG variable doesn't get substituted in Dockerfile. ARG IS really an environment variable. During the build, docker "runs" the container using ARG variables as environment variables. Easy to prove (you can test it): Try RUN printenv on your Dockerfile and you'll see the ARG as environment variable
So, you've got two problems:
First:
The Steps in console DOESN'T substitute the ARG variable. So, your jar is really in the container, your line:
ADD build/libs/$APP_NAME.jar /client/$APP_NAME.jar
it's working. Try it.
Second:
Entrypoint is for the running container, not for the image, so you need to put your ARG into an ENV variable, and not to use the exec form. If your use the exec form of ENTRYPOINT does not invoke a command shell. This means that normal shell processing does not happen. If you want shell processing then either use the shell form or execute a shell directly, for example:
ENTRYPOINT cat ${APP_NAME_RUN}
So, try this working example:
FROM ubuntu
ARG APP_NAME=client
RUN mkdir -p /client/
ADD ./$APP_NAME.txt /client/$APP_NAME.txt
ENV APP_NAME_RUN="/client/${APP_NAME}.txt"
RUN echo $APP_NAME_RUN
ENTRYPOINT cat ${APP_NAME_RUN}

Related

How use ENV variables in Dockerfile ENTRYPOINT command

I'm brand new user of Docker...
I'm tring use Enviroments variables on my Dockerfile...
It's like that:
FROM openjdk:11-jdk-slim-buster
ENV JAVA_APP my-app
EXPOSE 8080
COPY target/$JAVA_APP-*.jar /app/$JAVA_APP.jar
CMD java -jar /app/$JAVA_APP.jar
The result is that: the COPY command gets the value of JAVA_APP variable. But the CMD command doesn't.
Is there some another way to use ENV variables?
If I make this super simple Dockerfile
FROM ubuntu
ENV JAVA_APP my-app
CMD echo $JAVA_APP
and build and run it with
docker build -t test .
docker run --rm test
docker run --rm -e JAVA_APP=Hello test
It prints 'my-app' and 'Hello'. So it does work. If it still doesn't work for you, can you expand your post with the command you use to run the container?

env variables not substituted in docker file

FROM alpine:3.11
COPY out/ /bin/
CMD ["command", "--flag1", "${HOST}", "--flag2", "${PORT}", "--flag3", "${AUTH_TOKEN}"]
This is the docker file used. I am loading the env variables during run through an env file.
But the variables are not substituted when running the command. If I override the CMD and exec into the container I am able to see the envs though.
What am I missing here?
You are running CMD in exec mode. Switch to shell mode and it will work out. As for the environment variables to be present you need a shell. more reading
your example:
CMD command --flag1 ${HOST} --flag2 ${PORT} --flag3 ${AUTH_TOKEN}
Full generic example:
Dockerfile:
FROM debian:stretch-slim
CMD echo ${env}
Run:
docker build .
docker run --rm -e env=hi <image id from build step>
hi

How to access build args in ENTRYPOINT dockerfile

I am trying to deploy an app in payara micro based on payara dockerimage and I need to pass one arguement snapshotversion in ENTRYPOINT(basically i want to access the build args in ENTRYFORM) exec form, as exec form of ENTRYPOINT is preferred: my docker file is as follows:
FROM payara/micro:5.193.1
ARG snapshotversion
ENV snapshotvs=$snapshotversion
RUN jar xf payara-micro.jar
COPY /service/war/target/app-emailverification-service-war-${snapshotversion}.war ${DEPLOY_DIR}/
COPY ojdbc6.jar ${PAYARA_HOME}/
COPY --chown=payara domain.xml /opt/payara/MICRO-INF/domain/domain.xml
RUN cd /opt/payara/MICRO-INF/domain && ls -lrt
#ENTRYPOINT ["java", "-jar", "/opt/payara/payara-micro.jar", "--deploy", "/opt/payara/deployments/app-service-war-$snapshotvs.war", "--domainConfig", "/opt/payara/MICRO-INF/domain/domain.xml","--addLibs", "/opt/payara/ojdbc6.jar"]
ENTRYPOINT java -jar /opt/payara/payara-micro.jar --deploy /opt/payara/deployments/app-service-war-$snapshotvs.war --domainConfig /opt/payara/MICRO-INF/domain/domain.xml --addLibs /opt/payara/ojdbc6.jar
The commented ENTRYPOINT does not work. Container logs says invalid deployment. What am i missing here? Also how can I use CMD with this. Can someone post an example.
The commented line doesn't work, because it is an exec form of ENTRYPOINT, which doesn't invoke shell (/bin/sh -c), so variable substitution doesn't happening.
If you want to use an exec form and environment variables you need to specify it directly:
ENTRYPOINT ["sh", "-c", "your command with env variable"]
To your question about how can you use CMD with this, for example like this:
ENTRYPOINT ["sh", "-c"]
CMD ["your command with env variable"]
You mentioned, that you want to use build args in ENTRYPOINT instruction. It's not really possible, because nor ARG nor ENV are expanded in ENTRYPOINT or CMD: https://docs.docker.com/engine/reference/builder/#environment-replacement, https://docs.docker.com/engine/reference/builder/#scope
Also you could take a look at great page with best practices for writing Dockerfile and ENTRYPOINT instructions specifically.
Two suggestions that complement each other:
If you're COPYing a file into the image, you can give it a fixed name inside the image. That avoids this problem.
WORKDIR /opt/payara
COPY service/war/target/app-emailverification-service-war-${snapshotversion}.war deployments/app-service.war
If you have a particularly long or involved command that you're trying to make be the main container process, wrap it in a shell script. You want to make sure to exec the main container process to avoid some trouble around signal handling (resulting in docker stop pausing for 10 seconds and then hard-killing your actual process).
#!/bin/sh
exec java \
-jar /opt/payara/payara-micro.jar \
--deploy /opt/payara/deployments/app-service.war \
--domainConfig /opt/payara/MICRO-INF/domain/domain.xml \
--addLibs /opt/payara/ojdbc6.jar
COPY launch.sh ./
RUN chmod +x launch.sh
CMD ["/opt/payara/launch.sh"]
In this second case, it's a shell script, so you can have ordinary shell variable substitutions.

Docker ENV in CMD

I am trying to do the following:
Pass a build arg to my docker build command
Store that as an env variable in my container
Use it in my CMD to start when my container launches.
Below is my setup:
FROM ubuntu:xenial
ARG EXECUTABLE
ENV EXECUTABLE ${EXECUTABLE}
CMD ["/opt/foo/bin/${EXECUTABLE}", "-bar"]
Here is how i'm building container
docker build --build-arg EXECUTABLE=$EXECUTABLE -t test_image .
Here is how i'm running image
docker run -d test_image
When I run the container it crashes and tells me
docker: Error response from daemon: OCI runtime create failed:
container_linux.go:296: starting container process caused
"exec: \"/opt/foo/bin/${EXECUTABLE}\": stat /opt/foo/bin/${EXECUTABLE}:
no such file or directory": unknown.
To use environment variables, you need to use shell.
https://docs.docker.com/engine/reference/builder/#cmd
Note: Unlike the shell form, the exec form does not invoke a command
shell. This means that normal shell processing does not happen. For
example, CMD [ "echo", "$HOME" ] will not do variable substitution on
$HOME. If you want shell processing then either use the shell form or
execute a shell directly, for example: CMD [ "sh", "-c", "echo $HOME"
]. When using the exec form and executing a shell directly, as in the
case for the shell form, it is the shell that is doing the environment
variable expansion, not docker.
Based on this, I think you can work fine by the following Dockerfile.
FROM ubuntu:xenial
ARG EXECUTABLE
ENV EXECUTABLE ${EXECUTABLE}
CMD [ "sh", "-c", "/opt/foo/bin/${EXECUTABLE}", "-bar"]
You'll have to write out an executable or shim as ARG / ENV substitution is not supported for CMD.
The list of supported substitutions:
ADD
COPY
ENV
EXPOSE
FROM
LABEL
STOPSIGNAL
USER
VOLUME
WORKDIR
as well as:
ONBUILD (when combined with one of the supported instructions above)
A workaround is to write your executable to a file and execute that:
FROM ubuntu:xenial
ARG EXECUTABLE
RUN : \
&& /bin/echo -e "#!/bin/sh\nexec '/bin/$EXECUTABLE' -bar" > /exe \
&& chmod +x /exe
CMD ["/exe"]
Build:
docker build -t test --build-arg EXECUTABLE=echo .
Run:
$ docker run -ti test
-bar
Another way to access the environment variable passed is by running it as:
docker run -e EXECUTABLE=<some_value> <docker_image>
Then, in the dockerfile
CMD exec /opt/foo/bin/${EXECUTABLE} -bar

ENTRYPOINT and CMD with build arguments

This doesn't work:
FROM alpine:3.7
# build argument with default value
ARG PING_HOST=localhost
# environment variable with same value
ENV PING_HOST=${PING_HOST}
# act as executable
ENTRYPOINT ["/bin/ping"]
# default command
CMD ["${PING_HOST}"]
It should be possible to build an image with build-arg and to start a container with an environment variable to override cmd as well.
docker build -t ping-image .
docker run -it --rm ping-image
Error: ping: bad address '${PING_HOST}'
UPDATE:
FROM alpine:3.7
# build argument with default value
ARG PING_HOST=localhost
# environment variable with same value
ENV PING_HOST ${PING_HOST}
COPY ./entrypoint.sh /usr/local/bin/
# act as executable
ENTRYPOINT ["/usr/local/bin/entrypoint.sh"]
# default command
CMD $PING_HOST
entrypoint.sh
#!/bin/sh
/bin/ping $PING_HOST
This works because the entrypoint.sh enables variable substitution as expected.
For CMD to expand variables, you need to arrange for a shell because shell is responsible for expanding environment variables, not Docker. You can do that like this:
ENTRYPOINT ["/bin/sh"]
CMD ["-c" , "ping ${PING_HOST}"]
OR
CMD ["sh", "-c", "ping ${PING_HOST}"]

Resources