Reputation: 2580
I don't really make sense of docker-compose's behavior with regards to environment variables files.
I've defined a few variables for an simple echo server setup with 2 flask application running.
In .env
:
FLASK_RUN_PORT=5000
WEB_1_PORT=80
WEB_2_PORT=8001
Then in docker-compose.yml
:
version: '3.8'
x-common-variables: &shared_envvars
FLASK_ENV: development
FLASK_APP: main.py
FLASK_RUN_HOST: 0.0.0.0
COMPOSE_PROJECT_NAME: DOCKER_ECHOES
x-volumes: &com_volumes
- .:/project # maps the current directory, e.g. project root that is gitted, to /proj in the container so we can live-reload
services:
web_1:
env_file: .env
build:
dockerfile: dockerfile_flask
context: .
ports:
- "${WEB_1_PORT}:${FLASK_RUN_PORT}" # flask runs on 5000 (default). docker-compose --env-file .env up loads whatever env vars specified & allows them to be used this way here.
volumes: *com_volumes
environment:
<<: *shared_envvars # DRY: defined common stuff in a shared section above, & use YAML merge language syntaxe to include that k-v mapping here. pretty neat.
FLASK_NAME: web_1
web_2:
env_file: .env
build:
dockerfile: dockerfile_flask
context: .
ports:
- "${WEB_2_PORT}:${FLASK_RUN_PORT}" # flask by default runs on 5000 so keep it on container, and :8001 on host
volumes: *com_volumes
environment:
<<: *shared_envvars
FLASK_NAME: web_2
If I run docker-compose up
with the above, everything works as expected.
However, if I simply change the name of the file .env
for, say, flask.env
, and then accordingly change both env_file: .env
to env_file: flask.env
, then I get:
(venv) [fv@fv-hpz420workstation flask_echo_docker]$ docker-compose up
WARNING: The WEB_1_PORT variable is not set. Defaulting to a blank string.
WARNING: The FLASK_RUN_PORT variable is not set. Defaulting to a blank string.
WARNING: The WEB_2_PORT variable is not set. Defaulting to a blank string.
ERROR: The Compose file './docker-compose.yml' is invalid because:
So obviously the envvars defined in the file were not loaded in that case. I know that according to the documentation, the section environement:
, which I am using, overrides what is loaded in the env_file:
. But those aren't the same variables. And at any rate, if that was the issue, it shouldn't work either with the first way, right?
What's wrong with the above?
Upvotes: 4
Views: 5849
Reputation: 2580
Actually, the env_file
is loaded AFTER the images have been built. We can verify this. With the code I have posted above, I can see that env_file.env
has not been loaded at build time, because of the error message that I get (telling me WEB_PORT_1
is not set etc.).
But this could simply be that the file is never loaded. To rule that out, we build the image (say by providing the missing arguments with docker-compose build -e (...)
, then we can verify that it is indeed loaded (by logging its value in the flask application in my case, or a simple print to screen etc.).
This means the the content of env_file
is available to the running container, but not before (such as when building the image).
If those variables are to be used within the docker-compose.yml
file at BUILD time this file MUST be named .env
(unless there is a way to provide a name other than the default, but if so I haven't found any). This is why changing env_file: flask.env
to env_file: .env
SEEMED to make it work - but the real reason why it worked then was because my ports were specified in a .env
with the default name that docker-compose parses anyways. It didn't care that I specified it in docker-compose.yml
file or not.
To summarize - TL;DR
.env
. No further actions needed, other than ensure this file is in the same directory as the docker-compose.yml
. You can't change the default name .env
foo.env
and then specify env_file:foo.env
.environment: [vars]
, if just hard-coding them in the docker-compose.yml
is acceptable.. According to doc (not tested) those will override any variables also defined by the env_file
Upvotes: 19