How to remove a directory in docker?

When you can't seem to remove a directory, here are two possibilities:

  1. User confusion between images and containers. Each docker run creates a new container, and any changes in containers, like removing a directory, or running something that modifies the file system, are isolated from the original image, and all other containers.
  2. Aufs layering bug/feature. Look at docker info to see if you are using Storage Driver aufs or imagemapper. To reinstall docker to use imagemapper: backup any irreplaceable, unique images to tar files, remove docker.io, install lxc-docker from the ppa as described in the official install docs and change /etc/default/docker to contain DOCKER_OPTS="--storage-driver=devicemapper"

It is also probably an anti-pattern to commit directories and then remove them because that data may still be in there somewhere. Even if it disappears from the file system, it could still be wasting space internally.

Docker images are built in layers, each commit is a layer.
To see this, try docker history <image> to see what is in your image.

The first case is deserving of a short, simple example, but it looks like you are possibly experiencing the second case.

Images vs. Containers and removing directories

Let's create a private image called mystuff from ubuntu:14.04 and, later below, try to rm -rf /opt:

$ docker run -it ubuntu:14.04 /bin/bash
root@435e68479c5b:/# ls
bin  boot  dev  etc  home  lib  lib64  media  mnt  opt  proc  root  run  sbin  srv  sys  tmp  usr  var
root@435e68479c5b:/# exit
$ docker commit 435e6 mystuff

Let's look inside (-t is only used here for pretty printing on one line):

docker run -t mystuff ls
bin  boot  dev  etc  home  lib  lib64  media  mnt  opt  proc  root  run  sbin  srv  sys  tmp  usr  var

Now let's try to remove /opt (usually that is optional stuff, safe to remove):

docker run -t mystuff rm -rf /opt

And then look inside for it, and it is still there!!! (seems like the reported problem):

docker run -t mystuff ls
bin  boot  dev  etc  home  lib  lib64  media  mnt  opt  proc  root  run  sbin  srv  sys  tmp  usr  var

What happened?

  • each time docker run mystuff is used, it makes a new container from the image mystuff
  • Changes to the image are not committed unless you use docker commit

If you look in the container, the changes are there:

docker ps -a
... lots of stuff...
e9e8be13d928        mystuff:latest              "rm -rf /opt"          2 minutes ago        Exited (0) 2 minutes ago                                  nostalgic_archimedes    

Get a tarball out and look for opt, grep it for dir beginning with opt, it isn't there!:

docker export e9e8 | tar tv | grep ^opt

Note: e9e8 is particular to my run of this example. To refer to a container, you can use part of the hex string from docker ps in the first col.

Now I commit the container that has the rm -rf change into a new image noopt:

docker commit e9e8 noopt

And look inside a container created from noopt:

docker run -t noopt ls
bin  boot  dev  etc  home  lib  lib64  media  mnt  proc  root  run  sbin  srv  sys  tmp  usr  var

And sure enough, opt is gone!

But because docker images are in layers, distributing noopt will include /opt in an earlier historical image, so you can't keep other people from getting it back:

docker history noopt
IMAGE               CREATED             CREATED BY                                      SIZE
bc4e69f9e871        59 minutes ago      rm -rf /opt                                     0 B
d198d23dab38        About an hour ago   /bin/bash                                       3 B
04c5d3b7b065        9 days ago          /bin/sh -c #(nop) CMD [/bin/bash]               0 B
d735006ad9c1        9 days ago          /bin/sh -c sed -i 's/^#\s*\(deb.*universe\)$/   1.895 kB
70c8faa62a44        9 days ago          /bin/sh -c echo '#!/bin/sh' > /usr/sbin/polic   194.5 kB
c7b7c6419568        9 days ago          /bin/sh -c #(nop) ADD file:d4aab24fc178303dc0   192.5 MB
511136ea3c5a        18 months ago                                                       0 B

To get back to the layer before /opt was removed, we just need to pick out d198d... and run it

docker run -t d198d23dab38 ls
bin  boot  dev  etc  home  lib  lib64  media  mnt  opt  proc  root  run  sbin  srv  sys  tmp  usr  var

Summary:

  • Docker has containers and images.
    • Images are intended to be more permanent.
    • Images are created in layers called commits, similar in concept to git repositories
    • Containers are created from images, and changes in containers are not kept in images (unless explicitly committed)

Docker also has a great build system that should have been used here. Whoever wrote that script should instead learn about docker build and write a proper Dockerfile

Tags:

Docker

Ubuntu