: tk
: インフラ
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
以上です。