You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

EC2实例终止前附加资源删除顺序及Boto3代码编写咨询

EC2实例终止前的附加资源处理顺序及Boto3代码实现

资源处理顺序(手动清理场景)

大部分和EC2实例关联的资源,部分可设置终止时自动删除,但如果需要手动清理,推荐按以下顺序操作,避免资源残留或报错:

  • 第一步:处理弹性IP(EIP):先分离实例绑定的EIP,再释放EIP。如果不手动释放,实例终止后EIP会继续保留在账户中产生费用。
  • 第二步:清理附加的弹性网络接口:实例的主网络接口会随实例终止自动删除,但手动附加的弹性网络接口需要先从实例分离,再删除接口本身。
  • 第三步:处理附加的EBS卷:如果是手动附加的非根卷(或根卷设置了“终止时保留”),先从实例分离卷,再删除卷。根卷如果默认设置“终止时删除”,则无需手动处理。
  • 第四步:移除负载均衡目标组关联:如果实例在负载均衡目标组中,先将实例从目标组移除,避免负载均衡后续出现健康检查错误。
  • 可选:清理专属安全组/密钥对:如果安全组或密钥对是专门为该实例创建的,且后续不再使用,可在实例终止后删除(无需在终止前操作)。

Boto3 Python代码实现

以下是完整的清理+终止实例代码,包含基础异常处理:

import boto3
from botocore.exceptions import ClientError

# 初始化EC2客户端
ec2 = boto3.client('ec2')
elbv2 = boto3.client('elbv2')  # 涉及负载均衡目标组时需初始化

# 目标实例ID
INSTANCE_ID = 'i-xxxxxxxxx'

def release_elastic_ips(instance_id):
    """分离并释放实例绑定的弹性IP"""
    try:
        addresses = ec2.describe_addresses(Filters=[{'Name': 'instance-id', 'Values': [instance_id]}])
        for addr in addresses['Addresses']:
            ec2.disassociate_address(AssociationId=addr['AssociationId'])
            ec2.release_address(AllocationId=addr['AllocationId'])
            print(f"已释放弹性IP: {addr['PublicIp']}")
    except ClientError as e:
        print(f"处理弹性IP时出错: {e.response['Error']['Message']}")

def cleanup_network_interfaces(instance_id):
    """清理附加的弹性网络接口"""
    try:
        enis = ec2.describe_network_interfaces(Filters=[{'Name': 'attachment.instance-id', 'Values': [instance_id]}])
        for eni in enis['NetworkInterfaces']:
            # 跳过主网络接口(随实例自动删除)
            if eni['Attachment']['DeviceIndex'] == 0:
                continue
            ec2.detach_network_interface(AttachmentId=eni['Attachment']['AttachmentId'])
            ec2.delete_network_interface(NetworkInterfaceId=eni['NetworkInterfaceId'])
            print(f"已删除弹性网络接口: {eni['NetworkInterfaceId']}")
    except ClientError as e:
        print(f"处理网络接口时出错: {e.response['Error']['Message']}")

def cleanup_ebs_volumes(instance_id):
    """清理附加的EBS卷"""
    try:
        volumes = ec2.describe_volumes(Filters=[{'Name': 'attachment.instance-id', 'Values': [instance_id]}])
        for vol in volumes['Volumes']:
            # 跳过根卷(默认终止时自动删除)
            if any(att['Device'] in ['/dev/sda1', '/dev/xvda'] for att in vol['Attachments']):
                continue
            ec2.detach_volume(VolumeId=vol['VolumeId'])
            ec2.delete_volume(VolumeId=vol['VolumeId'])
            print(f"已删除EBS卷: {vol['VolumeId']}")
    except ClientError as e:
        print(f"处理EBS卷时出错: {e.response['Error']['Message']}")

def remove_from_target_groups(instance_id):
    """将实例从所有负载均衡目标组移除"""
    try:
        target_groups = elbv2.describe_target_groups()
        for tg in target_groups['TargetGroups']:
            targets = elbv2.describe_target_health(TargetGroupArn=tg['TargetGroupArn'])
            for th in targets['TargetHealthDescriptions']:
                if th['Target']['Id'] == instance_id:
                    elbv2.deregister_targets(
                        TargetGroupArn=tg['TargetGroupArn'],
                        Targets=[{'Id': instance_id}]
                    )
                    print(f"已将实例从目标组移除: {tg['TargetGroupName']}")
    except ClientError as e:
        print(f"处理目标组时出错: {e.response['Error']['Message']}")

def terminate_ec2_instance(instance_id):
    """终止EC2实例"""
    try:
        ec2.terminate_instances(InstanceIds=[instance_id])
        print(f"已提交EC2实例终止请求: {instance_id}")
    except ClientError as e:
        print(f"终止实例时出错: {e.response['Error']['Message']}")

# 按顺序执行操作
if __name__ == "__main__":
    release_elastic_ips(INSTANCE_ID)
    cleanup_network_interfaces(INSTANCE_ID)
    cleanup_ebs_volumes(INSTANCE_ID)
    remove_from_target_groups(INSTANCE_ID)
    terminate_ec2_instance(INSTANCE_ID)

注意事项

  • 权限配置:确保执行代码的IAM角色/用户拥有ec2:DescribeAddresses、ec2:DisassociateAddress、ec2:ReleaseAddress、ec2:DescribeNetworkInterfaces、ec2:DetachNetworkInterface、ec2:DeleteNetworkInterface、ec2:DescribeVolumes、ec2:DetachVolume、ec2:DeleteVolume、ec2:TerminateInstances等权限(涉及负载均衡时需额外添加elbv2:DescribeTargetGroups、elbv2:DescribeTargetHealth、elbv2:DeregisterTargets权限)。
  • 自动删除设置:创建实例时可将EBS根卷的DeleteOnTermination设为True,实例终止时会自动删除根卷;实例创建时自动生成的网络接口也会随实例终止删除,无需手动处理。
  • 异常扩展:代码仅包含基础异常捕获,可根据实际需求添加重试、日志记录等逻辑。

内容的提问来源于stack exchange,提问作者Jagadish Manchala

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.03 21:50:36