Lewati ke konten
Rama's logo Qisthi Ramadhani
Go back

My Epic Quest to Remove Docker Images: A Guide to Slaying Digital Clutter (and Common Errors)

Alright, let’s have a little heart-to-heart. You, me, and that ever-growing, slightly terrifying list of Docker images cluttering up your machine. My name is Rama, and if you’re anything like me, your Docker environment sometimes resembles my garage back in Magetan—full of half-finished projects, things I swear I’ll use again someday, and a few mysterious items I don’t even remember acquiring. 😅

It was a Tuesday. Or maybe a Wednesday? The days blur when you’re deep in the code trenches. I was trying to spin up a new container for a slick little Remix project, and my terminal shot back an error that was the digital equivalent of my laptop sighing and shaking its head: No space left on device.

I stared at the screen. “No space? Impossible!” I have a top-of-the-line Mac with a terabyte of SSD. What was eating all my precious disk space? I ran df -h and my jaw hit the floor. My Docker directory was a behemoth, a digital kaiju greedily consuming hundreds of gigabytes. 😱

That was my wake-up call. I had been a digital hoarder. Every docker build without a --rm, every experimental image pulled from Docker Hub, every tagged and untagged version of my Laravel projects—they were all there, having a silent, disk-hogging party. That day, I didn’t just learn how to remove docker image; I went on a full-blown decluttering crusade. I learned the commands, wrestled with the errors, and emerged victorious, with a lean, mean, and clean Docker setup.

So, grab a coffee (or maybe something stronger), and let me be your guide. In this post, I’m going to share everything I learned on my quest. We’ll cover not just the simple commands to delete docker images, but the whole shebang: how to nuke everything at once, why you can’t delete an image that a container is using, and how to troubleshoot those soul-crushing errors that make you question your life choices. This is your ultimate survival guide to Docker cleanup. Let’s dive in!

First Things First: Why Is My Docker Full of Junk Anyway?

Before we start swinging the digital sledgehammer, it helps to understand how we got into this mess. Think of Docker images like cookie cutters. Every time you want to make a cookie (a container), you need the cutter (the image).

Over months of development, this digital debris accumulates. Each image might be a few hundred megabytes, but it adds up faster than you can say “It works on my machine.” The result? That dreaded No space left on device error, a sluggish system, and a general feeling of digital claustrophobia.

The Basic Toolkit: Your First Steps to a Cleaner Docker

Let’s start with the fundamentals. These are the commands you’ll use 90% of the time. Think of them as your trusty screwdriver and wrench for everyday Docker maintenance.

Listing What You’ve Got: The docker images Command

You can’t clean a room with your eyes closed. The first step is to see exactly what horrors you’re hoarding. Open your terminal and run:

docker images

or the slightly more modern syntax:

docker image ls

You’ll get a list that looks something like this:

REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
my-laravel-app      latest              a1b2c3d4e5f6        2 hours ago         1.2GB
my-remix-app        v1.2                f6e5d4c3b2a1        3 days ago          850MB
<none>              <none>              c3b2a1d4e5f6        4 days ago          780MB
postgres            14-alpine           b2a1c3d4e5f6        2 weeks ago         235MB
redis               latest              a1b2c3d4e5f6        3 months ago        117MB

Let’s break this down:

Notice that <none> repository? That’s a classic dangling image. It’s a prime candidate for deletion.

The Scalpel: How to Remove a Single Docker Image

Alright, you’ve identified your first target. Let’s say it’s that old version of your Remix app you no longer need. To delete a docker image, you use the docker rmi command, which stands for “remove image.”

The syntax is simple: docker rmi [IMAGE_ID_OR_NAME:TAG]

Using our example list, you could do it in a couple of ways:

  1. Using the IMAGE ID (The most precise way):

    docker rmi f6e5d4c3b2a1
  2. Using the REPOSITORY and TAG:

    docker rmi my-remix-app:v1.2

I personally prefer using the IMAGE ID. Why? Because it’s unique. Sometimes you might have multiple tags pointing to the same image ID, and using the name:tag combo can sometimes have unintended consequences if you’re not paying attention. But for a simple cleanup, either works fine.

The modern, more verbose (and arguably clearer) syntax is also available:

docker image rm my-remix-app:v1.2

It does the exact same thing as docker rmi. It’s really a matter of personal preference, like tabs vs. spaces. (It’s tabs, by the way. Just kidding… mostly. 😉)

“Help! It Won’t Delete!” – The Dreaded “In Use by a Container” Error

This is the part where everyone gets stuck. You triumphantly type docker rmi a1b2c3d4e5f6, hit enter, and Docker slaps you with this:

Error response from daemon: conflict: unable to remove repository reference "my-laravel-app:latest" (must force) - container a8b7c6d5e4f3 is using its referenced image a1b2c3d4e5f6

Translation: “Whoa there, cowboy! You can’t sell the car while someone is still driving it.”

