Sanitized mirror from private repository - 2026-03-18 10:31:50 UTC
This commit is contained in:
410
ansible/automation/playbooks/prune_containers.yml
Normal file
410
ansible/automation/playbooks/prune_containers.yml
Normal file
@@ -0,0 +1,410 @@
|
||||
---
|
||||
# Docker Cleanup and Pruning Playbook
|
||||
# Clean up unused containers, images, volumes, and networks
|
||||
# Usage: ansible-playbook playbooks/prune_containers.yml
|
||||
# Usage: ansible-playbook playbooks/prune_containers.yml -e "aggressive_cleanup=true"
|
||||
# Usage: ansible-playbook playbooks/prune_containers.yml -e "dry_run=true"
|
||||
|
||||
- name: Docker System Cleanup and Pruning
|
||||
hosts: "{{ host_target | default('all') }}"
|
||||
gather_facts: yes
|
||||
vars:
|
||||
dry_run: "{{ dry_run | default(false) }}"
|
||||
aggressive_cleanup: "{{ aggressive_cleanup | default(false) }}"
|
||||
keep_images_days: "{{ keep_images_days | default(7) }}"
|
||||
keep_volumes: "{{ keep_volumes | default(true) }}"
|
||||
backup_before_cleanup: "{{ backup_before_cleanup | default(true) }}"
|
||||
cleanup_logs: "{{ cleanup_logs | default(true) }}"
|
||||
max_log_size: "{{ max_log_size | default('100m') }}"
|
||||
|
||||
tasks:
|
||||
- name: Check if Docker is running
|
||||
systemd:
|
||||
name: docker
|
||||
register: docker_status
|
||||
failed_when: docker_status.status.ActiveState != "active"
|
||||
|
||||
- name: Create cleanup report directory
|
||||
file:
|
||||
path: "/tmp/docker_cleanup/{{ ansible_date_time.date }}"
|
||||
state: directory
|
||||
mode: '0755'
|
||||
|
||||
- name: Get pre-cleanup Docker system info
|
||||
shell: |
|
||||
echo "=== PRE-CLEANUP DOCKER SYSTEM INFO ==="
|
||||
echo "Date: {{ ansible_date_time.iso8601 }}"
|
||||
echo "Host: {{ inventory_hostname }}"
|
||||
echo ""
|
||||
|
||||
echo "System Usage:"
|
||||
docker system df
|
||||
echo ""
|
||||
|
||||
echo "Container Count:"
|
||||
echo "Running: $(docker ps -q | wc -l)"
|
||||
echo "Stopped: $(docker ps -aq --filter status=exited | wc -l)"
|
||||
echo "Total: $(docker ps -aq | wc -l)"
|
||||
echo ""
|
||||
|
||||
echo "Image Count:"
|
||||
echo "Total: $(docker images -q | wc -l)"
|
||||
echo "Dangling: $(docker images -f dangling=true -q | wc -l)"
|
||||
echo ""
|
||||
|
||||
echo "Volume Count:"
|
||||
echo "Total: $(docker volume ls -q | wc -l)"
|
||||
echo "Dangling: $(docker volume ls -f dangling=true -q | wc -l)"
|
||||
echo ""
|
||||
|
||||
echo "Network Count:"
|
||||
echo "Total: $(docker network ls -q | wc -l)"
|
||||
echo "Custom: $(docker network ls --filter type=custom -q | wc -l)"
|
||||
register: pre_cleanup_info
|
||||
changed_when: false
|
||||
|
||||
- name: Display cleanup plan
|
||||
debug:
|
||||
msg: |
|
||||
🧹 DOCKER CLEANUP PLAN
|
||||
======================
|
||||
🖥️ Host: {{ inventory_hostname }}
|
||||
📅 Date: {{ ansible_date_time.date }}
|
||||
🔍 Dry Run: {{ dry_run }}
|
||||
💪 Aggressive: {{ aggressive_cleanup }}
|
||||
📦 Keep Images: {{ keep_images_days }} days
|
||||
💾 Keep Volumes: {{ keep_volumes }}
|
||||
📝 Cleanup Logs: {{ cleanup_logs }}
|
||||
|
||||
{{ pre_cleanup_info.stdout }}
|
||||
|
||||
- name: Backup container list before cleanup
|
||||
shell: |
|
||||
backup_file="/tmp/docker_cleanup/{{ ansible_date_time.date }}/{{ inventory_hostname }}_containers_backup.txt"
|
||||
|
||||
echo "=== CONTAINER BACKUP - {{ ansible_date_time.iso8601 }} ===" > "$backup_file"
|
||||
echo "Host: {{ inventory_hostname }}" >> "$backup_file"
|
||||
echo "" >> "$backup_file"
|
||||
|
||||
echo "=== RUNNING CONTAINERS ===" >> "$backup_file"
|
||||
docker ps --format "table {{.Names}}\t{{.Image}}\t{{.Status}}\t{{.Ports}}" >> "$backup_file"
|
||||
echo "" >> "$backup_file"
|
||||
|
||||
echo "=== ALL CONTAINERS ===" >> "$backup_file"
|
||||
docker ps -a --format "table {{.Names}}\t{{.Image}}\t{{.Status}}\t{{.CreatedAt}}" >> "$backup_file"
|
||||
echo "" >> "$backup_file"
|
||||
|
||||
echo "=== IMAGES ===" >> "$backup_file"
|
||||
docker images --format "table {{.Repository}}\t{{.Tag}}\t{{.Size}}\t{{.CreatedAt}}" >> "$backup_file"
|
||||
echo "" >> "$backup_file"
|
||||
|
||||
echo "=== VOLUMES ===" >> "$backup_file"
|
||||
docker volume ls >> "$backup_file"
|
||||
echo "" >> "$backup_file"
|
||||
|
||||
echo "=== NETWORKS ===" >> "$backup_file"
|
||||
docker network ls >> "$backup_file"
|
||||
when: backup_before_cleanup | bool
|
||||
|
||||
- name: Remove stopped containers
|
||||
shell: |
|
||||
{% if dry_run %}
|
||||
echo "DRY RUN: Would remove stopped containers:"
|
||||
docker ps -aq --filter status=exited
|
||||
{% else %}
|
||||
echo "Removing stopped containers..."
|
||||
stopped_containers=$(docker ps -aq --filter status=exited)
|
||||
if [ -n "$stopped_containers" ]; then
|
||||
docker rm $stopped_containers
|
||||
echo "✅ Removed stopped containers"
|
||||
else
|
||||
echo "ℹ️ No stopped containers to remove"
|
||||
fi
|
||||
{% endif %}
|
||||
register: remove_stopped_containers
|
||||
|
||||
- name: Remove dangling images
|
||||
shell: |
|
||||
{% if dry_run %}
|
||||
echo "DRY RUN: Would remove dangling images:"
|
||||
docker images -f dangling=true -q
|
||||
{% else %}
|
||||
echo "Removing dangling images..."
|
||||
dangling_images=$(docker images -f dangling=true -q)
|
||||
if [ -n "$dangling_images" ]; then
|
||||
docker rmi $dangling_images
|
||||
echo "✅ Removed dangling images"
|
||||
else
|
||||
echo "ℹ️ No dangling images to remove"
|
||||
fi
|
||||
{% endif %}
|
||||
register: remove_dangling_images
|
||||
|
||||
- name: Remove unused images (aggressive cleanup)
|
||||
shell: |
|
||||
{% if dry_run %}
|
||||
echo "DRY RUN: Would remove unused images older than {{ keep_images_days }} days:"
|
||||
docker images --filter "until={{ keep_images_days * 24 }}h" -q
|
||||
{% else %}
|
||||
echo "Removing unused images older than {{ keep_images_days }} days..."
|
||||
old_images=$(docker images --filter "until={{ keep_images_days * 24 }}h" -q)
|
||||
if [ -n "$old_images" ]; then
|
||||
# Check if images are not used by any container
|
||||
for image in $old_images; do
|
||||
if ! docker ps -a --format "{{.Image}}" | grep -q "$image"; then
|
||||
docker rmi "$image" 2>/dev/null && echo "Removed image: $image" || echo "Failed to remove image: $image"
|
||||
else
|
||||
echo "Skipping image in use: $image"
|
||||
fi
|
||||
done
|
||||
echo "✅ Removed old unused images"
|
||||
else
|
||||
echo "ℹ️ No old images to remove"
|
||||
fi
|
||||
{% endif %}
|
||||
register: remove_old_images
|
||||
when: aggressive_cleanup | bool
|
||||
|
||||
- name: Remove dangling volumes
|
||||
shell: |
|
||||
{% if dry_run %}
|
||||
echo "DRY RUN: Would remove dangling volumes:"
|
||||
docker volume ls -f dangling=true -q
|
||||
{% else %}
|
||||
{% if not keep_volumes %}
|
||||
echo "Removing dangling volumes..."
|
||||
dangling_volumes=$(docker volume ls -f dangling=true -q)
|
||||
if [ -n "$dangling_volumes" ]; then
|
||||
docker volume rm $dangling_volumes
|
||||
echo "✅ Removed dangling volumes"
|
||||
else
|
||||
echo "ℹ️ No dangling volumes to remove"
|
||||
fi
|
||||
{% else %}
|
||||
echo "ℹ️ Volume cleanup skipped (keep_volumes=true)"
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
register: remove_dangling_volumes
|
||||
|
||||
- name: Remove unused networks
|
||||
shell: |
|
||||
{% if dry_run %}
|
||||
echo "DRY RUN: Would remove unused networks:"
|
||||
docker network ls --filter type=custom -q
|
||||
{% else %}
|
||||
echo "Removing unused networks..."
|
||||
docker network prune -f
|
||||
echo "✅ Removed unused networks"
|
||||
{% endif %}
|
||||
register: remove_unused_networks
|
||||
|
||||
- name: Clean up container logs
|
||||
shell: |
|
||||
{% if dry_run %}
|
||||
echo "DRY RUN: Would clean up container logs larger than {{ max_log_size }}"
|
||||
find /var/lib/docker/containers -name "*-json.log" -size +{{ max_log_size }} 2>/dev/null | wc -l
|
||||
{% else %}
|
||||
{% if cleanup_logs %}
|
||||
echo "Cleaning up large container logs (>{{ max_log_size }})..."
|
||||
|
||||
log_count=0
|
||||
total_size_before=0
|
||||
total_size_after=0
|
||||
|
||||
for log_file in $(find /var/lib/docker/containers -name "*-json.log" -size +{{ max_log_size }} 2>/dev/null); do
|
||||
if [ -f "$log_file" ]; then
|
||||
size_before=$(stat -f%z "$log_file" 2>/dev/null || stat -c%s "$log_file" 2>/dev/null || echo 0)
|
||||
total_size_before=$((total_size_before + size_before))
|
||||
|
||||
# Truncate log file to last 1000 lines
|
||||
tail -1000 "$log_file" > "${log_file}.tmp" && mv "${log_file}.tmp" "$log_file"
|
||||
|
||||
size_after=$(stat -f%z "$log_file" 2>/dev/null || stat -c%s "$log_file" 2>/dev/null || echo 0)
|
||||
total_size_after=$((total_size_after + size_after))
|
||||
|
||||
log_count=$((log_count + 1))
|
||||
fi
|
||||
done
|
||||
|
||||
if [ $log_count -gt 0 ]; then
|
||||
saved_bytes=$((total_size_before - total_size_after))
|
||||
echo "✅ Cleaned $log_count log files, saved $(echo $saved_bytes | numfmt --to=iec) bytes"
|
||||
else
|
||||
echo "ℹ️ No large log files to clean"
|
||||
fi
|
||||
{% else %}
|
||||
echo "ℹ️ Log cleanup skipped (cleanup_logs=false)"
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
register: cleanup_logs_result
|
||||
when: cleanup_logs | bool
|
||||
|
||||
- name: Run Docker system prune
|
||||
shell: |
|
||||
{% if dry_run %}
|
||||
echo "DRY RUN: Would run docker system prune"
|
||||
docker system df
|
||||
{% else %}
|
||||
echo "Running Docker system prune..."
|
||||
{% if aggressive_cleanup %}
|
||||
docker system prune -af --volumes
|
||||
{% else %}
|
||||
docker system prune -f
|
||||
{% endif %}
|
||||
echo "✅ Docker system prune complete"
|
||||
{% endif %}
|
||||
register: system_prune_result
|
||||
|
||||
- name: Get post-cleanup Docker system info
|
||||
shell: |
|
||||
echo "=== POST-CLEANUP DOCKER SYSTEM INFO ==="
|
||||
echo "Date: {{ ansible_date_time.iso8601 }}"
|
||||
echo "Host: {{ inventory_hostname }}"
|
||||
echo ""
|
||||
|
||||
echo "System Usage:"
|
||||
docker system df
|
||||
echo ""
|
||||
|
||||
echo "Container Count:"
|
||||
echo "Running: $(docker ps -q | wc -l)"
|
||||
echo "Stopped: $(docker ps -aq --filter status=exited | wc -l)"
|
||||
echo "Total: $(docker ps -aq | wc -l)"
|
||||
echo ""
|
||||
|
||||
echo "Image Count:"
|
||||
echo "Total: $(docker images -q | wc -l)"
|
||||
echo "Dangling: $(docker images -f dangling=true -q | wc -l)"
|
||||
echo ""
|
||||
|
||||
echo "Volume Count:"
|
||||
echo "Total: $(docker volume ls -q | wc -l)"
|
||||
echo "Dangling: $(docker volume ls -f dangling=true -q | wc -l)"
|
||||
echo ""
|
||||
|
||||
echo "Network Count:"
|
||||
echo "Total: $(docker network ls -q | wc -l)"
|
||||
echo "Custom: $(docker network ls --filter type=custom -q | wc -l)"
|
||||
register: post_cleanup_info
|
||||
changed_when: false
|
||||
|
||||
- name: Generate cleanup report
|
||||
copy:
|
||||
content: |
|
||||
🧹 DOCKER CLEANUP REPORT - {{ inventory_hostname }}
|
||||
===============================================
|
||||
|
||||
📅 Cleanup Date: {{ ansible_date_time.iso8601 }}
|
||||
🖥️ Host: {{ inventory_hostname }}
|
||||
🔍 Dry Run: {{ dry_run }}
|
||||
💪 Aggressive Mode: {{ aggressive_cleanup }}
|
||||
📦 Image Retention: {{ keep_images_days }} days
|
||||
💾 Keep Volumes: {{ keep_volumes }}
|
||||
📝 Log Cleanup: {{ cleanup_logs }}
|
||||
|
||||
📊 BEFORE CLEANUP:
|
||||
{{ pre_cleanup_info.stdout }}
|
||||
|
||||
🔧 CLEANUP ACTIONS:
|
||||
|
||||
🗑️ Stopped Containers:
|
||||
{{ remove_stopped_containers.stdout }}
|
||||
|
||||
🖼️ Dangling Images:
|
||||
{{ remove_dangling_images.stdout }}
|
||||
|
||||
{% if aggressive_cleanup %}
|
||||
📦 Old Images:
|
||||
{{ remove_old_images.stdout }}
|
||||
{% endif %}
|
||||
|
||||
💾 Dangling Volumes:
|
||||
{{ remove_dangling_volumes.stdout }}
|
||||
|
||||
🌐 Unused Networks:
|
||||
{{ remove_unused_networks.stdout }}
|
||||
|
||||
{% if cleanup_logs %}
|
||||
📝 Container Logs:
|
||||
{{ cleanup_logs_result.stdout }}
|
||||
{% endif %}
|
||||
|
||||
🧹 System Prune:
|
||||
{{ system_prune_result.stdout }}
|
||||
|
||||
📊 AFTER CLEANUP:
|
||||
{{ post_cleanup_info.stdout }}
|
||||
|
||||
💡 RECOMMENDATIONS:
|
||||
- Schedule regular cleanup: cron job for this playbook
|
||||
- Monitor disk usage: ansible-playbook playbooks/disk_usage_report.yml
|
||||
- Consider log rotation: ansible-playbook playbooks/log_rotation.yml
|
||||
{% if not aggressive_cleanup %}
|
||||
- For more space: run with -e "aggressive_cleanup=true"
|
||||
{% endif %}
|
||||
|
||||
✅ CLEANUP COMPLETE
|
||||
|
||||
dest: "/tmp/docker_cleanup/{{ ansible_date_time.date }}/{{ inventory_hostname }}_cleanup_report.txt"
|
||||
|
||||
- name: Display cleanup summary
|
||||
debug:
|
||||
msg: |
|
||||
|
||||
✅ DOCKER CLEANUP COMPLETE - {{ inventory_hostname }}
|
||||
=============================================
|
||||
|
||||
🔍 Mode: {{ 'DRY RUN' if dry_run else 'LIVE CLEANUP' }}
|
||||
💪 Aggressive: {{ aggressive_cleanup }}
|
||||
|
||||
📊 SUMMARY:
|
||||
{{ post_cleanup_info.stdout }}
|
||||
|
||||
📄 Full report: /tmp/docker_cleanup/{{ ansible_date_time.date }}/{{ inventory_hostname }}_cleanup_report.txt
|
||||
|
||||
🔍 Next Steps:
|
||||
{% if dry_run %}
|
||||
- Run without dry_run to perform actual cleanup
|
||||
{% endif %}
|
||||
- Monitor: ansible-playbook playbooks/disk_usage_report.yml
|
||||
- Schedule regular cleanup via cron
|
||||
|
||||
=============================================
|
||||
|
||||
- name: Restart Docker daemon if needed
|
||||
systemd:
|
||||
name: docker
|
||||
state: restarted
|
||||
when:
|
||||
- restart_docker | default(false) | bool
|
||||
- not dry_run | bool
|
||||
register: docker_restart
|
||||
|
||||
- name: Verify services after cleanup
|
||||
shell: |
|
||||
echo "Verifying critical services are still running..."
|
||||
sleep 10 # Give services time to start
|
||||
|
||||
critical_services=("plex" "immich-server" "vaultwarden" "grafana" "prometheus")
|
||||
failed_services=()
|
||||
|
||||
for service in "${critical_services[@]}"; do
|
||||
if ! docker ps --filter "name=$service" --format "{{.Names}}" | grep -q "$service"; then
|
||||
failed_services+=("$service")
|
||||
fi
|
||||
done
|
||||
|
||||
if [ ${#failed_services[@]} -eq 0 ]; then
|
||||
echo "✅ All critical services verified running"
|
||||
else
|
||||
echo "⚠️ Some services may need attention: ${failed_services[*]}"
|
||||
fi
|
||||
register: service_verification
|
||||
when:
|
||||
- not dry_run | bool
|
||||
- verify_services | default(true) | bool
|
||||
|
||||
- name: Display service verification
|
||||
debug:
|
||||
msg: "{{ service_verification.stdout }}"
|
||||
when: service_verification is defined
|
||||
Reference in New Issue
Block a user