🐩

AWS DMSのレプリケーションインスタンスの自動起動停止(CloudFormation付き)

に公開

1.はじめに

AWS Database Migration Service(以下DMS)のレプリケーションインスタンスは利用時間に応じて料金を支払う必要があるため、データベース移行タスクを実行していない時間帯は極力レプリケーションインスタンスを停止しておきたい。
しかしDMSレプリケーションインスタンスに停止はなく、起動か削除のみがサポートされている。

DMS のレプリケーションインスタンスでは停止機能、スナップショット作成機能ともに提供されていません。(2022/08/15 時点)

https://dev.classmethod.jp/articles/tsnote-dms-replication-instance-stop/

マネジメントコンソールからDMSレプリケーションインスタンスの起動と削除を実行すると、セットアップに5~10分ほど要することが多く、都度手動で起動と削除するのは中々にストレスである。

今回は、EventBridge Schedulerで日中時間帯(AM10:00~PM7:00)のみレプリケーションインスタンスが起動されるようにスケジュールを構築する。

2.作成リソースの概要と前提

今回作成するリソースの概要図は以下の通り。

作成に当たっての前提を以下に記す。

  1. レプリケーションインスタンスをVPC内に作成することを想定している。
    • DMSサブネットグループが作成済みであること。
    • レプリケーションインスタンスに付けるセキュリティグループが作成済みであること。
      • セキュリティグループの細かいルール(インバウンド&アウトバンド)については本記事とは取り扱わない。
  2. レプリケーションインスタンス起動API(CreateReplicationInstance)でデフォルトの設定を利用している部分についてはパラメータを省略している。
    • API Reference CreateReplicationInstance
    • EngineVersion:レプリケーションインスタンスのエンジンバージョン。省略することで最新版が指定される。
    • KmsKeyId:レプリケーションインスタンスの暗号化に使用するKMSのID。省略することでAWSマネージドのKMSが使用される。
  3. レプリケーションインスタンスへの操作を引き受けるDMSのIAMロール(dms-vpc-role)が存在すること。

3.CloudFormationテンプレート

3.1.CloudFormationテンプレートの内容

AWSTemplateFormatVersion: '2010-09-09'
Description: EventBridge Schedule that calls DMS CreateReplicationInstance API and DeleteReplicationInstance API.

# ------------------------------------------------------------#
#  MetaData
# ------------------------------------------------------------#
Metadata:
  AWS::CloudFormation::Interface:
    ParameterGroups:
      - Label:
          default: "Environment name parameter"
        Parameters:
          - Env
      - Label:
          default: "DMS replication instance parameter"
        Parameters:
          - IAMPassRoleARN
          - AllocatedStorage
          - AvailabilityZone
          - PreferredMaintenanceWindow
          - ReplicationInstanceClass
          - ReplicationInstanceIdentifier
          - ReplicationSubnetGroupIdentifier
          - VpcSecurityGroupIds
# ------------------------------------------------------------#
#  Parameters
# ------------------------------------------------------------#
Parameters:
  Env:
    Description: Environment name.
    Type: String
    Default: dev
  IAMPassRoleARN:
    Description: This role is passed from EventBridge.
    Type: String
    Default: arn:aws:iam::xxxxx:role/dms-vpc-role
  AllocatedStorage:
    Description: The amount of storage (in gigabytes) to be initially allocated for the replication instance.
    Type: Number
    Default: 50
  AvailabilityZone:
    Description: The Availability Zone where the replication instance will be created. The default value is a random, system-chosen Availability Zone in the endpoint's AWS Region, for example us-east-1d.
    Type: String
    Default: ap-northeast-1a
  PreferredMaintenanceWindow:
    Description: The weekly time range during which system maintenance can occur, in Universal Coordinated Time (UTC).
    Type: String
    Default: Mon:21:00-Mon:21:30
  ReplicationInstanceClass:
    Description: The compute and memory capacity of the replication instance as defined for the specified replication instance class. For example to specify the instance class dms.c4.large, set this parameter to "dms.c4.large".
    Type: String
    Default: dms.t3.medium
  ReplicationInstanceIdentifier:
    Description: The replication instance identifier. This parameter is stored as a lowercase string.
    Type: String
  ReplicationSubnetGroupIdentifier:
    Description: A subnet group to associate with the replication instance.
    Type: String
    Default: xxxxx-subnet-group
  VpcSecurityGroupIds:
    Description: Specifies the VPC security group to be used with the replication instance. The VPC security group must work with the VPC containing the replication instance.
    Type: String
    Default: sg-xxxxx
