[CloudFormation]リソース置換時の挙動をUpdateReplacePolicyで制御する

コンニチハ、千葉です。

CloudFormationでリソース置換時の挙動を制御するUpdateReplacePolicy について調べてみました。

そもそもを整理すると、CloudFormationではリソース変更の種類が複数あり、それぞれに対応した挙動を設定できます。

  • リソース作成(CreationPolicy):シグナル受信またはタイムアウトするまで作成完了にならない(例えばEC2でアプリインストール後にシグナルを送るなど)
  • スタック削除(DeletionPolicy):スタック削除時に、リソースを削除・保持・スナップショット取得を指定する
  • リソース更新(UpdatePolicy):AutoScalingなど特定リソースに対してローリングアップデートなどを指定する
  • リソース置換(UpdateReplacePolicy):リソース置換時に、リソースを削除・保持・スナップショット取得を指定する

挙動を見ると、DeletionPolicyのリソース置換バージョンと見ればよさそうです。

やってみた

実際にCloudFormationでリソース置換時の挙動として、DeleteRetainSnapshotをそれぞれ指定して動きを確認してみました。(何も指定しない場合デフォルト動作としてはDeleteの動作になります)

今回サンプルのテンプレートとして、EC2を作るCloudFormationスタックで試してみます。3種類のUpdateReplacePolicyを指定した3台のEC2を起動します。(CFnのコードは後術)

スタックを作ると、EC2がそれぞれ作成されました。

置換するために, ap-northeast-1aap-northeast-1c に変更しスタックの更新を行います。変更セットのプレビューを見ると置換がTrueとなってます。

更新した結果、想定した挙動になりました!確認してみましょう。

  • UpdateReplacePolicy: DeleteはEC2が削除
  • UpdateReplacePolicy: SnapshotはEC2が削除
  • UpdateReplacePolicy: RetainはEC2が残る

UpdateReplacePolicyにスナップショットが残っているか見ましたが、残ってませんでした

スナップショットをサポートしていないリソースに対して UpdateReplacePolicy の snapshot オプションを指定すると、CloudFormation はデフォルトオプション (Delete) の動作になります

とのことです。

スナップショットをサポートするリソースは以下のとおりです。

  • AWS::EC2::Volume
  • AWS::ElastiCache::CacheCluster
  • AWS::ElastiCache::ReplicationGroup
  • AWS::Neptune::DBCluster
  • AWS::RDS::DBCluster
  • AWS::RDS::DBInstance
  • AWS::Redshift::Cluster

最後に

UpdateReplacePolicyの挙動を実際に確認してみました。特にUpdateReplacePolicyにスナップショットを指定しておくと、間違って置換してしまっても復旧できるので、センシティブなデータについてはスナップショットを指定しておくといいのかなと思いました。また、スナップショットに対応しているリソースは決まっているので注意しましょう。

参考

おまけ

今回試したCloudFormationテンプレートをおいておきます。

AWSTemplateFormatVersion: '2010-09-09'
Description: This CloudFormation template to create EC2 instances.

Mappings:
  EC2:
    KeyName: { Value: xxxxx }
    ImageId: { Value: ami-xxxxx }
    InstanceType: { Value: t3a.nano }
    Ec2SecurityGroup: { Value: sg-xxxxx }
    AZ: { Value: ap-northeast-1a }

Resources:
## UpdateReplacePolicy:Delete
  Delete:
    Type: AWS::EC2::Instance
    Properties:
      ImageId: !FindInMap [ EC2, ImageId, Value ]
      KeyName: !FindInMap [ EC2, KeyName, Value ]
      InstanceType: !FindInMap [ EC2, InstanceType, Value ]
      SecurityGroupIds:
      - !FindInMap [ EC2, Ec2SecurityGroup, Value ]
      BlockDeviceMappings:
      -
        DeviceName: /dev/sda1
        Ebs:
          VolumeSize: 10
      AvailabilityZone: !FindInMap [ EC2, AZ, Value ]
      Tags:
        - Key: Name
          Value: UpdateReplacePolicy:Delete
    UpdateReplacePolicy: Delete

## UpdateReplacePolicy:Retain
  Retain:
    Type: AWS::EC2::Instance
    Properties:
      ImageId: !FindInMap [ EC2, ImageId, Value ]
      KeyName: !FindInMap [ EC2, KeyName, Value ]
      InstanceType: !FindInMap [ EC2, InstanceType, Value ]
      SecurityGroupIds:
      - !FindInMap [ EC2, Ec2SecurityGroup, Value ]
      BlockDeviceMappings:
      -
        DeviceName: /dev/sda1
        Ebs:
          VolumeSize: 10
      AvailabilityZone: !FindInMap [ EC2, AZ, Value ]
      Tags:
        - Key: Name
          Value: UpdateReplacePolicy:Retain
    UpdateReplacePolicy: Retain

## UpdateReplacePolicy:Snapshot
  Snapshot:
    Type: AWS::EC2::Volume
    Properties:
    Type: AWS::EC2::Instance
    Properties:
      ImageId: !FindInMap [ EC2, ImageId, Value ]
      KeyName: !FindInMap [ EC2, KeyName, Value ]
      InstanceType: !FindInMap [ EC2, InstanceType, Value ]
      SecurityGroupIds:
      - !FindInMap [ EC2, Ec2SecurityGroup, Value ]
      BlockDeviceMappings:
      -
        DeviceName: /dev/sda1
        Ebs:
          VolumeSize: 10
      AvailabilityZone: !FindInMap [ EC2, AZ, Value ]
      Tags:
        - Key: Name
          Value: UpdateReplacePolicy:Snapshot
    UpdateReplacePolicy: Snapshot