- 公開日
- 最終更新日
CloudFormation で EC2 のボリュームサイズ変更時に置換が発生する理由と対策
この記事を共有する
目次
はじめに
先日 AWS CloudFormation(以下、CloudFormation)で EC2 インスタンスのボリュームサイズを変更しようとした際に「置換(Replacement)」が発生しそうになりました。
置換が発生するとインスタンスが一度削除され、新しいインスタンスが作成されるため、
IP アドレスやインスタンス ID が変わり、本番環境では大きな影響が出てしまいます。
本記事では、この問題の原因と対策を紹介します。
いきなり結論
結論:EC2 のルートボリュームサイズ変更は置換が発生する仕様です。
CloudFormation テンプレート内で EC2 インスタンスのルートボリュームサイズ(BlockDeviceMappings)を変更すると、
CloudFormation はそのプロパティを「置換不可」と判定し、既存インスタンスを削除して新しいインスタンスを作成してしまいます。
置換が発生する理由
CloudFormation の更新動作
CloudFormation でリソースのプロパティを変更すると、以下の 3 つのいずれかの動作が選択されます。
- 中断なしの更新(Update with No interruption): リソースを停止せずにプロパティを変更
- 一部中断ありの更新(Updates with Some interruption): 一時的にサービスが停止する変更
- 置換(Replacement): 既存リソースを削除し新しいリソースを作成
EC2 のルートボリュームサイズ変更は 3 の「置換」に該当します。
EC2 のルートボリュームサイズが置換扱いとなる理由
EC2 インスタンスのルートボリュームサイズは、インスタンス作成時に確定されるプロパティです。CloudFormation では、このプロパティを「置換不可」として扱っており、変更時には以下が実行されます。
- 既存 EC2 インスタンスを削除
- 新しいボリュームサイズを指定して新しいインスタンスを作成
- インスタンス ID・プライベート IP アドレス・Elastic IP の関連付けが変更
実装例
置換が発生するテンプレート例
AWSTemplateFormatVersion: '2010-09-09'
Parameters:
ImageId:
Type: AWS::EC2::Image::Id
Description: EC2 インスタンスに使用する AMI ID
InstanceType:
Type: String
Default: t3.micro
Resources:
MyEC2Instance:
Type: AWS::EC2::Instance
Properties:
ImageId: !Ref ImageId
InstanceType: !Ref InstanceType
BlockDeviceMappings:
- DeviceName: /dev/xvda
Ebs:
VolumeSize: 20
VolumeType: gp3
DeleteOnTermination: true
このテンプレートで VolumeSize を 20 から 30 に変更すると、CloudFormation は置換を実行します。
変更セットでの確認方法
変更セットを作成し、AWS CLI の describe-change-set で内容を確認すると、対象リソースの Replacement が True と表示されます。
{
"ResourceChange": {
"Action": "Modify",
"LogicalResourceId": "MyEC2Instance",
"ResourceType": "AWS::EC2::Instance",
"Replacement": "True",
"Details": [
{
"Target": {
"Attribute": "Properties",
"Name": "BlockDeviceMappings",
"RequiresRecreation": "Always"
}
}
]
}
}
Replacement が True と出た場合、デプロイ前に必ず影響範囲を確認してください。
対策
ボリュームサイズ変更時に置換を回避する対策として、以下の 2 つがあります。
- 追加ボリュームを別リソースとして定義する(拡張性が必要な場合)
- ボリュームサイズを CloudFormation 管理外で運用する(運用後に柔軟に拡張する場合)
対策 1:追加ボリュームを別リソースとして定義
追加容量が必要な場合は AWS::EC2::Volume リソースで別途定義します。
別リソースとして切り出すことで、容量を変更しても EC2 インスタンスは再作成されません。
Resources:
MyEC2Instance:
Type: AWS::EC2::Instance
Properties:
ImageId: !Ref ImageId
InstanceType: !Ref InstanceType
BlockDeviceMappings:
- DeviceName: /dev/xvda
Ebs:
VolumeSize: 20
VolumeType: gp3
DeleteOnTermination: true
AdditionalVolume:
Type: AWS::EC2::Volume
Properties:
AvailabilityZone: !GetAtt MyEC2Instance.AvailabilityZone
Size: 50
VolumeType: gp3
VolumeAttachment:
Type: AWS::EC2::VolumeAttachment
Properties:
Device: /dev/sdf
InstanceId: !Ref MyEC2Instance
VolumeId: !Ref AdditionalVolume
対策 2:ボリュームサイズを CloudFormation 管理外で運用
ルートボリュームの拡張を AWS CLI やコンソールから直接実施する運用です。
BlockDeviceMappings 内の VolumeSize はリソース定義上必須ではないため、CloudFormation で構築後に CLI 側で変更すれば、置換を発生させずに容量を拡張できます。
aws ec2 modify-volume --volume-id vol-xxxxx --size 100
ボリュームの拡張状態は describe-volumes-modifications で確認できます。
新規構築時に拡張性を見越せる場合は対策 1、運用開始後に容量を伸ばしたい場合は対策 2と、
用途に応じて使い分けるのが現実的だと感じています。
まとめ
CloudFormation で EC2 のボリュームサイズを変更する際は、ルートボリュームの仕様により置換が発生することを理解しました。
今後も重要な変更の際は変更セットを必ず確認し、事故のない運用につなげていきたいです。
この記事は私が書きました
野間 太一
記事一覧猫とCloudFormationが好きです。