v1
This commit is contained in:
@@ -0,0 +1,82 @@
|
|||||||
|
# Docker Factory Reset Script for Ubuntu
|
||||||
|
|
||||||
|
A comprehensive Python script that completely resets Docker to a fresh installation state on Ubuntu systems. This script removes all containers, images, volumes, networks, build cache, and even wipes the Docker data directories to give you a clean slate.
|
||||||
|
|
||||||
|
## 🚨 Warning
|
||||||
|
|
||||||
|
**This script is EXTREMELY DESTRUCTIVE!**
|
||||||
|
|
||||||
|
It will permanently delete:
|
||||||
|
- ✗ All Docker containers (running and stopped)
|
||||||
|
- ✗ All Docker images
|
||||||
|
- ✗ All Docker volumes (including all data stored in them)
|
||||||
|
- ✗ All custom Docker networks
|
||||||
|
- ✗ All build cache
|
||||||
|
- ✗ All Docker system data (`/var/lib/docker` and `/var/lib/containerd`)
|
||||||
|
|
||||||
|
**There is NO undo. All data will be permanently lost.**
|
||||||
|
|
||||||
|
Only use this script if you:
|
||||||
|
- Want to completely reset Docker to a fresh state
|
||||||
|
- Are experiencing issues that require a clean Docker installation
|
||||||
|
- Are decommissioning a system and want to clean up Docker
|
||||||
|
- Understand that ALL Docker data will be lost
|
||||||
|
|
||||||
|
## 📋 Features
|
||||||
|
|
||||||
|
- ✅ **Real-time output**: See exactly what's happening as commands execute
|
||||||
|
- ✅ **Progress indicators**: Visual progress bars for batch operations
|
||||||
|
- ✅ **Step-by-step execution**: Clear indication of each phase
|
||||||
|
- ✅ **Safety confirmation**: Requires explicit confirmation before proceeding
|
||||||
|
- ✅ **Comprehensive cleanup**: Removes everything Docker-related
|
||||||
|
- ✅ **Service management**: Properly stops and restarts Docker daemon
|
||||||
|
- ✅ **Final state report**: Shows the clean state after reset
|
||||||
|
- ✅ **Execution time tracking**: Reports how long the reset took
|
||||||
|
|
||||||
|
## 🔧 Requirements
|
||||||
|
|
||||||
|
### System Requirements
|
||||||
|
- **Operating System**: Ubuntu (18.04, 20.04, 22.04, 24.04 or later)
|
||||||
|
- **Docker**: Must be installed (any version)
|
||||||
|
- **Python**: Python 3.6 or later (usually pre-installed on Ubuntu)
|
||||||
|
- **Privileges**: Must be run as root (using `sudo`)
|
||||||
|
|
||||||
|
### Dependencies
|
||||||
|
All dependencies are part of Python's standard library:
|
||||||
|
- `subprocess` - For running system commands
|
||||||
|
- `sys` - For system operations
|
||||||
|
- `os` - For file system operations
|
||||||
|
- `time` - For timing and delays
|
||||||
|
|
||||||
|
No additional packages need to be installed.
|
||||||
|
|
||||||
|
## 🚀 Usage
|
||||||
|
|
||||||
|
Run the script with sudo:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
sudo python3 docker_full_factory_reset.py
|
||||||
|
```
|
||||||
|
|
||||||
|
The script will ask you to type `RESET_DOCKER_UBUNTU` to confirm.
|
||||||
|
|
||||||
|
## 📖 What Each Step Does
|
||||||
|
|
||||||
|
1. **Containers**: Stops and removes all containers
|
||||||
|
2. **Images**: Removes all images
|
||||||
|
3. **Networks**: Removes custom networks (keeps default ones)
|
||||||
|
4. **Volumes**: Removes all volumes
|
||||||
|
5. **Prune**: Clears build cache and system artifacts
|
||||||
|
6. **Stop services**: Stops `docker` and `containerd`
|
||||||
|
7. **Delete directories**: Removes `/var/lib/docker` and `/var/lib/containerd`
|
||||||
|
8. **Start services**: Restarts Docker and verifies with `docker info`
|
||||||
|
|
||||||
|
## 🔍 Verify After Reset
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker run hello-world
|
||||||
|
```
|
||||||
|
|
||||||
|
## ⚠ Final Warning
|
||||||
|
|
||||||
|
This script deletes **ALL** Docker data. Back up anything important first.
|
||||||
@@ -0,0 +1,406 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
"""
|
||||||
|
Docker Factory Reset Script for Ubuntu
|
||||||
|
Completely resets Docker to a fresh installation state.
|
||||||
|
"""
|
||||||
|
import subprocess
|
||||||
|
import sys
|
||||||
|
import os
|
||||||
|
import time
|
||||||
|
from typing import List
|
||||||
|
|
||||||
|
|
||||||
|
class ProgressBar:
|
||||||
|
"""Simple progress indicator for operations."""
|
||||||
|
|
||||||
|
def __init__(self, total: int, description: str = ""):
|
||||||
|
self.total = total
|
||||||
|
self.current = 0
|
||||||
|
self.description = description
|
||||||
|
|
||||||
|
def update(self, increment: int = 1):
|
||||||
|
self.current += increment
|
||||||
|
self._display()
|
||||||
|
|
||||||
|
def _display(self):
|
||||||
|
if self.total == 0:
|
||||||
|
percentage = 100
|
||||||
|
else:
|
||||||
|
percentage = int((self.current / self.total) * 100)
|
||||||
|
|
||||||
|
bar_length = 40
|
||||||
|
filled = int((percentage / 100) * bar_length)
|
||||||
|
bar = '█' * filled + '░' * (bar_length - filled)
|
||||||
|
|
||||||
|
print(f"\r [{bar}] {percentage}% ({self.current}/{self.total}) {self.description}", end='', flush=True)
|
||||||
|
|
||||||
|
def complete(self):
|
||||||
|
self.current = self.total
|
||||||
|
self._display()
|
||||||
|
print() # New line after completion
|
||||||
|
|
||||||
|
|
||||||
|
def run_cmd_realtime(cmd: List[str], check: bool = False, show_output: bool = True) -> int:
|
||||||
|
"""
|
||||||
|
Run a command and stream stdout/stderr in real-time.
|
||||||
|
Returns the exit code.
|
||||||
|
If check=True, exits the script on non-zero return code.
|
||||||
|
"""
|
||||||
|
if show_output:
|
||||||
|
print(f"\n▶ RUN: {' '.join(cmd)}")
|
||||||
|
print("─" * 60)
|
||||||
|
|
||||||
|
try:
|
||||||
|
process = subprocess.Popen(
|
||||||
|
cmd,
|
||||||
|
stdout=subprocess.PIPE,
|
||||||
|
stderr=subprocess.STDOUT, # Merge stderr into stdout
|
||||||
|
text=True,
|
||||||
|
bufsize=1, # Line buffered
|
||||||
|
)
|
||||||
|
|
||||||
|
# Stream output line by line
|
||||||
|
if show_output:
|
||||||
|
for line in process.stdout:
|
||||||
|
print(line, end='') # Print without adding extra newline
|
||||||
|
else:
|
||||||
|
# Consume output even if not showing
|
||||||
|
for _line in process.stdout:
|
||||||
|
pass
|
||||||
|
|
||||||
|
process.wait()
|
||||||
|
code = process.returncode
|
||||||
|
|
||||||
|
if show_output:
|
||||||
|
if code != 0:
|
||||||
|
print(f"✗ Command exited with code {code}")
|
||||||
|
if check:
|
||||||
|
sys.exit(code)
|
||||||
|
else:
|
||||||
|
print(f"✓ Command completed successfully")
|
||||||
|
|
||||||
|
return code
|
||||||
|
|
||||||
|
except FileNotFoundError:
|
||||||
|
print(f"✗ ERROR: Command not found: {' '.join(cmd)}")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
|
||||||
|
def run_cmd_quiet(cmd: List[str]) -> tuple:
|
||||||
|
"""
|
||||||
|
Run a command quietly and return (exit_code, stdout, stderr).
|
||||||
|
Used for listing/checking operations.
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
result = subprocess.run(
|
||||||
|
cmd,
|
||||||
|
stdout=subprocess.PIPE,
|
||||||
|
stderr=subprocess.PIPE,
|
||||||
|
text=True,
|
||||||
|
)
|
||||||
|
return result.returncode, result.stdout.strip(), result.stderr.strip()
|
||||||
|
except FileNotFoundError:
|
||||||
|
print(f"✗ ERROR: Command not found: {' '.join(cmd)}")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
|
||||||
|
def require_root():
|
||||||
|
if os.geteuid() != 0:
|
||||||
|
print("✗ This script must be run as root (use sudo).")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
|
||||||
|
def docker_installed() -> bool:
|
||||||
|
code, out, err = run_cmd_quiet(["docker", "--version"])
|
||||||
|
if code != 0:
|
||||||
|
print("✗ Docker does not appear to be installed or accessible.")
|
||||||
|
if err:
|
||||||
|
print(err)
|
||||||
|
return False
|
||||||
|
print(f"✓ Docker found: {out}")
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
def list_ids(cmd: List[str]) -> List[str]:
|
||||||
|
code, out, _err = run_cmd_quiet(cmd)
|
||||||
|
if code != 0:
|
||||||
|
return []
|
||||||
|
return [line.strip() for line in out.splitlines() if line.strip()]
|
||||||
|
|
||||||
|
|
||||||
|
def stop_and_remove_containers():
|
||||||
|
print("\n" + "=" * 60)
|
||||||
|
print("STEP 1/8: CONTAINERS")
|
||||||
|
print("=" * 60)
|
||||||
|
|
||||||
|
container_ids = list_ids(["docker", "ps", "-aq"])
|
||||||
|
if not container_ids:
|
||||||
|
print("ℹ No containers found.")
|
||||||
|
return
|
||||||
|
|
||||||
|
print(f"ℹ Found {len(container_ids)} container(s)")
|
||||||
|
|
||||||
|
running_ids = list_ids(["docker", "ps", "-q"])
|
||||||
|
if running_ids:
|
||||||
|
print(f"\nℹ Stopping {len(running_ids)} running container(s)...")
|
||||||
|
progress = ProgressBar(len(running_ids), "stopping containers")
|
||||||
|
|
||||||
|
for container_id in running_ids:
|
||||||
|
run_cmd_realtime(["docker", "stop", container_id], show_output=False)
|
||||||
|
progress.update()
|
||||||
|
progress.complete()
|
||||||
|
else:
|
||||||
|
print("ℹ No running containers to stop.")
|
||||||
|
|
||||||
|
print(f"\nℹ Removing all {len(container_ids)} container(s)...")
|
||||||
|
progress = ProgressBar(len(container_ids), "removing containers")
|
||||||
|
|
||||||
|
for container_id in container_ids:
|
||||||
|
run_cmd_realtime(["docker", "rm", "-f", container_id], show_output=False)
|
||||||
|
progress.update()
|
||||||
|
progress.complete()
|
||||||
|
|
||||||
|
print("✓ All containers removed")
|
||||||
|
|
||||||
|
|
||||||
|
def remove_images():
|
||||||
|
print("\n" + "=" * 60)
|
||||||
|
print("STEP 2/8: IMAGES")
|
||||||
|
print("=" * 60)
|
||||||
|
|
||||||
|
image_ids = list_ids(["docker", "images", "-aq"])
|
||||||
|
if not image_ids:
|
||||||
|
print("ℹ No images found.")
|
||||||
|
return
|
||||||
|
|
||||||
|
print(f"ℹ Found {len(image_ids)} image(s)")
|
||||||
|
print("\nℹ Removing all images...")
|
||||||
|
progress = ProgressBar(len(image_ids), "removing images")
|
||||||
|
|
||||||
|
for image_id in image_ids:
|
||||||
|
run_cmd_realtime(["docker", "rmi", "-f", image_id], show_output=False)
|
||||||
|
progress.update()
|
||||||
|
progress.complete()
|
||||||
|
|
||||||
|
print("✓ All images removed")
|
||||||
|
|
||||||
|
|
||||||
|
def remove_networks():
|
||||||
|
print("\n" + "=" * 60)
|
||||||
|
print("STEP 3/8: NETWORKS")
|
||||||
|
print("=" * 60)
|
||||||
|
|
||||||
|
code, out, err = run_cmd_quiet(["docker", "network", "ls", "--format", "{{.Name}}"])
|
||||||
|
if code != 0:
|
||||||
|
print(f"✗ Error listing networks: {err}")
|
||||||
|
return
|
||||||
|
|
||||||
|
default_networks = {"bridge", "host", "none"}
|
||||||
|
networks = [n.strip() for n in out.splitlines() if n.strip()]
|
||||||
|
custom_networks = [n for n in networks if n not in default_networks]
|
||||||
|
|
||||||
|
if not custom_networks:
|
||||||
|
print("ℹ No custom networks found.")
|
||||||
|
return
|
||||||
|
|
||||||
|
print(f"ℹ Found {len(custom_networks)} custom network(s): {', '.join(custom_networks)}")
|
||||||
|
print("\nℹ Removing custom networks...")
|
||||||
|
progress = ProgressBar(len(custom_networks), "removing networks")
|
||||||
|
|
||||||
|
for network in custom_networks:
|
||||||
|
run_cmd_realtime(["docker", "network", "rm", network], show_output=False)
|
||||||
|
progress.update()
|
||||||
|
progress.complete()
|
||||||
|
|
||||||
|
print("✓ All custom networks removed")
|
||||||
|
|
||||||
|
|
||||||
|
def remove_volumes():
|
||||||
|
print("\n" + "=" * 60)
|
||||||
|
print("STEP 4/8: VOLUMES")
|
||||||
|
print("=" * 60)
|
||||||
|
|
||||||
|
volume_names = list_ids(["docker", "volume", "ls", "-q"])
|
||||||
|
if not volume_names:
|
||||||
|
print("ℹ No volumes found.")
|
||||||
|
return
|
||||||
|
|
||||||
|
print(f"ℹ Found {len(volume_names)} volume(s)")
|
||||||
|
print("\nℹ Removing all volumes...")
|
||||||
|
progress = ProgressBar(len(volume_names), "removing volumes")
|
||||||
|
|
||||||
|
for volume in volume_names:
|
||||||
|
run_cmd_realtime(["docker", "volume", "rm", "-f", volume], show_output=False)
|
||||||
|
progress.update()
|
||||||
|
progress.complete()
|
||||||
|
|
||||||
|
print("✓ All volumes removed")
|
||||||
|
|
||||||
|
|
||||||
|
def prune_system():
|
||||||
|
print("\n" + "=" * 60)
|
||||||
|
print("STEP 5/8: SYSTEM PRUNE & BUILD CACHE")
|
||||||
|
print("=" * 60)
|
||||||
|
|
||||||
|
print("ℹ Pruning builder cache...")
|
||||||
|
run_cmd_realtime(["docker", "builder", "prune", "-af"])
|
||||||
|
|
||||||
|
print("\nℹ Running system prune (extra safety)...")
|
||||||
|
run_cmd_realtime(["docker", "system", "prune", "-af", "--volumes"])
|
||||||
|
|
||||||
|
|
||||||
|
def stop_docker_service():
|
||||||
|
print("\n" + "=" * 60)
|
||||||
|
print("STEP 6/8: STOP DOCKER DAEMON")
|
||||||
|
print("=" * 60)
|
||||||
|
|
||||||
|
print("ℹ Stopping Docker service...")
|
||||||
|
run_cmd_realtime(["systemctl", "stop", "docker"])
|
||||||
|
|
||||||
|
print("\nℹ Stopping containerd service...")
|
||||||
|
run_cmd_realtime(["systemctl", "stop", "containerd"])
|
||||||
|
|
||||||
|
print("✓ Docker daemon stopped")
|
||||||
|
|
||||||
|
|
||||||
|
def wipe_docker_data_dirs():
|
||||||
|
print("\n" + "=" * 60)
|
||||||
|
print("STEP 7/8: DELETE DOCKER DATA DIRECTORIES")
|
||||||
|
print("=" * 60)
|
||||||
|
|
||||||
|
paths = ["/var/lib/docker", "/var/lib/containerd"]
|
||||||
|
existing_paths = [p for p in paths if os.path.exists(p)]
|
||||||
|
|
||||||
|
if not existing_paths:
|
||||||
|
print("ℹ No Docker data directories found.")
|
||||||
|
return
|
||||||
|
|
||||||
|
print(f"ℹ Found {len(existing_paths)} data director(ies) to delete")
|
||||||
|
progress = ProgressBar(len(existing_paths), "deleting directories")
|
||||||
|
|
||||||
|
for p in paths:
|
||||||
|
if os.path.exists(p):
|
||||||
|
print(f"\nℹ Deleting {p} ...")
|
||||||
|
code, out, _err = run_cmd_quiet(["du", "-sh", p])
|
||||||
|
if code == 0 and out:
|
||||||
|
print(f" Size: {out.split()[0]}")
|
||||||
|
|
||||||
|
run_cmd_realtime(["rm", "-rf", p], show_output=False)
|
||||||
|
progress.update()
|
||||||
|
else:
|
||||||
|
print(f"ℹ {p} does not exist; skipping.")
|
||||||
|
|
||||||
|
progress.complete()
|
||||||
|
print("✓ All Docker data directories deleted")
|
||||||
|
|
||||||
|
|
||||||
|
def start_docker_service():
|
||||||
|
print("\n" + "=" * 60)
|
||||||
|
print("STEP 8/8: START DOCKER DAEMON")
|
||||||
|
print("=" * 60)
|
||||||
|
|
||||||
|
print("ℹ Starting containerd service...")
|
||||||
|
run_cmd_realtime(["systemctl", "start", "containerd"])
|
||||||
|
|
||||||
|
print("\nℹ Starting Docker service...")
|
||||||
|
run_cmd_realtime(["systemctl", "start", "docker"])
|
||||||
|
|
||||||
|
print("\nℹ Waiting for Docker to initialize...")
|
||||||
|
for i in range(5):
|
||||||
|
time.sleep(1)
|
||||||
|
code, out, _err = run_cmd_quiet(["systemctl", "is-active", "docker"])
|
||||||
|
if code == 0 and out.strip() == "active":
|
||||||
|
print(f"✓ Docker service is active (took {i+1}s)")
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
print("⚠ Warning: Docker service may not be active yet.")
|
||||||
|
|
||||||
|
print("\nℹ Running docker info to verify...")
|
||||||
|
run_cmd_realtime(["docker", "info"])
|
||||||
|
|
||||||
|
|
||||||
|
def show_final_state():
|
||||||
|
print("\n" + "=" * 60)
|
||||||
|
print("FINAL DOCKER STATE")
|
||||||
|
print("=" * 60)
|
||||||
|
|
||||||
|
cmds = [
|
||||||
|
(["docker", "ps", "-a"], "CONTAINERS"),
|
||||||
|
(["docker", "images"], "IMAGES"),
|
||||||
|
(["docker", "network", "ls"], "NETWORKS"),
|
||||||
|
(["docker", "volume", "ls"], "VOLUMES"),
|
||||||
|
]
|
||||||
|
|
||||||
|
for cmd, title in cmds:
|
||||||
|
print(f"\n▶ {title}")
|
||||||
|
print("─" * 60)
|
||||||
|
code, out, err = run_cmd_quiet(cmd)
|
||||||
|
if code == 0:
|
||||||
|
print(out if out else "(empty)")
|
||||||
|
else:
|
||||||
|
print("✗ Command failed")
|
||||||
|
if err:
|
||||||
|
print(err)
|
||||||
|
|
||||||
|
|
||||||
|
def show_banner():
|
||||||
|
banner = """
|
||||||
|
╔════════════════════════════════════════════════════════════╗
|
||||||
|
║ ║
|
||||||
|
║ DOCKER FACTORY RESET FOR UBUNTU ║
|
||||||
|
║ ║
|
||||||
|
║ Completely resets Docker to fresh state ║
|
||||||
|
║ ║
|
||||||
|
╚════════════════════════════════════════════════════════════╝
|
||||||
|
"""
|
||||||
|
print(banner)
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
show_banner()
|
||||||
|
require_root()
|
||||||
|
|
||||||
|
if not docker_installed():
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
print("\n⚠ WARNING: This script will COMPLETELY RESET Docker on this Ubuntu host.")
|
||||||
|
print("\nIt will:")
|
||||||
|
print(" • Stop and remove ALL containers (running and stopped)")
|
||||||
|
print(" • Remove ALL images")
|
||||||
|
print(" • Remove ALL volumes")
|
||||||
|
print(" • Remove ALL custom networks")
|
||||||
|
print(" • Prune ALL build cache and system data")
|
||||||
|
print(" • STOP Docker daemon")
|
||||||
|
print(" • DELETE /var/lib/docker and /var/lib/containerd")
|
||||||
|
print(" • START Docker daemon again")
|
||||||
|
print("\n⚠ You will lose ALL Docker data on this machine.")
|
||||||
|
print("\n" + "─" * 60)
|
||||||
|
|
||||||
|
confirm = input("\nType 'RESET_DOCKER_UBUNTU' to continue: ")
|
||||||
|
if confirm != "RESET_DOCKER_UBUNTU":
|
||||||
|
print("\n✗ Aborted.")
|
||||||
|
sys.exit(0)
|
||||||
|
|
||||||
|
start_time = time.time()
|
||||||
|
|
||||||
|
stop_and_remove_containers()
|
||||||
|
remove_images()
|
||||||
|
remove_networks()
|
||||||
|
remove_volumes()
|
||||||
|
prune_system()
|
||||||
|
stop_docker_service()
|
||||||
|
wipe_docker_data_dirs()
|
||||||
|
start_docker_service()
|
||||||
|
show_final_state()
|
||||||
|
|
||||||
|
elapsed_time = time.time() - start_time
|
||||||
|
|
||||||
|
print("\n" + "=" * 60)
|
||||||
|
print("✓ DOCKER FACTORY RESET COMPLETE")
|
||||||
|
print(f" Total time: {elapsed_time:.2f} seconds")
|
||||||
|
print("=" * 60)
|
||||||
|
print("\nDocker has been reset to a fresh installation state.\n")
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
Reference in New Issue
Block a user