Sign inSign up

rinzlerfr/docker-cleaner

By rinzlerfr

•Updated 11 months ago

Image
0

494

rinzlerfr/docker-cleaner repository overview

⁠Docker Cleaner

╔══════════════════════════════════════════════════════════════╗
║                                                              ║
║    ██████╗  ██████╗  ██████╗██╗  ██╗███████╗██████╗         ║
║    ██╔══██╗██╔═══██╗██╔════╝██║ ██╔╝██╔════╝██╔══██╗        ║
║    ██║  ██║██║   ██║██║     █████╔╝ █████╗  ██████╔╝        ║
║    ██║  ██║██║   ██║██║     ██╔═██╗ ██╔══╝  ██╔══██╗        ║
║    ██████╔╝╚██████╔╝╚██████╗██║  ██╗███████╗██║  ██║        ║
║    ╚═════╝  ╚═════╝  ╚═════╝╚═╝  ╚═╝╚══════╝╚═╝  ╚═╝        ║
║                                                              ║
║         ██████╗██╗     ███████╗ █████╗ ███╗   ██╗           ║
║        ██╔════╝██║     ██╔════╝██╔══██╗████╗  ██║           ║
║        ██║     ██║     █████╗  ███████║██╔██╗ ██║           ║
║        ██║     ██║     ██╔══╝  ██╔══██║██║╚██╗██║           ║
║        ╚██████╗███████╗███████╗██║  ██║██║ ╚████║           ║
║         ╚═════╝╚══════╝╚══════╝╚═╝  ╚═╝╚═╝  ╚═══╝           ║
║                                                              ║
╚══════════════════════════════════════════════════════════════╝

⁠🧹 Automated Docker Cleanup Container

Reclaim disk space instantly with secure, one-shot Docker cleanup

License: MIT Docker Image Docker Pulls Shell Script Platform PRs Welcome


⁠📋 Table of Contents


⁠✨ At a Glance

🎯 Feature📊 Details
Execution ModeOne-shot (cron-ready)
SecurityNon-root, GID matching, no --privileged
Configurability15+ environment variables
Multi-HostDocker context support
SafetyDRY_RUN mode, conservative defaults
Performance~50MB memory, 30s-4min execution
PlatformsLinux, macOS (Docker daemon required)

Automated Docker cleanup container that reclaims disk space by removing unused containers, images, volumes, networks, and build cache. Designed for one-shot execution with secure, non-privileged access to Docker daemon.

🔑 Key Advantages:

  • ✅ Security First: No --privileged mode needed
  • ✅ Local Execution: Always cleans the host where it runs
  • ✅ Safe Defaults: Protects volumes and critical resources
  • ✅ Production Ready: Comprehensive logging and error handling

⬆️ Back to top⁠


⁠🤔 Why Docker Cleaner?

⁠The Problem

Docker accumulates disk space quickly:

  • Stopped containers pile up after deployments
  • Dangling images from builds consume GBs
  • Unused volumes remain after testing
  • Build cache grows indefinitely
⁠The Solution

docker-cleaner provides:

Featuredocker-cleanerdocker system pruneManual cleanup
One command✅✅❌
Scheduled execution✅❌❌
Multi-host support✅❌❌
Non-root security✅N/AN/A
Comprehensive logging✅⚠️❌
Configuration flexibility✅⚠️✅
DRY_RUN preview✅⚠️❌
⁠Use Cases
  • 🏠 Home Labs: Schedule weekly cleanups on Docker NAS/servers
  • 🔧 CI/CD: Reclaim space after builds in pipelines
  • 💻 Development: Keep local Docker environment lean
  • 🏢 DevOps: Manage cleanup across multiple hosts

⬆️ Back to top⁠


⁠🚀 Quick Start

# Pull latest version
docker pull rinzlerfr/docker-cleaner:latest

# Run complete cleanup
docker run --rm \
  -v /var/run/docker.sock:/var/run/docker.sock \
  -e PRUNE_ALL=true \
  -e PRUNE_VOLUMES=true \
  -e CLEANUP_VOLUMES=true \
  rinzlerfr/docker-cleaner:latest
⁠Build from Source
# Clone repository
git clone https://github.com/rinzlerfr/docker-cleaner.git
cd docker-cleaner

