Docker cleanup script

Vaibhav UpareVaibhav Upare
3 min read

I created a production-safe shell script that helps clean up unused Docker resources like stopped containers, dangling images, unused volumes, and networks. This is important in a real-time production environment to optimize disk usage and prevent performance issues caused by leftover Docker artifacts.

Here’s a breakdown of the script:

βœ… Enhanced cleanup-docker.sh with --dry-run Mode

#!/bin/bash

# ==============================
# vaibhav upare
# Docker Cleanup Script (Safe for Production)
# - Supports --dry-run for first-time safe checks
# - Deletes:
#   - Stopped containers
#   - Dangling images
#   - Unused volumes
#   - Unused networks
# ==============================

set -e

DRY_RUN=false

if [[ "$1" == "--dry-run" ]]; then
  DRY_RUN=true
  echo "πŸ” Running in DRY RUN mode β€” No deletions will occur."
  echo
elif [[ -n "$1" ]]; then
  echo "❌ Invalid option: $1"
  echo "Usage: $0 [--dry-run]"
  exit 1
fi

echo "πŸ“¦ Disk usage BEFORE cleanup:"
docker system df
echo

if $DRY_RUN; then
  echo "πŸ§ͺ [Dry Run] These are the resources that would be removed:"
  echo
  echo "Containers to be removed:"
  docker ps -a -f status=exited

  echo
  echo "Dangling images to be removed:"
  docker images -f dangling=true

  echo
  echo "Unused volumes to be removed:"
  docker volume ls -f dangling=true

  echo
  echo "Unused networks to be removed:"
  docker network ls | grep "bridge" | grep -v "docker0"

  echo
  echo "⚠️ No changes have been made. Run the script WITHOUT '--dry-run' to apply cleanup."
  exit 0
fi

# === ACTUAL DELETION BELOW ===
echo "πŸ—‘οΈ Removing stopped containers..."
docker container prune -f

echo "πŸ—‘οΈ Removing dangling images..."
docker image prune -f

echo "πŸ—‘οΈ Removing unused volumes..."
docker volume prune -f

echo "πŸ—‘οΈ Removing unused networks..."
docker network prune -f

echo
echo "πŸ“¦ Disk usage AFTER cleanup:"
docker system df
echo
echo "βœ… Docker Cleanup Completed Successfully."

πŸ§ͺ Usage

Run in safe mode (dry run) first:

$ ./cleanup-docker.sh --dry-run

πŸ” Running in DRY RUN mode β€” No deletions will occur.

πŸ“¦ Disk usage BEFORE cleanup:
TYPE            TOTAL     ACTIVE    SIZE      RECLAIMABLE
Images          10        5         3.2GB     1.1GB (35%)
Containers      5         1         400MB     300MB (75%)
Local Volumes   4         2         800MB     400MB (50%)
Build Cache     -         -         150MB     150MB

πŸ§ͺ [Dry Run] These are the resources that would be removed:

Containers to be removed:
123abc456def    some_app_container   Exited (0) 2 days ago
789ghi012jkl    test_service         Exited (0) 4 days ago

Dangling images to be removed:
<none>          <none>              abcdef123456   2 weeks ago   300MB

Unused volumes to be removed:
my_old_volume

Unused networks to be removed:
bridge          br-f1a2b3c4d5e6

⚠️ No changes have been made. Run the script WITHOUT '--dry-run' to apply cleanup.
  • πŸš€ Actual Cleanup Output

      $ ./cleanup-docker.sh
    
      πŸ“¦ Disk usage BEFORE cleanup:
      TYPE            TOTAL     ACTIVE    SIZE      RECLAIMABLE
      Images          10        5         3.2GB     1.1GB (35%)
      Containers      5         1         400MB     300MB (75%)
      Local Volumes   4         2         800MB     400MB (50%)
      Build Cache     -         -         150MB     150MB
    
      πŸ—‘οΈ Removing stopped containers...
      Deleted Containers:
      123abc456def
      789ghi012jkl
    
      πŸ—‘οΈ Removing dangling images...
      Deleted Images:
      abcde12345: <none>
    
      πŸ—‘οΈ Removing unused volumes...
      Deleted Volumes:
      my_old_volume
    
      πŸ—‘οΈ Removing unused networks...
      Deleted Networks:
      br-f1a2b3c4d5e6
    
      πŸ“¦ Disk usage AFTER cleanup:
      TYPE            TOTAL     ACTIVE    SIZE      RECLAIMABLE
      Images          7         5         2.5GB     400MB (16%)
      Containers      1         1         100MB     0B (0%)
      Local Volumes   2         2         400MB     0B (0%)
      Build Cache     -         -         150MB     150MB
    
      βœ… Docker Cleanup Completed Successfully.
    

    "To make the script production-safe, I added a --dry-run option. This lets the user preview what will be deleted without actually performing the cleanup. Only when run without the flag does the script proceed with deletion, which is ideal for cautious DevOps operations in live environments."

0
Subscribe to my newsletter

Read articles from Vaibhav Upare directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Vaibhav Upare
Vaibhav Upare

"Passionate DevOps Engineer dedicated to crafting robust, scalable, and automated solutions for seamless software delivery. With expertise in cloud technologies, CI/CD pipelines, and infrastructure as code, I thrive on optimizing workflows and driving collaboration between development and operations teams. Let's build together for continuous innovation and efficiency."