Docker file set arguments from environment variables - docker

I want to just print HOMEPATH variable from my machine:
This is my Dockerfile:
FROM python:3.8-slim
ARG some_path=$HOMEPATH
RUN echo "this is some_path: $some_path"
but receiving empty string, during image creation - docker build -t test_image . :
What I am doing wrong ?

Docker doesn't expose the builder to this sort of security risk. The build environment could have sensitive data in environment variables that they do not want exposed when the build arbitrary docker images. To inject a variables during build, you must explicitly pass it on the build command line with:
docker build --build-arg "some_path=$HOMEPATH" -t test_image .
Note that the path on the build server is typically not something you would want to inject in a build. The same build should work regardless of where you perform the build.

Related

Pass Linux enviromental varibles into a dockerfile

I have a docker image that needs some credentials passed from the host-environment. How do I pass Linux environmental variables into dockerfile. No flags attachment only dockerfile.
When I build the Docker Image it fetches packages from a local repo that needs authentication. This is all automated and the credentials depend on the host machine that is running.
I have tried to google it and only found how to pass hard-coded varibles. But I need e.g.
export VAR=[PASSWORD]
to be passed into the dockerfile.
ENV PASSWORD = $VAR
You should use ARG with the ENV in your Dockerfile:
ARG name
ENV env_name $name
When you build your image, pass the arg from your local environment
docker build -t my_image --build-arg name=$MY_LOCAL_ENV_VAR .

Overwriting of environment variables in Dockerfile with passed by `--build-arg`

