検証RDS用のCloudFormationスタック削除時にスナップショットを残さない

CloudFormationテンプレートでDeletionPolicyをDeleteに設定する
2021.11.02

みなさんこんにちは、杉金です。

検証用のRDSをCloudFormationで気軽に作ったり消したい時に意識しておくべきDeletionPolicyについて紹介します。

先に結論

CloudFormationではAWS::RDS::DBClusterAWS::RDS::DBInstanceDeletionPolicyはデフォルトでSnapshotになっています。 CloudFormationスタック削除後にRDSのスナップショットが不要な場合やオプショングループも1つのCloudFormationテンプレートで合わせて作成/削除する場合はDeletionPolicyDeleteに設定すると良いです。

どういうこと?

実際の動きを一部紹介しながら解説します。まずはCloudFormationテンプレートを作成します。利用するリソースについての設定条件は次の通りですが、サンプル的なものですのでお好みで修正ください。

  • サブネットグループ : スタック作成時のパラメータで指定
  • セキュリティグループ : スタック作成時のパラメータで指定
  • パラメーターグループ : CloudFormationテンプレートで合わせて作成
  • オプショングループ : CloudFormationテンプレートで合わせて作成

条件をもとに以下のようなテンプレートを用意します。

AWSTemplateFormatVersion: '2010-09-09'
Description: DB Stack

Parameters:
  SubnetGroupName:
    Type: String
    Default: 'db-subnet-group'

  SecurityGroups:
    Type: String
    Default: 'sg-xxxxxxxxxxx'

Resources:
  MyDB:
    Type: AWS::RDS::DBInstance
    Properties:
      DBInstanceIdentifier: test-mysql
      Engine: mysql
      EngineVersion: 8.0.26
      MasterUsername: admin
      MasterUserPassword: '{{resolve:secretsmanager:xxxxxxx:SecretString:password}}'
      OptionGroupName: !Ref MyDBOptionGroup
      DBParameterGroupName: !Ref MyDBParameterGroup
      MultiAZ: false
      BackupRetentionPeriod: 0
      DBSubnetGroupName: !Ref SubnetGroupName
      VPCSecurityGroups:
        - !Ref SecurityGroups
      AutoMinorVersionUpgrade: false
      PreferredMaintenanceWindow: sat:15:00-sat:15:30
      DBInstanceClass: db.t3.medium
      StorageType: gp2
      AllocatedStorage: '20'

  MyDBParameterGroup:
    Type: AWS::RDS::DBParameterGroup
    Properties:
      Family: MySQL8.0
      Description: Database Parameter Group
      Parameters:
        character_set_client: utf8mb4
        character_set_connection: utf8mb4
        character_set_database: utf8mb4
        character_set_results: utf8mb4
        character_set_server: utf8mb4
        time_zone: Asia/Tokyo

  MyDBOptionGroup:
    Type: AWS::RDS::OptionGroup
    Properties: 
      EngineName: mysql
      MajorEngineVersion: '8.0'
      OptionGroupDescription: Database Option Group
      OptionConfigurations: 
        - OptionName: MARIADB_AUDIT_PLUGIN

このテンプレートを使ってCloudFormationスタックを作成します。検証を終えたと想定してスタックを削除しようとすると次のエラーが起きます。

The option group 'XXXXXXX' cannot be deleted because it is in use.

オプショングループを削除しようとしたけど他のリソースが使っているよ、と言っていますね。 使っているリソースを特定してみましょう。RDSのコンソールから対象のオプショングループを選択します。

「関連付けられたDBインスタンスとスナップショット」を見るとスナップショットで使われていることが分かります。

AWS::RDS::DBInstanceDeletionPolicyを定義しない場合、デフォルトのSnapshotになるため、削除時にRDSのスナップショットが作成されます。スナップショットを手動で削除して、再度CloudFormationスタックの削除を実行すると今後は削除に成功します。

オプショングループ作成のテンプレートを分けることでエラーは発生しませんが、スナップショットは残ります。 スナップショットが不要であれば、DeletionPolicyDeleteに設定することでスナップショットを残さず、オプショングループも合わせて削除できます。設定としてはテンプレートにDeletionPolicyを一行加えるだけです。DeletionPolicyを加えたテンプレートは以下です。

AWSTemplateFormatVersion: '2010-09-09'
Description: DB Stack

Parameters:
  SubnetGroupName:
    Type: String
    Default: 'db-subnet-group'

  SecurityGroups:
    Type: String
    Default: 'sg-xxxxxxxxxxx'

