127

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?

Rob Bednark
  • 25,981
  • 23
  • 80
  • 125
Aniketh
  • 1,411
  • 3
  • 12
  • 15
  • 1
    what is the problem with passing those at run time? Something like `docker run -e http_proxy http://1.2.3.4:3128 -e https_proxy 1.2.3.4:3129`? The doc of `docker run` http://docs.docker.com/reference/commandline/run/ – user2915097 Jul 03 '15 at 05:30
  • 3
    The problem is that one of the steps inside docker file invovles yum installation and it fails if i dont set the http/https ENV variables and without proper installation i can't build the image .so **docker run** doesnt help me here . – Aniketh Jul 03 '15 at 06:11
  • I am afraid you will have to build specific images, the only difference being the values of http_proxy(s) ONBUILD may help, but I am afraid it is not suited here, see the doc https://docs.docker.com/reference/builder/ – user2915097 Jul 03 '15 at 06:15
  • This have been discussed here https://github.com/docker/docker/issues/4962 and again here https://github.com/docker/docker/pull/9176 and closed, so at the moment, it seems you have no solution – user2915097 Jul 03 '15 at 06:25
  • Thank you user2915097 for your comments .I have already gone through the above github links ,I asked this question with a tiny hope that someone on Stackoverflow might have faced this similar situation. – Aniketh Jul 03 '15 at 06:31
  • Please feel free to chime in at https://github.com/docker/docker/pull/9176 to add your requirements for something like this. – nwinkler Jul 06 '15 at 13:12
  • Does this answer your question? [Get environment variable value in Dockerfile](https://stackoverflow.com/questions/19537645/get-environment-variable-value-in-dockerfile) – Michael Freidgeim Nov 28 '20 at 21:26

4 Answers4

189

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.

Melroy van den Berg
  • 2,697
  • 28
  • 31
Sin30
  • 1,891
  • 1
  • 11
  • 5
  • 18
    Because I overlooked it: You need ARG to tell docker that a build argument can be passed to the builder. Without specifying ARG it doesn't work. – Markus Bruckner Feb 07 '17 at 08:37
  • 10
    This `ENV APP_ENV ${APP_ENV}` is not needed. It's enough to have `ARG APP_ENV` without `=local` and it will grab build argument and use it as any variable set by `ENV` – ElmoVanKielmo Oct 06 '17 at 11:29
  • 9
    @ElmoVanKielmo That's true during the build, but `ARG` isn't persisted as an environment variable when the docker image is ran. Using `ENV APP_ENV ${APP_ENV}` ensures that the environment variable is still available when the container is running. – DuckPuppy May 22 '18 at 22:16
  • @DuckPuppy true but I sticked to the OP's question – ElmoVanKielmo May 23 '18 at 06:10
  • @ElmoVanKielmo OP's question is about passing `ENV` from command-line, so how does having `ARG` alone help? You need `ARG` so that you can pass one via `--build-arg` and then you need `ENV` to copy it to an environment variable to be persisted with the image. – haridsv May 23 '18 at 07:44
  • @haridsv OP's question is about passing `http_proxy` and `https_proxy` urls at build time and providing ready to use Dokcer images for different teams using different proxies. Value passed via `ARG` would be stored in a proper configuration file in the image without the need to take it again from `ENV` on container creation. Normally you would use `ENV` for configuration which is intended to be set on container creation, and a combination of `ARG` and `ENV` for settings with default values which can be overriden on container creation. – ElmoVanKielmo May 24 '18 at 09:26
  • Values passed via `ARG` will not be available at the time of container creation. – haridsv May 24 '18 at 12:06
  • yes, yes, 1000 time yes. This was the exact answer i needed. I know it's pointed out in the other comments about, but YOU MUST SPECIFIC THE ARGUMENT IN THE DOCKERFILE. Don't forget that. – Chris Mar 05 '20 at 20:31
52

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..
Melroy van den Berg
  • 2,697
  • 28
  • 31
Nick
  • 1,174
  • 11
  • 20
  • 7
    WOW, dang, happened to me too! No one is speaking about this, nowhere in the docs a mention, warning etc! Thanks a lot!!! – chrizzler Mar 03 '20 at 10:24
  • Might I mention this was critical if your deployment environment is from automatic CI. IE I found this when I was trying to make gitlab CI to scale across project domains. IE One project might be settling one different node versions etc... – Nick Sep 17 '20 at 19:04
  • 1
    Saved me some nerves, thank you! I would never figured out that placement of ARGs matters.. – Nikita Zavyalov Jan 27 '21 at 19:17
  • 3
    I think this is actually explained [here](https://docs.docker.com/engine/reference/builder/#understand-how-arg-and-from-interact): `An ARG declared before a FROM is outside of a build stage, so it can’t be used in any instruction after a FROM` – andras Mar 23 '21 at 08:05
  • 1
    Thanks so much, what an annoying problem to track down, cheers – Peroxy Mar 03 '22 at 11:18
5

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"]
Tugrul
  • 1,760
  • 4
  • 24
  • 39
0

To set multiple build arguments like in your case for http_proxy and https_proxy you've to do the following changes:

1). Dockerfile

FROM centos:latest

# Define ARG after FROM to indicate values coming from build arguments are part of the build stage.
ARG http_proxy 
ARG https_proxy

# Create the environment variables and assign the values from the build arguments.
ENV http_proxy=$http_proxy \
    https_proxy=$https_proxy \

# Print the values.
RUN echo "http_proxy: $http_proxy"
RUN echo "https_proxy: $https_proxy"

2). Command to run

sudo docker build \
--build-arg http_proxy=http://172.0.0.1 \
--build-arg https_proxy=https://10.20.30.2 \
.
varad_s
  • 764
  • 1
  • 12
  • 24