docker stack deploy doesn't interpolate env-files correctly
Nobody has claimed this yet.
- Dominant language
- Go
- Stars
- 6.1k
- Forks
- 2.2k
- Avg merge
- 1d 15h
- Merged PRs (30d)
- 43
Description
When using an --env-file, lines that do not set a value (and do not have an =) should take their value from an environment variable with the given name. If the given environment variable is not set in the current environment, then the variable should not be set on the container.
In the following example, the env-file contains 4 variables;
ENV_VAR1has a literal value set in the env-fileENV_VAR2is set to an empty value ("")ENV_VAR3has no value set, and will take its value from the$ENV_VAR3environment variable in the current environment (if set)ENV_VAR4has no value set, and will take its value from the$ENV_VAR4environment variable in the current environment. This variable is not set in the current environment, so theENV_VAR4will be omitted for the container
I noticed that when deploying a service as part of a stack doesn't function properly; the env-file is not interpreted correctly, 2. incorrectly takes its value from the current environment (instead of setting to an empty string)
Reproduction steps are below:
1. Preparation
Create a directory to work in, and inside the directory, create an env-file, and a docker-compose.yml:
mkdir test-dir && cd test-dir
Create an env-file:
cat > ./env_file <<'EOF'
# ENV_VAR1 is a literal value in the env-file
ENV_VAR1=this is ENV_VAR1 with a value from the env-file
# ENV_VAR2 should be "" (empty string) inside the container
ENV_VAR2=
# ENV_VAR3 in the container should have its value copied from the $ENV_VAR3 environment variable
ENV_VAR3
# ENV_VAR4 is similar, but is not set in the current environment, and should not be set in the container
ENV_VAR4
EOF
Create a compose file:
cat > docker-compose.yml <<'EOF'
version: "3.8"
services:
web:
image: busybox:latest
command: env
env_file:
- env_file
deploy:
restart_policy:
condition: none
EOF
Export environment variables ENV_VAR1, ENV_VAR2, ENV_VAR3, and make sure ENV_VAR4 is not set
export ENV_VAR1="ENV_VAR1 from env"
export ENV_VAR2="ENV_VAR2 from env"
export ENV_VAR3="ENV_VAR3 from env"
unset ENV_VAR4
2. run a container using the env-file
docker run --rm --env-file=./env_file busybox env
Check the output and verify that ENV_VAR1, ENV_VAR2 and ENV_VAR3 are set inside the container, and have the correct value:
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
HOSTNAME=94fce2f54a37
ENV_VAR1=this is ENV_VAR1 with a value from the env-file
ENV_VAR2=
ENV_VAR3=ENV_VAR3 from env
HOME=/root
3. run a service using the env-file
Don't set a restart-policy, because the container will exit after running env (and we don't need it to restart)
docker service create --name foo --detach --restart-condition=none --env-file=./env_file busybox env
Check the output using docker service logs and verify that ENV_VAR1, ENV_VAR2 and ENV_VAR3 are set inside the container, and have the correct value:
docker service logs foo
foo.1.y0lb0zplg2q6@docker-desktop | PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
foo.1.y0lb0zplg2q6@docker-desktop | HOSTNAME=2682fe2d21b7
foo.1.y0lb0zplg2q6@docker-desktop | ENV_VAR1=this is ENV_VAR1 with a value from the env-file
foo.1.y0lb0zplg2q6@docker-desktop | ENV_VAR2=
foo.1.y0lb0zplg2q6@docker-desktop | ENV_VAR3=ENV_VAR3 from env
foo.1.y0lb0zplg2q6@docker-desktop | HOME=/root
4. run a service using the env-file, using a compose file
Deploy a stack from the compose-file that was created in step 1:
docker stack deploy -c docker-compose.yml foo
Check the output using docker service logs:
docker service logs foo_web
foo_web.1.ycifza8exvdd@docker-desktop | PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
foo_web.1.ycifza8exvdd@docker-desktop | HOSTNAME=d00e7a9a345f
foo_web.1.ycifza8exvdd@docker-desktop | ENV_VAR1=this is ENV_VAR1 with a value from the env-file
foo_web.1.ycifza8exvdd@docker-desktop | ENV_VAR2=ENV_VAR2 from env
foo_web.1.ycifza8exvdd@docker-desktop | ENV_VAR3=ENV_VAR3 from env
foo_web.1.ycifza8exvdd@docker-desktop | HOME=/root
Notice that ENV_VAR2 takes its value from the environment, but should be empty, because it was set to an empty string in the env-file
docker version
Client: Docker Engine - Community
Version: 19.03.1
API version: 1.40
Go version: go1.12.5
Git commit: 74b1e89
Built: Thu Jul 25 21:18:17 2019
OS/Arch: darwin/amd64
Experimental: true
Server: Docker Engine - Community
Engine:
Version: 19.03.1
API version: 1.40 (minimum version 1.12)
Go version: go1.12.5
Git commit: 74b1e89
Built: Thu Jul 25 21:17:52 2019
OS/Arch: linux/amd64
Experimental: true
containerd:
Version: v1.2.6
GitCommit: 894b81a4b802e4eb2a91d1ce216b8817763c29fb
runc:
Version: 1.0.0-rc8
GitCommit: 425e105d5a03fabd737a126ad93d62a9eeede87f
docker-init:
Version: 0.18.0
GitCommit: fec3683
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start by tracing the docker stack deploy path that reads the compose file's env_file and compare it with docker run and docker service create behavior. Reproduce the case with ENV_VAR2= while ENV_VAR2 is exported, then verify that the deployed container preserves the empty value and still handles unset variables as described.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- docker, go
- Domain
- cli, devops
- Issue type
- Bug
- Difficulty
- 3/5
- Estimated time
- 1-2 days
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 45/100