はじめに
Lambdaのバッチ実行をCloudWatch Evnetと組み合わせて使うことがよくあると思いますが、
今回はその設定をTerraformを使って構築してみたいと思います。
事前準備
Terraform, aws-cliのインストールをお願いします。
brew install terraform
brew install awscli
ちなみに私の環境は下記のようになっています。
macOS Mojave 10.14.6
Terraform 0.12.6
aws-cli 1.16.21
フォルダ構成説明
.
├── main.tf →Mainファイル
├── variable.tf →変数定義ファイル
├── terraform.tfvars →外部変数設定ファイル
├── lambda_src →Lambdaソース置き場
│ ├── handler.py
│ └── requirements.txt
└── modules →AWS各サービスモジュール
├── cloudwatch
│ ├── main.tf
│ └── variable.tf
├── iam
│ ├── main.tf
│ └── variable.tf
└── lambda
├── main.tf
└── variable.tf
Terraform初期設定
AWSアクセスキーとtfstateファイルを管理するS3バケットは事前に作成してください。
アクセスキーは 名前付きプロファイル を使用すると便利です。
# Variables are not allowed in this block(このブロックで変数は使えません)
provider "aws" {
region = "ap-northeast-1"
version = "2.24.0"
profile = "sample-iam" ←ここ
}
# Variables are not allowed in this block(このブロックで変数は使えません)
terraform {
required_version = ">= 0.12"
backend "s3" {
bucket = "sample-tfstate-bucket" ←ここ
region = "ap-northeast-1"
key = "terraform.tfstate"
encrypt = true
profile = "sample-iam" ←ここ
}
}
# 初期化
terraform init
Lambda用IAMロール作成
MainファイルでIAMロール作成用のModuleを呼び出し、変数を渡します。
modules/iam/main.tf
にはLambdaのIAMロールに必要なポリシーが定義されています。
module "iam" {
source = "./modules/iam"
name = var.app_name
}
アプリ名を適宜置き換えてください。
app_name = "sample-app"
# Lambda Role
resource "aws_iam_role" "lambda_role" {
name = "${var.name}-lambda-role"
assume_role_policy = <<POLICY
{
"Version": "2012-10-17",
"Statement": [
{
"Action": "sts:AssumeRole",
"Principal": {
"Service": "lambda.amazonaws.com"
},
"Effect": "Allow"
}
]
}
POLICY
}
# Lambda Policy Data
data "aws_iam_policy_document" "lambda_policy_document" {
statement {
actions = [
"logs:CreateLogGroup",
"logs:CreateLogStream",
"logs:PutLogEvents",
]
effect = "Allow"
resources = ["*"]
}
}
# Lambda Attach Role to Policy
resource "aws_iam_role_policy" "lambda_role_policy" {
role = aws_iam_role.lambda_role.id
name = "${var.name}-lambda-policy"
policy = data.aws_iam_policy_document.lambda_policy_document.json
}
output "lambda_role_arn" {
value = aws_iam_role.lambda_role.arn
}
variable "name" {}
Lambda作成
MainファイルでLambda作成用のModuleを呼び出し、変数を渡します。
Lambdaのプログラムはlambda_src
内に格納してください。フォルダ毎zip化してアップロードされます。
タグや環境変数が必要な場合は変数を追加で記載してください。
module "lambda" {
source = "./modules/lambda"
name = var.app_name
role_arn = module.iam.lambda_role_arn
lambda_source_dir = "./lambda_src"
lambda_handler = "handler.main"
function_runtime = "python3.7"
memory_size = 128
timeout = 30
log_retention_in_days = 14
environment_key_1 = "STAGE"
environment_value_1 = "dev"
}
# Local Values
locals {
tag_terraform_value = "Terraform"
archive_file_type = "zip"
deploy_upload_filename = "lambda_src.zip"
}
# Lambda Function
resource "aws_lambda_function" "lambda" {
filename = data.archive_file.lambda_file.output_path
function_name = var.name
role = var.role_arn
handler = var.lambda_handler
runtime = var.function_runtime
source_code_hash = data.archive_file.lambda_file.output_base64sha256
memory_size = var.memory_size
timeout = var.timeout
environment {
variables = {
"${var.environment_key_1}" = var.environment_value_1
}
}
tags = {
CreateOwner = local.tag_terraform_value
}
}
# CloudWatch Logs
resource "aws_cloudwatch_log_group" "log_group" {
name = "/aws/lambda/${var.name}"
retention_in_days = var.log_retention_in_days
tags = {
Name = var.name
CreateOwner = local.tag_terraform_value
}
}
# Lambda File Zip
data "archive_file" "lambda_file" {
type = local.archive_file_type
source_dir = var.lambda_source_dir
output_path = local.deploy_upload_filename
}
output "arn" {
value = aws_lambda_function.lambda.arn
}
output "function_name" {
value = aws_lambda_function.lambda.function_name
}
variable "name" {}
variable "lambda_source_dir" {}
variable "role_arn" {}
variable "lambda_handler" {}
variable "function_runtime" {}
variable "memory_size" {}
variable "timeout" {}
variable "log_retention_in_days" {}
variable "environment_key_1" {}
variable "environment_value_1" {}
CloudWatch Event作成
MainファイルでCloudWatch Event作成用のModuleを呼び出し、変数を渡します。
時間の書き方はAWSドキュメントを参照してください。
module "cloudwatch_evnet" {
source = "./modules/cloudwatch"
name = var.app_name
schedule = "cron(0 0 1 * ? *)"
lambda_arn = module.lambda.arn
}
resource "aws_cloudwatch_event_rule" "event_rule" {
name = var.name
schedule_expression = var.schedule
}
resource "aws_cloudwatch_event_target" "event_target" {
rule = aws_cloudwatch_event_rule.event_rule.name
arn = var.lambda_arn
}
output "rule_arn" {
value = aws_cloudwatch_event_rule.event_rule.arn
}
variable "name" {}
variable "schedule" {}
variable "lambda_arn" {}
CloudWatch EventからLambda関数の呼び出しを許可
resource "aws_lambda_permission" "allow_cloudwatch" {
statement_id = "AllowExecutionFromCloudWatch"
action = "lambda:InvokeFunction"
function_name = module.lambda.function_name
principal = "events.amazonaws.com"
source_arn = module.cloudwatch_evnet.rule_arn
}
Finish
# 初期化
terraform init
# Dry Run
terraform plan
# 実行
terraform apply