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

基于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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.29 12:47:03