基于boto3制作共享Ubuntu AMI的最佳实践及清理方案问询
问题解决:Ubuntu共享AMI清理源实例密钥
1. 清理时机与思路
只能在创建AMI前清理实例——因为AMI是基于实例磁盘快照生成的只读镜像,创建后无法直接修改镜像内的文件。如果等到AMI创建后再处理,只能在每个新实例启动时单独清理,这会增加额外运维步骤,完全违背共享AMI的设计初衷。
核心清理思路:
- 清空或删除源实例中目标用户的
~/.ssh/authorized_keys文件(Ubuntu默认是ubuntu用户的/home/ubuntu/.ssh/authorized_keys),移除源实例的密钥信息 - 可选额外清理项:删除bash历史(
rm ~/.bash_history)、临时文件(rm -rf /tmp/*)、截断系统日志(truncate -s 0 /var/log/*.log)等,保证AMI的干净度
2. 执行方式说明
boto3仅能管理EC2的资源生命周期(创建实例、生成AMI、终止实例等),无法直接执行实例内部的命令,必须通过以下两种方式之一在实例上运行清理操作:
- SSM Run Command:推荐方案,无需管理SSH密钥,只要实例预装SSM Agent(Ubuntu官方AMI默认自带)且实例关联了具备SSM权限的IAM角色,即可通过boto3调用SSM API执行命令
- Paramiko/SSH:通过SSH连接实例执行命令,但需要持有实例的私钥,安全性和可维护性远不如SSM
3. Python代码示例(基于SSM方案)
以下代码实现:通过SSM清理源实例的authorized_keys,创建AMI,最后终止实例。
import boto3 import time def wait_for_ssm_command(command_id, instance_id): """等待SSM命令执行完成""" ssm_client = boto3.client('ssm') while True: response = ssm_client.get_command_invocation( CommandId=command_id, InstanceId=instance_id ) status = response['Status'] if status in ['Success', 'Failed', 'TimedOut']: return status print(f"SSM命令执行中,当前状态: {status}") time.sleep(5) def wait_for_ami_available(ami_id): """等待AMI状态变为可用""" ec2_client = boto3.client('ec2') while True: response = ec2_client.describe_images(ImageIds=[ami_id]) state = response['Images'][0]['State'] if state == 'available': return print(f"AMI创建中,当前状态: {state}") time.sleep(10) def main(): # 配置参数,替换为你的实际值 instance_id = 'i-0abcdef1234567890' ami_name = 'Clean-Ubuntu-Shared-AMI' ami_description = 'Ubuntu AMI with cleaned authorized_keys' # 初始化客户端 ssm_client = boto3.client('ssm') ec2_client = boto3.client('ec2') # 发送SSM清理命令 cleanup_commands = [ 'echo -n "" > /home/ubuntu/.ssh/authorized_keys', 'rm -f /home/ubuntu/.bash_history', 'rm -rf /tmp/*' ] response = ssm_client.send_command( InstanceIds=[instance_id], DocumentName='AWS-RunShellScript', Parameters={'commands': cleanup_commands}, TimeoutSeconds=60 ) command_id = response['Command']['CommandId'] print(f"发送SSM清理命令,命令ID: {command_id}") # 等待清理完成 command_status = wait_for_ssm_command(command_id, instance_id) if command_status != 'Success': print(f"清理命令执行失败,状态: {command_status}") return # 创建AMI response = ec2_client.create_image( InstanceId=instance_id, Name=ami_name, Description=ami_description, NoReboot=True # Ubuntu无需重启即可创建镜像 ) ami_id = response['ImageId'] print(f"开始创建AMI,AMI ID: {ami_id}") # 等待AMI可用 wait_for_ami_available(ami_id) print(f"AMI创建完成,可用ID: {ami_id}") # 终止源实例 ec2_client.terminate_instances(InstanceIds=[instance_id]) print(f"源实例 {instance_id} 已终止") if __name__ == '__main__': main()
代码注意事项
- 确保实例关联的IAM角色包含
AmazonSSMFullAccess权限,否则SSM无法连接实例 NoReboot=True适用于Ubuntu,可避免重启实例影响创建速度;若需严格保证文件系统一致性,可改为False- 可根据需求调整清理命令,比如清理其他用户的authorized_keys或更多系统垃圾
内容的提问来源于stack exchange,提问作者Ivan Sushkov
相关产品推荐
相关产品推荐

