Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does variables substitution not work when using multiple env_files in docker-compose.yml?

Tags:

I'm trying to get a docker-compose file working with multiple .env files, and I'm not having any luck. I'm trying to setup three .env files:

  • global settings that are the same across all container instances
  • environment-specific settings (stuff just for test or dev)
  • local settings - overridable things that a developer might need to change in case they have conflicts with, say, a port number

My docker-compose.yml file looks like this:

version: '2'
services:
  db:
    env_file:
      - ./.env
      - ./.env.${ENV}
      - ./.env.local
    image: postgres
    ports:
      - ${POSTGRES_PORT}:5432

.env looks like this:

POSTGRES_USER=myapp

and the .env.development looks like this:

POSTGRES_PASSWORD=supersecretpassword
POSTGRES_HOST=localhost
POSTGRES_PORT=25432
POSTGRES_DB=myapp_development

.env.local doesn't exist in this case.

After running ENV=development docker-compose up, I receive the following output:

$ ENV=development docker-compose up
WARNING: The POSTGRES_PASSWORD variable is not set. Defaulting to a blank string.
WARNING: The POSTGRES_DB variable is not set. Defaulting to a blank string.
WARNING: The POSTGRES_PORT variable is not set. Defaulting to a blank string.
ERROR: The Compose file './docker-compose.yml' is invalid because:
services.db.ports is invalid: Invalid port ":5432", should be [[remote_ip:]remote_port[-remote_port]:]port[/protocol]

From that error message, it looks like none of my environment variables are being used. I just upgraded to the newest available docker-compose as well - same errors:

$ docker-compose --version
docker-compose version 1.8.0-rc1, build 9bf6bc6

Any ideas here? Would be nice to have a single docker-compose.yml that would work across multiple environments.

like image 462
matt Avatar asked Jun 20 '16 15:06

matt


People also ask

Can you use variables in Docker compose file?

Docker Compose allows us to pass environment variables in via command line or to define them in our shell. However, it's best to keep these values inside the actual Compose file and out of the command line.

Does Docker compose override environment variables?

But docker-compose does not stop at the . env and the host's current environment variables. It's cool that you can simply override values of your . env file, but this flexibility is can also be the source of nasty bugs.

How do I pass environment variables to Docker containers?

With a Command Line Argument The command used to launch Docker containers, docker run , accepts ENV variables as arguments. Simply run it with the -e flag, shorthand for --env , and pass in the key=value pair: sudo docker run -e POSTGRES_USER='postgres' -e POSTGRES_PASSWORD='password' ...

Can I have multiple Docker compose files?

Using Multiple Docker Compose Files Use multiple Docker Compose files when you want to change your app for different environments (e.g., dev, staging, and production) or when you want to run admin tasks against a Compose application.

What is the difference between docker compose yml file and env_file?

The .env file in the CWD defines default environment variables available to compose, including COMPOSE_FILE, while the env_file list is used to define environment variables for the container. You are right, you don't need to specify .env as an env_file in a docker compose yml file.

How do I use multiple environment variables in Docker Compose?

If you have multiple environment variables, you can substitute them by providing a path to your environment variables file. By default, the docker-compose command will look for a file named .env in the project directory (parent folder of your Compose file).

Where value for a variable used in Docker-Compose YAML can be defined?

There are couple of location where value for a variable used in docker-compose.yaml can be defined e.g. shell, dockerfile, environment file, compose file but we will keep things simple and straight to understand main concepts.

Is it possible to create an ENV file with Docker stack deploy?

The .env file feature only works when you use the docker-compose up command and does not work with docker stack deploy. Both $VARIABLE and $ {VARIABLE} syntax are supported.


2 Answers

In order to apply different/multiple env_files depending on the running environment, such as development/staging/production, I think a better way for docker-compose is to use multiple docker-compose yml files.

For example:

1. Start with a base file that defines the canonical configuration for the services.

docker-compose.yml

web:
  image: example/my_web_app:latest
  env_file:
    - .env

2. Add the override file for development, as its name implies, can contain configuration overrides for existing services or entirely new services.

docker-compose.override.yml

web:
  build: .
  volumes:
    - '.:/code'
  ports:
    - 8883:80
  env_file:
    - .env.dev

When you run docker-compose up it reads the overrides automatically.

3. Create another override file for the production environment.

docker-compose.prod.yml

web:
  ports:
    - 80:80
  env_file:
    - .env.prod

To deploy with this production Compose file you can run

docker-compose -f docker-compose.yml -f docker-compose.prod.yml up

Note

My Docker version:

$ docker -v
Docker version 18.06.1-ce, build e68fc7a

$ docker-compose -v
docker-compose version 1.22.0, build f46880fe

Reference: https://docs.docker.com/compose/extends/

like image 164
Yuci Avatar answered Sep 30 '22 03:09

Yuci


Keep in mind that there are 2 different environments where you are defining variables. The host machine where you are executing the docker-compose command, and the container itself (running the db service in your case).

Your docker-compose.yml file has access to your host's environment variables. Hence ENV is reachable from the docker-compose command, but not these in your .env files.

On the contrary, the value for ENV is not reachable inside the container, but all variables defined in your .env files will.

I don't know if you really need your db container to access the variables defined on your .env.development. But at least seem that your host machine needs to have the content of that file, so when the docker-compose command is called, the POSTGRES_PORT variable is defined.

To fix your specific problem you would need to define the environment variables on your host machine too, not only for the container. You could do something like this:

#Set for host
ENV=development

#Also sets the variables on the host 
source ./.env.$ENV

#POSTGRES_PORT defined in .env.development is used here
docker-compose up

#since env_file also contains .env.development, the variables will be reachable from the container.

Hope that helps.

like image 40
Rogelio Tonatihu Rodriguez Rod Avatar answered Sep 30 '22 04:09

Rogelio Tonatihu Rodriguez Rod