ENGINEER BLOG ENGINEER BLOG
  • 公開日
  • 最終更新日

CloudFormation で EC2 のボリュームサイズ変更時に置換が発生する理由と対策

この記事を共有する

目次

はじめに

先日 AWS CloudFormation(以下、CloudFormation)で EC2 インスタンスのボリュームサイズを変更しようとした際に「置換(Replacement)」が発生しそうになりました。
置換が発生するとインスタンスが一度削除され、新しいインスタンスが作成されるため、
IP アドレスやインスタンス ID が変わり、本番環境では大きな影響が出てしまいます。

本記事では、この問題の原因と対策を紹介します。

いきなり結論

結論:EC2 のルートボリュームサイズ変更は置換が発生する仕様です。

CloudFormation テンプレート内で EC2 インスタンスのルートボリュームサイズ(BlockDeviceMappings)を変更すると、
CloudFormation はそのプロパティを「置換不可」と判定し、既存インスタンスを削除して新しいインスタンスを作成してしまいます。

置換が発生する理由

CloudFormation の更新動作

CloudFormation でリソースのプロパティを変更すると、以下の 3 つのいずれかの動作が選択されます。

  1. 中断なしの更新(Update with No interruption): リソースを停止せずにプロパティを変更
  2. 一部中断ありの更新(Updates with Some interruption): 一時的にサービスが停止する変更
  3. 置換(Replacement): 既存リソースを削除し新しいリソースを作成

EC2 のルートボリュームサイズ変更は 3 の「置換」に該当します。

EC2 のルートボリュームサイズが置換扱いとなる理由

EC2 インスタンスのルートボリュームサイズは、インスタンス作成時に確定されるプロパティです。CloudFormation では、このプロパティを「置換不可」として扱っており、変更時には以下が実行されます。

  1. 既存 EC2 インスタンスを削除
  2. 新しいボリュームサイズを指定して新しいインスタンスを作成
  3. インスタンス 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 で内容を確認すると、対象リソースの ReplacementTrue と表示されます。


{
    "ResourceChange": {
        "Action": "Modify",
        "LogicalResourceId": "MyEC2Instance",
        "ResourceType": "AWS::EC2::Instance",
        "Replacement": "True",
        "Details": [
            {
                "Target": {
                    "Attribute": "Properties",
                    "Name": "BlockDeviceMappings",
                    "RequiresRecreation": "Always"
                }
            }
        ]
    }
}

ReplacementTrue と出た場合、デプロイ前に必ず影響範囲を確認してください。

対策

ボリュームサイズ変更時に置換を回避する対策として、以下の 2 つがあります。

  1. 追加ボリュームを別リソースとして定義する(拡張性が必要な場合)
  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が好きです。

野間 太一

この記事を共有する

クラウドのご相談

CONTACT

クラウド導入や運用でお悩みの方は、お気軽にご相談ください。
専門家がサポートします。

サービス資料ダウンロード

DOWNLOAD

ビジネスをクラウドで加速させる準備はできていますか?
今すぐサービス資料をダウンロードして、詳細をご確認ください。