714

I have a dockerfile that download and builds GTK from source, but the following line is not updating my image's environment variable:

RUN PATH="/opt/gtk/bin:$PATH"
RUN export PATH

I read that that I should be using ENV to set environment values, but the following instruction doesn't seem to work either:

ENV PATH /opt/gtk/bin:$PATH

This is my entire Dockerfile:

FROM ubuntu
RUN apt-get update
RUN apt-get install -y golang gcc make wget git libxml2-utils libwebkit2gtk-3.0-dev libcairo2 libcairo2-dev libcairo-gobject2 shared-mime-info libgdk-pixbuf2.0-* libglib2-* libatk1.0-* libpango1.0-* xserver-xorg xvfb

# Downloading GTKcd
RUN wget http://ftp.gnome.org/pub/gnome/sources/gtk+/3.12/gtk+-3.12.2.tar.xz
RUN tar xf gtk+-3.12.2.tar.xz
RUN cd gtk+-3.12.2

# Setting environment variables before running configure
RUN CPPFLAGS="-I/opt/gtk/include"
RUN LDFLAGS="-L/opt/gtk/lib"
RUN PKG_CONFIG_PATH="/opt/gtk/lib/pkgconfig"
RUN export CPPFLAGS LDFLAGS PKG_CONFIG_PATH
RUN ./configure --prefix=/opt/gtk
RUN make
RUN make install

# running ldconfig after make install so that the newly installed libraries are found.
RUN ldconfig

# Setting the LD_LIBRARY_PATH environment variable so the systems dynamic linker can find the newly installed libraries.
RUN LD_LIBRARY_PATH="/opt/gtk/lib"

# Updating PATH environment program so that utility binaries installed by the various libraries will be found.
RUN PATH="/opt/gtk/bin:$PATH"
RUN export LD_LIBRARY_PATH PATH

# Collecting garbage
RUN rm -rf gtk+-3.12.2.tar.xz

# creating go code root
RUN mkdir gocode
RUN mkdir gocode/src
RUN mkdir gocode/bin
RUN mkdir gocode/pkg

# Setting the GOROOT and GOPATH enviornment variables, any commands created are automatically added to PATH
RUN GOROOT=/usr/lib/go
RUN GOPATH=/root/gocode
RUN PATH=$GOPATH/bin:$PATH
RUN export GOROOT GOPATH PATH
Daniel Walker
  • 6,380
  • 5
  • 22
  • 45
ILikeTacos
  • 17,464
  • 20
  • 58
  • 88
  • 2
    The LD_LIBRARY_PATH and PATH should be set using ENV not export. You are also LD_LIBRARY_PATH shouldn't be pointing at PATH!. Deleting files in the Dockerfile doesn't make your image smaller, check http://www.centurylinklabs.com/optimizing-docker-images/?hvid=4wO7Yt. – Javier Castellanos Nov 25 '14 at 07:23
  • is the current dockerfile a valid one ? – Hui Wang Apr 22 '16 at 14:52
  • @HuiWang it may not. It was written, it was written 1.5 years ago and a lot has changed since then. Just make sure you incorporate the changes described in the selected answer. – ILikeTacos Apr 22 '16 at 19:18

4 Answers4

1123

You can use Environment Replacement in your Dockerfile as follows:

ENV PATH="${PATH}:/opt/gtk/bin"
Dave Jarvis
  • 30,436
  • 41
  • 178
  • 315
Homme Zwaagstra
  • 11,713
  • 2
  • 17
  • 14
  • 22
    Is `=` equals sign necessary? – IgorGanapolsky Mar 28 '17 at 21:26
  • 29
    @IgorGanapolsky Not in this instance as it is specifying a single variable. However, it doesn't hurt and is mandatory when specifying multiple variables. See the [ENV documentation](https://docs.docker.com/engine/reference/builder/#env) for more details. – Homme Zwaagstra Mar 30 '17 at 15:22
  • 60
    That works! Please take care about the `=` it needs to be without spaces. If you add spaces next to `=` like this `ENV PATH = "/opt/gtk/bin:${PATH}"` WILL CRASH YOUR $PATH – Diego Juliao Aug 03 '17 at 21:54
  • This didn't work for me, so instead I create a bashrc and mounted it into the right place in my docker-compose.yml " - ./config/.bashrc:/root/.bashrc" – Cameron Nov 21 '19 at 23:27
  • 11
    Won't this update the image with the HOST's `$PATH` appended? – emmdee Jan 06 '20 at 23:59
  • 55
    ```ENV PATH="/opt/gtk/bin:${PATH}"``` may not be the same as ```ENV PATH="/opt/gtk/bin:$PATH"``` The former, with curly brackets, might provide you with the host's PATH. The documentation doesn't suggest this would be the case, but I have observed that it is. This is simple to check just do ```RUN echo $PATH``` and compare it to ```RUN echo ${PATH}``` – dankirkd Jan 13 '20 at 23:01
  • 2
    @dankirkd that is a highly useful observation, deserving of +100 upvotes, or perhaps an answer in its own right. thankyou. – Ed Randall Dec 01 '20 at 10:10
  • @dankirkd I did the `RUN echo` comparison as you suggested but got the container's PATH in both cases... Maybe they fixed this? I'm using `Docker version 19.03.13, build 4484c46d9d` (on Windows, MinGW). – Pedro A Sep 16 '21 at 23:49
  • 1
    @PedroA I'm using a Mac (Catalina 10.15.5) running Docker v20.10.8. and the behavior is as I describe, `$PATH` gives me the path within my Docker container, and `${PATH}` gives me the path on my Mac. – dankirkd Sep 18 '21 at 01:00
  • 2
    @dankirkd This is absolutely crazy. I decided to file an issue about this: https://github.com/moby/moby/issues/42863 feel free to add more info there if you want. – Pedro A Sep 18 '21 at 04:09
  • Also important to point out this section from the link above: "`ENV abc=hello ENV abc=bye def=$abc ENV ghi=$abc` will result in def having a value of hello, not bye. However, ghi will have a value of bye because it is not part of the same instruction that set abc to bye." I was having issues setting multiple ENV vars, because I was trying to do it all in the same instruction. – Mark Sep 23 '21 at 19:10
  • THE "=" caused issued with the PATH change. I would omit it? – rbigley Aug 29 '23 at 17:28