# ------------------------------------------------------------#
#  Resources
# ------------------------------------------------------------#
Resources:
  EventBridgeScheduleRole:
    Type: AWS::IAM::Role
    Properties:
      RoleName: !Sub ${Env}-dms-create-delete-role
      AssumeRolePolicyDocument:
        Version: '2012-10-17'
        Statement:
          - Effect: Allow
            Principal:
              Service: scheduler.amazonaws.com
            Action: sts:AssumeRole
      Policies:
        - PolicyName: !Sub ${Env}-dms-create-delete-policy
          PolicyDocument:
            Version: '2012-10-17'
            Statement:
              - Sid: DMSActions
                Effect: Allow
                Action:
                  - dms:CreateReplicationInstance
                  - dms:AddTagsToResource
                  - dms:DeleteReplicationInstance
                Resource: "*"
              - Sid: IAMPassRole
                Effect: Allow
                Action: iam:PassRole
                Resource: !Ref IAMPassRoleARN

  CreateReplicationInstanceSchedule:
    Type: AWS::Scheduler::Schedule
    Properties:
      Name: !Sub ${Env}-create-dms-instance-schedule
      ScheduleExpression: cron(0 1 ? * MON-FRI *)
      FlexibleTimeWindow:
        Mode: "OFF"
      Target:
        Arn: arn:aws:scheduler:::aws-sdk:databasemigration:createReplicationInstance
        RoleArn: !GetAtt EventBridgeScheduleRole.Arn
        Input: !Sub |-
          {
            "AllocatedStorage": ${AllocatedStorage},
            "AutoMinorVersionUpgrade": true,
            "AvailabilityZone": "${AvailabilityZone}",
            "MultiAZ": false,
            "NetworkType": "IPv4",
            "PreferredMaintenanceWindow": "${PreferredMaintenanceWindow}",
            "PubliclyAccessible": false,
            "ReplicationInstanceClass": "${ReplicationInstanceClass}",
            "ReplicationInstanceIdentifier": "${ReplicationInstanceIdentifier}",
            "ReplicationSubnetGroupIdentifier": "${ReplicationSubnetGroupIdentifier}",
            "ResourceIdentifier": "${ReplicationInstanceIdentifier}",
            "Tags": [
              {
                "Key": "Environment",
                "Value": "${Env}"
              }
            ],
            "VpcSecurityGroupIds": [ "${VpcSecurityGroupIds}" ]
          }
        RetryPolicy:
          MaximumEventAgeInSeconds: 60
          MaximumRetryAttempts: 1
      State: ENABLED

  DeleteReplicationInstanceSchedule:
    Type: AWS::Scheduler::Schedule
    Properties:
      Name: !Sub ${Env}-delete-dms-instance-schedule
      ScheduleExpression: cron(0 10 ? * MON-FRI *)
      FlexibleTimeWindow:
        Mode: "OFF"
      Target:
        Arn: arn:aws:scheduler:::aws-sdk:databasemigration:deleteReplicationInstance
        RoleArn: !GetAtt EventBridgeScheduleRole.Arn
        Input: !Sub |-
          {
            "ReplicationInstanceArn": "arn:aws:dms:${AWS::Region}:${AWS::AccountId}:rep:${ReplicationInstanceIdentifier}"
          }
        RetryPolicy:
          MaximumEventAgeInSeconds: 60
          MaximumRetryAttempts: 1
      State: ENABLED

3.2.スタックの動作確認

上記CloudFormationテンプレートからスタックを作成できることを確認した。

起動時刻にレプリケーションインスタンスが起動されることを確認した。

削除時刻にレプリケーションインスタンスが削除されることを確認した。

4.マネジメントコンソールから作成する場合

4.1.レプリケーションインスタンス起動スケジュール

Amazon EventBridge > スケジュール > スケジュールを作成 から新規スケジュールを作成する。
ターゲットとしてDMSのCreateReplicationInstanceを選択する。

CreateReplicationInstance へ渡すパラメータはCloudFormationテンプレートに記載のパラメータを設定する。

4.2.レプリケーションインスタンス削除スケジュール

Amazon EventBridge > スケジュール > スケジュールを作成 から新規スケジュールを作成する。
ターゲットとしてDMSのDeleteReplicationInstanceを選択する。

DeleteReplicationInstance へ渡すパラメータはCloudFormationテンプレートに記載のパラメータを設定する。

5.余談

CloudFormationで記述するに当たってハマったのが、EventBridge SchedulerのTarget Arnの書き方である。
よく記事に書かれるのがAPIアクション名を小文字始まりにしなければならないところだが、今回は正しいサービス名を指定するのに難航してしまった。

ハマりやすいポイント
EC2を停止させる際、 target.arnにAPI名のStopInstances をそのまま指定するとデプロイ時にエラーが発生します。
AWS SDKでは、小文字始まりのstopInstances が正しい形式となります。

https://iret.media/140672

Arn — ターゲットとする API オペレーションを含むサービス ARN 全体を、次の形式で示します: arn:aws:scheduler:::aws-sdk:service:apiAction
例えば、Amazon SQS の場合、指定するサービス名は arn:aws:scheduler:::aws-sdk:sqs:sendMessage です。

https://docs.aws.amazon.com/ja_jp/scheduler/latest/UserGuide/managing-targets-universal.html

CloudFormationに記載の通り、DMSの場合はarn:aws:scheduler:::aws-sdk:dmsではなく、arn:aws:scheduler:::aws-sdk:databasemigrationであった。。。

Discussion