Compose: Environment variables are not applied on container build

Created on 10 Aug 2015  路  16Comments  路  Source: docker/compose

When building container, environment variables are not applied.

docker-compose.yml:

img:
    build: img
    environment:
        VAR: Hello

/img/Dockerfile:

FROM python:2.7
RUN python -c 'import os; print os.environ["VAR"]'

Expected to have "Hello" written, received KeyError: VAR - missing environment variable.

If you get into container with docker-compose run --rm img bash (after removing that last failing line) and do python -c 'import os; print os.environ["VAR"]' you will get expected result.

docker-compose==1.3.3

docker-version:

Client version: 1.7.1
Client API version: 1.19
Go version (client): go1.4.2
Git commit (client): 786b29d
OS/Arch (client): linux/amd64
Server version: 1.7.1
Server API version: 1.19
Go version (server): go1.4.2
Git commit (server): 786b29d
OS/Arch (server): linux/amd64
kinquestion

Most helpful comment

the answer to this stack overflow question helped https://stackoverflow.com/questions/19537645/get-environment-variable-value-in-dockerfile

it is possible to map the .env environment variables to ARGS to be used by the Dockerfile during build.

docker-compose.yml

version: "2"
services:

  lumen:
    build:
      context: .
      dockerfile: ./Dockerfile
      args:
        - PORT=${PORT}
    volumes:
       ...

Dockerfile

FROM php:7.0-apache
ARG PORT

ENV PORT "$PORT"

EXPOSE ${PORT}
...

All 16 comments

This is expected. The environment: key in the docker-compose.yml is the same as specifying it to the docker run command to start the container. build and dockerfile are the old keys used for building the image.

This is maybe not obvious from the documentation and could be improved.

Docker doesn't support injecting environment into the build environment (it must be part of the Dockerfile), but I believe there are some open proposals to add support for something like that.

Just a reference for anyone who find this issue, here is docker discussion regarding build-time variables: https://github.com/docker/docker/issues/14634 and corresponding PR: https://github.com/docker/docker/pull/15182

This bit us hard, really needs better docs.

The documentation is really confusing, e.g. talks about env-file, which is used for docker-compose.yml and is used for docker run. Given that docker-compose is an orchestration tool for building and running containers, it is easy to assume that environment would apply to build time, using --env <key>=<value> or something like this.

Bit me as well.
Just to leave a note that environment variables can be set as build args in the compose file. Like others on this thread, I was initially expecting env_file or environment to be used by both build and run.
Verified with compose file v2, docker-compose v1.7, docker-engine v1.11 .

Note that if you need to include env vars from a file, you can do the following. This will require (in the docker-compose build section) args set from these variables, which you can then refer to in your docker file. This means that while you can't directly reuse your env_file, you can do so with a little extra work.

env $(cat vars.env | xargs) docker-compose up --build <whatever>

the answer to this stack overflow question helped https://stackoverflow.com/questions/19537645/get-environment-variable-value-in-dockerfile

it is possible to map the .env environment variables to ARGS to be used by the Dockerfile during build.

docker-compose.yml

version: "2"
services:

  lumen:
    build:
      context: .
      dockerfile: ./Dockerfile
      args:
        - PORT=${PORT}
    volumes:
       ...

Dockerfile

FROM php:7.0-apache
ARG PORT

ENV PORT "$PORT"

EXPOSE ${PORT}
...

@williamli Can you add a link to the Stack Overflow question?

Sorry guys - I am not sure I understand how to resolve this - and I would like to use a pre-built image.

For example, my compose file is:

version: '3'

services:
web1:
image: softwaremaker/web-w
environment:

  • wtmsdemo_customerapi01=http://api1/api/values
    ports:
  • "89:80"
    depends_on:
  • api1
    api:
    image: softwaremaker/api-w
    networks:
    default:
    external:

name: nat

I used to think that the api image (softwaremaker/api-w) will be able to resolve into the environment variables I had set up above but it doesnt work.

@PatrLind
added stackoverflow link to my original comment.

https://stackoverflow.com/questions/19537645/get-environment-variable-value-in-dockerfile

The issue is still relevant for env files other than default .env file.
F.e. Next code will not work:

  nginx:
    env_file:
      - .env
      - .env.local
    environment:
     - SERVER_NAME=${SERVER_NAME}
    build:
      context: ./nginx
      dockerfile: Dockerfile
      args:
        server_name: ${SERVER_NAME}

while SERVER_NAME is defined in second env file (.env.local).
I see no options to pass env vars from .env.local to build context ((

@remort
I can confirm this as well, if I have variables being used during build they are only passed to the build process if the the file is called .env if they are named .env.docker they don't get picked up. Even when the env_file is specified to use the .env.docker file.

My solution for this during my build copying the other named env file and renaming it to .env

COPY .env.docker ${APP_HOME}/.env
WORKDIR $APP_HOME

After this it appeared to pickup the environment variables when the container runs

Operating System: macOS (10.14.6)
Docker Desktop Version: 2.1.0.5 (40693)
Engine Version: 19.03.5
Compose: 1.24.1

Hi guys,

A quick question for all of you, will this be a better way to build an image for dev? It works fine so far. However, is this the recommended practice? All images are based on buster.

```
FROM redis:buster as redis
RUN mkdir /env && env > /env/.env_redis
RUN cat /etc/passwd
RUN ls -lah /home
FROM ruby:slim-buster AS ruby
RUN mkdir /env && env > /env/.env_ruby

FROM node:lts-buster-slim AS node
RUN mkdir /env && env > /env/.env_node

build nginx

FROM nginx:latest AS nginx
RUN mkdir /env && env > /env/.env_nginx

build php

FROM php:fpm-buster AS php

FROM php:7.3.14-fpm-buster AS php

RUN mkdir /env && env > /env/.env_php
COPY --from=redis / /
COPY --from=ruby / /
COPY --from=node / /
COPY --from=nginx / /

ADD conf/include-site.conf /etc/nginx/conf.d/include-site.conf
ADD conf/supervisord.conf /etc/supervisord.conf

RUN su root
EXPOSE 80 443
WORKDIR "/var/www/html"

ENTRYPOINT ["/bin/bash", "/start.sh"]

Problem is still exists.
env_file key in build section will be more clear than passing env vars through args to container build.
Like this:

#NOT_WORKING
build:
      context: ./client
      dockerfile: Dockerfile
      env_file: ${CURRENT_ENV_FILE}

Because i am using shell scripts to build and up docker compose.
For production i need different env_file than for dev/local.
And there are many docker-compose.env.yml files with many args so it's not convinient as i think

I think there needs to be some elegant way around this. I really like the docker syntax and using arguments instead of environment variables doesn't make sense to me. I would not want want someone to manually change my docker-compose files. Changing values in the .env files appears consistent to me.

Was this page helpful?
0 / 5 - 0 ratings