65

Although the answer that Gunter posted was correct, it is not different than what I already had posted. The problem was not the ENV directive, but the subsequent instruction RUN export $PATH

There's no need to export the environment variables, once you have declared them via ENV in your Dockerfile.

As soon as the RUN export ... lines were removed, my image was built successfully

ILikeTacos
  • 17,464
  • 20
  • 58
  • 88
  • 13
    `RUN A=B`, `RUN export A`, and `RUN export A=B`, are valid shell commands, but affect the environment _only_ of commands that follow in that same `RUN` directive (but none are given). Similarly, if you had `RUN export PATH=/foo; prog1; prog2;` (in the same RUN), the PATH modification would affect `prog1` and `prog2`. So, `RUN export $PATH` is a noop (because no program uses that modified environment) and it should make no difference if that directive is there or not. By "Gunter", do you mean [this answer](https://stackoverflow.com/a/38742545/5556676)? – init_js Apr 09 '19 at 21:47
  • The fix is really to change the PATH value with an ENV directive, not RUN. Then those changes would carry over when the docker builder invokes the following RUN. – init_js Apr 09 '19 at 21:52
57

[I mentioned this in response to the selected answer, but it was suggested to make it more prominent as an answer of its own]

It should be noted that

ENV PATH="/opt/gtk/bin:${PATH}" 

may not be the same as

ENV PATH="/opt/gtk/bin:$PATH" 

The former, with curly brackets, might provide you with the host's PATH. The documentation doesn't suggest this would be the case, but I have observed that it is. This is simple to check just do RUN echo $PATH and compare it to RUN echo ${PATH}

dankirkd
  • 1,739
  • 1
  • 15
  • 8
  • 2
    Just tried to verify this assertion, both commands gave the same output. Using docker 20.10.2. – rud Feb 18 '21 at 16:01
  • 3
    I just tried it with 20.10.2 on a Mac and the two were not the same. ${PATH} included paths on my laptop (such as /Library/... and /Users/...), while $PATH reflected only paths within the context of my container. – dankirkd Feb 22 '21 at 17:40
  • 7
    The latest https://docs.docker.com/engine/reference/builder/#environment-replacement says "Environment variables are notated in the Dockerfile either with $variable_name or ${variable_name}. They are treated equivalently" – mloskot May 19 '21 at 11:33
  • 2
    Hmmm... "equivalently" doesn't necessarily mean "exactly the same". I suggest anyone interested check whether this is true for $PATH and ${PATH}. 20.10.6 still has the differing behavior. – dankirkd May 20 '21 at 16:25
  • that's wild. I'm also seeing different output. – T.W.R. Cole May 21 '21 at 16:29
  • I was also curious about this but I tested it with docker 20.10.8 and I see the same output. It is NOT expanding the host variable. – atoMerz Aug 29 '21 at 07:32
  • Probably the same as on Windows where you have the the user env vars on top and the system env vars at the bottom of the env vars menu? – questionto42 Aug 30 '21 at 09:13
  • The inconsistency you are facing isn't Docker it's Linux shell (BASH/SH) related. Those ${} are native to Linux scripting. Likely docker has simply integrated with the native shell of the OS so when you put this into the file it will be interpreted by the host/system OS depending on the one you use. If you want the details I suggest you look into bash scripting. – Michael Nov 01 '22 at 16:16
10

This is discouraged (if you want to create/distribute a clean Docker image), since the PATH variable is set by /etc/profile script, the value can be overridden.

head /etc/profile:

if [ "`id -u`" -eq 0 ]; then
  PATH="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
else
  PATH="/usr/local/bin:/usr/bin:/bin:/usr/local/games:/usr/games"
fi
export PATH

At the end of the Dockerfile, you could add:

RUN echo "export PATH=$PATH" > /etc/environment

So PATH is set for all users.

Thomas Decaux
  • 21,738
  • 2
  • 113
  • 124
  • 10
    As per [this Ubuntu documentation](https://help.ubuntu.com/community/EnvironmentVariables#A.2Fetc.2Fenvironment), `/etc/environment` is a list of assignment expressions, not a script, and does not support variable expansion, so it is unlikely that the `RUN` syntax would work. – Nicolas Lefebvre Feb 26 '19 at 18:24
  • 3
    Yes, it will be expanded and `export PATH=` will be written to `/etc/environment`, which is still incorrect because that file is not a script but a list of `=`. `export` will likely make it fail unless your system supports some black magic outside the spec. – Nicolas Lefebvre Mar 28 '19 at 21:09
  • 1
    Most paths to running Docker containers don't read `/etc/profile` or `/etc/environment`, so changing these scripts is usually ineffective. – David Maze Apr 07 '22 at 11:16