Why is argument empty in docker? - docker

When I built docker I have argument that is empty.
ARG ENV=prod
RUN echo ${ENV} // this works very good it show right
CMD /my-project -env ${ENV} this ENV is empty it show empty

ARG is for building your docker image. ENV is what you want for a running container.
CMD is executed when your container is run.
https://vsupalov.com/docker-arg-vs-env/
ENV ENV prod
Might suggest changing your name to something that isn't a Dockerfile keyword though.

Related

Pass ARGs in docker ENTRYPOINT

I'm running my app on Azure App Services, so I don't have access to docker run command. Now, I want to pass some variables into ENTRYPOINT for which I'm trying to use ARGs during build time itself. Here is how it looks,
docker build -t $IMAGE_NAME --build-arg env=dev --build-arg amplify_key=xxxxxxxxxxxxxx .
In my Dockerfile,
ARG env
ARG amplify_key
ENTRYPOINT ["/bin/bash", "-c", "init.sh $env $amplify_key"]
But this doesn't seem to be working. Please let me know the issue.
$variable references can be either expanded in the Dockerfile or by the shell when a command gets run. Only some Dockerfile commands perform variable expansions; for RUN, CMD, and ENTRYPOINT, it is only done by a shell. When a shell does the expansion it's not aware of Docker-specific ARGs, only environment variables, so you need to copy the argument to an ENV. There's an example of this in the Dockerfile documentation.
ARG env
ARG amplify_key
ENV env=$env amplify_key=$amplify_key
CMD init.sh $env $amplify_key
Assuming init.sh is your own script, though, once you have those values in environment variables, you can just access them directly, without passing them through positional parameters.
#!/bin/sh
echo "Running in $env environment"
curl -H "Authorization: Bearer $amplify_key" ...
ARG env
ARG amplify_key
ENV env=$env amplify_key=$amplify_key
CMD ["init.sh"]
This lets you do things like override the variable values at startup time more easily, and if you need to manually supply parameters to the command, the set of mandatory options is much smaller. If you're using the pattern of ENTRYPOINT doing some first-time setup and then running exec "$#" to run the CMD, this also works much better (ENTRYPOINT and sh -c have some tricky interactions).

How to pass arguments to a bash file in the docker ENTRYPOINT?