# Build image
docker build -t docker-cleaner .

# Run cleanup
docker run --rm \
  -v /var/run/docker.sock:/var/run/docker.sock \
  -e PRUNE_ALL=true \
  docker-cleaner
⁠Preview Before Cleaning
# Test with DRY_RUN mode (recommended first time)
docker run --rm \
  -v /var/run/docker.sock:/var/run/docker.sock \
  -e PRUNE_ALL=true \
  -e PRUNE_VOLUMES=true \
  -e CLEANUP_VOLUMES=true \
  -e DRY_RUN=true \
  rinzlerfr/docker-cleaner:latest

Expected output:

🧹 Docker Cleanup Container v1.0.0
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
⚙️  Configuration:
   • Mode: DRY_RUN (no deletion)
   • Cleanup: containers, images (all), volumes, networks, cache
   • Filters: none
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

🔍 [DRY_RUN] Would remove 15 stopped containers
🔍 [DRY_RUN] Would remove 8 unused images (2.3 GB)
🔍 [DRY_RUN] Would remove 3 unused volumes (450 MB)
🔍 [DRY_RUN] Would remove 2 unused networks
🔍 [DRY_RUN] Would remove build cache (1.1 GB)

📊 Total space reclaimable: 3.85 GB
✅ Dry-run completed successfully
⁠Using Docker Compose
# FULL CLEANUP - Cleans EVERYTHING (recommended)
docker-compose --profile full up docker-cleaner-full

# Default cleanup (conservative - volumes protected)
docker-compose up docker-cleaner

# Dry-run mode (preview without deletion)
docker-compose --profile dryrun up docker-cleaner-dryrun
⁠Shell Scripts
# Complete cleanup in one pass
./examples/cleanup-all.sh

# Complete guaranteed cleanup (2 passes - removes orphaned images)
./examples/cleanup-complete.sh

# Test with dry-run
DRY_RUN=true ./examples/cleanup-all.sh

⬆️ Back to top⁠


⁠🔧 How It Works

⁠Architecture Overview
┌─────────────────────────────────────────────────────────┐
│                    HOST MACHINE                         │
│                                                          │
│  ┌──────────────────────────────────────────┐          │
│  │     Docker Daemon (dockerd)              │          │
│  │                                           │          │
│  │  /var/run/docker.sock (GID: 998)        │          │
│  └─────────────┬────────────────────────────┘          │
│                │ Socket Access                          │
│                │ (via GID matching)                     │
│  ┌─────────────▼────────────────────────────┐          │
│  │  docker-cleaner Container                │          │
│  │  ┌────────────────────────────────────┐  │          │
│  │  │ 1. Detect socket GID (998)        │  │          │
│  │  │ 2. Create group with GID 998      │  │          │
│  │  │ 3. Add user to group              │  │          │
│  │  │ 4. Execute cleanup as non-root    │  │          │
│  │  └────────────────────────────────────┘  │          │
│  │                                           │          │
│  │  User: cleaner (UID 1000) ✅ Non-root   │          │
│  │  Group: docker (GID 998)  ✅ Socket access│          │
│  └───────────────────────────────────────────┘          │
│                                                          │
│  Result: Secure cleanup without --privileged            │
└─────────────────────────────────────────────────────────┘
⁠Local Execution Principle

⚠️ IMPORTANT: The container always runs on the host to be cleaned - it never connects to remote hosts.

When you use Docker contexts (e.g., docker context use nas), the Docker client on your machine sends the docker run command to the remote daemon, which then executes the container locally on that host. The volume mount /var/run/docker.sock:/var/run/docker.sock is interpreted by the execution host's daemon, not your client machine.

In other words: If you run this container while in NAS context, the container runs ON the NAS and mounts the NAS's socket, cleaning the NAS's Docker resources. Your client machine only displays the output.

⁠Docker Socket GID Matching

Instead of requiring --privileged mode, the container uses dynamic GID matching:

  1. Detect GID of /var/run/docker.sock at startup
  2. Create or reuse group with matching GID
  3. Add non-root user to this group
  4. Execute cleanup operations as non-root user with Docker access

This provides secure, non-root access to the Docker daemon without privileged mode.

⬆️ Back to top⁠


