--- - 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" = "" ] || [ -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= for optimization operations 💡 Supported actions: cleanup, restart_high_usage, add_limits 💡 Monitor resource usage regularly for optimal performance