问题
In my docker-compose.yml, I defined two services, app
and db
.
version: "3.7"
services:
app:
image: my_app
container_name: my-app
ports:
- ${MY_PORT}:${MY_PORT}
env_file:
- ./app.env
...
depends_on:
- db
environment:
- DATABASE_URL=${DB_URL}
db:
image: my_db
container_name: my-db
env_file:
- ./db.env
ports:
- ${DB_PORT}:${DB_PORT}
As you can see above, I have defined two env files, app.env
and db.env
in the env_file
option of app
and db
services.
app.env:
MY_PORT=8081
db.env:
DB_PORT=4040
DB_URL=postgres://myapp:app@db:4040/myapp
I want to check if my docker-compose can successfully read the environment variables. So, I run the command docker-compose config
. However the output is
$ docker-compose config
WARNING: The MY_PORT variable is not set. Defaulting to a blank string.
WARNING: The DB_URL variable is not set. Defaulting to a blank string.
WARNING: The DB_PORT variable is not set. Defaulting to a blank string.
ERROR: The Compose file './docker-compose.yml' is invalid because:
services.app.ports is invalid: Invalid port ":", should be [[remote_ip:]remote_port[-remote_port]:]port[/protocol]
services.db.ports is invalid: Invalid port ":", should be [[remote_ip:]remote_port[-remote_port]:]port[/protocol]
Why my docker compose can't read environment variables from those env files I declared in the env_file
option in my docker-compose.yml?
Besides, I have another question, that's I understand that normally the env file shouldn't be version controlled since it could contain credentials. How normally should the env file be used for different environment e.g. development, staging and production environments? Imaging different environment has different values for those variables. Could someone please provide some examples?
回答1:
The reason this is failing, is that the environment variables that you are defining the the external named app.env
and db.env
files, and specifying in the env_file
option, are only being set inside the container that is started - and are not used for variable expansion inside the docker-compose.yml
file when parsed by docker-compose.
This is easily confused with the option of supplying a file named .env
in the same location as the docker-compose.yml
file. Since docker-compose will look for a file specifically named .env
next to the docker-compose.yml
file (or next to the file that you are specifying with the -f
switch) - and use the environment variables in that file for variable expansion in the docker-compose.yml
file, before parsing it.
In other words:
The env_file
option
- Will set environment variables inside your container, is is just a convenience feature that allows you to externalise the environment variables from the
docker-compose.yml
file - Environment variables in these files will NOT be used for variable expansion in the
docker-compose.yml
file before parsed by docker-compose.
The .env
file
- Will be used for environment variable expansion inside the
docker-compose.yml
file before parsing. - Will NOT set environment variables inside the started container.
Suggested solution to the first question
If you migrate your values into a single .env
file and place it in the same directory as your docker-compose.yml
file, this should work.
Second question
As I understand your second question, you are asking how the .env
file, or the env_file
option should be used to configure your services for your different environments.
I do not think that there is a simple and single answer to this. It can be solved in a number of ways. But it also depends on what you are deploying to? Is it kubernetes? Docker swarm? Or just a single node docker host?
Kubernetes and Docker swarm have different means of helping you out with this.
- Kubernetes secrets
- Docker swarm secrets
Those are highly secure solutions, where operators of the secrets can be limited, and the secrets will not be seen by developers or operators that do not have access.
But for the single node docker host, not operating in swarm mode (secrets only work in swarm mode), there really isn't a lot of fancy options. You will have to manage this pretty manually in your build and deploy pipes as far as I am aware.
You are right that the sensitive configuration of your services, should not go in the same repository as the service definition. Things like root password for a database, or credentials to your service discovery service for your production environment do not need to live next to the sources.
Traditionally, another repository would contain this - giving you the oppotunity to limit the group of people that have this access. The build/deployment server/service will check out the new revision of your service, build it perhaps, and then check out the configuration repository and start the services with the configurations from there. And, make sure to remove the configuration files afterwards.
That would be the solution I would recommend for a single node docker host deployment regime - two repositories, and some scripting that ensures that the correct .env file is put in place during deployment, and removed again.
I hope this is helpful?
来源:https://stackoverflow.com/questions/62518965/failed-to-read-environment-variables-from-the-file-declared-in-env-file