I've a dockerfile where I use a custom entrypoint.sh. In this file I want to use the ARGS which I pass from docker-compose to the dockerfile.
The problem is that I don't get the content of the variable to the dockerfile I just get the variable name.
For example:
ARGS ENVIROMENT=production
ENTRYPOINT ["/var/www/html/entrypoint.sh"]
CMD ["${ENVIROMENT}"]
entrypoint.sh
#!/bin/sh
cd /var/www/html
composer update
echo $1;
The echo $1 show "${Enviroment}" instead of "production" what I expect.
Ouch ! You've hit a sensible point of Docker with this question.
But first, let me clarify some point here :
First of all, you have a typo in your example. It's ARG not ARGS
ARG allows you to define a build-time variable. Meaning that this variable will only be usefull when doing a docker image build command. You'll then be able to override it with --build-arg. For example :
docker image build --build-arg ENVIROMENT=integration ...`
At the opposite, ENV allows you to define an environment variable which can be used during runtime.
You can find all the info you need in the official documentation for env and arg
Now, back to the point...
To make it simple:
Do not use both ENTRYPOINT and CMD when you want to pass some environment variable to your entrypoint from your cmd. It's just a pain. Really.
When you want to use a environment variable inside CMD, then you'll have to either use bash format, or to prefix the command with sh -c for exec format :
CMD ["sh", "-c", "echo ${GREETINGS}"]
#or
CMD echo ${GREETINGS}
Here is a Dockerfile that works with both syntax (just uncomment the CMD you want to use) :
FROM debian:8
ENV GREETINGS="hello world"
#CMD ["sh", "-c", "echo ${GREETINGS}"]
#CMD echo ${GREETINGS}
You can find more detailled info on those issues :
Issue 5509
Issue 34772
I would like to complete Marc abouchacra's answer.
What is still missing is how to use the ARG command.
A possible solution could be:
ARG ENVIRONMENT=production
ENV ENVIRONMENT=$ENVIRONMENT
CMD exec /var/www/html/entrypoint.sh $ENVIRONMENT
The exec is there to make sure your entrypoint.sh is the process with the PID=1.

Pass ARG to ENTRYPOINT

Say I have this in a Dockerfile:
ARG FOO=1
ENTRYPOINT ["docker.r2g", "run"]
where I build the above with:
docker build -t "$tag" --build-arg FOO="$(date +%s)" .
is there a way to do something like:
ENTRYPOINT ["docker.r2g", "run", ARG FOO] // something like this
I guess the argument could also be passed with docker run instead of during the docker build phase?
You could combine ARG and ENV in your Dockerfile, as I mention in "ARG or ENV, which one to use in this case?"
ARG FOO
ENV FOO=${FOO}
That way, you docker.r2g can access the ${FOO} environment variable.
I guess the argument could also be passed with docker run instead of during the docker build phase?
That is also possible, if it makes more sense to give FOO a value at runtime:
docker run -e FOO=$(...) ...
This simple technique works for me:
FROM node:9
# ...
ENTRYPOINT dkr2g run "$dkr2g_run_args"
then we launch the container with:
docker run \
-e dkr2g_run_args="$run_args" \
--name "$container_name" "$tag_name"
there might be some edge case issues with spreading an env variable into command line arguments, but should work for the most part.
ENTRYPOINT can work either like so:
ENTRYPOINT ["foo", "--bar", "$baz"] # $baz will not be interpreted
or like so:
ENTRYPOINT foo --bar $baz
not sure why the latter is not preferred - but env variable interpolation/interpretation is only possible using the latter. See: How do I use Docker environment variable in ENTRYPOINT array?
However, a more robust way of passing arguments is to use $# instead of an env variable. So what you should do then is override --entrypoint using the docker run command, like so:
docker run --entrypoint="foo" <tag> --bar $#
To learn the correct syntax of how to properly override entrypoint, you have to look that up, to be sure, but in general it's weird - you have to put --entrypoint="foo" before the tag name, and the arguments to --entrypoint, after the tag name. weird.
In my case I needed this to be set on build time, meaning I didn't have the control over the docker run command so I really struggled with it because it didn't work to use it as ARG or ENV directives in the Dockerfile. So below was is my solution and it worked like a charm:
ENTRYPOINT export $(grep -v '^#' .env | xargs -d '\n') \
&& your_command_passing_the_variable ${FOO}
Basically what I did was copy the variables into a file and then export the values in the same bash instance created by the ENTRYPOINT directive. The value is captured and passed correctly to the command. Hopefully, this helps.
Note: If you need to put secrets in that file, do not add the file to the version control system (e.g. git), instead create the file during your pipeline and be sure to clean up any sensitive information.

Dockerfile placeholders not replaced during build

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}

Can we pass ENV variables through cmd line while building a docker image through dockerfile?

I am working on a task that involves building a docker image with centOs as its base using a Dockerfile . One of the steps inside the dockerfile needs http_proxy and https_proxy ENV variables to be set in order to work behind the proxy.
As this Dockerfile will be used by multiple teams having different proxies, I want to avoid having to edit the Dockerfile for each team. Instead I am looking for a solution which allows me to pass ENV variables at build time, e.g.,
sudo docker build -e http_proxy=somevalue .
I'm not sure if there is already an option that provides this. Am I missing something?
Containers can be built using build arguments (in Docker 1.9+) which work like environment variables.
Here is the method:
FROM php:7.0-fpm
ARG APP_ENV=local
ENV APP_ENV=${APP_ENV}
RUN cd /usr/local/etc/php && ln -sf php.ini-${APP_ENV} php.ini
and then build a production container:
docker build --build-arg APP_ENV=prod .
For your particular problem:
FROM debian
ENV http_proxy=${http_proxy}
and then run:
docker build --build-arg http_proxy=10.11.24.31 .
Note that if you build your containers with docker-compose, you can specify these build-args in the docker-compose.yml file, but not on the command-line. However, you can use variable substitution in the docker-compose.yml file, which uses environment variables.
So I had to hunt this down by trial and error as many people explain that you can pass ARG -> ENV but it doesn't always work as it highly matters whether the ARG is defined before or after the FROM tag.
The below example should explain this clearly. My main problem originally was that all of my ARGS were defined prior to FROM which resulted all the ENV to be undefined always.
# ARGS PRIOR TO FROM TAG ARE AVAIL ONLY TO FROM for dynamic a FROM tag
ARG NODE_VERSION
FROM node:${NODE_VERSION}-alpine
# ARGS POST FROM can bond/link args to env to make the containers environment dynamic
ARG NPM_AUTH_TOKEN
ARG EMAIL
ARG NPM_REPO
ENV NPM_AUTH_TOKEN=${NPM_AUTH_TOKEN}
ENV EMAIL=${EMAIL}
ENV NPM_REPO=${NPM_REPO}
# for good measure, what do we really have
RUN echo NPM_AUTH_TOKEN: $NPM_AUTH_TOKEN && \
echo EMAIL: $EMAIL && \
echo NPM_REPO: $NPM_REPO && \
echo $HI_5
# remember to change HI_5 every build to break `docker build`'s cache if you want to debug the stdout
..... # rest of whatever you want RUN, CMD, ENTRYPOINT etc..
I faced the same situation.
According to Sin30's answer pretty solution is using shell,
CMD ["sh", "-c", "cd /usr/local/etc/php && ln -sf php.ini-$APP_ENV php.ini"]

Resources