Files
homelab-optimized/ansible/automation/playbooks/container_resource_optimizer.yml
Gitea Mirror Bot dbda72a5db
Some checks failed
Documentation / Deploy to GitHub Pages (push) Has been cancelled
Documentation / Build Docusaurus (push) Has been cancelled
Sanitized mirror from private repository - 2026-03-19 08:48:54 UTC
2026-03-19 08:48:54 +00:00

370 lines
15 KiB
YAML

---
- name: Container Resource Optimization
hosts: all
gather_facts: yes
vars:
optimization_timestamp: "{{ ansible_date_time.iso8601 }}"
optimization_report_dir: "/tmp/optimization_reports"
cpu_threshold_warning: 80
cpu_threshold_critical: 95
memory_threshold_warning: 85
memory_threshold_critical: 95
tasks:
- name: Create optimization reports directory
file:
path: "{{ optimization_report_dir }}"
state: directory
mode: '0755'
delegate_to: localhost
run_once: true
- name: Check if Docker is available
shell: command -v docker >/dev/null 2>&1
register: docker_available
changed_when: false
ignore_errors: yes
- name: Skip Docker tasks if not available
set_fact:
skip_docker: "{{ docker_available.rc != 0 }}"
- name: Collect container resource usage
shell: |
if ! command -v docker >/dev/null 2>&1; then
echo "Docker not available"
exit 0
fi
echo "=== CONTAINER RESOURCE USAGE ==="
# Get current resource usage
echo "Current Resource Usage:"
docker stats --no-stream --format "table {{.Container}}\t{{.CPUPerc}}\t{{.MemUsage}}\t{{.MemPerc}}\t{{.NetIO}}\t{{.BlockIO}}" 2>/dev/null || echo "No running containers"
echo ""
# Get container limits
echo "Container Resource Limits:"
docker ps --format "{{.Names}}" 2>/dev/null | while read container; do
if [ -n "$container" ]; then
echo "Container: $container"
# CPU limits
cpu_limit=$(docker inspect "$container" --format '{{.HostConfig.CpuQuota}}' 2>/dev/null)
cpu_period=$(docker inspect "$container" --format '{{.HostConfig.CpuPeriod}}' 2>/dev/null)
if [ "$cpu_limit" != "0" ] && [ "$cpu_period" != "0" ]; then
cpu_cores=$(echo "scale=2; $cpu_limit / $cpu_period" | bc 2>/dev/null || echo "N/A")
echo " CPU Limit: $cpu_cores cores"
else
echo " CPU Limit: unlimited"
fi
# Memory limits
mem_limit=$(docker inspect "$container" --format '{{.HostConfig.Memory}}' 2>/dev/null)
if [ "$mem_limit" != "0" ]; then
mem_mb=$(echo "scale=0; $mem_limit / 1024 / 1024" | bc 2>/dev/null || echo "N/A")
echo " Memory Limit: ${mem_mb}MB"
else
echo " Memory Limit: unlimited"
fi
# Restart policy
restart_policy=$(docker inspect "$container" --format '{{.HostConfig.RestartPolicy.Name}}' 2>/dev/null)
echo " Restart Policy: $restart_policy"
echo ""
fi
done
register: resource_usage
changed_when: false
when: not skip_docker
- name: Analyze resource efficiency
shell: |
if ! command -v docker >/dev/null 2>&1; then
echo "Docker not available"
exit 0
fi
echo "=== RESOURCE EFFICIENCY ANALYSIS ==="
# Identify resource-heavy containers
echo "High Resource Usage Containers:"
docker stats --no-stream --format "{{.Container}}\t{{.CPUPerc}}\t{{.MemPerc}}" 2>/dev/null | while IFS=$'\t' read container cpu mem; do
if [ -n "$container" ] && [ "$container" != "CONTAINER" ]; then
cpu_num=$(echo "$cpu" | sed 's/%//' | cut -d'.' -f1)
mem_num=$(echo "$mem" | sed 's/%//' | cut -d'.' -f1)
if [ "$cpu_num" -gt "{{ cpu_threshold_warning }}" ] 2>/dev/null || [ "$mem_num" -gt "{{ memory_threshold_warning }}" ] 2>/dev/null; then
echo "⚠️ $container - CPU: $cpu, Memory: $mem"
fi
fi
done
echo ""
# Check for containers without limits
echo "Containers Without Resource Limits:"
docker ps --format "{{.Names}}" 2>/dev/null | while read container; do
if [ -n "$container" ]; then
cpu_limit=$(docker inspect "$container" --format '{{.HostConfig.CpuQuota}}' 2>/dev/null)
mem_limit=$(docker inspect "$container" --format '{{.HostConfig.Memory}}' 2>/dev/null)
if [ "$cpu_limit" = "0" ] && [ "$mem_limit" = "0" ]; then
echo "⚠️ $container - No CPU or memory limits"
elif [ "$cpu_limit" = "0" ]; then
echo "⚠️ $container - No CPU limit"
elif [ "$mem_limit" = "0" ]; then
echo "⚠️ $container - No memory limit"
fi
fi
done
echo ""
# Identify idle containers
echo "Low Usage Containers (potential over-provisioning):"
docker stats --no-stream --format "{{.Container}}\t{{.CPUPerc}}\t{{.MemPerc}}" 2>/dev/null | while IFS=$'\t' read container cpu mem; do
if [ -n "$container" ] && [ "$container" != "CONTAINER" ]; then
cpu_num=$(echo "$cpu" | sed 's/%//' | cut -d'.' -f1)
mem_num=$(echo "$mem" | sed 's/%//' | cut -d'.' -f1)
if [ "$cpu_num" -lt "5" ] 2>/dev/null && [ "$mem_num" -lt "10" ] 2>/dev/null; then
echo "💡 $container - CPU: $cpu, Memory: $mem (consider downsizing)"
fi
fi
done
register: efficiency_analysis
changed_when: false
when: not skip_docker
- name: System resource analysis
shell: |
echo "=== SYSTEM RESOURCE ANALYSIS ==="
# Overall system resources
echo "System Resources:"
echo "CPU Cores: $(nproc)"
echo "Total Memory: $(free -h | awk 'NR==2{print $2}')"
echo "Available Memory: $(free -h | awk 'NR==2{print $7}')"
echo "Memory Usage: $(free | awk 'NR==2{printf "%.1f%%", $3*100/$2}')"
echo "Load Average: $(uptime | awk -F'load average:' '{print $2}')"
echo ""
# Docker system resource usage
if command -v docker >/dev/null 2>&1; then
echo "Docker System Usage:"
docker system df 2>/dev/null || echo "Docker system info not available"
echo ""
# Count containers by status
echo "Container Status Summary:"
echo "Running: $(docker ps -q 2>/dev/null | wc -l)"
echo "Stopped: $(docker ps -aq --filter status=exited 2>/dev/null | wc -l)"
echo "Total: $(docker ps -aq 2>/dev/null | wc -l)"
fi
echo ""
# Disk usage for Docker
if [ -d "/var/lib/docker" ]; then
echo "Docker Storage Usage:"
du -sh /var/lib/docker 2>/dev/null || echo "Docker storage info not accessible"
fi
register: system_analysis
changed_when: false
- name: Generate optimization recommendations
shell: |
echo "=== OPTIMIZATION RECOMMENDATIONS ==="
# System-level recommendations
total_mem_mb=$(free -m | awk 'NR==2{print $2}')
used_mem_mb=$(free -m | awk 'NR==2{print $3}')
mem_usage_percent=$(echo "scale=1; $used_mem_mb * 100 / $total_mem_mb" | bc 2>/dev/null || echo "0")
echo "System Recommendations:"
if [ "$(echo "$mem_usage_percent > 85" | bc 2>/dev/null)" = "1" ]; then
echo "🚨 High memory usage (${mem_usage_percent}%) - consider adding RAM or optimizing containers"
elif [ "$(echo "$mem_usage_percent > 70" | bc 2>/dev/null)" = "1" ]; then
echo "⚠️ Moderate memory usage (${mem_usage_percent}%) - monitor closely"
else
echo "✅ Memory usage acceptable (${mem_usage_percent}%)"
fi
# Load average check
load_1min=$(uptime | awk -F'load average:' '{print $2}' | awk -F',' '{print $1}' | xargs)
cpu_cores=$(nproc)
if [ "$(echo "$load_1min > $cpu_cores" | bc 2>/dev/null)" = "1" ]; then
echo "🚨 High CPU load ($load_1min) exceeds core count ($cpu_cores)"
else
echo "✅ CPU load acceptable ($load_1min for $cpu_cores cores)"
fi
echo ""
# Docker-specific recommendations
if command -v docker >/dev/null 2>&1; then
echo "Container Recommendations:"
# Check for containers without health checks
echo "Containers without health checks:"
docker ps --format "{{.Names}}" 2>/dev/null | while read container; do
if [ -n "$container" ]; then
health_check=$(docker inspect "$container" --format '{{.Config.Healthcheck}}' 2>/dev/null)
if [ "$health_check" = "<nil>" ] || [ -z "$health_check" ]; then
echo "💡 $container - Consider adding health check"
fi
fi
done
echo ""
# Check for old images
echo "Image Optimization:"
old_images=$(docker images --filter "dangling=true" -q 2>/dev/null | wc -l)
if [ "$old_images" -gt "0" ]; then
echo "🧹 $old_images dangling images found - run 'docker image prune'"
fi
unused_volumes=$(docker volume ls --filter "dangling=true" -q 2>/dev/null | wc -l)
if [ "$unused_volumes" -gt "0" ]; then
echo "🧹 $unused_volumes unused volumes found - run 'docker volume prune'"
fi
fi
register: recommendations
changed_when: false
- name: Create optimization report
set_fact:
optimization_report:
timestamp: "{{ optimization_timestamp }}"
hostname: "{{ inventory_hostname }}"
docker_available: "{{ not skip_docker }}"
resource_usage: "{{ resource_usage.stdout if not skip_docker else 'Docker not available' }}"
efficiency_analysis: "{{ efficiency_analysis.stdout if not skip_docker else 'Docker not available' }}"
system_analysis: "{{ system_analysis.stdout }}"
recommendations: "{{ recommendations.stdout }}"
- name: Display optimization report
debug:
msg: |
==========================================
⚡ RESOURCE OPTIMIZATION - {{ inventory_hostname }}
==========================================
📊 DOCKER AVAILABLE: {{ 'Yes' if optimization_report.docker_available else 'No' }}
🔍 RESOURCE USAGE:
{{ optimization_report.resource_usage }}
📈 EFFICIENCY ANALYSIS:
{{ optimization_report.efficiency_analysis }}
🖥️ SYSTEM ANALYSIS:
{{ optimization_report.system_analysis }}
💡 RECOMMENDATIONS:
{{ optimization_report.recommendations }}
==========================================
- name: Generate JSON optimization report
copy:
content: |
{
"timestamp": "{{ optimization_report.timestamp }}",
"hostname": "{{ optimization_report.hostname }}",
"docker_available": {{ optimization_report.docker_available | lower }},
"resource_usage": {{ optimization_report.resource_usage | to_json }},
"efficiency_analysis": {{ optimization_report.efficiency_analysis | to_json }},
"system_analysis": {{ optimization_report.system_analysis | to_json }},
"recommendations": {{ optimization_report.recommendations | to_json }},
"optimization_actions": [
"Review containers without resource limits",
"Monitor high-usage containers for optimization opportunities",
"Consider downsizing low-usage containers",
"Implement health checks for better reliability",
"Regular cleanup of unused images and volumes"
]
}
dest: "{{ optimization_report_dir }}/{{ inventory_hostname }}_optimization_{{ ansible_date_time.epoch }}.json"
delegate_to: localhost
- name: Apply optimizations (when optimize_action is specified)
block:
- name: Validate optimization action
fail:
msg: "Invalid action. Supported actions: cleanup, restart_high_usage, add_limits"
when: optimize_action not in ['cleanup', 'restart_high_usage', 'add_limits']
- name: Execute optimization action
shell: |
case "{{ optimize_action }}" in
"cleanup")
echo "Performing Docker cleanup..."
docker image prune -f 2>/dev/null || echo "Image prune failed"
docker volume prune -f 2>/dev/null || echo "Volume prune failed"
docker container prune -f 2>/dev/null || echo "Container prune failed"
echo "Cleanup completed"
;;
"restart_high_usage")
echo "Restarting high CPU/memory usage containers..."
docker stats --no-stream --format "{{.Container}}\t{{.CPUPerc}}\t{{.MemPerc}}" 2>/dev/null | while IFS=$'\t' read container cpu mem; do
if [ -n "$container" ] && [ "$container" != "CONTAINER" ]; then
cpu_num=$(echo "$cpu" | sed 's/%//' | cut -d'.' -f1)
mem_num=$(echo "$mem" | sed 's/%//' | cut -d'.' -f1)
if [ "$cpu_num" -gt "{{ cpu_threshold_critical }}" ] 2>/dev/null || [ "$mem_num" -gt "{{ memory_threshold_critical }}" ] 2>/dev/null; then
echo "Restarting high-usage container: $container (CPU: $cpu, Memory: $mem)"
docker restart "$container" 2>/dev/null || echo "Failed to restart $container"
fi
fi
done
;;
"add_limits")
echo "Adding resource limits requires manual Docker Compose file updates"
echo "Recommended limits based on current usage:"
docker stats --no-stream --format "{{.Container}}\t{{.CPUPerc}}\t{{.MemUsage}}" 2>/dev/null | while IFS=$'\t' read container cpu mem; do
if [ -n "$container" ] && [ "$container" != "CONTAINER" ]; then
echo "$container:"
echo " deploy:"
echo " resources:"
echo " limits:"
echo " cpus: '1.0' # Adjust based on usage: $cpu"
echo " memory: 512M # Adjust based on usage: $mem"
echo ""
fi
done
;;
esac
register: optimization_action_result
when: not skip_docker
- name: Display optimization action result
debug:
msg: |
⚡ Optimization action '{{ optimize_action }}' completed on {{ inventory_hostname }}
Result:
{{ optimization_action_result.stdout }}
{% if optimization_action_result.stderr %}
Errors:
{{ optimization_action_result.stderr }}
{% endif %}
when: optimize_action is defined and not skip_docker
- name: Summary message
debug:
msg: |
⚡ Resource optimization analysis complete for {{ inventory_hostname }}
📄 Report saved to: {{ optimization_report_dir }}/{{ inventory_hostname }}_optimization_{{ ansible_date_time.epoch }}.json
{% if optimize_action is defined %}
🔧 Action performed: {{ optimize_action }}
{% endif %}
💡 Use -e optimize_action=<action> for optimization operations
💡 Supported actions: cleanup, restart_high_usage, add_limits
💡 Monitor resource usage regularly for optimal performance