370 lines
15 KiB
YAML
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
|