Answers: <p>A solution is to remove the <code>not empty directory</code> using <code>find</code>:</p>
  
  <p><strong>Dockerfile</strong></p>
  
  <pre><code>FROM alpine
  
  RUN mkdir dir &amp;&amp; cd dir &amp;&amp; wget http://google.com &amp;&amp; cd / &amp;&amp; echo -e "BEFORE\n" &amp;&amp; ls &amp;&amp; find /dir -delete &amp;&amp; echo -e "\nAFTER\n" &amp;&amp; ls
  </code></pre>
  
  <p><strong>Outcome</strong></p>
  
  <pre><code>Sending build context to Docker daemon  2.048kB
  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; cd / &amp;&amp; echo -e "BEFORE\n" &amp;&amp; ls &amp;&amp; find /dir -delete &amp;&amp; echo -e "\nAFTER\n" &amp;&amp; ls
   ---&gt; Running in ba93a1742a76
  Connecting to google.com (172.217.20.110:80)
  Connecting to www.google.nl (172.217.20.99:80)
  index.html           100% |*******************************| 11092   0:00:00 ETA
  
  BEFORE
  
  bin
  dev
  dir
  etc
  home
  lib
  media
  mnt
  proc
  root
  run
  sbin
  srv
  sys
  tmp
  usr
  var
  
  AFTER
  
  bin
  dev
  etc
  home
  lib
  media
  mnt
  proc
  root
  run
  sbin
  srv
  sys
  tmp
  usr
  var
   ---&gt; 2e3109285a2d
  Removing intermediate container ba93a1742a76
  Successfully built 2e3109285a2d
  </code></pre>
  
Answers: CC BY-SA 3.0
Answers: 2017-04-03T14:11:59.220Z
Answers: You have unnecessary stuff in there, I believe you missed the point in Xiong's answer - the problem is not the `-rf` options to the `rm` cmd.
Answers: Dan Cornilescu
Answers: CC BY-SA 3.0
Answers: 2017-04-04T10:18:06.600Z
Answers: If I specify the whole path /path/to/dir and run it from / it still fails even with rf. I had to remove all the content from the folder.
Answers: 030
Answers: CC BY-SA 3.0
Answers: 2017-04-04T12:21:53.460Z
Answers: Are you saying `rm -rf` doesn't work and one has to manually empty every dir before deleting the dir? Very odd.
Answers: Dan Cornilescu
Answers: CC BY-SA 3.0
Answers: 2017-04-06T08:07:50.173Z
Answers: The `rm -rf` does not work indeed. I had to use `find /path -delete`
Answers: 030
Answers: CC BY-SA 3.0
Answers: 2017-04-02T12:51:06.963Z
Answers: 2017-04-14T07:52:48.080Z
Answers: 2017-04-14T07:52:48.080Z
Answers: 030
Answers: <p>Recent Dockerfile spec allows for multiple FROM statements.</p>
  
  <p><a href="https://docs.docker.com/engine/userguide/eng-image/multistage-build/" rel="noreferrer">https://docs.docker.com/engine/userguide/eng-image/multistage-build/</a></p>
  
  <p>Using this approach, you can retain your compilation results to a pure runtime environment.</p>
  
Answers: CC BY-SA 4.0
Answers: 2020-06-03T12:19:41.187Z
Answers: My situation is that - due to security reasons I am downloading the packages in the intermediate layer. Then, ADD'ing them to the final image. Followed by using RUN command to install the packages and delete the packages. My goal is to delete the downloaded packages once the RUN command installs them. Is there any way to a) combine the ADD and RUN into one layer; b) remove the ADD layer?
Answers: variable
Answers: CC BY-SA 3.0
Answers: 2017-12-30T11:02:13.467Z
Answers: 2017-12-30T11:02:13.467Z
Answers: Ta Mu
Answers: <p>Building on Xiong Chiamiov's answer, which correctly identified the root cause of the problem - the <code>dir</code> reference by relative path when attempting to empty or delete that directory depends on the working directory at the time, which was not correctly set in the cases mentioned in the OP.</p>
  <p>So there are 2 solutions available:</p>
  <ul>
  <li><p>set the proper working dir prior to executing the <code>dir</code> removal:</p>
  <pre><code>  RUN mkdir dir &amp;&amp; cd dir &amp;&amp; wget http://google.com &amp;&amp; cd .. &amp;&amp; rm -rf dir
  </code></pre>
  </li>
  <li><p>use a <code>/dir</code> full path reference to that directory instead. But with care (adjust if needed) if used in cases just similar, but not identical to this one, since this approach assumes the initial working dir was <code>/</code>:</p>
  <pre><code>  RUN mkdir dir &amp;&amp; cd dir &amp;&amp; wget http://google.com &amp;&amp; rm -rf /dir
  </code></pre>
  </li>
  </ul>
  
