I have a docker-compose-test.yml like so:
services:
environment-service:
image: ubuntu:24.04
command: "echo 'you should see string as the next string: $DRYRUNG'"
I run it like so:
docker-compose --file docker-compose-test.yml run -e DRYRUNG=string environment-service
with the following output:
WARNING: The DRYRUNG variable is not set. Defaulting to a blank string.
Pulling environment-service (ubuntu:24.04)...
24.04: Pulling from library/ubuntu
5a7813e071bf: Already exists
Digest: sha256:72297848456d5d37d1262630108ab308d3e9ec7ed1c3286a32fe09856619a782
Status: Downloaded newer image for ubuntu:24.04
Creating mbonnet_environment-service_run ... done
you should see string as the next string:
A second attempt, post-image-pull, gives
WARNING: The DRYRUNG variable is not set. Defaulting to a blank string.
Creating mbonnet_environment-service_run ... done
you should see string as the next string:
I expected output like:
Creating mbonnet_environment-service_run ... done
you should see string as the next string: string
Relevant system information:
$ docker-compose --version
docker-compose version 1.29.2, build unknown
$ docker -v
Docker version 28.0.0, build f9ced58
$ lsb_release -a
No LSB modules are available.
Distributor ID: Ubuntu
Description: Ubuntu 24.04.2 LTS
Release: 24.04
Codename: noble
To be clear, I do not wish to set wider environment variables in the shell I am using, nor do I wish to set them via an environment file like .env
. I want to be able to do arbitrary values when I execute the docker-compose
command.
These are also not secrets/credentials - the wider use is passing them as arguments to a command line tool, within Docker.
I have a docker-compose-test.yml like so:
services:
environment-service:
image: ubuntu:24.04
command: "echo 'you should see string as the next string: $DRYRUNG'"
I run it like so:
docker-compose --file docker-compose-test.yml run -e DRYRUNG=string environment-service
with the following output:
WARNING: The DRYRUNG variable is not set. Defaulting to a blank string.
Pulling environment-service (ubuntu:24.04)...
24.04: Pulling from library/ubuntu
5a7813e071bf: Already exists
Digest: sha256:72297848456d5d37d1262630108ab308d3e9ec7ed1c3286a32fe09856619a782
Status: Downloaded newer image for ubuntu:24.04
Creating mbonnet_environment-service_run ... done
you should see string as the next string:
A second attempt, post-image-pull, gives
WARNING: The DRYRUNG variable is not set. Defaulting to a blank string.
Creating mbonnet_environment-service_run ... done
you should see string as the next string:
I expected output like:
Creating mbonnet_environment-service_run ... done
you should see string as the next string: string
Relevant system information:
$ docker-compose --version
docker-compose version 1.29.2, build unknown
$ docker -v
Docker version 28.0.0, build f9ced58
$ lsb_release -a
No LSB modules are available.
Distributor ID: Ubuntu
Description: Ubuntu 24.04.2 LTS
Release: 24.04
Codename: noble
To be clear, I do not wish to set wider environment variables in the shell I am using, nor do I wish to set them via an environment file like .env
. I want to be able to do arbitrary values when I execute the docker-compose
command.
These are also not secrets/credentials - the wider use is passing them as arguments to a command line tool, within Docker.
Share Improve this question edited yesterday mkrmo 311 bronze badge asked 2 days ago Michael BonnetMichael Bonnet 2504 silver badges13 bronze badges1 Answer
Reset to default 2Compose itself expands environment variables it sees in the Compose file. It does this using the host environment and the .env
file (if any), before it considers anything in the container-specific setup or a per-container docker-compose run -e
option.
If you need to override the command in the Compose file, but you need it to take a container-specific environment variable, then you need to make sure a shell gets run as part of the command:
, and that Compose doesn't expand the variable itself. This could look like
command:
- /bin/sh
- -c
- echo "you should see string as the next string: $$DRYRUNG"
Breaking down this syntax: it explicitly splits command:
into three words, using YAML block-sequence syntax so that we can minimize the number of quotation marks we need. /bin/sh
is the shell, and -c
is an option that causes it to read the next argument as a command. The third argument (one list item == one argument) is the command; in that command we use double quotes so the shell does expand it, and we double the dollar sign so that Compose does not expand it.
... passing them as arguments to a command line tool ...
One pattern you occasionally see is the "container as command" pattern; there's an example of this in the Docker documentation. In this pattern, the image's ENTRYPOINT
is the command to run and its CMD
is additional arguments. When the container is run, the CMD
is easy to replace, and the two lists of words are just concatenated together. So if the Dockerfile said
FROM busybox
ENTRYPOINT ["/bin/echo", "the word is: "]
anything you passed to docker-compose run
would be interpreted as the CMD
and appended to this.
version: '3.8'
services:
environment:
build: .
docker-compose run environment string
That might be an easier setup for this specific use case.
(Note that this setup makes it harder to replace the actual command; you need an awkward --entrypoint
option if you want to do something else other than the thing baked into the image, for example to get a debugging shell. In most cases I tend to prefer CMD
as the actual command, but there are occasional reasons such as this setup to put it in ENTRYPOINT
instead.)