[Terraform]CloudFront+Lambda@EdgeでLambdaのみで静的ページをホストする
Posted On 2024-04-20
CloudFront+Lambda@Edgeで割と簡単に静的ページをホストできるって前に読んだので、気になっていたパターン。ChatGPTに聞かせてTerraformで作って動かしてみた。
目次
GPT Log
https://chat.openai.com/share/fb21f16b-164a-470c-abd4-10ea6f7cfd0a
人間が書いた記事はいっぱい出てくるのでぐぐって
ディレクトリ構成
- main.tf
- lambda_function.py
LambdaはPythonで定義。Lambda@EdgeはNode.jsとPythonが対応している。
ちなみに、Lambda@Edgeはus-east-1
のリージョンである必要があるので、Terraformのproviderの取り回しに注意が必要。複数のリージョンをまたいだデプロイになるため、異なるリージョンをエイリアスで結べば良い。
コード
main.tf
provider "aws" {
region = "ap-northeast-1"
profile = "develop"
}
provider "aws" {
alias = "east" # 別のリージョン用のエイリアス
region = "us-east-1" # Lambda@Edgeはus-east-1である必要がある
profile = "develop"
}
terraform {
backend "local" {
path = ".cache/terraform.tfstate"
}
}
data "aws_caller_identity" "current" {}
resource "aws_s3_bucket" "my_bucket" {
bucket = "shikoan-homepage-bucket" # Enter your backet name
}
# Lambda setting
data "archive_file" "lambda_zip" {
type = "zip"
source_file = "lambda_function.py"
output_path = ".cache/lambda_function.zip"
}
resource "aws_lambda_function" "edge_lambda" {
provider = aws.east # deploy to us-east-1
function_name = "LambdaAtEdgeExample"
filename = data.archive_file.lambda_zip.output_path
source_code_hash = data.archive_file.lambda_zip.output_base64sha256
handler = "lambda_function.handler"
runtime = "python3.12"
role = aws_iam_role.lambda_exec.arn
publish = true # Must publish
}
resource "aws_iam_role" "lambda_exec" {
name = "lambda_exec_role"
assume_role_policy = jsonencode({
Version = "2012-10-17"
Statement = [
{
Action = "sts:AssumeRole"
Effect = "Allow"
Principal = {
Service = "lambda.amazonaws.com"
}
},
{
Action = "sts:AssumeRole"
Effect = "Allow"
Principal = {
Service = "edgelambda.amazonaws.com"
}
}
]
})
}
resource "aws_lambda_permission" "allow_cloudfront" {
provider = aws.east
statement_id = "AllowExecutionFromCloudFront"
action = "lambda:InvokeFunction"
function_name = aws_lambda_function.edge_lambda.arn
principal = "edgelambda.amazonaws.com"
source_arn = "arn:aws:cloudfront::${data.aws_caller_identity.current.account_id}:distribution/${aws_cloudfront_distribution.example_distribution.id}"
}
# Cloud front
resource "aws_cloudfront_distribution" "example_distribution" {
origin {
domain_name = aws_s3_bucket.my_bucket.bucket_regional_domain_name
origin_id = "S3-myBucket"
}
enabled = true
is_ipv6_enabled = true
default_cache_behavior {
target_origin_id = "S3-myBucket"
viewer_protocol_policy = "redirect-to-https"
allowed_methods = ["GET", "HEAD", "OPTIONS"]
cached_methods = ["GET", "HEAD"]
lambda_function_association {
event_type = "origin-request"
lambda_arn = "${aws_lambda_function.edge_lambda.arn}:${aws_lambda_function.edge_lambda.version}"
}
forwarded_values {
query_string = false
cookies {
forward = "none"
}
}
min_ttl = 0
default_ttl = 3600
max_ttl = 86400
}
price_class = "PriceClass_100"
restrictions {
geo_restriction {
restriction_type = "none"
}
}
viewer_certificate {
cloudfront_default_certificate = true
}
}
output "cloudfront_distribution_url" {
value = "https://${aws_cloudfront_distribution.example_distribution.domain_name}"
description = "URL for the CloudFront distribution"
}
CloudFrontの設定は、以前のCloudFront+S3のケースを使いまわしたので割とガバガバかもしれない。
lambda_function.py
def handler(event, context):
html_content = """
<html>
<head><title>Welcome</title></head>
<body><h1>Hello from Lambda@Edge!</h1>
<h2>I am shikoan.</h2></body>
</html>
"""
response = {
'status': '200',
'statusDescription': 'OK',
'headers': {
'content-type': [{
'key': 'Content-Type',
'value': 'text/html'
}]
},
'body': html_content
}
return response
Lambdaの中にHTMLを書いていくスタイル。わかりやすい。
結果
まあうまくいく
ちなみにLambda(HTMLの内容)を変更してterraform apply
してもその内容がすぐには反映されないが、これはCloudFrontのキャッシュのせい。CloudFrontから明示的にキャッシュ削除を依頼する。
すると変更が反映される。
所感
- CloudFrontのデプロイに少々時間がかかる(3分程度)が、単純な構成の割にはいろいろできそうなので楽しそう。
- ちなみに普通のLambdaと異なり、CloudWatch Logsに書き出さないようで、AWSLambdaBasicExecutionRoleを付与してもログには見れなかった。Lambdaがどのタイミングで起動されたかは気になった。
terraform destroy
時に、CloudFrontを削除してすぐだとLambda@Edgeを削除できない。これはLambda@Edgeの仕様により、他のリージョンに複製されるため。レプリカが削除されるまで数時間かかるらしい- Lambdaのパーミッションの部分に、リージョン変えたprovider指定しなくてハマった。
Shikoan's ML Blogの中の人が運営しているサークル「じゅ~しぃ~すくりぷと」の本のご案内
技術書コーナー
北海道の駅巡りコーナー