⁠🎯 Cleanup Levels

Cleans EVERYTHING except running containers and volumes in use:

docker run --rm -v /var/run/docker.sock:/var/run/docker.sock \
  -e PRUNE_ALL=true \
  -e PRUNE_VOLUMES=true \
  -e CLEANUP_VOLUMES=true \
  rinzlerfr/docker-cleaner:latest

What gets removed:

  • ✅ Stopped containers (exited, created)
  • ✅ Unused images (all, not just dangling)
  • ✅ Unused volumes (not mounted by containers)
  • ✅ Unused networks (not used by containers)
  • ✅ Build cache (intermediate layers)

What is protected:

  • ✅ Running containers
  • ✅ Volumes mounted by running containers
  • ✅ Networks used by running containers
  • ✅ Images used by running containers

⚠️ Important note: Docker checks image usage AT THE TIME of pruning. If you have stopped containers that are removed by cleanup, their base images remain because they were referenced at the time of verification. To remove these orphaned images, simply run docker-cleaner a second time.

⁠🛡️ Conservative (Default)

Conservative cleanup that protects volumes:

docker run --rm -v /var/run/docker.sock:/var/run/docker.sock \
  rinzlerfr/docker-cleaner:latest

What gets removed:

  • ✅ Stopped containers
  • ✅ Dangling images (untagged)
  • ✅ Unused networks
  • ✅ Build cache

What is protected:

  • ✅ ALL volumes (even unused)
  • ✅ Tagged images (even unused)
  • ✅ Running containers

⬆️ Back to top⁠


⁠⚙️ Configuration

All configuration is done via environment variables:

⁠Core Operations
VariableDefaultDescription
PRUNE_ALLfalseRemove all unused images (not just dangling)
PRUNE_VOLUMESfalseInclude volumes in cleanup ⚠️ DANGER
PRUNE_FORCEtrueSkip confirmation prompts
⁠Selective Operations
VariableDefaultDescription
CLEANUP_CONTAINERStruePrune stopped containers
CLEANUP_IMAGEStruePrune unused images
CLEANUP_VOLUMESfalsePrune unused volumes ⚠️
CLEANUP_NETWORKStruePrune unused networks
CLEANUP_BUILD_CACHEtruePrune build cache
⁠Filters
VariableDefaultDescription
PRUNE_FILTER_UNTIL(none)Remove resources older than duration
PRUNE_FILTER_LABEL(none)Filter by label (e.g., keep!=true)
⁠Logging
VariableDefaultDescription
LOG_LEVELINFOLog level: DEBUG, INFO, WARN, ERROR
LOG_FORMATtextOutput format: text or json
QUIETfalseMinimal output
⁠Execution Mode
VariableDefaultDescription
DRY_RUNfalsePreview without deleting

⬆️ Back to top⁠


⁠💡 Use Cases

⁠Use Case 1: Local Mac Cleanup
# One-time cleanup
docker run --rm -v /var/run/docker.sock:/var/run/docker.sock \
  rinzlerfr/docker-cleaner:latest

# Weekly cron job
0 2 * * 0 docker run --rm -v /var/run/docker.sock:/var/run/docker.sock \
  rinzlerfr/docker-cleaner:latest
⁠Use Case 2: Remote NAS Cleanup

Option A: Using --context flag (Recommended)

# Run cleanup on NAS without switching context
docker --context nas run --rm -v /var/run/docker.sock:/var/run/docker.sock \
  rinzlerfr/docker-cleaner:latest

# Your active context remains unchanged

Option B: Using context switching

# Switch to NAS context
docker context use nas

# Run cleanup (executes on NAS, cleans NAS Docker)
docker run --rm -v /var/run/docker.sock:/var/run/docker.sock \
  rinzlerfr/docker-cleaner:latest

# Switch back
docker context use default
⁠Use Case 3: CI/CD Pipeline Cleanup
⁠GitLab CI
cleanup:
  stage: post-build
  script:
    - docker run --rm -v /var/run/docker.sock:/var/run/docker.sock \
        rinzlerfr/docker-cleaner:latest
⁠GitHub Actions
name: Docker Cleanup
on:
  schedule:
    - cron: '0 2 * * *'

