docker / docker/cli

docker stack deploy doesn't interpolate env-files correctly

Open
#2,075 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

area/stack area/swarm kind/bug version/19.03
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;

  1. ENV_VAR1 has a literal value set in the env-file
  2. ENV_VAR2 is set to an empty value ("")
  3. ENV_VAR3 has no value set, and will take its value from the $ENV_VAR3 environment variable in the current environment (if set)
  4. ENV_VAR4 has no value set, and will take its value from the $ENV_VAR4 environment variable in the current environment. This variable is not set in the current environment, so the ENV_VAR4 will 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

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. 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

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.