问题
I find it quite common that I have multiple environments (for example test and prod) but the Docker containers that I wish to start are the same in both environments. The only difference is the application configuration which I want to specify using an env-file. Since I have multiple containers and dependencies between them I want to use docker-compose. But afaik I can only specify an env-file inside the docker-compose.yml file (see docs). If this is the case then I need to clone my original docker-compose.yml to two different files (one for test and one for prod) just to point to different env files. This means that I have to maintain two docker-compose.yml files instead of one and if I make any changes I need to update both files.
Is this really according to design? Why won't docker-compose let me specify --env-file when I do docker-compose up or docker-compose run?
回答1:
See Update #2 below. This is now possible!
This is a much requested feature of Docker Compose. Unfortunately, the answer at the moment is that you can't. I'd recommend subscribing to these GitHub issues to get a better idea when and if this feature gets implemented:
- https://github.com/docker/compose/issues/495
- https://github.com/docker/compose/pull/76
- https://github.com/docker/compose/pull/845
Issue #495 is actually the most commented in their issue repository at the moment. You are definitely not alone in wanting to do this.
Update:
The latest issue tracking is at https://github.com/docker/compose/issues/1377.
Update #2:
This functionality has been merged and is available as of Docker Compose 1.5.0. See https://github.com/docker/compose/blob/129092b7/docs/yml.md#variable-substitution for usage information.
回答2:
It isn't a direct inclusion from the command line, but if you need a work-around before the #1765 merge (the fix for #1377) makes it into a release, you can use the extends directive along with the env_file directive. For convenience, the files from the simple examples below are reproduced in this repository.
Stupid simple example
base.yml
base:
image: busybox
command: bash -c 'echo "${WHO:-Simon} says, \"${SHOUTOUT:-Silence is golden.}\""'
one.env
WHO=Da Schwartz
SHOUTOUT=Get to...
one_glue.yml
one:
extends:
file: base.yml
service: base
env_file:
- one.env
two.env
WHO=Da Schwartz
SHOUTOUT=...da choppa!
two_glue.yml
two:
extends:
file: base.yml
service: base
env_file:
- two.env
Use
% for i in base one_glue two_glue ; do docker-compose --file "${i}.yml" up ; done
Recreating dockercomposeextendsenv_base_1...
Attaching to dockercomposeextendsenv_base_1
base_1 | Simon says, "Silence is golden."
dockercomposeextendsenv_base_1 exited with code 0
Gracefully stopping... (press Ctrl+C again to force)
Recreating dockercomposeextendsenv_one_1...
Attaching to dockercomposeextendsenv_one_1
one_1 | Da Schwartz says, "Get to..."
dockercomposeextendsenv_one_1 exited with code 0
Gracefully stopping... (press Ctrl+C again to force)
Recreating dockercomposeextendsenv_two_1...
Attaching to dockercomposeextendsenv_two_1
two_1 | Da Schwartz says, "...da choppa!"
dockercomposeextendsenv_two_1 exited with code 0
Gracefully stopping... (press Ctrl+C again to force)
Even simplerer example
The above works if you benefit from using .env files. If you aren't so limited, you could keep the environment variable settings in the environment-specific "glue" .yml files:
red_glue.yml
red:
extends:
file: base.yml
service: base
environment:
- WHO=Stallion
- SHOUTOUT=I am...
blue_glue.yml
blue:
extends:
file: base.yml
service: base
environment:
- WHO=Stallion
- SHOUTOUT=...the law!
Use
% for i in red_glue blue_glue ; do docker-compose --file "${i}.yml" up ; done
Creating dockercomposeextendsenv_red_1...
Attaching to dockercomposeextendsenv_red_1
red_1 | Stallion says, "I am..."
dockercomposeextendsenv_red_1 exited with code 0
Gracefully stopping... (press Ctrl+C again to force)
Creating dockercomposeextendsenv_blue_1...
Attaching to dockercomposeextendsenv_blue_1
blue_1 | Stallion says, "...the law!"
dockercomposeextendsenv_blue_1 exited with code 0
Gracefully stopping... (press Ctrl+C again to force)
A little more complicated
For what it's worth, the approach described in this answer allows for different .env files on a per-instance basis, rather than per-invocation/environment. (I'm not sure how beneficial this is in practice, however.) In other words, you could do something like this:
testing.yml
# Only instance1 and instance2 are needed for testing
instance1:
extends:
file: base.yml
service: base
env_file:
- test.env # environment-specific
- instance1_test.env # instance-specific
instance2:
extends:
file: base.yml
service: base
env_file:
- test.env
- instance2_test.env
production.yml
# All four instances are used for production
instance1:
extends:
file: base.yml
service: base
env_file:
- prod.env # environment-specific
- instance1_prod.env # instance-specific
instance2:
extends:
file: base.yml
service: base
env_file:
- prod.env
- instance2_prod.env
instance3:
extends:
file: base.yml
service: base
env_file:
- prod.env
- instance3_prod.env
instance4:
extends:
file: base.yml
service: base
env_file:
- prod.env
- instance4_prod.env
You can start to see that extends is pretty powerful, much more so than what the #1765 merge allows for.
回答3:
Nice clear examples, however this did not initially work for me until I updated the base.yml to call the ash shell.
base.yml
base:
image: busybox
command: ash -c 'echo "${WHO:-Simon} says, \"${SHOUTOUT:-Silence is golden.}\""'
来源:https://stackoverflow.com/questions/29062522/different-env-file-but-same-yml-with-docker-compose