本文目录导读:

- 核心设计思路
- AWS 环境 (Python + Boto3)
- Azure 环境 (Bash + Azure CLI)
- 阿里云环境 (Python + Aliyun SDK)
- Kubernetes 环境 (清理 Service 或 Pod 残留子网)
- 风险控制与最佳实践
清理未使用的子网是云资源管理和成本优化中的重要任务,由于不同云平台(AWS、Azure、GCP、阿里云等)的API和资源模型差异较大,自动化脚本需要针对具体平台编写。
以下提供几种主流云平台的自动化脚本示例,以及通用的设计思路和风险控制措施。
核心设计思路
- 列举所有子网:通过云平台API列出当前区域/项目下的所有子网。
- 检测关联资源:检查子网是否被以下资源关联(这是最关键的过滤条件):
- 云主机/虚拟机:网卡(ENI)是否位于该子网。
- 负载均衡器:其可用区交换机是否指向该子网。
- 数据库服务(RDS, Redis, MongoDB等):是否部署在该子网。
- 容器服务(K8s, ECS Fargate, ACK):Pod或Service是否使用该子网。
- NAT网关、VPN连接、专线等网络设备。
- 弹性网卡/辅助网卡。
- 其他VPC对等连接/TR(中转路由器)的路由表条目。
- 标记与清理:
- 先标记:列出未使用子网清单,人工确认或发通知。
- 后删除:只有确认无依赖后,才调用API删除。强烈不建议直接删除。
AWS 环境 (Python + Boto3)
AWS 的 VPC 和子网管理非常成熟,核心是检查子网内是否有 EC2、ENI、RDS、ELB 等。
import boto3
from botocore.exceptions import ClientError
def list_unused_subnets(region='us-east-1'):
"""列出指定区域内所有未使用的子网"""
ec2_client = boto3.client('ec2', region_name=region)
ec2_resource = boto3.resource('ec2', region_name=region)
# 1. 获取所有子网
subnets = list(ec2_resource.subnets.all())
print(f"总子网数量: {len(subnets)}")
# 2. 获取所有正在使用的网卡 (ENI)
# 注意:ENI是判断子网是否被使用的核心,每个EC2、NAT、ELB等都会创建ENI
used_enis = set()
paginator = ec2_client.get_paginator('describe_network_interfaces')
for page in paginator.paginate():
for eni in page['NetworkInterfaces']:
if 'SubnetId' in eni:
used_enis.add(eni['SubnetId'])
# 3. 获取所有子网级别的路由表关联(排除主路由表,主表通常有默认路由)
# 逻辑:如果子网显式关联了路由表,且该表关联了其他资源如IGW、NAT等,也算在使用
used_subnets_in_routes = set()
route_tables = ec2_client.describe_route_tables()['RouteTables']
for rt in route_tables:
for assoc in rt['Associations']:
if 'SubnetId' in assoc:
used_subnets_in_routes.add(assoc['SubnetId'])
# 4. 检查其他服务(如RDS, ElastiCache, Redshift等)
# 可以通过DescribeDBSubnetGroups等API获取关联的子网
used_rds_subnets = set()
try:
rds_client = boto3.client('rds', region_name=region)
paginator = rds_client.get_paginator('describe_db_subnet_groups')
for page in paginator.paginate():
for group in page['DBSubnetGroups']:
for subnet in group['Subnets']:
used_rds_subnets.add(subnet['SubnetIdentifier'])
except ClientError:
pass # 没有权限或没有RDS资源
# 综合所有使用中的子网
all_used = used_enis.union(used_subnets_in_routes, used_rds_subnets)
# 5. 筛选未使用的子网
unused_subnets = []
for subnet in subnets:
if subnet.id not in all_used:
# 可选:进一步检查子网内的ENI数量,确保没有隐藏的对象
eni_in_subnet = ec2_client.describe_network_interfaces(
Filters=[{'Name': 'subnet-id', 'Values': [subnet.id]}]
)['NetworkInterfaces']
if len(eni_in_subnet) == 0:
unused_subnets.append({
'id': subnet.id,
'vpc_id': subnet.vpc_id,
'cidr': subnet.cidr_block,
'az': subnet.availability_zone
})
return unused_subnets
# 执行并生成报告
if __name__ == "__main__":
unused = list_unused_subnets()
if unused:
print(f"发现 {len(unused)} 个未使用子网:")
for subnet in unused:
print(f" - {subnet['id']} (VPC: {subnet['vpc_id']}, CIDR: {subnet['cidr']})")
# 安全删除(建议先导出人工确认)
# for subnet in unused:
# ec2 = boto3.resource('ec2')
# ec2.Subnet(subnet['id']).delete()
else:
print("没有找到未使用的子网。")
Azure 环境 (Bash + Azure CLI)
Azure 的 VNet 和子网检查逻辑类似,但资源模型略有不同。
#!/bin/bash
# 检查未使用的 Azure 子网
# 前提:已登录 az login
RG="your-resource-group" # 可选,指定资源组;不指定则检查所有
SUBSCRIPTION_ID=$(az account show --query id -o tsv)
echo "开始扫描子网..."
# 1. 获取所有子网 ID
if [ -z "$RG" ]; then
SUBNETS=$(az network vnet list --query "[].subnets[].id" -o tsv)
else
SUBNETS=$(az network vnet list -g $RG --query "[].subnets[].id" -o tsv)
fi
# 2. 获取所有与子网关联的网络接口 (NIC)
ALL_NICS=$(az network nic list --query "[].ipConfigurations[].subnet.id" -o tsv)
# 3. 获取负载均衡器、应用网关等关联的后端子网
ALL_LB_SUBNETS=$(az network lb list --query "[].frontendIPConfigurations[].subnet.id" -o tsv)
ALL_APPGW_SUBNETS=$(az network application-gateway list --query "[].gatewayIPConfigurations[].subnet.id" -o tsv)
# 合并所有被使用的子网(去重)
USED_SUBNETS=$(echo -e "$ALL_NICS\n$ALL_LB_SUBNETS\n$ALL_APPGW_SUBNETS" | sort -u)
# 4. 对比并输出未使用的子网
UNUSED_COUNT=0
for SUBNET_ID in $SUBNETS; do
SUB_NAME=$(echo $SUBNET_ID | awk -F'/' '{print $NF}')
VNET_NAME=$(echo $SUBNET_ID | awk -F'/' '{print $9}')
if ! echo "$USED_SUBNETS" | grep -Fxq "$SUBNET_ID"; then
# 可选:检查路由表关联,确保没有隐藏用途
RT_ASSOC=$(az network vnet subnet show --ids $SUBNET_ID --query "routeTable.id" -o tsv)
if [ -z "$RT_ASSOC" ]; then # 如果没关联路由表,则确认未使用
echo "未使用子网: $VNET_NAME -> $SUB_NAME ($SUBNET_ID)"
((UNUSED_COUNT++))
fi
fi
done
echo "总计 $UNUSED_COUNT 个未使用子网。"
# 如果要删除,可以添加:
# for SUBNET in ...; do
# az network vnet subnet delete --ids $SUBNET_ID
# done
阿里云环境 (Python + Aliyun SDK)
阿里云使用 VPC API,核心检查对象是 ReservedPublicAddress、NetworkInterface 和 VSwitch。
from aliyunsdkvpc.request.v20160428 import DescribeVSwitchesRequest, DeleteVSwitchRequest
from aliyunsdkecs.request.v20140526 import DescribeNetworkInterfacesRequest
import json
def get_unused_vswitches(region_id='cn-hangzhou'):
# 客户端初始化 (需配置AccessKey)
from aliyunsdkcore.client import AcsClient
client = AcsClient('your-access-key-id', 'your-access-key-secret', region_id)
# 1. 获取所有交换机
request = DescribeVSwitchesRequest.DescribeVSwitchesRequest()
request.set_PageSize(50)
response = client.do_action_with_exception(request)
vswitch_list = json.loads(response)['VSwitches']['VSwitch']
# 2. 获取所有弹性网卡 (ENI),并提取其所属的VSwitch ID
eni_request = DescribeNetworkInterfacesRequest.DescribeNetworkInterfacesRequest()
eni_request.set_PageSize(100)
eni_response = client.do_action_with_exception(eni_request)
eni_list = json.loads(eni_response)['NetworkInterfaceSets']['NetworkInterfaceSet']
# 收集已使用的VSwitch ID
used_vswitches = set()
for eni in eni_list:
if 'VSwitchId' in eni:
used_vswitches.add(eni['VSwitchId'])
# 3. 过滤出未使用的交换机
unused = []
for vsw in vswitch_list:
vsw_id = vsw['VSwitchId']
if vsw_id not in used_vswitches:
# 可选:检查是否有默认SNAT条目或其他依赖
# 略...
unused.append({
'id': vsw_id,
'vpc': vsw['VpcId'],
'cidr': vsw['CidrBlock'],
'zone': vsw['ZoneId']
})
return unused
if __name__ == "__main__":
unused = get_unused_vswitches()
for vsw in unused:
print(f"未使用交换机: {vsw['id']} (VPC: {vsw['vpc']}, CIDR: {vsw['cidr']})")
Kubernetes 环境 (清理 Service 或 Pod 残留子网)
如果是自建 K8s 集群(例如使用 Calico、Flannel)或云原生集群(AKS/EKS/ACK),子网可能被 Service 的 LoadBalancer 或 Pod 网络的 IP 占用,但 API 层面可能不显示。
# 检查 Kubernetes 集群中是否还有指向某子网的 Service # 查找所有 LoadBalancer 类型的 Service,以及其关联的 IP 段 kubectl get svc --all-namespaces | grep LoadBalancer # 检查 Ingress Controller 是否占用子网 kubectl get ingress --all-namespaces # 检查 NodePort 或 ClusterIP 通常不占用子网,但如果你使用了云厂商的 VPC-CNI 插件 # 需要检查 Pod 是否还在使用该子网的 IP 段 # 可以使用 calicoctl 或 cilium 的命令来检查 IP 分配情况
风险控制与最佳实践
- 安全第一:切勿直接删除,先导出未使用子网清单,发给所有相关团队(网络、安全、应用)确认。
- 设置保护锁:在云控制台或 Terraform/Pulumi 中为关键子网添加
PreventDestroy或禁止删除标签。 - 保留一定时间窗口:标记为“未使用”后,设置一个冷却期(如7天),期间该子网被再次使用则移出清理名单。
- 考虑CIDR冲突:删除子网可能会导致现有VPC的CIDR范围缩小,未来无法复用该IP段,可先在内部网络规划中记录。
- 自动化通知:将脚本集成到 CI/CD 或定时任务中,定期生成报告并发送到 Slack/邮件,由管理员手动批准删除。
- 检查非显式依赖:
- 保留路由规则:如果子网已在路由表中有显式路由(如指向NAT/IGW),可能预示着未来扩展。
- DHCP选项集:非常用,但可能有关联。
- DNS解析记录:子网的Private DNS Zone若有记录,可能被其他服务引用。
没有“万能一键清理脚本”,因为每个环境的拓扑、权限和业务依赖不同,推荐的做法是:
- 第一步:使用上述脚本扫描并生成未使用子网清单。
- 第二步:人工复核(联系网络/应用团队)。
- 第三步:设置自动清理任务,但仅对为
auto-delete=true或创建超过30天的空闲子网执行删除。
这样可以最大程度地避免“误删可用资源”导致的生产事故。
版权声明:NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播