I am building two docker images, one is a base docker image, and another is a custom image.
The custom image is build from base image, but I want to assign different environment variables in the image.
For example, I prepare following Dockerfiles for these two images.
For base image:
# base.Dockerfile
FROM ubuntu
ARG MY_ENV
ENV MY_ENV=${MY_ENV}
# RUNs to install basic tools
# ...
For custom image
# base.Dockerfile
FROM my_base_image
ARG MY_ENV
ENV MY_ENV=${MY_ENV}
ENV IMAGE='This container is from a custom image'
# RUNs to setup custom images
# ...
Then build and run like follows.
# build a base image
docker build --file 'base.Dockerfile' \
--build-arg MY_ENV='my_value_in_base' \
--tag 'my_base_image' .
# build a custom image
docker build --file 'custom.Dockerfile' \
--build-arg MY_ENV='my_value_in_custom' \
--tag 'my_custom_image' .
I expected that in
I expected that 'my_value_in_custom' is stored in MY_ENV in my_custom_image, but 'my_value_in_base' is stored.
$ docker run my_custom_image env
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
HOSTNAME=9fd195c99739
MY_ENV=my_value_in_base
IMAGE=This container is from custom image
HOME=/root
How can I overwrite MY_ENV when I build the custom image?
docker run -e MY_ENV='my_value_in_custom' changes the environment variables in the container, but this is not what I am looking for as I want to change the environment variables in the custom image.
I suspect it's not possible to replace environment variables in the specific way you suggest.
The documentation on Dockerfile ARG notes:
Environment variables defined using the ENV instruction always override an ARG instruction of the same name.
You're probably in this case. In the second Dockerfile, an environment variable $MY_ENV is defined (from the base image), and so even though there's an ARG without an ENV before it in this Dockerfile, the extant environment variable still takes precedence.
In practice you may not need to set this variables in a Dockerfile at all. You can also specify environment variable values when you run a container, and this is a more appropriate way to specify many values (related host names, credentials). The `docker run -e' invocation at the end of your question does this, and for a user-provided setting, I'd frequently expect that to be correct.
If you really need to override the environment variable in the derived image, and the value really needs to be build-time configurable, then you need to give the ARG a different name.
FROM my_base_image
ARG CUSTOM_MY_ENV
ENV MY_ENV=${CUSTOM_MY_ENV}
docker build --file 'custom.Dockerfile' \
--build-arg CUSTOM_MY_ENV='my_value_in_custom' \
--tag 'my_custom_image' .

How to read environment variable during build time when using baseimage-docker from phusion

I build my docker image using based on phusion/baseimage
The command I run to build my image is:
docker build --build-arg ENV_FILE=.env -t demo:latest .
my .env file looks like this:
VAR1=foo
VAR2=bar
and my dockerfile is like this
FROM phusion/baseimage:jammy-1.0.1
ARG VAR1
# I would like to print VAR1
RUN echo "my var1 equals to : $VAR1"
However I can't get VAR1 printed, it just shows an empty value
....
---> Running in 8f78bb5d59cc
my var1 equals to :
Any idea how I can read it when building the image?
You can do
(source .env; docker build --build-arg VAR1=$VAR1 -t demo:latest .)
You have to specify each variable though. I don't think there's a way to pass them all in as build arguments. .env files are meant for use at run-time.

Docker build time arguments

I have a bunch of Dockerfiles that are build from a common automated place using the same build command:
docker build -t $name:$tag --build-arg BRANCH=$branch .
Some of the Dockerfiles contain this:
ARG BRANCH=master
And that argument is used for some steps of the image build.
But for some Dockerfiles which doesn't need that argument I get this error at the end:
One or more build-args [BRANCH] were not consumed, failing build.
How can I overcome this problem without including the argument to all the Dockerfiles?
Have you considered grepping your Dockerfile for BRANCH and using it result to decide if you should supply your ARG or not?
You could replace your automation build trigger with something like:
if grep BRANCH Dockerfile; then docker build -t $name:$tag --build-arg BRANCH=$branch .; else docker build -t $name:$tag . ; fi
I don't see any documented way to avoid this error without changing your input or your Dockerfile. robertobado already covers changing your input. As a second option, you can include an effectively unused build arg at the end of your Dockerfile which would have a very minor impact on your build.
ARG BRANCH=undefined
RUN echo "Built from branch ${BRANCH}"
Since this doesn't modify the filesystem, I believe the image checksum will be identical.

Create dynamic environment variables at build time in Docker

My specific use case is that I want to organize some data about the EC2 instance a container is running on and make i available as an environment variable. I'd like to do this when the container is built.
I was hoping to be able to do something like ENV VAR_NAME $(./script/that/gets/var) in my Dockerfile, but unsurprisingly that does not work (you just get the string $(./script...).
I should mention that I know the docker run --env... will do this, but I specifically want it to be built into the container.
Am I missing something obvious? Is this even possible?
Docker v1.9 or newer
If you are using Docker v1.9 or newer, this is possible via support for build time arguments. Arguments are declared in the Dockerfile by using the ARG statement.
ARG REQUIRED_ARGUMENT
ARG OPTIONAL_ARGUMENT=default_value
When you later actually build your image using docker build you can pass arguments via the flag --build-arg as described in the docker docs.
$ docker build --build-arg REQUIRED_ARGUMENT=this-is-required .
Please note that it is not recommended to use build-time variables for passwords or secrets such as keys or credentials.
Furthermore, build-time variables may have great impact on caching. Therefore the Dockerfile should be constructed with great care to be able to utilize caching as much as possible and therein speed up the building process.
Edit: the "docker newer than v1.9"-part was added after input from leedm777:s answer.
Docker before v1.9
If you are using a Docker-version before 1.9, the ARG/--build-arg approach was not possible. You couldn't resolve this kind of info during the build so you had to pass them as parameters to the docker run command.
Docker images are to be consistent over time whereas containers can be tweaked and considered as "throw away processes".
More info about ENV
A docker discussion about dynamic builds
The old solution to this problem was to use templating. This is not a neat solution but was one of very few viable options at the time. (Inspiration from this discussion).
save all your dynamic data in a json or yaml file
create a docker file "template" where the dynamic can later be expanded
write a script that creates a Dockerfile from the config data using some templating library that you are familiar with
Docker 1.9 has added support for build time arguments.
In your Dockerfile, you add an ARG statement, which has a similar syntax to ENV.
ARG FOO_REQUIRED
ARG BAR_OPTIONAL=something
At build time, you can pass pass a --build-arg argument to set the argument for that build. Any ARG that was not given a default value in the Dockerfile must be specified.
$ docker build --build-arg FOO_REQUIRED=best-foo-ever .
To build ENV VAR_NAME $(./script/that/gets/var) into the container, create a dynamic Dockerfile at build time:
$ docker build -t awesome -f Dockerfile .
$ # get VAR_NAME value:
$ VAR_VALUE=`docker run --rm awesome \
bash -c 'echo $(./script/that/gets/var)'`
$ # use dynamic Dockerfile:
$ {
echo "FROM awesome"
echo "ENV VAR_NAME $VAR_VALUE"
} | docker build -t awesome -
https://github.com/42ua/docker-autobuild/blob/master/emscripten-sdk/README.md#build-docker-image

Resources