Answers: CC BY-SA 3.0
Answers: 2017-04-03T17:28:46.300Z
Answers: Hmm. Why not `rm -rf ../dir`? That avoids the absolute path reference
Answers: jpaugh
Answers: CC BY-SA 3.0
Answers: 2017-04-03T18:29:47.330Z
Answers: @jpaugh it *might* work, but it feels weird (cutting the branch you're sitting on?)
Answers: Dan Cornilescu
Answers: CC BY-SA 3.0
Answers: 2017-04-03T18:39:10.793Z
Answers: That's true; but it works essentially the same way when you specify an absolute path. FWIW, I've done this before, in an interactive shell. `ls` tends to lose its meaning... ;-) You can even `rm -rf ../dir && mkdir ../dir && cd ../dir`, which puts you in an new, empty (valid) folder
Answers: jpaugh
Answers: CC BY-SA 3.0
Answers: 2017-04-03T20:06:38.470Z
Answers: @jpaugh You're right, that's why I said `it feels` - it's just a feeling :)
Answers: Dan Cornilescu
Answers: CC BY-SA 4.0
Answers: 2017-04-03T14:09:19.167Z
Answers: 2022-12-06T20:40:49.817Z
Answers: 2022-12-06T20:40:49.817Z
Answers: Dan Cornilescu
Answers: <p><code>mkdir dir &amp;&amp; cd dir &amp;&amp; wget http://google.com &amp;&amp; rm -rf dir</code> doesn't do what you think it does.</p>
  
  <p>Let's break it down:</p>
  
  <ol>
  <li><code>mkdir dir</code> creates <code>dir</code>.</li>
  <li><code>cd dir</code> changes directory into it.</li>
  <li><code>wget http://google.com</code> downloads google.com inside <code>dir/</code>.</li>
  <li><code>rm -rf dir</code> attempts to delete a directory called <code>dir</code> that's in the current directory.</li>
  </ol>
  
  <p>The problem is that there is not <code>dir</code> in the current directory, because you're already <code>cd</code>ed into it.  And since you've added the <code>-f</code> 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.</p>
  
  <p>Since you didn't use the <code>WORKDIR</code> command, the directory change <a href="https://stackoverflow.com/q/17891981/120999">is discarded at the end of the <code>RUN</code></a>.  Thus, the next line executes in the original working directory, where it tries to <code>mkdir dir</code> but, as we've previously discussed, that directory still exists with the wgetted contents inside it.</p>
  
Answers: CC BY-SA 3.0
Answers: 2017-04-02T16:34:04.420Z
Answers: Sure it's possible to remove directories; you just specified the wrong path.
Answers: Xiong Chiamiov
Answers: CC BY-SA 3.0
Answers: 2017-04-02T18:59:27.123Z
Answers: It's a bit of a strange error, considering that that's precisely what `rm -r` is intended to address.  You can probably add `-f` in this case, but I would do some further investigation to see what exactly is in that directory (e.g. an `ls -A`).  But you've gone past the original question at this point.
Answers: Xiong Chiamiov
Answers: CC BY-SA 3.0
Answers: 2017-04-02T04:01:12.017Z
Answers: 2017-04-02T04:01:12.017Z
Answers: 2017-05-23T12:39:34.013Z
Answers: Xiong Chiamiov
Body: <p><strong>Why this question?</strong></p>
  
  <p>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.</p>
  
  <p><strong>Attempts to solve the issue</strong></p>
  
  <p>It works to remove a directory when the remove command is defined in the same layer as the creation of the folder:</p>
  
  <pre><code>FROM alpine
  RUN mkdir dir &amp;&amp; cd dir &amp;&amp; wget http://google.com &amp;&amp; rm -rf dir
  </code></pre>
  
  <p>This results in:</p>
  
  <pre><code>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
  </code></pre>
  
  <p>When the aim is to remove the directory in another layer, this fails:</p>
  
  <pre><code>FROM alpine
  RUN mkdir dir &amp;&amp; cd dir &amp;&amp; wget http://google.com
  RUN rm -r dir
  </code></pre>
  
  <p>And this fails:</p>
  
  <pre><code>FROM alpine
  RUN mkdir dir &amp;&amp; cd dir &amp;&amp; wget http://google.com
  RUN rm -rf dir
  </code></pre>
  
  <p>Another attempt was using workdir:</p>
  
  <pre><code>FROM alpine
  
  RUN mkdir dir
  WORKDIR dir
  RUN wget http://google.com
  WORKDIR /
  RUN ls
  RUN rm -r dir
  </code></pre>
  
  <p>Building the image resulted in:</p>
  
  <pre><code>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
  </code></pre>
  
