如何使用boto3在不关闭EC2实例的情况下创建AWS快照?
嗨,我之前也碰到过这个坑——控制台创建运行中实例的快照完全不用关机,但自己写的boto3脚本却把实例停了,这在生产环境里绝对是红线问题。
问题根源
大概率是你的脚本里不小心加了停止实例的逻辑(比如调用了ec2.stop_instances()),或者误解了快照创建的流程:AWS EBS本身就支持在线快照,运行中的实例挂载的卷完全可以直接创建快照,根本不需要关机。
正确的自动化快照脚本
下面是我一直在用的生产级脚本,遍历所有运行中的实例,为它们的EBS卷创建快照,全程不会停止实例:
import boto3 from datetime import datetime def create_online_snapshots(): # 初始化EC2资源客户端 ec2 = boto3.resource('ec2') # 筛选所有处于运行状态的实例 running_instances = ec2.instances.filter( Filters=[{'Name': 'instance-state-name', 'Values': ['running']}] ) for instance in running_instances: # 获取实例名称(如果有标签的话) instance_name = next((tag['Value'] for tag in instance.tags if tag['Key'] == 'Name'), instance.id) print(f"=== 开始处理实例: {instance_name} ({instance.id}) ===") # 遍历实例挂载的所有EBS卷 for volume in instance.volumes.all(): # 生成带时间戳的快照描述,方便后续识别 snapshot_desc = f"Auto-snapshot | Instance: {instance_name} | Volume: {volume.id} | Created: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}" # 直接创建快照,无需停止实例 snapshot = volume.create_snapshot(Description=snapshot_desc) print(f"已创建快照: {snapshot.id} (对应卷: {volume.id})") # 可选:等待快照完成(生产环境可以异步处理,不用阻塞) snapshot.wait_until_completed() print(f"快照 {snapshot.id} 已完成") if __name__ == "__main__": create_online_snapshots()
关键注意点
不要停止实例:移除脚本中任何
stop_instances()的调用,Volume.create_snapshot()方法本身就支持在线操作。文件系统一致性(可选但推荐):如果你的应用对数据一致性要求极高(比如数据库实例),可以在创建快照前临时冻结文件系统,完成后再解冻——不用关机,用AWS SSM就能远程执行命令:
import boto3 ssm_client = boto3.client('ssm') def freeze_filesystem(instance_id, mount_point="/"): # 执行文件系统冻结 response = ssm_client.send_command( InstanceIds=[instance_id], DocumentName='AWS-RunShellScript', Parameters={'commands': [f"fsfreeze -f {mount_point}"]} ) # 等待命令执行完成 command_id = response['Command']['CommandId'] ssm_client.get_waiter('command_executed').wait( CommandId=command_id, InstanceId=instance_id ) print(f"已冻结实例 {instance_id} 的文件系统: {mount_point}") def unfreeze_filesystem(instance_id, mount_point="/"): # 解冻文件系统 response = ssm_client.send_command( InstanceIds=[instance_id], DocumentName='AWS-RunShellScript', Parameters={'commands': [f"fsfreeze -u {mount_point}"]} ) command_id = response['Command']['CommandId'] ssm_client.get_waiter('command_executed').wait( CommandId=command_id, InstanceId=instance_id ) print(f"已解冻实例 {instance_id} 的文件系统: {mount_point}")你可以在创建快照前调用
freeze_filesystem,创建完成后调用unfreeze_filesystem,这样能保证快照的数据一致性,同时完全不影响实例运行。IAM权限:确保执行脚本的角色/用户有
ec2:CreateSnapshot、ec2:DescribeInstances、ec2:DescribeVolumes等权限,如果用SSM的话,还需要ssm:SendCommand和ssm:GetCommandInvocation权限。
总结
只要去掉脚本中停止实例的逻辑,直接调用卷的create_snapshot()方法,就能实现和控制台一样的在线快照功能,完全符合生产环境的要求。
内容的提问来源于stack exchange,提问作者Chrisjx

