はじめに
開発にあたり、インフラはTerraform、バックエンドはServerless Frameworkで作りたかったので、
それぞれをどのように定義するといい感じに参照できるか検討したので備忘メモ✍️
考え方
- CloudFront -> API Gateway -> Lambdaでバックエンド処理をしたい
-
/api
配下に来たリクエストをAPI Gatewayへ流す
-
- CloudFront -> S3で静的コンテンツを配信したい
- 上記にマッチしなかったリクエストをS3へ流す
- インフラとバックエンドは別々に管理したい
- CloudFrontl、S3はインフラ(Terraform)
- API GatewayとLambdaはバックエンド(Serverless Framework)
方法
Serverless Frameworkは、 sls deploy
すると裏でCloudFormationのスタックを作成するので、
Terraformからaws_cloudformation_stackとして参照します
serverless.yml(抜粋)
service:
name: example-backend
provider:
name: aws
runtime: nodejs10.x
stage: ${opt:stage, self:custom.defaultStage}
region: ap-northeast-1
# リージョナルのAPI Gatewayを作成
endpointType: REGIONAL
# Lambdaで使うRoleはこちらで作る。ActionやResourceは適宜設定
iamRoleStatements:
- Effect: Allow
Action:
- secretsmanager:GetSecretValue
Resource: "*"
functions:
example:
handler: src/example.lambdaHandler
# これだけでLambda Proxy統合のAPI Gatewayができる
events:
- http: POST api/example
custom:
defaultStage: prod
ServiceEndpoint
というキーの値が使えそう
Terraformは以下のような感じ(ほぼ省略ですが...)
実際はスタック名はvarで注入するなどしてください
terraform.tf(抜粋)
data "aws_cloudformation_stack" "backend" {
# これでCloudFormationの出力が参照できる
name = "example-backend-prod"
}
resource "aws_cloudfront_distribution" "infra" {
# 省略
# API Gatewayのオリジンを作る
origin {
# ServiceEndpointから xxx.execute-api.ap-northeast-1.amazonaws.com と prod を抜き出す
domain_name = "${split("/", data.aws_cloudformation_stack.backend.outputs["ServiceEndpoint"])[2]}"
origin_path = "/${split("/", data.aws_cloudformation_stack.backend.outputs["ServiceEndpoint"])[3]}"
# 省略
}
# S3のオリジンを作る
origin {
# 省略
}
# API Gatewayの定義
ordered_cache_behavior {
# Serverless Frameworkで指定したのと合わせる
path_pattern = "/api/*"
# 省略
}
# こっちでS3を定義。/api/*にマッチしないリクエストを扱う
default_cache_behavior {
# 省略
}
}