How to Effectively Remove Docker Images and Containers

Docker has revolutionized how we build, package, and deploy applications by providing a lightweight and portable container runtime. Throughout the development process, you‘ll likely end up with a large number of Docker images and containers on your system. These can quickly consume significant disk space and resources, so it‘s important to clean them up periodically. In this article, we‘ll dive deep into everything you need to know to effectively remove Docker images and containers.

Understanding Docker Images and Containers

Before we get into the how, let‘s make sure we understand the what and why. Docker images are the blueprints from which containers are launched. They are made up of read-only layers that define the application and its dependencies. When you start a container, Docker creates a thin writable layer on top of the image layers.

Containers are the runnable instances of images. You can have many containers based off the same image. Containers encapsulate the application process and its isolated view of the operating system.

Over time, as you iterate on your application and rebuild images, you‘ll accumulate old image versions. Similarly, as you start and stop containers, the container instances will remain on disk even when not running. This is why cleaning up unused images and containers is necessary to reclaim disk space and keep your Docker environment tidy.

Removing Individual Docker Images

To delete a specific Docker image, you‘ll use the docker rmi command followed by the image ID or tag. First, list the images on your system:

$ docker images
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
myapp               latest              abc123def456        14 minutes ago      428MB
node                12                  0b5da1e4b876        6 days ago          918MB
nginx               alpine              377c0837328f        2 weeks ago         19.7MB

Then, remove an image by referencing its ID:

$ docker rmi abc123def456
Untagged: myapp:latest
Deleted: sha256:abc123def456...

You can also remove multiple images at once:

$ docker rmi abc123def456 0b5da1e4b876

If an image is tagged in multiple repositories, you must use the repository:tag notation or the image ID to remove it. Using just the tag will only untag the image, not delete it.

When deleting images, Docker will throw an error if the image is being used by any containers, including stopped ones. You‘ll need to remove the dependent containers first.

Removing Docker Containers

To delete a Docker container, use the docker rm command with the container ID or name. First, list your containers:

$ docker ps -a
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS                      PORTS               NAMES
d7e1d3a87567        myapp:latest        "docker-entrypoint.sā€¦"   18 minutes ago      Exited (0) 17 minutes ago                       mycontainer

Then, remove the container:

$ docker rm d7e1d3a87567
d7e1d3a87567

You can only remove stopped containers. If the container is still running, you‘ll get an error. Force remove a running container with the -f flag:

$ docker rm -f d7e1d3a87567 

Just like with images, you can delete multiple containers at once by providing their IDs/names.

Batch Removing All Unused Images and Containers

As you can imagine, removing images and containers one by one can be tedious. Docker provides the docker system prune command to clean up unused images, containers, volumes, and networks with a single command:

$ docker system prune
WARNING! This will remove:
  - all stopped containers
  - all networks not used by at least one container
  - all dangling images
  - all build cache
Are you sure you want to continue? [y/N] y
Deleted Containers:
d7e1d3a87567db...
f08dbbe0db0e7e...

Deleted Images:
untagged: myapp@sha256:abc123...
deleted: sha256:abc123def456...
untagged: node@sha256:def456...
deleted: sha256:def456abc123...

Total reclaimed space: 1.5GB

By default, this will remove:

  • All stopped containers
  • All networks not used by at least one container
  • All dangling images (layers with no relationship to tagged images)
  • All build cache

For a more aggressive clean, pass the -a flag to remove all unused images, not just dangling ones.

You can also prune just images or just containers rather than the whole system:

$ docker container prune
$ docker image prune

Removing Images in a CI/CD Pipeline

Cleaning up old images is especially important in automated build pipelines, where a VM worker may process many builds over time. Leaving old images will slowly eat away at disk space until there is none left.

Here is an example of how to add a clean up step to a Jenkins declarative pipeline:

pipeline {
  agent any
  stages {
    stage(‘Build‘) {
      steps {
        sh ‘docker build -t myapp:$BUILD_NUMBER .‘ 
      }
    }
    stage(‘Push‘) {
      steps {
        sh ‘docker push myrepo/myapp:$BUILD_NUMBER‘
      }
    }
    stage(‘CleanUp‘) {
      steps {
        sh ‘docker system prune -f‘  
      }
    }
  }
}

The -f flag automatically confirms the deletion without prompting.

Avoiding the `–rm` Argument on `docker run`

You may have seen the advice to use --rm when running containers to avoid having to manually delete them later:

$ docker run --rm -d --name mycontainer myimage 

However, this practice is not recommended for a few reasons:

  1. You lose the ability to inspect the container‘s logs or filesystem after it exits. This can make debugging issues more difficult.

  2. Orchestrators and CI tools typically expect containers to remain after they exit for logging and auditing. Deleting them immediately can break integrations.

  3. It doesn‘t actually solve image/layer cleanup, which is a larger concern for disk usage.

Instead, leave off --rm and periodically run docker container prune -f to retroactively clean up stopped containers.

Removing Images That Have Multiple Tags

Sometimes an image layer will be shared by multiple tagged images in different repositories. For example:

REPOSITORY                TAG                 IMAGE ID            CREATED             SIZE
myapp                     v1                  abc123def456        14 minutes ago      428MB
myapp                     latest              abc123def456        14 minutes ago      428MB
company/myapp             v1                  abc123def456        14 minutes ago      428MB

All three tagged images share the same underlying layer abc123def456. Removing any of the individual tags will untag that image but not remove the actual layer:

$ docker rmi myapp:v1
Untagged: myapp:v1

To completely remove the image layer, you must explicitly target the IMAGE ID:

$ docker rmi abc123def456
Untagged: myapp:latest
Untagged: company/myapp:v1
Deleted: sha256:abc123def456...

This will untag the image from all repositories and delete the underlying layer.

Saving and Loading Docker Images

In some cases, you may want to remove images from your local machine to free up space but still keep them around for future use. Two commands let you save images to tar files and load them back later: docker save and docker load.

To save an image:

$ docker save myimage:latest > myimage.tar

Then, to remove it:

$ docker rmi myimage:latest

And later, load it back in when needed:

$ docker load < myimage.tar

This can be handy for keeping base images you use for builds even if you don‘t always actively need them in your daemon.

Conclusion

We covered a lot! To recap:

  • Remove individual images with docker rmi and containers with docker rm
  • Clean up unsed images and containers in bulk with docker system prune
  • Target image IDs to fully remove shared layers across multiple tags
  • Incorporate container clean up into automated build pipelines
  • Avoid using the --rm argument to docker run
  • Save images to files if you need to remove them temporarily

Taking the time to prune your Docker environment will keep it lean and efficient. Working with a streamlined set of images and containers makes development and debugging easier in the long run. I encourage you to set up periodic Docker clean up on your development machines and build servers. Your future self will thank you!

Similar Posts