使用AWS CLI创建的AMI无法保留user-data修改,控制台创建则正常
问题根源:运行中实例创建AMI时的磁盘一致性差异
你遇到的这个问题,核心原因是AWS控制台和CLI在创建AMI时,默认对实例的处理方式不同:
- 控制台创建AMI时,默认会先停止实例,确保磁盘上所有未写入的缓存都同步到磁盘,然后再创建根卷快照,这样生成的AMI会完整包含实例上的所有修改。
- 而CLI的
aws ec2 create-image命令默认是重启实例(而非停止),虽然重启也会尝试同步磁盘,但在某些场景下(比如实例刚完成user-data操作,缓存还没完全写入),快照可能无法捕获所有最新修改;更极端的情况是,如果重启过程中出现异常,甚至可能导致快照和实例当前状态不一致。
另外还有个容易忽略的细节:aws ec2 wait instance-running只是等待实例进入运行状态,并不会等待cloud-init完全执行完毕。即使你通过SSH登录验证了修改存在,也可能存在部分写入操作还在后台缓存中,未持久化到磁盘。
解决方案:确保创建AMI时磁盘状态一致
方案1:创建AMI前先停止实例(推荐)
修改你的脚本,在创建AMI前先停止实例,等待实例完全停止后再执行create-image操作。这样能保证磁盘快照完整包含所有修改,和控制台的默认行为一致:
# 先停止实例,确保磁盘写入完全同步 echo "Stopping instance ${ec2_id}" aws ec2 stop-instances --instance-ids ${ec2_id} aws ec2 wait instance-stopped --instance-ids ${ec2_id} # 创建AMI echo "Creating image from instance ${ec2_id}" image_id=$(aws ec2 create-image --name ${image_name} --instance-id ${ec2_id} --output text --query 'ImageId') echo "Image ID is ${image_id}" # 等待AMI可用 echo "Waiting for image ${image_id} to be available" aws ec2 wait image-available --image-ids ${image_id} echo "Image ${image_id} (${image_name}) is now available" # 可选:如果需要保留实例,可以重新启动它 aws ec2 start-instances --instance-ids ${ec2_id}
方案2:创建前强制同步磁盘缓存
如果不想停止实例,可以通过SSH连接到实例,执行sync命令强制将内存中的缓存写入磁盘,然后再创建AMI:
# 获取实例公网IP(假设你的实例有公网访问权限) instance_ip=$(aws ec2 describe-instances --instance-ids ${ec2_id} --output text --query 'Reservations[0].Instances[0].PublicIpAddress') # 执行sync命令,确保缓存写入磁盘 echo "Syncing disk cache on instance ${ec2_id}" ssh -i "${key_name}.pem" ec2-user@${instance_ip} "sync && sudo sync" # 之后再执行create-image命令 echo "Creating image from instance ${ec2_id}" image_id=$(aws ec2 create-image --name ${image_name} --instance-id ${ec2_id} --output text --query 'ImageId') # ... 后续等待AMI可用的代码不变
验证方法:检查AMI的快照来源
你可以通过以下命令验证CLI创建的AMI是否使用了实例的根卷快照:
- 获取实例根卷的快照ID:
volume_id=$(aws ec2 describe-instances --instance-ids ${ec2_id} --output text --query 'Reservations[0].Instances[0].BlockDeviceMappings[0].Ebs.VolumeId') snapshot_id=$(aws ec2 describe-volumes --volume-ids ${volume_id} --output text --query 'Volumes[0].SnapshotId') echo "Instance root volume snapshot ID: ${snapshot_id}"
- 获取新创建AMI的根卷快照ID:
ami_snapshot_id=$(aws ec2 describe-images --image-ids ${image_id} --output text --query 'Images[0].BlockDeviceMappings[0].Ebs.SnapshotId') echo "AMI root volume snapshot ID: ${ami_snapshot_id}"
如果两个快照ID不同,说明CLI创建的AMI没有使用实例的最新快照,这时候就需要检查实例状态和创建流程了。
内容的提问来源于stack exchange,提问作者Marakai
相关产品推荐
相关产品推荐

