统计指定时间内排除特定标签的已终止EC2实例数量问题排查
问题描述
- 需求1:统计2024年1月1日至今日已终止的EC2实例总数
- 需求2:统计过去一年已终止的EC2实例,但需排除标签key为
databricks的实例;当前使用提供的bash脚本查询时计数为0,移除jq语句中的select(.tags[]?.key != "databricks")后可得到有效计数,需排查脚本问题
原脚本:
MAX_RETRIES=5 RETRY_DELAY=5 RETRY_COUNT=0 while [ $RETRY_COUNT -lt $MAX_RETRIES ]; do aws cloudtrail lookup-events \ --region us-east-1 \ --lookup-attributes AttributeKey=EventName,AttributeValue=TerminateInstances \ --start-time 2024-01-01T00:00:00Z \ --end-time 2024-12-10T23:59:59Z \ --query 'Events[*].CloudTrailEvent' \ --output json | tee terminated_instances.json | jq '[.[] | fromjson | .requestParameters.instancesSet.items[] | select(.tags[]?.key != "databricks") | .instanceId] | length' if [ $? -eq 0 ]; then break fi RETRY_COUNT=$((RETRY_COUNT + 1)) echo "Retry $RETRY_COUNT/$MAX_RETRIES..." sleep $((RETRY_DELAY * RETRY_COUNT)) done if [ $RETRY_COUNT -eq $MAX_RETRIES ]; then echo "Failed after $MAX_RETRIES attempts." exit 1 fi
脚本问题排查与修复
问题根源
原脚本的核心错误有两点:
- CloudTrail事件不包含实例标签:
TerminateInstances事件的requestParameters字段仅记录要终止的实例ID,不会携带实例的标签属性,因此.tags字段根本不存在,导致select(.tags[]?.key != "databricks")条件永远无法匹配,最终计数为0。 - 结束时间固定:原脚本的
--end-time写死为2024-12-10T23:59:59Z,无法满足需求1中“至今日”的统计要求。
修复后的脚本
MAX_RETRIES=5 RETRY_DELAY=5 RETRY_COUNT=0 while [ $RETRY_COUNT -lt $MAX_RETRIES ]; do # 获取2024-01-01至今日所有终止的EC2实例ID,去重避免重复统计 INSTANCE_IDS=$(aws cloudtrail lookup-events \ --region us-east-1 \ --lookup-attributes AttributeKey=EventName,AttributeValue=TerminateInstances \ --start-time 2024-01-01T00:00:00Z \ --end-time $(date -u +%Y-%m-%dT%H:%M:%SZ) \ --query 'Events[*].CloudTrailEvent' \ --output json | jq -r '[.[] | fromjson | .requestParameters.instancesSet.items[] | .instanceId] | unique | .[]') if [ $? -eq 0 ]; then if [ -z "$INSTANCE_IDS" ]; then echo "2024年1月1日至今无已终止的EC2实例" break fi # 查询实例标签,排除含databricks标签的实例并统计数量 FILTERED_COUNT=$(aws ec2 describe-instances \ --region us-east-1 \ --instance-ids $INSTANCE_IDS \ --query 'Reservations[*].Instances[*] | [.[] | .[] | select( not(.Tags[]? | .Key == "databricks") )] | length' \ --output text) echo "符合条件的已终止EC2实例总数:$FILTERED_COUNT" break fi RETRY_COUNT=$((RETRY_COUNT + 1)) echo "Retry $RETRY_COUNT/$MAX_RETRIES..." sleep $((RETRY_DELAY * RETRY_COUNT)) done if [ $RETRY_COUNT -eq $MAX_RETRIES ]; then echo "Failed after $MAX_RETRIES attempts." exit 1 fi
关键说明
- 拆分统计逻辑:先通过CloudTrail收集所有终止的实例ID,再调用
aws ec2 describe-instances查询实例标签属性,实现精准过滤。 - 正确的标签过滤逻辑:
select( not(.Tags[]? | .Key == "databricks") )确保:- 无标签的实例会被保留
- 任何包含
databricks标签的实例会被排除
- 动态结束时间:用
$(date -u +%Y-%m-%dT%H:%M:%SZ)自动获取当前UTC时间,满足需求1中“至今日”的统计要求。 - 去重处理:通过jq的
unique对实例ID去重,避免因多次终止请求(如批量终止)导致重复统计。
内容的提问来源于stack exchange,提问作者user1223334
相关产品推荐
相关产品推荐

