How to substitute environment variable in command of service in docker-compose.yml at runtime of container?

Viewed 1582

The following docker-compose.yml defines command, which contains an environment variable FOO

version: '3.7'
services:
  tmp:
    image: alpine
    environment:
      FOO: foo
    command: ["echo", "${FOO:-foobar}"]

If you run

docker-compose -p app up

and look at the logs of the container using

docker logs app_tmp_1

you see

foobar

since the environment variable FOO is substituted, when/before docker-compose.yml is parsed/read. If the environment variable FOO would be substituted at runtime of the container app_tmp_1, the output would be

foo

as the environment variable FOO=foo is configured for the container.

How to configure command to substitute/evaluate the environment variable at runtime of container app_tmp_1 (i.e. output foo in the example)?

2 Answers

Edit:

You can escape the environment variable (double dollar symbol $$ instead of one $) in docker-compose.yml to prevent it from being replaced in the command of the container. However, since the replacement should be done at runtime, a shell (command) has to be run in the container to do the replacement, e.g.

version: '3.7'
services:
  tmp:
    image: alpine
    environment:
      FOO: foo
    command: sh -c 'echo "$${FOO:-foobar}"'

Old answer:

I just figured out that nested environment variables are not replaced.

version: '3.7'
services:
  tmp:
    image: alpine
    environment:
      FOO: foo
    command: sh -c 'echo FOO is "${FOO_OVERWRITE:-${FOO:-foobar}}" && env'

If you run

docker-compose -p app up

you get

# echo output
FOO is foo
# env output
FOO=foo

You get the same result, even if you run

FOO=ignored docker-compose -p app up

However, if you run

FOO_OVERWRITE=overwritten docker-compose -p app up

you get

# echo output
FOO is overwritten}
# env output
FOO=foo

The overwrite does not work probably, since } is part of the output. Considering this, you should not use this solution ;)

Note: You do not get } if you run the same command in a shell (no Docker involved):

$ sh -c 'echo FOO is "${FOO_OVERWRITE:-${FOO:-foobar}}"' 
FOO is foobar

If the environment variable is not defined in the container, i.e. remove

    environment:
      FOO: foo

from docker-compose.yml, i.e.

version: '3.7'
services:
  tmp:
    image: alpine
    command: sh -c 'echo FOO is "${FOO_OVERWRITE:-${FOO:-foobar}}" && env'

you get the default defined in the command

# echo output
FOO is foobar
# env output does not contain FOO

Docker Compose version 1.26.0

It looks like the environment variables in the docker-compose are not available at the time of creating the container with the docker-compose.

The same problem you have is when putting environment variables in docker-compose and expect them to be available during building-phase with Dockerfile (in the build-stage of docker-compose). Then they are also not available.

What you could do is the following:

docker-compose.yml

version: '3.7'
services:
  tmp:
    image: alpine
    container_name: fooContainer
    volumes:
      - ./start.sh:/root/start.sh:ro
    environment:
      FOO: foo
    command: ["/root/start.sh"]

start.sh

And since start.sh script runs inside the container you will have environment variable available. start.sh looks something like this:

#!/bin/sh
echo $FOO

result

$ docker-compose up
Creating fooContainer ... done
Attaching to fooContainer
fooContainer | foo
fooContainer exited with code 0
Related