使用CloudFormation调整EC2根卷大小时避免实例销毁重建的方案咨询
问题根源
你现在把根卷配置直接写在AWS::EC2::Instance资源的内嵌BlockDeviceMappings属性里,CloudFormation对这个属性的内置更新规则非常机械:只要改了VolumeSize这类参数,就直接判定要把整个EC2实例销毁重建。
这套规则和你在控制台手动扩容的逻辑是完全脱节的:控制台操作走的是EBS服务的原生ModifyVolume接口,全程只调整EBS卷本身的参数,根本不会触碰EC2实例的运行状态,自然不会触发重建。
无重建的根卷扩容可行方案
方案1:把根卷从EC2的内嵌块映射里拆出来,单独做成独立的EBS卷资源
这是最符合CloudFormation原生设计逻辑的方案,改完之后长期运维最省心,改造步骤:
- 先删掉EC2资源定义里所有的
BlockDeviceMappings配置,让EC2第一次启动的时候,直接用AMI自带的默认大小临时根卷跑起来 - 单独写一个
AWS::EC2::Volume资源,配置你需要的根卷大小、加密、卷类型参数,一定要把这个EBS卷的可用区设置成和EC2实例同一个可用区,跨区是挂载不上的 - 再加一个
AWS::EC2::VolumeAttachment资源,把这个独立EBS卷挂载到EC2的/dev/xvda设备路径上 - 改造完之后,后续要扩容根卷,只需要改这个独立EBS卷的
VolumeSize值就行——CloudFormation对独立EBS卷的大小调整是支持原地操作的,直接调用EBS的扩容接口,全程不动正在跑的EC2实例 - 收尾注意点:第一次部署的时候EC2用来临时启动的那个小卷,记得设置成终止实例时不删除,或者等正式的大卷挂载好之后手动删掉,别让它一直挂在那产生没用的存储费用
方案2:用自定义资源走旁路扩容,完全不改现有模板的结构
如果不想大动已经跑了很久的模板,怕改坏了,就可以用自定义资源绕开CloudFormation的替换判定:
- 原封不动保留现在模板里EC2和内嵌块映射的所有配置,不让CloudFormation直接管根卷大小的变更
- 新增一个和栈更新流程绑定的自定义资源:这个资源的逻辑很简单,每次栈更新的时候对比一下你自定义参数里写的根卷大小,和EC2实际挂的根卷大小有没有差,如果有差就自动调用EBS的
ModifyVolume接口做原地扩容,甚至可以联动SSM Run Command,自动在实例里把分区和文件系统扩开,不用人手动登服务器敲命令 - 这种模式下,CloudFormation看到的EC2资源本身的属性一点没变,自然不会触发销毁重建,所有扩容操作都是走自定义资源的旁路流程完成的
方案3:零代码临时扩容法,适合不想折腾改模板的场景
如果就是临时要扩一次盘,不想改任何模板结构,也不想写自定义资源,就可以按这个流程来,完全没有代码量:
- 千万别先改CloudFormation模板里的
VolumeSize值,先直接去EC2控制台,对着正在跑的实例的根卷手动点扩容,扩完了同步把实例里的文件系统扩开,确保系统能识别到新的磁盘空间 - 这些手动操作全做完了,再打开CloudFormation的模板,把原来写死的
VolumeSize值改成你刚才手动扩完的实际大小,再触发栈更新 - 这时候CloudFormation比对一下,模板里写的期望值和实际资源的状态是完全一致的,根本不会触发任何资源操作,就是把配置同步成和实际状态一样而已,全程不会动正在跑的实例
通用提醒
- 不管用哪种方案,EBS卷大小调整完之后,一定要确认实例内的分区和文件系统已经扩展,不然系统看到的盘大小还是没变,这一步完全可以用SSM Run Command自动化,不用每台机器都手动登上去敲命令
- 操作的时候别脑子一热把根卷给卸载了,不然实例直接就挂了起不来
内容的提问来源于stack exchange,提问作者WarrenG
相关产品推荐
相关产品推荐

