Terraformサンプル
bucket
resource "aws_s3_bucket" "s3" {
bucket = "bucket_name"
acl = "private"
versioning {
enabled = true
}
}
Lambda・S3間のネットワーク
resource "aws_vpc" "prod" {
cidr_block = "10.0.0.0/16"
instance_tenancy = "default"
enable_dns_support = true
enable_dns_hostnames = true
tags = {
Name = "vpc_prod"
}
}
resource "aws_internet_gateway" "prod" {
vpc_id = aws_vpc.prod.id
tags = {
Name = "internet_gateway_prod"
}
}
resource "aws_route_table" "public" {
vpc_id = aws_vpc.prod.id
route {
cidr_block = "0.0.0.0/0"
gateway_id = aws_internet_gateway.prod.id
}
tags = {
Name = "route_tablepublic"
}
}
resource "aws_vpc_endpoint" "private-s3" {
vpc_id = aws_vpc.prod.id
service_name = "com.amazonaws.ap-northeast-1.s3"
route_table_ids = [aws_route_table.public.id]
}
aws_vpc_endpoint
が鍵でこれがないとLambdaからs3にアクセスできません。
役割としてはパブリックなネットワークを介さずにs3にアクセスするために必要です。
Lambda functionとRole
data "archive_file" "source_zip" {
type = "zip"
source_dir = "./source"
output_path = "./source/source.zip"
}
resource "aws_lambda_function" "sample" {
filename = data.archive_file.source_zip.output_path
function_name = "sample"
role = aws_iam_role.sample.arn
handler = "main"
source_code_hash = data.archive_file.source_zip.output_base64sha256
runtime = "go1.x"
memory_size = 128
timeout = 10
environment {
variables = {
S3_BUCKET_NAME = aws_s3_bucket.s3.bucket
}
}
}
resource "aws_iam_role" "sample" {
name = "sample_iam_role"
assume_role_policy = <<POLICY
{
"Version": "2012-10-17",
"Statement": [
{
"Action": "sts:AssumeRole",
"Principal": {
"Service": "lambda.amazonaws.com"
},
"Effect": "Allow",
"Sid": ""
}
]
}
POLICY
}
resource "aws_iam_role_policy" "sample" {
name = "sample_iam_role_policy"
role = aws_iam_role.sample.id
policy = <<POLICY
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"logs:CreateLogGroup",
"logs:CreateLogStream",
"logs:PutLogEvents",
"ec2:CreateNetworkInterface",
"ec2:DescribeNetworkInterfaces",
"ec2:DeleteNetworkInterface",
"s3:PutObject",
"s3:GetObject",
"s3:DeleteObject"
],
"Resource": "*"
}
]
}
POLICY
}
resource "aws_cloudwatch_event_target" "output_report_every_month" {
rule = aws_cloudwatch_event_rule.every_2m.name
target_id = "output_report"
arn = aws_lambda_function.sample.arn
}
resource "aws_lambda_permission" "allow_cloudwatch_to_call_output_report" {
statement_id = "AllowExecutionFromCloudWatch"
action = "lambda:InvokeFunction"
function_name = aws_lambda_function.sample.function_name
principal = "events.amazonaws.com"
source_arn = aws_cloudwatch_event_rule.every_2m.arn
}
resource "aws_cloudwatch_event_rule" "every_2m" {
name = "every_2m"
description = "every_2m"
schedule_expression = "cron(1/2 * * * ? *)"
}
archive_file
を使うとterraform plan
時に対象のディレクトリをzipにしてくれますaws_cloudwatch_event_rule
を使うと2分ごとに実行などができるようになります
実行スクリプトサンプル
上のarchive_file
で指定したディレクトリ内にビルドしたバイナリを置きましょう
main.go
package main
import (
"bytes"
"errors"
"fmt"
"github.com/aws/aws-lambda-go/lambda"
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/aws/awserr"
"github.com/aws/aws-sdk-go/aws/endpoints"
"github.com/aws/aws-sdk-go/aws/request"
"github.com/aws/aws-sdk-go/aws/session"
"github.com/aws/aws-sdk-go/service/s3"
"os"
"time"
)
func run() (string, error) {
s3BucketName := os.Getenv("S3_BUCKET_NAME")
if s3BucketName == "" {
return "failed", errors.New("must set env value S3_BUCKET_NAME")
}
err := uploadToS3(s3BucketName, fmt.Sprintf("file_%s", time.Now().UTC().Format("2006-01-02")))
if err != nil {
return "failed", err
}
return "success", nil
}
func main() {
lambda.Start(run)
}
func uploadToS3(s3BucketName, fileName string) error {
sess := session.Must(session.NewSession(&aws.Config{
Region: aws.String(endpoints.ApNortheast1RegionID),
}))
svc := s3.New(sess)
wb := new(bytes.Buffer)
_, _ = fmt.Fprint(wb, "テキスト")
res, err := svc.PutObject(&s3.PutObjectInput{
Bucket: aws.String(s3BucketName),
Key: aws.String(fileName + ".txt"),
Body: bytes.NewReader(wb.Bytes()),
})
if err != nil {
fmt.Println(res)
if err, ok := err.(awserr.Error); ok && err.Code() == request.CanceledErrorCode {
fmt.Printf("upload canceled due to timeout, %v\n", err)
return err
} else {
fmt.Printf("failed to upload object, %v\n", err)
return err
}
}
fmt.Printf("successfully uploaded file\n")
return nil
}
ビルド
go get ./...
GOOS=linux GOARCH=amd64 go build -o ./source/main main.go
main.go
をビルドして、mainという名前のバイナリを作成する。
mainという名前はaws_lambda_function
のhandler = "main"
で指定する名前と同じにします。
コメント