dockerdocker-composeenvironment-variables

Dockerfile setting ENV PATH causing values from host PATH to be used inside container


I'm somewhat confused by the behavior of the environment variable $PATH inside a Docker container.

The value of echo $PATH on the host is:

$ echo $PATH
/usr/local/bin:/usr/bin:/bin

(Plus some other stuff which I have omitted for breivty.)

Here is my Dockerfile:

FROM ubuntu:24.04
WORKDIR /kdb
ENV QHOME=/kdb
ENV PATH="${QHOME}/bin:${QHOME}:$PATH"
ENV QLIC=/kdb/kc.lic
COPY ./q q
COPY ./bin bin
COPY ./src src
CMD ["/bin/bash", "-c", "sleep infinity"]

and the docker-compose.yml

services:
    kdb:
        container_name: kdb
        build: .
        command: echo $PATH
        ports:
            - 5000:5000

I have set the default command in the docker-compose.yml to be echo $PATH, such that the value of PATH will be shown in the logs.

docker logs shows that the same value from the host is being used inside the container. The Container PATH variable does not include /kdb/bin or /kdb.

Why is this?


Solution

  • Because Compose substitutes environment-variable references before it does its processing. This is a little more commonly used in other parts of the file (for example to substitute the image tag or provide a configurable host port).

    The other complication here is that the Compose command: does not automatically run a shell, unlike Dockerfile CMD. You need to provide a shell yourself. So you need to write

    command: sh -c 'echo $$PATH'
    

    with an explicit sh -c wrapper, and escaping the dollar sign.


    There's an easier way to do this, though, especially while you're debugging. You can docker-compose run a container based off a Compose specification, but replacing the command: or Dockerfile CMD with something you type in at the command line.

    docker compose run kdb sh -c 'echo $PATH'
    

    Then you can delete the command: override in the Compose file. Since you can easily enough launch an interactive shell if you need to, also make the Dockerfile CMD run the thing you normally want the container to run, probably something like CMD ["kdb"]; there's no reason to have a container running a meaningless sleep command.