これは旧eviry tech blogから移行した記事です。
eviry開発のtkです。
AWS DynamoDBというNoSQLを提供してくれているサービスは、キャパシティを設定することで読み込み・書き込みをさばくことができます。
また、このキャパシティはオートスケーリングに対応しているので、急なリクエストの増加にも対応することが可能です。
ところが、このキャパシティのオートスケーリングは関して注意が必要です。
それは、リクエストが全くなくなるとスケールアウトしないから。
これは公式のドキュメントでも言及されています。
DynamoDB Auto Scaling によるスループットキャパシティの自動管理 - Amazon DynamoDB
これの対処法として、Cloudwatch Eventを使ってlambda経由で定期的にDynamoDBに定期的にリクエストを送り続ける、というものがあります。
今回はこの構築をterraformでやってみました。
まず、ファイル構成は以下のようになります。
. ├── lambda_function │ └── main.py └── main.tf
lambda_functionディレクトリにmain.pyを配置し、これをAWS Lambdaに登録します。
main.pyの実装は以下のようになっています。
今回は書き込みキャパシティのスケールアウトを想定したので、念の為書き込みリクエストを送るようにしています。
テーブル名やキー名などは適宜書き換えてください。
import boto3 import datetime dynamodb = boto3.resource('dynamodb') def lambda_handler(event, context): table = dynamodb.Table('tablename') table.put_item( Item={ 'tablekeyname': 'tablekeyvalue' } ) return { 'statusCode': 200, 'body': 'Send Request success' }
次に、tfファイルは次のようになります。
ここも環境に合わせてcredentialsファイルへのパスとprofile名を変更してください。
provider "aws" { region = "ap-northeast-1" shared_credentials_file = "/pass/to/credentials" profile = "profilename" } resource "aws_iam_role" "lambda_exec" { name = "AWSDynamoDBForLambda" assume_role_policy = <<EOF { "Version": "2012-10-17", "Statement": [ { "Action": "sts:AssumeRole", "Principal": { "Service": "lambda.amazonaws.com" }, "Effect": "Allow", "Sid": "" } ] } EOF } resource "aws_iam_policy" "putitem_dynamodb_policy" { name = "AWSDynamoDBPutItemAccess" description = "Provides putitem access for Amazon DynamoDB" policy = <<EOF { "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Action": [ "dynamodb:PutItem" ], "Resource": "*" } ] } EOF } resource "aws_iam_policy_attachment" "dynamodb_policy_to_lambda" { name = "dynamodb_policy_to_lambda" policy_arn = "${aws_iam_policy.putitem_dynamodb_policy.arn}" groups = [] users = [] roles = ["${aws_iam_role.lambda_exec.id}"] } data "archive_file" "lambda_function" { type = "zip" source_dir = "lambda_function" output_path = "lambda_function.zip" } resource "aws_lambda_function" "send_putitem_lambda" { function_name = "SendPutRequestToDynamoDB" filename = "${data.archive_file.lambda_function.output_path}" role = "${aws_iam_role.lambda_exec.arn}" handler = "main.lambda_handler" runtime = "python3.6" } resource "aws_cloudwatch_event_rule" "lambda" { name = "SendPutRequestEventToDynamoDBBy5MIN" description = "send put request event to dynamoDB by 5 min" schedule_expression = "rate(5 minutes)" } resource "aws_cloudwatch_event_target" "lambda" { rule = "${aws_cloudwatch_event_rule.lambda.name}" target_id = "send_putitem_lambda" arn = "${aws_lambda_function.send_putitem_lambda.arn}" } resource "aws_lambda_permission" "allow_cloudwatch_to_call_lambda" { statement_id = "AllowExecuteFromCloudWatch" action = "lambda:InvokeFunction" function_name = "${aws_lambda_function.send_putitem_lambda.function_name}" principal = "events.amazonaws.com" source_arn = "${aws_cloudwatch_event_rule.lambda.arn}" }
これで追加されるものは
- Lambda関数用ロールの作成
- DynamoDBにPutItemリクエストを実行するためのpolicyの作成
- Lambda関数用ロールへのpolicyの追加
- lambda_functionディレクトリをzip圧縮
- Lambda関数の作成
- CloudWatch Eventのルールの作成
- CloudWatch EventのルールとLambda関数を紐づけ
- CloudWatch EventのルールにLambda関数の呼び出しを許可
これを使用すると、「5分毎にlambdaを実行し、DynamoDBに対して書き込みリクエストを送出する」環境ができます。
また、lambda_functionディレクトリをzipに圧縮しLambda関数として登録するので、手動でzipを作る必要はありません。
あとはterraformを実行し、環境構築を行います。
terraform init terraform apply
以上です。