compose
compose copied to clipboard
[BUG] Environment variables not loaded from the 2nd env_file in the command shell
Description
It appears that environment variables are not loaded from the 2nd env_file
, during the execution of a shell in command
. Only the variables from the 1st env_file
are loaded. On the other hand, after the container is up, execing into the container shows also the variables loaded from the 2nd env_file
.
Steps To Reproduce
-
Run
docker compose up
, with the followingdocker-compose.yml
services: test: image: nginx:stable-bullseye env_file: - .env - .env.1 command: bash -c 'printenv TEST && echo $TEST'
the following
.env
TEST=0
and
.env.1
fileTEST=1
This produces the following, unexpected output. I believe the 2nd output line should also be
1
, since the.env.1
is expected to "win" https://github.com/docker/docs/pull/3822test-1 | 1 test-1 | 0
Note that
printenv
shows the expected value, but echo does not. -
Despite this behavior, the config suggest the environment should contain
TEST=1
as expecteddocker compose --env-file .env --env-file .env.1 config name: test services: test: command: - bash - -c - printenv TEST && echo 1 environment: TEST: "1" image: nginx:stable-bullseye networks: default: null networks: default: name: test_default
-
Run the container in detached mode, then exec and echo the variable
cat docker-compose.yml | sed 's/command: .*/command: bash -c "sleep infinity"/' | docker compose -f - up -d docker compose exec test bash -c 'echo $TEST'
Output is
1
as expected. -
Note that the problem seems to be specific to docker compose, docker itself behaves as expected
docker run --rm --name test --env-file .env --env-file .env.1 nginx:stable-bullseye bash -c 'printenv TEST && echo $TEST'
Output
1 1
Compose Version
Docker Compose version v2.21.0
Docker Compose version v2.21.0
Docker Environment
Client:
Context: default
Debug Mode: false
Plugins:
app: Docker App (Docker Inc., v0.9.1-beta3)
buildx: Docker Buildx (Docker Inc., v0.9.1-docker)
compose: Docker Compose (Docker Inc., v2.21.0)
scan: Docker Scan (Docker Inc., v0.23.0)
Server:
Containers: 18
Running: 0
Paused: 0
Stopped: 18
Images: 219
Server Version: 24.0.7
Storage Driver: overlay2
Backing Filesystem: extfs
Supports d_type: true
Using metacopy: false
Native Overlay Diff: true
userxattr: false
Logging Driver: json-file
Cgroup Driver: cgroupfs
Cgroup Version: 1
Plugins:
Volume: local
Network: bridge host ipvlan macvlan null overlay
Log: awslogs fluentd gcplogs gelf journald json-file local logentries splunk syslog
Swarm: inactive
Runtimes: io.containerd.runc.v2 runc
Default Runtime: runc
Init Binary: docker-init
containerd version: 3dd1e886e55dd695541fdcd67420c2888645a495
runc version: v1.1.10-0-g18a0cb0
init version: de40ad0
Security Options:
apparmor
seccomp
Profile: builtin
Kernel Version: 5.15.0-91-generic
Operating System: Ubuntu 20.04.6 LTS
OSType: linux
Architecture: x86_64
CPUs: 4
Total Memory: 31.2GiB
Name: test
ID: XXXX:XXXX:XXXX:XXXX:XXXX:XXXX:XXXX:XXXX:XXXX:XXXX:XXXX:XXXX
Docker Root Dir: /var/lib/docker
Debug Mode: false
Username: test
Registry: https://index.docker.io/v1/
Labels:
Experimental: false
Insecure Registries:
127.0.0.0/8
Live Restore Enabled: false
Anything else?
Tested also with
Docker Compose version v2.23.3
and
Client:
Version: 24.0.7-rd
Context: rancher-desktop
Debug Mode: false
Plugins:
buildx: Docker Buildx (Docker Inc.)
Version: v0.12.0
Path: /Users/test/.docker/cli-plugins/docker-buildx
compose: Docker Compose (Docker Inc.)
Version: v2.23.3
Path: /Users/test/.docker/cli-plugins/docker-compose
Server:
Containers: 4
Running: 0
Paused: 0
Stopped: 4
Images: 37
Server Version: 23.0.6
Storage Driver: overlay2
Backing Filesystem: extfs
Supports d_type: true
Using metacopy: false
Native Overlay Diff: true
userxattr: false
Logging Driver: json-file
Cgroup Driver: cgroupfs
Cgroup Version: 1
Plugins:
Volume: local
Network: bridge host ipvlan macvlan null overlay
Log: awslogs fluentd gcplogs gelf journald json-file local logentries splunk syslog
Swarm: inactive
Runtimes: io.containerd.runc.v2 runc
Default Runtime: runc
Init Binary: docker-init
containerd version: 0cae528dd6cb557f7201036e9f43420650207b58
runc version: 860f061b76bb4fc671f0f9e900f7d80ff93d4eb7
init version:
Security Options:
seccomp
Profile: builtin
Kernel Version: 6.1.64-0-virt
Operating System: Alpine Linux v3.18
OSType: linux
Architecture: aarch64
CPUs: 4
Total Memory: 7.749GiB
Name: lima-rancher-desktop
ID: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
Docker Root Dir: /var/lib/docker
Debug Mode: false
Experimental: false
Insecure Registries:
127.0.0.0/8
Live Restore Enabled: false
Tested with latest codebase, and I get the expected result:
Attaching to test-1
test-1 | 1
test-1 | 1
test-1 exited with code 0
Can you please upgrade to latest release ?
The latest vesion I have access to today is
docker compose version
Docker Compose version v2.24.1
and it still has the issue.
@marcindulak https://github.com/docker/compose/releases/tag/v2.24.2
Still no improvement (it's on Ubuntu 20.04)
docker compose version
Docker Compose version v2.24.2
docker compose up
[+] Running 2/2
✔ Network tmp_default Created 0.1s
✔ Container tmp-test-1 Created 0.1s
Attaching to test-1
test-1 | 1
test-1 | 0
test-1 exited with code 0
docker info
Client: Docker Engine - Community
Version: 25.0.0
Context: default
Debug Mode: false
Plugins:
buildx: Docker Buildx (Docker Inc.)
Version: v0.12.1
Path: /usr/libexec/docker/cli-plugins/docker-buildx
compose: Docker Compose (Docker Inc.)
Version: v2.24.2
Path: /home/test/.docker/cli-plugins/docker-compose
Guess I understood the confusion here:
As you set command in you compose file with command: bash -c 'printenv TEST && echo $TEST'
the $TEST
value is interpolated by compose during parsing, using your .env
file to get variables. .env.1
is not involved here. You can confirm this by running docker compose config
If you want to get $TEST
to be passed to your command as a shell variable, you have to double the dollar sign so compose won't parse it:
command: bash -c 'printenv TEST && echo $$TEST'
. And then you get the expected result:
$docker compose run test
1
1
I would say this quite an unexpected behavior. Can you point to an official documentation that requires double dollars?
Otherwise, please keep the issue open until it's documented.
https://github.com/compose-spec/compose-spec/blob/master/12-interpolation.md
There is still one thing unclear: what is meant by parsing - or why only .env
is involved when parsing?
I don't have TEST=0
set in the shell that invokes docker compose up
, neither use anything that would load the variables from .env
in that shell.
Do you mean that .env
has some kind of special meaning for docker compose, and it's used for that parsing even if .env
is not listed in docker-compose.yml
? It appears that if I remove .env
from disk, and update docker-compose.yml
to use .env.1
and .env.2
, then the TEST variable is undefined during that parsing.
I think this behavior requires a clarification in the docker compose docs. See the bottom of this comment for an attempt of a summary.
The special behavior of .env
is further clarified at https://stackoverflow.com/questions/46455610/usage-of-env-variable-in-docker-compose-run-command/46456139#46456139
On the other hand, https://docs.docker.com/compose/environment-variables/set-environment-variables/#additional-information says
You can use multiple .env files in your compose.yml with the env_file attribute, and Docker Compose reads them in the order specified. If the same variable is defined in multiple files, the last definition takes precedence
Here is the example from that page modified to make it runnable
services:
webapp:
image: nginx:stable-bullseye
env_file:
- .env
- .env.override
command: bash -c 'echo $TEST'
.env
TEST=0
.env.override
TEST=1
This is the current behavior of the example
docker compose version
Docker Compose version v2.24.2
docker compose up
[+] Running 1/0
✔ Container tmp-webapp-1 Created 0.0s
Attaching to webapp-1
webapp-1 | 0
webapp-1 exited with code 0
I find the setence If the same variable is defined in multiple files, the last definition takes precedence
does not describe the current behavior sufficiently. The main problem is that there is a difference in behavior between command: bash -c 'echo $TEST'
in docker-compose.yml, and using this command for container run or exec, as shown below
No current shell variable interpolation, due to single quotes
docker compose run webapp sh -c 'echo $TEST'
1
With current shell variable interpolation, due to double quotes
docker compose run webapp sh -c "echo $TEST"
I would interpret that takes precedence
in this case suggests to the user that TEST=1
is used, in the same way as both docker run and exec do it.
Please add a warning somewhere around https://docs.docker.com/compose/environment-variables/set-environment-variables/#additional-information, which clarifies some of these observations.
To summarize: the issue is that the behavior of command
placed in docker-compose.yml file differs from the behavior of the command
of docker compose run
and exec
.
Hi @ndeloof and @Danio84, Friendly question from a Docker Captain. Why is this issue closed? I can still reproduce the faulty behaviour. Best :)
@ldynia have you read https://github.com/docker/compose/issues/11373#issuecomment-1909695119 ?
the root cause for this is
- misunderstanding about
env_file
which isn't involved in variable interpolation but.env
is loaded by default for this purpose -
$TEST
set in command being interpolated during parsing, not expanded by container's shell based on environment
Thanks @ndeloof,
No, I didn't read it. Now it makes sense $$