How to remove directories and files in another layer using Docker? Why this question?

The reason for posting this Q&amp;A is that sometimes certain software is required to compile software in a docker image. Once compiled, these packages are superfluous and should be removed in order to reduce the image size. In some cases images that were more than 1.5GB where reduced to less than 300MB. The following use case does not represent a real world scenario, but provides an example of this use case.

Attempts to solve the issue

It works to remove a directory when the remove command is defined in the same layer as the creation of the folder:

FROM alpine
RUN mkdir dir &amp;&amp; cd dir &amp;&amp; wget http://google.com &amp;&amp; rm -rf dir


This results in:

user@host$ docker build -t dir .
Sending build context to Docker daemon 1.336 MB
Step 1/2 : FROM alpine
 ---&gt; 4a415e366388
Step 2/2 : RUN mkdir dir &amp;&amp; cd dir &amp;&amp; wget http://google.com &amp;&amp; rm -rf dir
 ---&gt; Using cache
 ---&gt; c283805e687f
Successfully built c283805e687f


When the aim is to remove the directory in another layer, this fails:

FROM alpine
RUN mkdir dir &amp;&amp; cd dir &amp;&amp; wget http://google.com
RUN rm -r dir


And this fails:

FROM alpine
RUN mkdir dir &amp;&amp; cd dir &amp;&amp; wget http://google.com
RUN rm -rf dir


Another attempt was using workdir:

FROM alpine

RUN mkdir dir
WORKDIR dir
RUN wget http://google.com
WORKDIR /
RUN ls
RUN rm -r dir


Building the image resulted in:

Sending build context to Docker daemon 2.048 kB
Step 1/7 : FROM alpine
 ---&gt; 4a415e366388
Step 2/7 : RUN mkdir dir
 ---&gt; Using cache
 ---&gt; aed5c75218cb
Step 3/7 : WORKDIR dir
 ---&gt; Using cache
 ---&gt; 715de09e7e08
Step 4/7 : RUN wget http://google.com
 ---&gt; Using cache
 ---&gt; c07bfb3e1133
Step 5/7 : WORKDIR /
 ---&gt; Using cache
 ---&gt; c6de86d0191a
Step 6/7 : RUN ls
 ---&gt; Using cache
 ---&gt; 9567593cce39
Step 7/7 : RUN rm -r dir
 ---&gt; Running in 7fe7b28294bf
rm: can't remove 'dir': Directory not empty
The command '/bin/sh -c rm -r dir' returned a non-zero code: 1
mkdir dir &amp;&amp; cd dir &amp;&amp; wget http://google.com &amp;&amp; rm -rf dir doesn't do what you think it does.

Let's break it down:


mkdir dir creates dir.
cd dir changes directory into it.
wget http://google.com downloads google.com inside dir/.
rm -rf dir attempts to delete a directory called dir that's in the current directory.


The problem is that there is not dir in the current directory, because you're already cded into it.  And since you've added the -f flag, the command doesn't produce an error.  This is one of the reasons why you shouldn't use force flags without being very sure you need them.

Since you didn't use the WORKDIR command, the directory change is discarded at the end of the RUN.  Thus, the next line executes in the original working directory, where it tries to mkdir dir but, as we've previously discussed, that directory still exists with the wgetted contents inside it.