Build the docker image with environment variables - docker

so the objective is to have a different image for prod and testing so there are certain variables change accordingly so I need to set env variables during the build.
# Dockerfile
ENV Somename: $value
...
docker build --build-arg Somename=value -t test .
docker run -d -p port:port test
this work flow is not taking the env variables

First you need to consume the build-arg inside you dockerfile using the ARG command.
FROM alpine
# consume the build arg
ARG somename
# persist the env variable in the built image
ENV somename=$somename
# somename will appear as an env variable
RUN echo $somename
RUN env
And running the build command docker build --build-arg somename=hello . will show you an env variable somename=hello

your syntax is not correct, do not put
:
it is either
ENV somename somevalue
or
ENV somename=somevalue
Check the doc
https://docs.docker.com/engine/reference/builder/#env

Related

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' .

Why can't I load environment variables in dockerfile? [duplicate]

I'm building a container for a ruby app. My app's configuration is contained within environment variables (loaded inside the app with dotenv).
One of those configuration variables is the public ip of the app, which is used internally to make links.
I need to add a dnsmasq entry pointing this ip to 127.0.0.1 inside the container, so it can fetch the app's links as if it were not containerized.
I'm therefore trying to set an ENV in my Dockerfile which would pass an environment variable to the container.
I tried a few things.
ENV REQUEST_DOMAIN $REQUEST_DOMAIN
ENV REQUEST_DOMAIN `REQUEST_DOMAIN`
Everything passes the "REQUEST_DOMAIN" string instead of the value of the environment variable though.
Is there a way to pass environment variables values from the host machine to the container?
You should use the ARG directive in your Dockerfile which is meant for this purpose.
The ARG instruction defines a variable that users can pass at build-time to the builder with the docker build command using the --build-arg <varname>=<value> flag.
So your Dockerfile will have this line:
ARG request_domain
or if you'd prefer a default value:
ARG request_domain=127.0.0.1
Now you can reference this variable inside your Dockerfile:
ENV request_domain=$request_domain
then you will build your container like so:
$ docker build --build-arg request_domain=mydomain Dockerfile
Note 1: Your image will not build if you have referenced an ARG in your Dockerfile but excluded it in --build-arg.
Note 2: If a user specifies a build argument that was not defined in the Dockerfile, the build outputs a warning:
[Warning] One or more build-args [foo] were not consumed.
So you can do:
cat Dockerfile | envsubst | docker build -t my-target -
Then have a Dockerfile with something like:
ENV MY_ENV_VAR $MY_ENV_VAR
I guess there might be a problem with some special characters, but this works for most cases at least.
This is for those looking to pass env variable from docker-compose using .env file to dockerfile during build and then pass those args as env variable to container.
Typical docker-compose file
services:
web:
build:
context: ./api
dockerfile: Dockerfile
args:
- SECRET_KEY=$SECRET_KEY
- DATABASE_URL=$DATABASE_URL
- AWS_ACCESS_KEY_ID=$AWS_ACCESS_KEY_ID
Pass the env variable present in .env file to args in build command.
Typical .env file
SECRET_KEY=blahblah
DATABASE_URL=dburl
Now when you run docker-compose up -d command, docker-compose file takes values from .env file then pass it to docker-compose file. Now Dockerfile of web containes all those varibales through args during build. Now typical dockerfile of web,
FROM python:3.6-alpine
ARG SECRET_KEY
ARG DATABASE_URL
ARG AWS_ACCESS_KEY_ID
ARG AWS_SECRET_ACCESS_KEY
ARG AWS_BUCKET
ARG AWS_REGION
ARG CLOUDFRONT_DOMAIN
ENV CELERY_BROKER_URL redis://redis:6379/0
ENV CELERY_RESULT_BACKEND redis://redis:6379/0
ENV C_FORCE_ROOT true
ENV SECRET_KEY ${SECRET_KEY?secretkeynotset}
ENV DATABASE_URL ${DATABASE_URL?envdberror}
Now we recieved those secret_key and db url as arg in dokcerfile. Now let's use those in ENV as ENV SECRET_KEY ${SECRET_KEY?secretkeynotset}. Now even docker container has those variables in it's environment.
Remember not to use ARG $SECRET_KEY(which I did). It should be ARG SECRET_KEY
An alternative using envsubst without losing the ability to use commands like COPY or ADD, and without using intermediate files would be to use Bash's Process Substitution:
docker build -f <(envsubst < Dockerfile) -t my-target .
Load environment variables from a file you create at runtime.
export MYVAR="my_var_outside"
cat > build/env.sh <<EOF
MYVAR=${MYVAR}
EOF
... then in the Dockerfile
ADD build /build
RUN /build/test.sh
where test.sh loads MYVAR from env.sh
#!/bin/bash
. /build/env.sh
echo $MYVAR > /tmp/testfile
If you just want to find and replace all environment variables ($ExampleEnvVar) in a Dockerfile then build it this would work:
envsubst < /path/to/Dockerfile | docker build -t myDockerImage . -f -
When using build-arg...
docker build --build-arg CODE_VERSION=1.2 Dockerfile
...consider that the variable is not availabe after FROM:
ARG CODE_VERSION=latest
FROM base:${CODE_VERSION}
An ARG declared before a FROM is outside of a build stage, so it can’t be used in any instruction after a FROM.
Generally ARGs should be placed after FROM if not required during FROM:
FROM base:xy
ARG ABC=123
To use the default value of an ARG declared before the first FROM use an ARG instruction without a value inside of a build stage:
ARG VERSION=latest
FROM busybox:$VERSION
ARG VERSION
RUN echo $VERSION > image_version
https://docs.docker.com/engine/reference/builder/#understand-how-arg-and-from-interact
add -e key for passing environment variables to container.
example:
$ MYSQLHOSTIP=$(sudo docker inspect -format="{{ .NetworkSettings.IPAddress }}" $MYSQL_CONRAINER_ID)
$ sudo docker run -e DBIP=$MYSQLHOSTIP -i -t myimage /bin/bash
root#87f235949a13:/# echo $DBIP
172.17.0.2

