如何编写bash脚本基于SQS队列负载实现EC2实例自动扩缩容
问题1:仅用bash脚本实现自动扩缩容的可行性
完全可以实现,不需要依赖CloudWatch和Auto Scaling Groups。你只需要找一个固定运行的环境(比如本地机器、一台长期运行的轻量EC2)跑控制脚本即可,核心逻辑如下:
- 每15秒调用
aws sqs get-queue-attributes接口拉取目标队列的ApproximateNumberOfMessages指标,用你给出的公式计算需要的总实例数 - 调用
aws ec2 describe-instances接口过滤出你提前打了统一业务标签的运行中EC2实例,统计当前运行数N - 计算差值:差值为正则创建对应数量的实例,差值为负则销毁对应数量的多余实例
- 整个逻辑放入死循环,每次循环结束执行
sleep 15即可
这里给出核心控制脚本的参考实现:
# 自定义配置项 QUEUE_URL="替换为你的SQS队列URL" WORKER_TAG="Key=sqs-worker,Value=business" AMI_ID="替换为你使用的AMI ID,推荐用预装了aws-cli的Amazon Linux 2/2023的公共AMI" INSTANCE_TYPE="t2.micro" IAM_PROFILE_NAME="替换为你提前创建的有权限访问SQS的IAM实例配置文件名" USER_DATA_PATH="./worker_process.sh" # 替换为你的实例消息处理脚本路径 while true; do # 获取队列待处理消息数 MSG_COUNT=$(aws sqs get-queue-attributes \ --queue-url "$QUEUE_URL" \ --attribute-names ApproximateNumberOfMessages \ --query 'Attributes.ApproximateNumberOfMessages' \ --output text) # 计算期望实例数,整数除法向上取整 DESIRED_COUNT=$(( (MSG_COUNT + 9) / 10 )) # 统计当前运行的worker实例数 RUNNING_COUNT=$(aws ec2 describe-instances \ --filters "Name=tag:$WORKER_TAG" "Name=instance-state-name,Values=running" \ --query 'Reservations[*].Instances[*].InstanceId' \ --output text | wc -w) # 计算扩缩容差值 DIFF=$(( DESIRED_COUNT - RUNNING_COUNT )) if [ $DIFF -gt 0 ]; then # 批量创建不足的实例 aws ec2 run-instances \ --image-id "$AMI_ID" \ --instance-type "$INSTANCE_TYPE" \ --iam-instance-profile Name="$IAM_PROFILE_NAME" \ --tag-specifications "ResourceType=instance,Tags=[{$WORKER_TAG}]" \ --count $DIFF \ --user-data "file://$USER_DATA_PATH" echo "完成扩容:新增$DIFF个worker实例" elif [ $DIFF -lt 0 ]; then # 销毁多余实例,优先销毁启动时间最早的实例 TERMINATE_NUM=$(( -DIFF )) TERMINATE_IDS=$(aws ec2 describe-instances \ --filters "Name=tag:$WORKER_TAG" "Name=instance-state-name,Values=running" \ --query "sort_by(Reservations[*].Instances[], &LaunchTime)[:$TERMINATE_NUM].InstanceId" \ --output text) aws ec2 terminate-instances --instance-ids $TERMINATE_IDS echo "完成缩容:销毁$TERMINATE_NUM个多余worker实例" fi sleep 15 done
问题2:创建可直接处理SQS消息的EC2实例最简方案
不需要额外配置私有VPC和安全组,用AWS默认VPC的默认配置即可满足需求,默认安全组本来就放通了所有出方向流量,默认VPC的EC2可以直接访问公网SQS端点。你只需要提前做好1项权限配置即可:
- 在IAM控制台创建一个EC2类型的实例配置文件(Instance Profile),附加仅允许访问目标SQS队列的权限策略(也可以临时用
AmazonSQSFullAccess权限做测试) - 创建EC2实例时指定上述实例配置文件,不需要在实例里硬编码AK/SK即可直接调用SQS接口
- 把消息处理逻辑写入实例的用户数据(UserData),实例启动后会自动执行该逻辑,直接拉取SQS消息处理即可
这里给出实例内消息处理脚本的参考实现:
#!/bin/bash # 预装依赖(Amazon Linux默认已装aws-cli,若用其他系统需要自行安装) yum install -y jq aws-cli QUEUE_URL="替换为你的SQS队列URL" while true; do # 长轮询拉取消息,最多等20秒 MESSAGE=$(aws sqs receive-message \ --queue-url "$QUEUE_URL" \ --max-number-of-messages 1 \ --wait-time-seconds 20) # 没拉到消息就继续循环 [ -z "$MESSAGE" ] && continue # 解析消息内容和删除凭证 MSG_BODY=$(echo "$MESSAGE" | jq -r '.Messages[0].Body') RECEIPT_HANDLE=$(echo "$MESSAGE" | jq -r '.Messages[0].ReceiptHandle') # 这里替换为你自己的业务处理逻辑 echo "处理消息内容:$MSG_BODY" # 处理完成后删除队列中的消息 aws sqs delete-message --queue-url "$QUEUE_URL" --receipt-handle "$RECEIPT_HANDLE" done
内容的提问来源于stack exchange,提问作者Doraemon
相关产品推荐
相关产品推荐