You cannot remove a docker image if a container—even a stopped one—is based on it. Docker does this to protect you from accidentally breaking your running applications. This is where the process becomes a two-step dance.

Step 1: Find and Stop the Container

First, you need to see which containers are hanging around. To see currently running containers:

docker ps

or

docker container ls

But the sneaky ones are the stopped containers. They don’t show up with docker ps. To see all containers, running or stopped, you need to add the -a flag:

docker ps -a

You’ll see a list of containers. Find the one that’s using your image (the error message even gives you the container ID!).

Once you’ve found the container (let’s say its ID is a8b7c6d5e4f3), you need to stop it if it’s running:

docker stop a8b7c6d5e4f3

This sends a graceful shutdown signal. If the container is being stubborn, you can use the more aggressive kill command:

docker kill a8b7c6d5e4f3

Think of stop as politely asking someone to leave the party, and kill as calling security.

Step 2: Remove the Container

A stopped container is still a thing. It exists on your system, holding a reference to the image. You need to remove it.

docker rm a8b7c6d5e4f3

or the modern version:

docker container rm a8b7c6d5e4f3

Step 3: Try Deleting the Image Again

Now that the container is gone, the image is no longer in use. You can finally delete the docker image:

docker rmi a1b2c3d4e5f6

Success! The terminal will reply with a satisfying list of Untagged and Deleted SHAs, and you’ve reclaimed a little piece of your hard drive.

Level Up: Mass Deletion and Advanced Cleanup

Cleaning up images one by one is fine for a little spring cleaning. But what about after a six-month-long project where you’ve accumulated hundreds of images? You need bigger weapons. This is where we go from using a scalpel to wielding a chainsaw. metaphorical, of course. Please don’t take a chainsaw to your MacBook. 💻

The Nuclear Option: How to Delete ALL Docker Images

⚠️ WARNING: This is a destructive command. There is no “undo” button. Use this with extreme caution. It will delete ALL your Docker images—the good, the bad, and the ugly. Only do this if you want a completely fresh start.

I remember the first time I did this. It was liberating. It was terrifying. It was like deleting your entire photo gallery because a few pictures were blurry. Effective, but you might lose some memories.

The command is a combination of two commands. First, docker images -q lists the IDs of all images, and only the IDs (the -q stands for “quiet”). Then, we pipe (|) that list into the docker rmi command.

docker rmi $(docker images -q)

or, for the modernists among us:

docker image rm $(docker image ls -q)

This command says, “Hey Docker, give me a list of every single image ID you have. Now, take that list and remove every single one of them.”

Docker will try its best, but it will still fail on any images currently being used by containers. To truly achieve a full reset, you need to stop and remove all containers first.

The Complete System Prune: The Professional’s Way to Clean House

So, how do we do a full reset safely and efficiently? You orchestrate a sequence of commands. This is my go-to “scorched earth” cleanup routine when I want to start fresh.

Step 1: Stop All Running Containers

First, we need to politely ask all the party guests to leave.

docker stop $(docker ps -aq)

Let’s break that down: docker ps -a lists all containers (running and stopped), and the -q flag gives us just their IDs. We pass that list to docker stop. This is the ultimate docker stop all containers command.

Step 2: Remove All Containers

Now that the party is over and everyone has left, we need to clean up the empty glasses and pizza boxes (the stopped containers).

docker rm $(docker ps -aq)

or, more explicitly:

docker container rm $(docker container ls -a -q)

This is the most effective way to delete all docker containers or remove all docker containers. With all containers gone, our images are now vulnerable.

Step 3: Delete All Docker Images

Now we can run our nuclear option from before, confident that no containers are protecting any images.

docker rmi $(docker images -q)

Step 4 (Optional but Recommended): Prune Everything Else

Even after all that, there can be leftover junk: build caches, unused networks, and those pesky dangling images. Docker has a magical, all-in-one cleanup command for this: docker system prune.

docker system prune -a --volumes

Running this command feels so good. It gives you a summary of all the junk it cleaned up and how much space you reclaimed. It’s the digital equivalent of a deep-clean detox for your system.

A Gentler Approach: docker image prune

If the “scorched earth” approach feels a bit too much, there’s a more civilized command: docker image prune.

docker image prune