jobs:
  cleanup:
    runs-on: ubuntu-latest
    steps:
      - name: Run Docker Cleanup
        run: |
          docker run --rm \
            -v /var/run/docker.sock:/var/run/docker.sock \
            -e PRUNE_FILTER_UNTIL=168h \
            rinzlerfr/docker-cleaner:latest
⁠Use Case 4: Multiple Hosts Management
# Define contexts for each host
docker context create dev-server --docker "host=ssh://dev-server"
docker context create staging-server --docker "host=ssh://staging-server"

# Cleanup script for all hosts (using --context flag, recommended)
for ctx in default dev-server staging-server; do
  echo "Cleaning $ctx..."
  docker --context $ctx run --rm -v /var/run/docker.sock:/var/run/docker.sock \
    rinzlerfr/docker-cleaner:latest
done
# No need to restore context - it was never changed!

⁠Remote Docker Host Setup

To use docker-cleaner on remote Docker hosts via contexts, you need to configure remote access to the Docker daemon.

⁠Prerequisites

IMPORTANT: Remote Docker hosts must expose the Docker API on port 2375 (TCP) or 2376 (TLS).

The easiest and safest way to expose Docker remotely without modifying daemon configuration:

# On the remote Docker host, run:
docker run -d \
  --name docker-socat \
  --restart unless-stopped \
  --network host \
  -v /var/run/docker.sock:/var/run/docker.sock \
  alpine/socat \
  tcp-listen:2375,fork,reuseaddr unix-connect:/var/run/docker.sock

Security Notes:

  • This exposes Docker without authentication on port 2375
  • Only use on trusted networks (internal LAN, VPN)
  • For production environments, use SSH-based contexts or TLS authentication
  • Consider restricting access with firewall rules

Verify it's working:

# On remote host
docker ps | grep docker-socat

# From local machine
curl http://remote-host:2375/version
⁠Option 2: SSH-Based Context (Most Secure)

For production environments, use SSH-based contexts instead:

# No special configuration needed on remote host
# Just ensure SSH access is available

# Create SSH-based context
docker context create remote-nas \
  --docker "host=ssh://user@remote-host"

# Test it
docker --context remote-nas ps

Advantages:

  • Uses existing SSH authentication
  • Encrypted communication
  • No additional ports to open
  • Works with existing SSH keys
⁠Creating the Context

Once the remote host is configured (socat or SSH), create a Docker context:

# For TCP access (with socat)
docker context create nas \
  --docker "host=tcp://nas.local:2375"

# For SSH access (recommended)
docker context create nas \
  --docker "host=ssh://[email protected]"

# Verify the context
docker context ls
docker --context nas ps
⁠Using with docker-cleaner
# Run cleanup on remote host via context
docker --context nas run --rm \
  -v /var/run/docker.sock:/var/run/docker.sock \
  rinzlerfr/docker-cleaner:latest

For more details on context setup and security considerations, see docs/testing-guide.md⁠.

⁠Example Output
$ docker run --rm -v /var/run/docker.sock:/var/run/docker.sock \
    -e PRUNE_ALL=true -e PRUNE_VOLUMES=true -e CLEANUP_VOLUMES=true \
    rinzlerfr/docker-cleaner:latest

🧹 Docker Cleanup Container v1.0.0
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
⚙️  Configuration:
   • Mode: CLEANUP (deletion enabled)
   • Cleanup: containers, images (all), volumes, networks, cache
   • Filters: none
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

🗑️  Removing stopped containers...
    ✓ Removed 15 containers

🗑️  Removing unused images (all)...
    ✓ Removed 8 images
    ✓ Reclaimed 2.3 GB

🗑️  Removing unused volumes...
    ✓ Removed 3 volumes
    ✓ Reclaimed 450 MB

🗑️  Removing unused networks...
    ✓ Removed 2 networks

🗑️  Removing build cache...
    ✓ Removed cache
    ✓ Reclaimed 1.1 GB

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
📊 Summary:
   • Total space reclaimed: 3.85 GB
   • Operations: 5/5 successful
   • Exit code: 0
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
✅ Cleanup completed successfully

⬆️ Back to top⁠


⁠🔒 Security Considerations

⁠Risks

