はじめに
今回は以下の構成をTerraformで作成します。
Terraformの導入については、以下の記事で解説しています。よろしければ併せてご覧ください。
フォルダ構成
フォルダ構成は以下の通りです。
赤字の部分のフォルダ、ファイルは手で作成するものです。
黒字のファイルはplan等で自動生成されるファイルです。
├── envs
│ ├── backend.tf
│ ├── main.tf
│ ├── provider.tf
│ ├── terraform.tfstate
└── modules
├── api-gateway
│ └── api-gateway.tf
├── dynamodb
│ ├── dynamodb.tf
│ └── user.json
├── iam
│ └── iam.tf
└── lambda
├── lambda.tf
├── src
│ └── lambda.py
└── upload
└── lambda.zip
envs配下
provider.tf
provider "aws" {
region = "ap-northeast-1"
}
backend.tf
# ローカル管理
terraform {
backend "local" {
path = "./terraform.tfstate"
}
}
main.tf
各リソースのmodules配下を作成後に記述してください。
module "dynamodb" {
source = "../modules/dynamodb"
prefix = "test"
}
module "iam" {
source = "../modules/iam"
prefix = "test"
table_arn = module.dynamodb.user_table_output.arn
}
module "lambda" {
source = "../modules/lambda"
prefix = "test"
dynamodb_table_name = module.dynamodb.user_table_output.name
role_arn = module.iam.lambda_role_arn_output
api_gateway_arn = module.api_gateway.api_gateway_arn_output
}
module "api_gateway" {
source = "../modules/api-gateway"
prefix = "users"
lambda_arn = module.lambda.lambda_arn_output
}
modules配下
DynamoDB
dynamodb.tf
aws_dynamodb_tableがテーブルを、aws_dynamodb_table_itemがテーブルに登録するデータを表しています。データー情報はuser.jsonに切り出しています。
詳しい各パラメータは公式が詳しいです。
variable "prefix" {
type = string
}
locals {
json_data = file("${path.module}/user.json")
config = jsondecode(local.json_data)
}
resource "aws_dynamodb_table" "user_table" {
name = "${var.prefix}_user_table"
billing_mode = "PAY_PER_REQUEST"
hash_key = "UserId"
attribute {
name = "UserId"
type = "S"
}
}
resource "aws_dynamodb_table_item" "user_item" {
for_each = local.config
table_name = aws_dynamodb_table.user_table.name
hash_key = "UserId"
item = jsonencode(each.value)
}
output "user_table_output" {
value = aws_dynamodb_table.user_table
}
user.json
{
"user01": {
"UserId": {
"S": "A001"
},
"Name": {
"S": "Taro"
},
"Age": {
"S": "25"
}
},
"user02": {
"UserId": {
"S": "A002"
},
"Name": {
"S": "Jiro"
},
"Age": {
"S": "20"
}
},
"user03": {
"UserId": {
"S": "A003"
},
"Name": {
"S": "Saburo"
},
"Age": {
"S": "10"
}
}
}
IAM
iam.tf
aws_iam_role:ロール作成
aws_iam_role_policy:ポリシー作成
aws_iam_role_policy_attachment:ポリシーをロールにアタッチ
variable "prefix" {
type = string
}
variable "table_arn" {
type = string
}
resource "aws_iam_role" "lambda_role" {
name = "${var.prefix}_lambda_role"
assume_role_policy = jsonencode({
Version = "2012-10-17"
Statement = [
{
Action = "sts:AssumeRole"
Effect = "Allow"
Sid = ""
Principal = {
Service = "lambda.amazonaws.com"
}
}
]
})
}
resource "aws_iam_role_policy_attachment" "lambda_role_policy_attach" {
role = aws_iam_role.lambda_role.name
policy_arn = "arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole"
}
resource "aws_iam_role_policy" "lambda_role_policy" {
name = "${var.prefix}_lambda_policy"
role = aws_iam_role.lambda_role.id
policy = jsonencode({
Version = "2012-10-17"
Statement = [
{
Effect = "Allow"
Action = [
"dynamodb:GetItem"
]
Resource = [
var.table_arn
]
}
]
})
}
output "lambda_role_arn_output" {
value = aws_iam_role.lambda_role.arn
}
Lambda
lambda.tf
aws_lambda_functionはLambda関数を定義します。
aws_lambda_permissionはLambda関数に対するアクセス許可を定義します。
variable "prefix" {
type = string
}
variable "dynamodb_table_name" {
type = string
}
variable "role_arn" {
type = string
}
variable "api_gateway_arn" {
type = string
}
data "archive_file" "lambda_file" {
type = "zip"
source_dir = "${path.module}/src"
output_path = "${path.module}/upload/lambda.zip"
}
resource "aws_lambda_function" "lambda_function" {
filename = data.archive_file.lambda_file.output_path
function_name = "${var.prefix}_lambda"
role = var.role_arn
handler = "lambda.handler"
source_code_hash = data.archive_file.lambda_file.output_base64sha256
runtime = "python3.9"
timeout = 29
environment {
variables = {
table_name = var.dynamodb_table_name
}
}
}
resource "aws_lambda_permission" "lambda_permission" {
statement_id = "AllowAPIGatewayGetTrApi"
action = "lambda:InvokeFunction"
function_name = aws_lambda_function.lambda_function.arn
principal = "apigateway.amazonaws.com"
source_arn = "${var.api_gateway_arn}/test/GET/"
}
output "lambda_arn_output" {
value = aws_lambda_function.lambda_function.invoke_arn
}
lambda.py
Lambdaに記述するコード(Python)です。
DynamoDBからユーザーを取得し、クライアントに返しています。
import os
import json
import boto3
dynamodb = boto3.resource('dynamodb')
table = dynamodb.Table(os.getenv('table_name'))
def handler(event, context):
user_info = table.get_item(Key={'UserId': 'A001'})['Item']
user_id = user_info['UserId']
name = user_info['Name']
age = user_info['Age']
return {
'statusCode': 200,
'body': json.dumps({
'Id': user_id,
'Name': name,
'Age': age,
})
}
API Gateway
api-gateway.tf
aws_api_gateway_rest_apiはAPI GatewayのREST APIを定義します。
aws_api_gateway_methodはAPI Gatewayのメソッド(HTTPメソッド)を定義します。
aws_api_gateway_integrationはAPI Gatewayのメソッドとバックエンド(Lambda)の統合を定義します。
aws_api_gateway_deploymentはAPI Gatewayのデプロイ情報を定義します。このリソースタイプを使用して、デプロイメントのステージ(開発、本番など)、APIの設定などを指定できます。
variable "prefix" {
type = string
}
variable "lambda_arn" {
type = string
}
resource "aws_api_gateway_rest_api" "api" {
name = "${var.prefix}_api"
}
resource "aws_api_gateway_method" "api_gateway_get" {
authorization = "NONE"
http_method = "GET"
resource_id = aws_api_gateway_rest_api.api.root_resource_id
rest_api_id = aws_api_gateway_rest_api.api.id
}
resource "aws_api_gateway_integration" "api_gateway_get" {
http_method = aws_api_gateway_method.api_gateway_get.http_method
resource_id = aws_api_gateway_rest_api.api.root_resource_id
rest_api_id = aws_api_gateway_rest_api.api.id
integration_http_method = "POST"
type = "AWS_PROXY"
uri = var.lambda_arn
}
resource "aws_api_gateway_deployment" "api_deploy" {
depends_on = [
aws_api_gateway_integration.api_gateway_get
]
rest_api_id = aws_api_gateway_rest_api.api.id
stage_name = "test"
triggers = {
redeployment = filebase64("${path.module}/api-gateway.tf")
}
}
output "api_gateway_arn_output" {
value = aws_api_gateway_rest_api.api.execution_arn
}
終わりに
本記事はここまでとなります。
AWSの学習にはハンズオンで学習できるUdemyが非常に効率的でおすすめです。
以下におすすめ教材を紹介しておりますので、是非ご活用ください。
ご覧いただきありがとうございました。ご指摘等がございましたら頂けますと嬉しいです。
引き続き、プログラミングについて定期的に発信していきますのでよろしくお願いします!
また、もしよろしければtwitterもフォローしていただけると嬉しいです!🐢
コメント