By default, this command will only remove dangling images—those <none>:` ones we saw earlier. It’s a safe and easy way to get rid of the most obvious waste without touching any of your tagged, potentially useful images.

To be a bit more aggressive, you can add the -a flag:

docker image prune -a

This will remove all unused images (images not tied to a container), not just dangling ones. It’s essentially a safer, image-focused version of the docker system prune -a command. It won’t touch your containers, networks, or volumes.

Docker vs. Docker Compose: A Tale of Two Workflows

A lot of the confusion around cleanup, especially for developers like me working with complex stacks (hello, Laravel + React + Redis + Postgres!), comes from the interplay between docker and docker-compose. Let’s clear this up once and for all.

When it comes to cleanup, the same logic applies.

If you started your services with docker-compose up, you should stop them with docker-compose down.

docker-compose down

This command is a beautiful thing. It doesn’t just stop the containers defined in your docker-compose.yml file; it also removes the containers and any networks it created. It’s a one-command cleanup for your entire application stack.

To also remove the volumes (again, be careful with your precious data!), you can add the -v flag:

docker-compose down -v

Crucially, docker-compose down does NOT remove the images themselves. It only removes the containers. After you run docker-compose down, you still need to use the docker rmi or docker image prune commands we discussed earlier to actually delete the docker images that your Compose file used.

This separation is by design. Your application stack (the containers) is ephemeral, but the blueprints (the images) are meant to be more permanent so you can quickly spin the stack back up again.

Into the Weeds: Demystifying Dockerfiles and Common Errors

Now let’s put on our developer hats and talk about the source of all our images: the Dockerfile. A misconfigured Dockerfile is often the root cause of bloated images and frustrating errors. I’ve spent more hours than I care to admit staring at Dockerfile syntax, wondering where I went wrong. Let me save you some of that pain.

Dockerfile 101: A Recipe for Your App

A Dockerfile is just a text file with a set of instructions on how to build your image. Here’s a super simple example for a Laravel application, a world I live in every day at qisthi.dev.

# Stage 1: Build the frontend assets
FROM node:18-alpine AS assets

WORKDIR /app
COPY package.json yarn.lock ./
RUN yarn install
COPY . .
RUN yarn build

# Stage 2: Setup the PHP environment
FROM php:8.2-fpm-alpine AS app

# Install system dependencies & PHP extensions
RUN apk add --no-cache ... # install things like libzip-dev, etc.
RUN docker-php-ext-install pdo pdo_mysql zip ...

# Install Composer
COPY --from=composer/composer:latest-bin /composer /usr/bin/composer

WORKDIR /var/www/html

# Copy vendor files
COPY --from=assets /app/vendor /var/www/html/vendor

# Copy application files
COPY . .

# Copy built assets from the 'assets' stage
COPY --from=assets /app/public/build /var/www/html/public/build

# Set permissions
RUN chown -R www-data:www-data /var/www/html

# Expose port
EXPOSE 9000

# Set the entrypoint
CMD ["php-fpm"]

This is a multi-stage build, a fantastic technique for keeping final image sizes small. But let’s look at some key instructions and common trip-ups:

Troubleshooting Your Docker Environment on a Mac

As a Mac user, I’ve run into my fair share of platform-specific quirks. If you’re struggling with the install docker in mac process or running into errors, here are the usual suspects.

Installing Docker on macOS (install docker macos) is generally a breeze these days thanks to the Docker Desktop application. You download the .dmg file from the official Docker website, drag it to your Applications folder, and run it. It handles all the complex VM and networking setup for you. Gone are the days of docker-machine and VirtualBox headaches, and for that, I am eternally grateful. 🙏

My Final Confession and Your Docker Decluttering Vow

So, how much space did I reclaim on that fateful Tuesday? After stopping and removing all my containers, running docker system prune -a, and feeling a mix of terror and glee, I freed up over 250GB. Yes, you read that right. It was a digital hoard of epic proportions.

The biggest lesson I learned wasn’t just a set of commands. It was about adopting a new mindset: Docker hygiene. Just like you clean up your code, you need to clean up your development environment.

Here’s the vow I now live by, and I encourage you to take it too:

  1. I will be mindful when I docker build. I’ll use multi-stage builds to keep my final images lean. I’ll leverage layer caching properly to speed up my builds.
  2. I will use docker-compose down when I’m finished. When I’m done with a project for the day, I won’t just leave the containers running or stopped. I’ll tear down the stack to free up resources.
  3. I will run docker image prune regularly. Once a week, I’ll run a quick prune to get rid of any dangling images that have accumulated. It’s like taking out the digital trash.
  4. I will question every latest tag. The latest tag is mutable. It can change. For anything important, I’ll use a specific version tag (postgres:15.4-alpine) to ensure my builds are repeatable and predictable. This is key for good docker versioning.
  5. I will not fear the prune. I will understand the difference between docker image prune, docker system prune, and docker system prune -a --volumes. I will use the right tool for the job without accidentally nuking my precious database volumes.

Learning to masterfully remove docker images and manage your containers is a rite of passage for any developer. It takes you from being a casual Docker user to a true professional who understands and respects their tools and environment.

So go forth! Run docker images and take a long, hard look at what you’ve been hoarding. Start small. Delete a docker image you know you don’t need. Remove a few stopped containers. Run docker image prune. Feel the satisfaction of reclaiming that disk space.

Your laptop, your teammates, and your future self will thank you.


Share this post on:
LLM-friendly version:
Open in ChatGPT Open in Claude

Related Posts


Previous Post
My Epic Quest to Master PSQL: From 'Show Tables' to Dropping Everything (Accidentally, Of Course)
Next Post
My Epic SQL Saga: From Clumsy Queries to Database Dominance (And How You Can Get There Too!)