Dockerfile: pass argument to RUN npm run build

I have a dockerfile with these lines:
ARG ENVIRONMENT
ENV ENVIRONMENT $ENVIRONMENT
RUN npm run ng build --configuration=${ENVIRONMENT}
I cant get the "RUN npm run ng build --configuration= to pass the value of $ENVIRONMENT to the npm command.
What is the syntax for this?
Per the Dockerfile ARG docs,
The ARG instruction defines a variable that users can pass at build-time to the builder with the docker build command using the --build-arg = flag.
in order to accept an argument as part of the build, we use --build-arg.
Dockerfile ENV docs:
The ENV instruction sets the environment variable to the value .
We also need to include an ENV statement because the CMD will be executed after the build is complete, and the ARG will not be available.
FROM busybox
ARG ENVIRONMENT
ENV ENVIRONMENT $ENVIRONMENT
CMD echo $ENVIRONMENT
will cause an environment variable to be set in the image, so that it is available during a docker run command.
docker build -t test --build-arg ENVIRONMENT=awesome_environment .
docker run -it test
This will echo awesome_environment.
Try changing your RUN command do this:
RUN npm run ng build --configuration=$ENVIRONMENT
This should work. Check here
Thanks.

Dockerfile and environnement variables

I have a strange behavior with my Dockerfile. I try to make it write file with text coming from environment varibales :
FROM ubuntu:14.04
ENV KEY ''
ENV VAL ''
RUN echo "${KEY}:${VAL}" > /etc/test
CMD []
I built this image and run it like this :
docker run -it --rm -e KEY=aaa -e VAL=bbb mytest
If I display the /etc/test file, it is empty (it is present, but empty). It seems that when it creates the file, environment variables are not set.
Any idea?
Thank you
The command in the docker file RUN echo "${KEY}:${VAL}" > /etc/test is executed when you build the image using docker build ...
Thus this is logical, since at that point the env variables are empty.
You need to move the commad to the CMD command which will run when the image is started.
You can define KEY and VALUE as arguments and set their values when you're building the docker image.
FROM ubuntu:14.04
ARG KEY
ARG VAL
RUN echo "${KEY}:${VAL}" > /etc/test
CMD []
Then you can build the image using like this:
docker build --build-arg KEY=<value> --build-arg VAL=<value> .
https://docs.docker.com/engine/reference/builder/#using-arg-variables

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