Resources:
  MyDB:
    Type: AWS::RDS::DBInstance
    Properties:
      DBInstanceIdentifier: test-mysql
      Engine: mysql
      EngineVersion: 8.0.26
      MasterUsername: admin
      MasterUserPassword: '{{resolve:secretsmanager:xxxxxxx:SecretString:password}}'
      OptionGroupName: !Ref MyDBOptionGroup
      DBParameterGroupName: !Ref MyDBParameterGroup
      MultiAZ: false
      BackupRetentionPeriod: 0
      DBSubnetGroupName: !Ref SubnetGroupName
      VPCSecurityGroups:
        - !Ref SecurityGroups
      AutoMinorVersionUpgrade: false
      PreferredMaintenanceWindow: sat:15:00-sat:15:30
      DBInstanceClass: db.t3.medium
      StorageType: gp2
      AllocatedStorage: '20'
    DeletionPolicy: Delete

  MyDBParameterGroup:
    Type: AWS::RDS::DBParameterGroup
    Properties:
      Family: MySQL8.0
      Description: Database Parameter Group
      Parameters:
        character_set_client: utf8mb4
        character_set_connection: utf8mb4
        character_set_database: utf8mb4
        character_set_results: utf8mb4
        character_set_server: utf8mb4
        time_zone: Asia/Tokyo

  MyDBOptionGroup:
    Type: AWS::RDS::OptionGroup
    Properties: 
      EngineName: mysql
      MajorEngineVersion: '8.0'
      OptionGroupDescription: Database Option Group
      OptionConfigurations: 
        - OptionName: MARIADB_AUDIT_PLUGIN

このテンプレートであればスタック削除時にRDSのスナップショットを作成せずにRDSインスタンスとオプショングループ、パラメーターグループを削除します。1行加えるだけで、スタック削除後に手動でスナップショットを削除する手間が省けます。ちなみにパラメーターグループはスナップショットの情報に保持されないため、パラメーターグループ削除時にオプショングループのような使用中エラーは起きずに削除されます。

どこまで1つのテンプレートに定義するべきか

今回はサブネットグループやセキュリティグループは事前に作成したものを指定していましたので、このあたりのリソース作成もテンプレートに含めると依存関係の問題が発生しやすいです。オプショングループやパラメーターグループを複数のRDSで共有するケースもあります。どこまで1つのテンプレートに含めるべきかは悩ましくケースバイケースですが、CloudFormationのベストプラクティスにガイドラインが載っていますので参考になります。

Organize your stacks by lifecycle and ownership

DeletionPolicyについて

DeletionPolicyを設定する多くのケースでは、CloudFormationスタック削除後も残しておきたいリソースを定義する際にDeletionPolicyを使用します。DeletionPolicyについては以下のページに情報が記載されています。

DeletionPolicy attribute

Exception: The default policy is Snapshot for AWS::RDS::DBCluster resources and for AWS::RDS::DBInstance resources that don't specify the DBClusterIdentifier property.

RDSについて抜粋しましたがAWS::RDS::DBClusterAWS::RDS::DBInstanceDeletionPolicyはデフォルトでSnapshotであるため今回のようなケースであればDeleteを定義します。Deleteに定義したテンプレートをそのまま本番用に流用するのは危険ですので、テンプレートをチェックする際にDeletionPolicyで検索をかけてみて誤った定義をしていないかチェックすると良いでしょう。また、CloudFormationのテンプレート記法はJSONかYAMLどちらでも良いですが、YAMLであれば#でコメントを書けますので、補足的なコメントを加えるとなお良いです。 CloudFormationデザイナーでテンプレートを作成する際は#によるコメントは非推奨ですのでご注意ください。

AWS CloudFormation template formats

We recommend that you don't add # YAML comments to your templates in Designer. If your YAML template has # comments, Designer doesn't preserve those comments when converting the template to JSON. In addition, if you modify your template in Designer (for example, if you move a resource on the canvas), your comments are lost.

最後に

スタックの削除保護があるため普段からDeletionPolicyを意識したことはそれほどありませんでした。今回のケースに遭遇して、オプショングループとスナップショットって紐付けられているんだということに気づきました。RDSのDeletionPolicyのデフォルトがSnapshotになっているのは転ばぬ先の杖っぽくて良い考えだと思います。手軽にリソースを作成、削除できるのがクラウドサービスの利点である一方で、誤って削除した時のこと(フールプルーフ)も意識しておくべきだなと改めて思いました。

参考情報