CloudWatch EventsとLambdaでDynamoDBのテーブルを定期作成する

2017.08.29

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

こんにちは、菊池です。

やりたいこと

DynamoDBのテーブルを月ごとに分けて利用している環境で、以下のオペレーションを定期的に自動で実行したいというケースを想定しています。

  • 前月のテーブルのRCU/WCUを下げる
  • 翌月のテーブルを作成する

DynamoDBではテーブルが存在するだけで、割り当てたRCU/WCU分の利用料が発生します。新しいテーブルは必要になるタイミングで作成し、古くなってアクセス頻度が減ったテーブルは割り当てるRCU/WCUを小さくすることでコストを抑えることができます。

上記のオペレーションを実行するLambda関数を作成し、CloudWatch Eventsで自動実行することで、この要件を実現します。

dynamodb-table-001

環境構築

テーブル自動作成

まずはテーブルを定期的に作成する環境です。

Lambda関数の作成

DynamoDBのテーブルを新規に作る関数を作成します。

dynamodb-table-002

トリガーは後から設定しますので、何もせず次に進みます。

dynamodb-table-003

関数名を入力し、ランタイムはPython 3.6にしました。

dynamodb-table-004

以下のコードをPython 3.6のランタイムで作成します。実行日時の10日後の年月でtable_yyyymmという名称のテーブルを作成するコードです。同名のテーブルが存在する場合には何もしません。

import boto3
import datetime

def lambda_handler(event, context):
    dynamodb = boto3.client('dynamodb')

    WCU = event['wcu']
    RCU = event['rcu']

    now = datetime.datetime.now()
    next_month = now + datetime.timedelta(days=10)

    new_table_name = "table_" + next_month.strftime("%Y%m")

    tables = dynamodb.list_tables()['TableNames']

    if new_table_name not in tables:
        newtable = dynamodb.create_table(
            AttributeDefinitions=[
                {
                    'AttributeName': 'id',
                    'AttributeType': 'S'
                }
            ],
            TableName = new_table_name,
            KeySchema=[
                {
                    'AttributeName': 'id',
                    'KeyType': 'HASH'
                }
            ],
            ProvisionedThroughput={
                'ReadCapacityUnits': RCU,
                'WriteCapacityUnits': WCU
            }
        )
        print("New table is created.")
    else:
        print("New table is already exist.")

    return 0

続いて、IAMロールの選択です。あらかじめ作成していなければ、新規に作成します。

dynamodb-table-005

利用するIAMロールには、AmazonDynamoDBFullAccessの管理ポリシーをアタッチしておきます。

dynamodb-table-008

関数ができたら、テストイベントを入力してテストしてみます。JSONで指定したwcurcuの値でテーブルが作成されます。

{
  "wcu": 5,
  "rcu": 5
}

dynamodb-table-006

実行して成功すれば、テーブルが作成されているはずです。テーブル名は、table_yyyymmとなります。今回のコードでは実行日+10日の月で作成されますので、実行タイミングに合わせて調整しましょう。

dynamodb-table-007

CloudWatch Eventsの設定

続いて、定期実行させるためのイベントを作成します。CloudWatchから、[イベント]-[ルールの作成]を選びます。

dynamodb-table-009

イベントソースに、[スケージュール]、[Cron式]を選択します。今回は毎月25日の日本時間9時に実行したいので、0 0 25 * ? *と入力します。設定パターンはこちらを参照ください。イベントターゲットは、作成したLambda関数を選択し、入力にwcu、rcuの値を指定するJSONを設定します。

dynamodb-table-010

イベントルール名を指定し、作成します。

dynamodb-table-011

WCU/RCUの自動変更

続いて、古くなったテーブルのキャパシティを変更する関数を作成します。

Lambda関数

同様に、Python3.6の関数を作成します。table_yyyymmという名称のテーブルのRCU/WCUを指定した値に変更するコードです。yyyymmは実行日の10日前の年月になりますので、実行タイミングによって調整しましょう。対象のテーブルが存在しない場合には何もしません。

import boto3
import datetime

def lambda_handler(event, context):
    dynamodb = boto3.client('dynamodb')

    TARGET_WCU = event['decreace_target_wcu']
    TARGET_RCU = event['decreace_target_rcu']

    now = datetime.datetime.now()
    last_month = now - datetime.timedelta(days=10)

    old_table_name = "table_" + last_month.strftime("%Y%m")

    tables = dynamodb.list_tables()['TableNames']

    if old_table_name in tables:
        old_table = dynamodb.describe_table(
            TableName=old_table_name
        )
        wcu = old_table['Table']['ProvisionedThroughput']['WriteCapacityUnits']
        rcu = old_table['Table']['ProvisionedThroughput']['ReadCapacityUnits']
        if rcu == TARGET_RCU and wcu == TARGET_WCU:
            print("Old table is not modified.")
        else:
            modify = dynamodb.update_table(
                TableName= old_table_name,
                ProvisionedThroughput={
                    'ReadCapacityUnits': TARGET_RCU,
                    'WriteCapacityUnits': TARGET_WCU
                }
            )
            print("Old table CU is modified.")
    else:
        print("Old table is not exist.")

    return 0

テストイベントで、設定するwcu/rcuを指定し、テストしてみましょう。

{
  "decreace_target_wcu": 5,
  "decreace_target_rcu": 5
}

dynamodb-table-012

CloudWatch Eventsの設定

続いて、定期実行させるためのイベントを作成します。先程と同様に、CloudWatchから、[イベント]-[ルールの作成]を選びます。

設定の方法は同じです。こちらは毎月5日の日本時間9時に実行しますので、0 0 5 * ? *と入力します。ターゲットのLambda関数と入力のJSONを設定します。

dynamodb-table-013

以上で環境が準備できました。それぞれ、CloudWatch Eventsで指定した日時になれば実行されます。

dynamodb-table-014

最後に

以上です。

定期的に実行するオペレーションは、Lambda + CloudWatch Eventsを使うことで自動化することができます。

なお、今回紹介した構成はあくまでサンプルですので、運用環境に適用する際には、エラー発生時の検知や、対応方法も併せて検討しましょう。