LoginSignup
22
9

More than 3 years have passed since last update.

はじめに

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バケットは事前に作成してください。
アクセスキーは 名前付きプロファイル を使用すると便利です。

main.tf
# 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ロールに必要なポリシーが定義されています。

main.tf
module "iam" {
  source = "./modules/iam"
  name   = var.app_name
}

アプリ名を適宜置き換えてください。

terraform.tfvars
app_name = "sample-app"
modules/iam/main.tf
# 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
}
modules/iam/variable.tf
variable "name" {}

Lambda作成

MainファイルでLambda作成用のModuleを呼び出し、変数を渡します。
Lambdaのプログラムはlambda_src内に格納してください。フォルダ毎zip化してアップロードされます。
タグや環境変数が必要な場合は変数を追加で記載してください。

main.tf
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"
}
modules/lambda/main.tf
# 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
}
modules/lambda/variable.tf
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ドキュメントを参照してください。

main.tf
module "cloudwatch_evnet" {
  source     = "./modules/cloudwatch"
  name       = var.app_name
  schedule   = "cron(0 0 1 * ? *)"
  lambda_arn = module.lambda.arn
}
modules/cloudwatch/main.tf
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
}
modules/cloudwatch/variable.tf
variable "name" {}
variable "schedule" {}
variable "lambda_arn" {}

CloudWatch EventからLambda関数の呼び出しを許可

main.tf
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
22
9
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
22
9