KramKroc
KramKroc

Reputation: 496

Docker variable expansion in compose environment

I've found that if I define an environment variable in a docker-compose service entry, that it will not be expanded in other variables defined in the environment section but it will be expanded if the variable is defined in an env file, e.g.

  someserver:
    image: "some-server:latest"
    restart: always
    ports:
      - "8849:8849"
    environment:
       javaMemoryLimit: 3056M
       JAVA_OPTS: "-Xmx${javaMemoryLimit} -Dcom.sun.management.jmxremote=true -Dcom.sun.management.jmxremote.port=8849 -Dcom.sun.management.jmxremote.authenticate=false -Dcom.sun.management.jmxremote.ssl=false -Dcom.sun.management.jmxremote.local.only=false -Dcom.sun.management.jmxremote.rmi.port=8849 -Djava.rmi.server.hostname=localhost"

When I do a docker-compose up with this I get warnings about variable not being set:

WARNING: The javaMemoryLimit variable is not set. Defaulting to a blank string.

The same occurs if I use the list form of environment definition.

But if the variable javaMemoryLimit is defined in a .env then the expansion is fine. I've also tried using $$javaMemoryLimit and then I don't get the warning message but the variable is not expanded when the container actually starts. Any ideas?

Upvotes: 4

Views: 4400

Answers (2)

Stabledog
Stabledog

Reputation: 3370

Environment variable expansion in docker compose files

Sometimes you can workaround the problem with command: and $$var_name

In the command: property of a compose file, you actually can expand variables defined in environment:.

(No idea why this does not seem to be documented anywhere, or whether it will remain true forever? From docker 25.0.2 -- ymmv!)

services:
  dumtest:
    image: some-basic-image
    environment:
      - foo_cmd=/bin/ls -ald /etc
    command: >
      bash -c '
        set -ue; 
        echo Notice how we are expanding "foo_cmd" inline within the command, and 
        echo this expansion is happening in the container environment, not the 
        echo parser of the compose file. 
        echo Be aware that one must be careful not to use a single quote
        echo anywhere in this command block! It cannot be escaped.

        echo Expand the PATH inside the container:
        echo $$PATH; 
        echo [foo_cmd=$$foo_cmd]; 
        echo Run foo_cmd inside the container:
        eval $$foo_cmd

        echo Expand the PATH in the compose.yaml parser:
        echo $PATH
      '

Output from a test run:

$/testdir> docker compose dumtest
Notice how we are expanding foo_cmd inline within the command, and this
expansion is happening in the container environment, not the
parser of the compose file.
Be aware that one must be careful not to use a single quote
anywhere in this command block! It cannot be escaped.
Expand the PATH inside the container:
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
[foo_cmd=/bin/ls -ald /etc]
Run foo_cmd inside the container:
drwxr-xr-x. 1 root root 66 Jan  6 11:54 /etc
Expand the PATH in the compose.yaml parser:
/opt/bb/bin/code-server/lib/vscode/bin/remote-cli:/root/.local/bin:/usr/share/Modules/bin:/opt/bb/lib64/bin:/opt/bb/sbin:/opt/bb/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/root/bin

Upvotes: 0

nyet
nyet

Reputation: 596

This is deliberate variable substitution behavior. Only .env and variables from the shell environment are evaluated at the docker-compose.yaml level. Otherwise, ${javaMemoryLimit} will expand to an empty string.

As a side note: even more annoying is the fact that NO variable substitution whatsoever is done in files specified byenv_file:.

That said, if you do "-Xmx$${javaMemoryLimit} -D... whatever expands JAVA_OPTS might work since that should expand to -Xmx${javaMemoryLimit} -D... (instead of -Xmx -D...) in your ENTRYPOINT.

Upvotes: 4

Related Questions