Comments: CC BY-SA 3.0
Comments: 2017-04-02T03:20:10.567Z
Comments: You most certainly can have multiple RUN statements in your Dockerfile.
Comments: David Ficociello
Comments: CC BY-SA 3.0
Comments: 2017-04-02T03:21:04.487Z
Comments: Check your Dockerfile. Looks like you copy pasted the same line twice. If you look at step 2 and 3 they are both executing the same code. That's why you're getting the no dir found. You've already deleted it in step 2
Comments: David Ficociello
Tags: <dockerfile>
Title: How to remove directories and files in another layer using Docker?
UserDisplayName: 030
ThreadText: # How to remove directories and files in another layer using Docker?
  
  (Asked by: username_0 on 2017-03-31)
  
  **Why this question?**
  
  The reason for posting this Q&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 && cd dir && wget http://google.com && 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
   ---> 4a415e366388
  Step 2/2 : RUN mkdir dir && cd dir && wget http://google.com && rm -rf dir
   ---> Using cache
   ---> c283805e687f
  Successfully built c283805e687f
  
  ```
  
  When the aim is to remove the directory in another layer, this fails:
  
  ```
  FROM alpine
  RUN mkdir dir && cd dir && wget http://google.com
  RUN rm -r dir
  
  ```
  
  And this fails:
  
  ```
  FROM alpine
  RUN mkdir dir && cd dir && 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
   ---> 4a415e366388
  Step 2/7 : RUN mkdir dir
   ---> Using cache
   ---> aed5c75218cb
  Step 3/7 : WORKDIR dir
   ---> Using cache
   ---> 715de09e7e08
  Step 4/7 : RUN wget http://google.com
   ---> Using cache
   ---> c07bfb3e1133
  Step 5/7 : WORKDIR /
   ---> Using cache
   ---> c6de86d0191a
  Step 6/7 : RUN ls
   ---> Using cache
   ---> 9567593cce39
  Step 7/7 : RUN rm -r dir
   ---> 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
  
  ```
  
  **Tags:** dockerfile
  
  > **Comments:**
  > **username_1**: You most certainly can have multiple RUN statements in your Dockerfile.  
  > **username_1**: Check your Dockerfile. Looks like you copy pasted the same line twice. If you look at step 2 and 3 they are both executing the same code. That's why you're getting the no dir found. You've already deleted it in step 2  
  
  ---
  
  ## 4 answers
  
  ### Answer by username_0 on 2017-04-02. Score: 1 | Accepted answer
  
  A solution is to remove the `not empty directory` using `find`:
  
  **Dockerfile**
  
  ```
  FROM alpine
  
  RUN mkdir dir && cd dir && wget http://google.com && cd / && echo -e "BEFORE\n" && ls && find /dir -delete && echo -e "\nAFTER\n" && ls
  
  ```
  
  **Outcome**
  
  ```
  Sending build context to Docker daemon  2.048kB
  Step 1/2 : FROM alpine
   ---> 4a415e366388
  Step 2/2 : RUN mkdir dir && cd dir && wget http://google.com && cd / && echo -e "BEFORE\n" && ls && find /dir -delete && echo -e "\nAFTER\n" && ls
   ---> Running in ba93a1742a76
  Connecting to google.com (172.217.20.110:80)
  Connecting to www.google.nl (172.217.20.99:80)
  index.html           100% |*******************************| 11092   0:00:00 ETA
  
  BEFORE
  
  bin
  dev
  dir
  etc
  home
  lib
  media
  mnt
  proc
  root
  run
  sbin
  srv
  sys
  tmp
  usr
  var
  
  AFTER
  
  bin
  dev
  etc
  home
  lib
  media
  mnt
  proc
  root
  run
  sbin
  srv
  sys
  tmp
  usr
  var
   ---> 2e3109285a2d
  Removing intermediate container ba93a1742a76
  Successfully built 2e3109285a2d
  
  ```
  
  > **Comments:**
  > **username_2**: You have unnecessary stuff in there, I believe you missed the point in username_6's answer - the problem is not the `-rf` options to the `rm` cmd.  
  > **username_0**: If I specify the whole path /path/to/dir and run it from / it still fails even with rf. I had to remove all the content from the folder.  
  > **username_2**: Are you saying `rm -rf` doesn't work and one has to manually empty every dir before deleting the dir? Very odd.  
  > **username_0**: The `rm -rf` does not work indeed. I had to use `find /path -delete`  
  
  ---
  
  ### Answer by username_6 on 2017-04-02. Score: 19
  
  `mkdir dir && cd dir && wget http://google.com && rm -rf dir` doesn't do what you think it does.
  
  Let's break it down:
  
  1. `mkdir dir` creates `dir`.
  2. `cd dir` changes directory into it.
  3. `wget http://google.com` downloads google.com inside `dir/`.
  4. `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 `cd`ed 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`](https://stackoverflow.com/q/17891981/120999). 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.
  
  > **Comments:**
  > **username_6**: Sure it's possible to remove directories; you just specified the wrong path.  
  > **username_6**: It's a bit of a strange error, considering that that's precisely what `rm -r` is intended to address.  You can probably add `-f` in this case, but I would do some further investigation to see what exactly is in that directory (e.g. an `ls -A`).  But you've gone past the original question at this point.  
  
  ---
  
  ### Answer by username_3 on 2017-12-30. Score: 7
  
  Recent Dockerfile spec allows for multiple FROM statements.
  
  <https://docs.docker.com/engine/userguide/eng-image/multistage-build/>
  
  Using this approach, you can retain your compilation results to a pure runtime environment.
  
  > **Comments:**
  > **username_4**: My situation is that - due to security reasons I am downloading the packages in the intermediate layer. Then, ADD'ing them to the final image. Followed by using RUN command to install the packages and delete the packages. My goal is to delete the downloaded packages once the RUN command installs them. Is there any way to a) combine the ADD and RUN into one layer; b) remove the ADD layer?  
  
  ---
  
  ### Answer by username_2 on 2017-04-03. Score: 6
  
  Building on username_6 username_6's answer, which correctly identified the root cause of the problem - the `dir` reference by relative path when attempting to empty or delete that directory depends on the working directory at the time, which was not correctly set in the cases mentioned in the OP.
  
  So there are 2 solutions available:
  
  * set the proper working dir prior to executing the `dir` removal:
  
    ```
      RUN mkdir dir && cd dir && wget http://google.com && cd .. && rm -rf dir
  
    ```
  * use a `/dir` full path reference to that directory instead. But with care (adjust if needed) if used in cases just similar, but not identical to this one, since this approach assumes the initial working dir was `/`:
  
    ```
      RUN mkdir dir && cd dir && wget http://google.com && rm -rf /dir
  
    ```
  
  > **Comments:**
  > **username_5**: Hmm. Why not `rm -rf ../dir`? That avoids the absolute path reference  
  > **username_2**: @username_5 it *might* work, but it feels weird (cutting the branch you're sitting on?)  
  > **username_5**: That's true; but it works essentially the same way when you specify an absolute path. FWIW, I've done this before, in an interactive shell. `ls` tends to lose its meaning... ;-) You can even `rm -rf ../dir && mkdir ../dir && cd ../dir`, which puts you in an new, empty (valid) folder  
  > **username_2**: @username_5 You're right, that's why I said `it feels` - it's just a feeling :)  
  
  ---
  
  