自动化脚本如何清理未使用资源

wen 实用脚本 1

从闲置到高效,企业云成本优化的终极指南

目录导读

  1. 未使用资源的隐形代价 — 为什么你每月都在为“空气”付费?
  2. 自动化清理的核心逻辑 — 三大脚本范式与选择标准
  3. 实战:四类主流资源的清理脚本案例(AWS/Azure/阿里云/本地VM)
  4. 零误删安全策略 — 标签、快照与灰度发布
  5. 常见问题与问答 — 当脚本“误杀”时怎么办?
  6. SEO关键词整合与行动建议

未使用资源的隐形代价

在《福布斯》2024年的一份报告中指出,企业云支出平均有 32% 浪费在闲置或过度配置的资源上,典型的“僵尸资源”包括:

自动化脚本如何清理未使用资源

  • 连续运行但无流量的负载均衡器(每月约$30~$300)
  • 已挂载但不再被访问的旧数据卷(每100GB每月约$15~$50)
  • 开发测试完成后无人回收的虚拟机(每台每月$50~$500)
  • 长期未更新的API网关、孤立的弹性IP(每IP每月约$3.6)

核心痛点:人工排查不仅耗时(平均每次全量扫描需2~8小时),且易遗漏,自动化脚本能让这一过程从“天级”降至“分钟级”。


自动化清理的核心逻辑

任何清理脚本都应遵循 “识别→确认→标记→清理” 模块化设计,常见范式有:

1 基于标签的过期策略

  • 在创建资源时强制要求标签:OwnerExpiryDateEnvironment
  • 脚本逻辑:扫描所有资源,若 ExpiryDate 早于当前日期且无最新活动记录,则自动发送告警并创建快照后删除。

2 基于活动状态的筛选器

  • 针对流量类资源(Elastic Load Balancer、CDN):过去30天平均流量 < 1MB
  • 针对存储类资源(EBS卷):最后挂载时间 > 90天且无正在运行的实例使用
  • 通过云提供商API获取Metric数据,而非仅看状态。

3 基于引用链的孤儿资源识别

  • 扫描关联关系:例如未被任何安全组引用的独立安全组、未被任何EC2实例连接的EIP
  • 使用图算法(如BFS)遍历所有资源间的引用,找出“孤立节点”。

选择标准

  • 单环境小团队:Bash/PowerShell + 云CLI(快速上手)
  • 多账号大规模:Python + Boto3/Azure SDK + Terraform State集成
  • 需要可视化:推荐采用Airflow或AWS Step Functions编排

实战:四类主流资源的清理脚本案例

案例1:AWS ElastiCache未使用节点清理(Python + Boto3)

import boto3
import datetime
def list_idle_redis_nodes():
    client = boto3.client('elasticache')
    nodes = client.describe_cache_clusters()['CacheClusters']
    idle_nodes = []
    for node in nodes:
        # 使用CloudWatch获取3天内的CPU利用率
        cw = boto3.client('cloudwatch')
        response = cw.get_metric_statistics(
            Namespace='AWS/ElastiCache',
            MetricName='CPUUtilization',
            Dimensions=[{'Name':'CacheClusterId','Value': node['CacheClusterId']}],
            StartTime=datetime.datetime.utcnow() - datetime.timedelta(days=3),
            EndTime=datetime.datetime.utcnow(),
            Period=3600*24,
            Statistics=['Average']
        )
        datapoints = response['Datapoints']
        if not datapoints or max(p['Average'] for p in datapoints) < 5:  # CPU<5%
            idle_nodes.append(node['CacheClusterId'])
    return idle_nodes
if __name__ == '__main__':
    idle = list_idle_redis_nodes()
    print(f"发现 {len(idle)} 个闲置Redis集群:{idle}")
    # 接下来发送Slack通知,等待人工确认后再执行删除

案例2:阿里云弹性公网IP包年包月到期自动释放(Shell + aliyun CLI)

#!/bin/bash
# 获取所有包年包月但未被绑定的EIP
aliyun ecs DescribeEipAddresses --RegionId cn-hangzhou \
  --Status Available --query "EipAddresses.EipAddress[?PackageType=='PrePaid']" > eip_list.json
for ip in $(cat eip_list.json | jq -r '.[].AllocationId'); do
    expire_date=$(aliyun ecs DescribeEipAddresses --RegionId cn-hangzhou \
      --AllocationId "$ip" --query "EipAddresses.EipAddress[0].ExpiredTime" --output text)
    now=$(date +%s)
    expire=$(date -d "$expire_date" +%s)
    if [ $now -gt $expire ]; then
        echo "释放已过期EIP: $ip"
        aliyun ecs ReleaseEipAddress --AllocationId "$ip" --RegionId cn-hangzhou
    fi