⚠️ WARNING: Mounting docker.sock grants equivalent root access to the host.

  • Container can start new containers, including privileged ones
  • Container can mount any host path
  • Container can read/write all Docker resources
⁠Mitigations
  1. Least Privilege Execution

    • Non-root user in container (UID 1000)
    • No --privileged flag required
    • GID matching for secure socket access
  2. Resource Protection

    • Label-based filters to protect critical resources
    • Running container protection (Docker's default)
    • Volume-in-use protection (Docker's default)
    • Conservative defaults (no volumes, no all images)
  3. Audit Trail

    • Comprehensive logging of all operations
    • Structured logging for SIEM integration
    • Security warnings about socket sharing
  4. Best Practices

    • Only run on hosts you control
    • Use trusted images
    • Review logs regularly
    • Test with DRY_RUN=true first
    • Use label filters to protect important resources
⁠Acceptable Use
  • ✅ Scheduled cleanup on development/staging hosts
  • ✅ CI/CD pipeline cleanup after builds
  • ✅ Manual cleanup on production (with caution and dry-run first)
  • ❌ Untrusted hosts
  • ❌ Multi-tenant environments without isolation

For detailed security documentation, see docs/security-guide.md⁠.

⬆️ Back to top⁠


⁠📊 Performance

⁠Execution Times

Expected execution times vary based on resource count:

Resource CountEstimated Time
Small (<50)~30 seconds
Medium (50-200)~1 minute
Large (200-1000)~2 minutes
Very Large (>1000)~4 minutes

Memory usage: ~50MB peak

⁠Exit Codes
  • 0: Success (all operations succeeded)
  • 1: Partial failure (some operations failed, some succeeded)
  • 2: Complete failure (cannot connect to Docker or all operations failed)

⬆️ Back to top⁠


⁠🐳 Docker Hub

The docker-cleaner image is automatically published to Docker Hub with each release:

# Pull latest version
docker pull rinzlerfr/docker-cleaner:latest

# Pull specific version
docker pull rinzlerfr/docker-cleaner:v1.0.0

# Run from Docker Hub
docker run --rm -v /var/run/docker.sock:/var/run/docker.sock \
  rinzlerfr/docker-cleaner:latest
⁠Available Tags
  • latest - Latest stable release
  • v1.0.0, v1.0, v1 - Semantic version tags
  • Multi-architecture support: amd64, arm64
⁠Automated Releases

Releases are triggered automatically when you push a version tag:

# Create and push a release tag
git tag -a v1.0.0 -m "Release v1.0.0"
git push origin v1.0.0

This triggers a GitHub Action that:

  • Builds multi-architecture images (amd64 and arm64)
  • Pushes to Docker Hub with semantic version tags
  • Updates Docker Hub description with README content

⬆️ Back to top⁠


⁠🛠️ Development and Testing

⁠Building
docker build -t docker-cleaner .
⁠Testing

docker-cleaner includes a comprehensive testing framework that validates cleanup operations across different execution contexts:

  • Local Script Testing: Test cleanup script directly in terminal
  • Container Testing: Test docker-cleaner Docker image on local host
  • Remote Context Testing: Test docker-cleaner on remote Docker hosts
⁠Quick Testing
# Run complete test suite (local + container + remote)
./tests/99-run-all-tests.sh

# Run only local script tests
./tests/99-run-all-tests.sh --only-local

# Run only container tests
./tests/99-run-all-tests.sh --only-container

# Run specific test types
./tests/11-test-local-cleanup.sh           # Local script testing
./tests/12-test-container-cleanup.sh       # Container testing
./tests/13-test-remote-contexts.sh         # Remote context testing

# Test with different configurations
./tests/11-test-local-cleanup.sh --prune-all --prune-volumes
./tests/11-test-local-cleanup.sh --dry-run

# Test on specific Docker context
./tests/99-run-all-tests.sh --context remote-nas
⁠Test Resource Management
# Create test resources for manual testing
./tests/01-setup-test-resources.sh

# Cleanup test resources
./tests/03-cleanup-test-resources.sh

# Validate cleanup operations
./tests/02-vali

Tag summary

Content type

Image

Digest

sha256:47adb508e…

Size

74.7 MB

Last updated

11 months ago

docker pull rinzlerfr/docker-cleaner