Containers – Clean up your House
Introduction
In this post I am going to revisit some of the most basic commands of the Docker CLI. But don’t worry, you should still read this post since I am going to use that “basic” knowledge to discuss some advanced methods on how to keep your Docker environment clean. And, as we all know, only an orderly environment keeps us productive.
Stopping and Removing Containers
As we play around with containers the list of running instances or instances that are in stopped
or exited
status grows longer and longer. This can lead to some serious memory and performance problems if we do not pay attention.
First let’s repeat some of the basic Docker commands that help us discover what’s currently running or hanging around in our system. To get a list of the currently running containers we use the command
docker ps
This will list all the currently running containers on our system (or host). If we are using Docker for Mac or Docker for Windows that will be the mini-VM which represents the Docker Host on our development machine.
In the image above we can see that I have currently 2 containers running on my system. One with Mongo DB and one with MySQL. The list shows the columns ID
, Image
, Command
, Created
, Status
, Ports
and Name
.
- Image is the name of the Docker image from which I created the container(s)
- Name is the name of the container itself and needs to be unique
- ID is the unique generated ID of the Docker container instance
- Status tells us in what status the container currently is. It can be
Created
,Up
(Running), orExited
ID and Name are most important to us when we try to manipulate a container, say stop it. If I want to e.g. stop the MySQL container I can do this using either of the following commands
docker stop mysql
or docker stop fc3e2d9e6e99
Note that I do NOT have to provide the full ID (i.e. fc3e2d9e6e99) to the command. Usually the first two to three characters are enough. Thus the following command works as well
docker stop fc
This is very convenient since it avoids us to have to type a lot.
If we now issue a docker ps
we won’t see the mysql
container anymore. The command only shows us the running containers. But MySQL is now in Exited
status and thus not included in the list. If we want to see all containers, including the exited ones we have to add the command line parameter -a
or --all
to the command; thus
docker ps -a
If we do so we see this
Note the status of the mysql
container which is Exited
.
It is very important to know that the name of a container has to be unique. That means that in the above example I cannot start another container with the name mysql
even thought the MySQL container is in Exited
status and not running. We first have to remove this container. We can do so using
docker rm mysql
or docker rm fc3e2d9e6e99
Only then is the MySQL container completely gone and I can (if I want to) reuse the name mysql
for another container.
Please also note that I can only remove a container that is in Exited
(or stopped) status. That is, if I have a running container then I need to first stop it and then I can remove it. That is sometimes a bit too much effort and therefore I can use a force remove to stop and remove a container in one single command. If I want to do this with my mongo
container the command would then be
docker rm -f mongo
Notice the -f
parameter. I could also use --force
instead.
Stopping or removing multiple containers
Often times we have a bunch of containers running and want to stop or remove them all at once without having to type the respective command over and over for each instance. There we can use the fact that most of the Docker commands can deal with a list of items. Let’s see how we can forcibly remove all containers currently running or hanging in our system
docker rm --force $(docker ps --all --quiet)
The above combined command uses docker ps
with --all
and --quite
to generate a list of all IDs of the containers on my system. This list is then consumed by the docker rm --force
command. And voila, all containers are gone.
As always, I can also use the shorter form of arguments and even combine them. Thus instead of writing --all --quiet
I can instead use -a -q
or even -aq
. Nice. So my short form of the above command is
docker rm -f $(docker ps -aq)
Much less typing – I love it.
Since I use the above command so often, I have created an alias for it in my .bash_profile
alias drmf='docker rm -f $(docker ps -aq)'
Cleaning up Images
As we work with Docker, over time we download a lot of images and we also generate a fair amount of images which all take up space and make the list of images looking messy when issuing the command
docker images
If I run the above command on my laptop currently I get the following output
As you can see, that’s a big mess and clearly deserves some cleanup. With the Docker CLI we can of course also remove specific obsolete images as follows
docker rmi [image-id]
For example I could remove the last image (the top one) in the list using
docker rmi 6f3
If I have many images to delete I can provide a list of IDs instead to the docker rmi
command. Once again it is useful to combine a few shell commands to achieve the goal. Let’s say I want to delete all images that have a name and/or tag of none, then I can use this command to do so
docker rmi $(docker images | grep "<none>" | awk '{print $3}')
What does this command do? First let’s look into the part in parentheses: we generate a list of all images using docker images
pipe them into the grep "<none>"
command which will filter out the lines form the list which contain “none” and then we pipe the result into the awk
command. The awk
filters out the 3rd column of the list which happens to be the IDs. Now having this list of IDs we feed them into the docker rmi
command. Job done.
Again, since I use this command so often I have created an alias/function in my bash profile for it
dclean() { docker rmi -f $(docker images | grep $1 | awk '{print $3}'); }
With this I can enter the following command in my console to achieve the same result
dclean "<none>"
which is way easier to remember and much shorter to type.
The docker images
command also has the parameter --quiet
to just output the list of IDs of all images. I can use this fact to create a simple command to cleanup all images that are currently cached on my Docker host
docker rmi $(docker images --quiet)
After I have done this my Docker Host is clean and pristine.
Sometimes Docker does not allow me to delete an image. Most often this is the case if I have still a container running that uses this image. Thus I have to first remove all containers before I can cleanup all my images.
Volumes
If we are using volumes with our Docker containers we might over time have some orphaned volumes hanging around in our system that occupy a lot of space. The consequences might be that all of a sudden we cannot start a new container anymore. To me it happened with the MongoDB container. Although I had no other containers running and very few images on my system the Mongo container would simply refuse to start and tell me that there is not enough space for it to create his journal file. The reason was, guess what, that I had plenty of orphaned volumes still hangign around.
We can use this command to list all the volumes on our system
docker volume ls
On my machine this looks like this
We can use the docker volume rm [volume name]
command to remove individual volumes. Note that the volume name is often a long hash code and in this case we have to use the whole code as name; we cannot shorten it the same way as we can shorten the ID of an image or container in the context of certain Docker commands. Thus if I want to delete the first volume in the list I have to issue this
docker volume rm 0d62e958fc4b9b63614e3ef0e024472880e946364bb29c42686914e6574bc238
If we want to remove all orphaned containers at once we can use this command
docker volume rm $(docker volume ls | awk '{print $2}')
Once we have removed all unnecessary volumes our system is clean and light weight again and in my particular case the mongo container would start happily as expected.
Summary
In this post I have discussed various techniques and commands which allow us to keep our Docker environment clean and pristine. Three things we need to watch out for: containers that are either running or in status Exited
, Docker images that are obsolete and finally orphaned Docker volumes.
I am fully aware that I have repeated and discussed some of the basic commands of the Docker CLI yet I am not ashamed of it since only if I master the basic concepts blindly, I can also tackle and solve the more tricky problems in and around containers.