done

案例3:本地VMware中孤立的VMDK文件清理(PowerCLI)

# 扫描所有数据存储中不被任何VM引用的VMDK文件
$allVDisks = Get-Datastore | Get-Datastore -Name "DS1" | Get-HardDisk | Select-Object @{N="Path";E={$_.DiskFile}}
$orphans = Get-ChildItem -Path "vmfs/volumes/DS1" -Recurse -Filter "*.vmdk" | 
           Where-Object { $allVDisks.Path -notcontains $_.FullName }
$orphans | ForEach-Object {
    Write-Warning "发现孤立磁盘: $($_.FullName)"
    Remove-Item $_.FullName -Force -WhatIf  # 先执行WhatIf测试
}

案例4:Azure Unmanaged Disk残留Managed Disk引用清理

# 配合Azure Resource Graph查询所有未被任何VM或容器使用的Managed Disk
az graph query --graph-query "
resources
| where type == 'microsoft.compute/disks'
| where properties.diskState == 'Unattached'
| extend CreatedDays = datetime_diff('day', now(), properties.timeCreated)
| where CreatedDays > 90
| project name, resourceGroup, location, createdTime=properties.timeCreated
" --output tsv

零误删安全策略:先模拟再执行

常见误删案例:清理团队误将处于“临时资源状态”的数据库从属磁盘删除,导致生产中断,以下是关键防护措施:

阶段 措施 脚本实现
模拟运行 所有删除前添加 --dry-run-WhatIf 参数 输出 [DRY RUN] 将删除:xxx,不真实执行
人工审批 脚本生成CSV/JSON列表后,发送至Slack/钉钉webhook并等待approve回复 使用 input() 或等待文件中出现“YES”标记
快照保护 对存储类资源,删除前自动创建最终增量快照(保留7天) 调用 CreateSnapshot API并在删除命令之前执行
资源锁定 对有 Is Production 标签的资源跳过清理逻辑 if tags.get('env') == 'prod': continue
分批执行 每次最多处理5个资源,持续15分钟观察影响 使用 for i in range(0, len(resources), 5) + time.sleep(900)

常见问题与问答(基于维基百科、Reddit r/devops 及AWS官方文档综合)

Q1:脚本清理了正在被监控但无流量的测试环境资源,导致警报误报怎么办?
A:加入“白名单”,在脚本的配置文件中维护一个 EXCEPTION_LIST(如资源ID、标签 skip=true),并在筛选逻辑开始前进行一次过滤,可对接CMDB,只清理“正式标记为可清理”的资源。

Q2:如何保证脚本不一次性删除大量核心资源?
A:实施“百分比阈值”,总清理数量超过当前资源总数的10%时自动暂停并告警;另一种方式是设置“每次最多删除10个,隔天执行下一批”。

Q3:跨多个云账号的清理脚本如何统一管理?
A:推荐采用Terraform Workspace + GitOps流程:每个账号对应一个工作区,Git仓库中的 cleanup_config.yaml 定义清理策略,通过CI/CD定时触发,也可使用AWS Organizations中的AWS Config高级查询来跨账号扫描。

Q4:脚本运行时产生高API调用费用怎么办?
A:利用云厂商的缓存机制或批量查询接口,例如在AWS中,使用describe_*时指定MaxResults并分页获取;在Azure中,使用资源图(Resource Graph)一次性检索所有资源,大幅减少API调用次数。

Q5:清理后的资源日志如何存储与审计?
A:脚本将每次操作的行记录(操作前状态、操作时间、操作人、清理结果)输出到中央日志系统(如ELK、CloudWatch Logs、S3),并设置保留90天,每次清理后自动触发一个下游工作流,发送摘要到Audit邮箱。


SEO关键词整合与行动建议

核心关键词(已自然植入):

  • 自动化清理未使用资源脚本
  • 云成本优化僵尸资源管理
  • AWS闲置资源自动检测
  • Python Boto3脚本清理云资源
  • 零误删云资源清理策略

建议下一步行动

  1. 在你的生产环境中先选取一个非关键区域(如开发账号),部署一个Dry Run脚本观察一周;
  2. 将脚本集成到 CI/CD流水线(如GitLab CI定时任务),每周日凌晨自动扫描;
  3. 设置成本告警阈值(如预计节省$500/月就Slack通知),持续优化。

最终提醒:自动化清理不是“一刀切”,而是持续的数据驱动决策,从最小范围开始,逐步扩展到全量资源,始终保留“人工最终确认”的熔断机制。


全文共1472字,基于AWS、Azure、阿里云官方文档、Reddit DevOps社区讨论及Stack Overflow常见方案综合整理,所有域名引用处已按指示替换为通用表述。

抱歉,评论功能暂时关闭!