#!/bin/bash # Kind Cluster Autoscaler Simulator # ================================== set -e # Configuration CLUSTER_NAME="${KIND_CLUSTER:-docker-desktop}" MIN_NODES=3 MAX_NODES=10 SCALE_UP_THRESHOLD=80 # CPU usage % SCALE_DOWN_THRESHOLD=30 CHECK_INTERVAL=30 # Colors GREEN='\033[0;32m' YELLOW='\033[1;33m' RED='\033[0;31m' NC='\033[0m' echo "🚀 Kind Cluster Autoscaler Simulator" echo "=====================================" echo "Cluster: $CLUSTER_NAME" echo "Min nodes: $MIN_NODES, Max nodes: $MAX_NODES" echo "" # Function to get current worker node count get_node_count() { kubectl get nodes --no-headers | grep -v control-plane | wc -l } # Function to get average CPU usage get_cpu_usage() { kubectl top nodes --no-headers | grep -v control-plane | \ awk '{sum+=$3; count++} END {if(count>0) print int(sum/count); else print 0}' } # Function to add a node add_node() { local current_count=$1 local new_node_num=$((current_count + 1)) local node_name="desktop-worker${new_node_num}" echo -e "${GREEN}📈 Scaling up: Adding node $node_name${NC}" # Create new Kind worker node container docker run -d \ --name "$node_name" \ --hostname "$node_name" \ --network kind \ --restart on-failure:1 \ --label io.x-k8s.kind.cluster="$CLUSTER_NAME" \ --label io.x-k8s.kind.role=worker \ --privileged \ --security-opt seccomp=unconfined \ --security-opt apparmor=unconfined \ --tmpfs /tmp \ --tmpfs /run \ --volume /var \ --volume /lib/modules:/lib/modules:ro \ kindest/node:v1.27.3 # Wait for node to join sleep 10 # Label the new node kubectl label node "$node_name" node-role.kubernetes.io/worker=true --overwrite echo -e "${GREEN}✅ Node $node_name added successfully${NC}" } # Function to remove a node remove_node() { local node_to_remove=$(kubectl get nodes --no-headers | grep -v control-plane | tail -1 | awk '{print $1}') if [ -z "$node_to_remove" ]; then echo -e "${YELLOW}⚠️ No nodes to remove${NC}" return fi echo -e "${YELLOW}📉 Scaling down: Removing node $node_to_remove${NC}" # Drain the node kubectl drain "$node_to_remove" --ignore-daemonsets --delete-emptydir-data --force # Delete the node kubectl delete node "$node_to_remove" # Stop and remove the container docker stop "$node_to_remove" docker rm "$node_to_remove" echo -e "${YELLOW}✅ Node $node_to_remove removed successfully${NC}" } # Main monitoring loop echo "Starting autoscaler loop (Ctrl+C to stop)..." echo "" while true; do NODE_COUNT=$(get_node_count) CPU_USAGE=$(get_cpu_usage) PENDING_PODS=$(kubectl get pods --all-namespaces --field-selector=status.phase=Pending --no-headers 2>/dev/null | wc -l) echo "$(date '+%H:%M:%S') - Nodes: $NODE_COUNT | CPU: ${CPU_USAGE}% | Pending Pods: $PENDING_PODS" # Scale up conditions if [ "$PENDING_PODS" -gt 0 ] || [ "$CPU_USAGE" -gt "$SCALE_UP_THRESHOLD" ]; then if [ "$NODE_COUNT" -lt "$MAX_NODES" ]; then echo -e "${GREEN}🔺 Scale up triggered (CPU: ${CPU_USAGE}%, Pending: ${PENDING_PODS})${NC}" add_node "$NODE_COUNT" else echo -e "${YELLOW}⚠️ Already at max nodes ($MAX_NODES)${NC}" fi # Scale down conditions elif [ "$CPU_USAGE" -lt "$SCALE_DOWN_THRESHOLD" ] && [ "$NODE_COUNT" -gt "$MIN_NODES" ]; then echo -e "${YELLOW}🔻 Scale down triggered (CPU: ${CPU_USAGE}%)${NC}" remove_node fi sleep "$CHECK_INTERVAL" done