業務でLambda@Edgeを使う機会があったので、Lambda@Edgeの基本的な知識とTerraformを使って構築するときのポイントについてまとめた。
そもそもLambda@Edgeとはなんなのだろうか。
結論から言うと、CloudFrontのエッジサーバでコード(Node.js、Python)を実行するLambdaのことで、「Lambdaを(CloudFrontの)Edgeで実行する」機能である。
Edge
はエッジサーバのエッジであり、CloudFrontにおけるエッジサーバ(世界中に分散して配置されたユーザにレスポンスを返すサーバ)を意味している。CloudFrontにLambda@Edgeを紐付けることで、CloudFrontに対してリクエストを送ったユーザの最寄りのエッジサーバ上でLambdaで定義されたコードが実行される。
なおLambda@Edgeは通常のLambdaのようにトリガイベントを柔軟に指定できるわけではなく、CloudFrontのイベントをトリガに実行される。
Lambda@Edgeの特徴
Lambda実行のトリガ
CloudFrontへのリクエスト、オリジンへの転送、オリジンからのレスポンスの受信、CloudFrontからレスポンスを返すとき、という4つのイベントのどれかがLambda@Edgeを発火させるトリガとなりうる。
- CloudFront がビューワーからリクエストを受信した後 (ビューワーリクエスト)
- CloudFront がリクエストをオリジンサーバーに転送する前 (オリジンリクエスト)
- CloudFront がオリジンからレスポンスを受信した後 (オリジンレスポンス)
- CloudFront がビューワーにレスポンスを転送する前 (ビューワーレスポンス)
Ref:Lambda 関数をトリガーできる CloudFront イベント
Lambda@Edgeの削除は遅い
Lambda@Edgeは各リージョンにレプリケートされて実行させるので、簡単には削除できない。各リージョンにレプリケートされた関数のレプリカがCloudFrontによって削除されないとダメ。そしてレプリカの削除は手動で行うことはできない。
削除手順
- CloudFrontのBehaviorの設定からLambda@Edgeの連携を削除
- Lambda@EdgeがCloudFrontディストリビューションに関連付けされなくなったら自動的に削除されていく
- 公式ドキュメントによれば「数時間」かかるとのこと。体感だと1時間くらいで終わることが多い。
- Lambda@Edgeを削除
サポートしているランタイム
- (2021年3月現在)サポートしているランタイムは
Python
とNode
のみ - 環境変数は使用不可
Ref:Lambda 関数の要件と制限
Terraformを使ったLambda@Edgeの構築
Terraformを使ってLambda@Edgeを構築する際の注意点についてまとめた。
Terraformを使って構築する時のポイント
aws_iam_role
lambda.amazonaws.com
及びedgelambda.amazonaws.com
からのAssume Roleを許可する
aws_lambda_function
- 変更があるたびに新しいversionをpublishする
- 関数は
us-east-1
regionにデプロイされる必要がある(mulitu-prividerを用いる)
resource "aws_lambda_function" "cf_verifixation_fix_path" {
・・・
publish = true
}
aws_cloudfront_distribution
lambda_function_association
をcache_behavior
に書くことで関連付けをおこなうqualified_arn
(バージョン付きのARN)を指定する- event_typeは発火のタイミングを指定している
resource "aws_cloudfront_distribution" "distribution" {
# ...
# or default_cache_behavior
ordered_cache_behavior {
# ...
lambda_function_association {
event_type = "origin-request"
lambda_arn = "${aws_lambda_function.lambda_edge.qualified_arn}"
}
}
}
修飾ARN(Qualified ARN)を指定する
- Lambda@Edgeを指定する時は、バージョン付きの修飾ARN(Qualified ARN)を指定する必要がある
$LATEST
は使用不可
The ARN of the Lambda function. You must specify the ARN of a function version; you can't specify a Lambda alias or $LATEST.
Lambda@Edgeを削除する時のエラーについて
Terraformを使って作成したLambda@Edgeを削除しようとした時に、以下のエラーが出力されることがある。これはLambda@Edgeそのもの削除に時間がかかることに起因する。
Error: Error deleting Lambda Function: InvalidParameterValueException: Lambda was unable to delete arn:aws:lambda:us-east-1:XXXXXXXXXXXX:function:cf_verification_modify_path:1 because it is a replicated function. Please see our documentation for Deleting Lambda@Edge Functions and Replicas.
{
RespMetadata: {
StatusCode: 400,
RequestID: "fc01ee33-9606-4a4c-8307-348554aa2016"
},
Message_: "Lambda was unable to delete arn:aws:lambda:us-east-1:XXXXXXXXXXXX:function:cf_verification_modify_path:1 because it is a replicated function. Please see our documentation for Deleting Lambda@Edge Functions and Replicas."
}
対応としては、関数のレプリカが削除されるのを待ってから再度terraform apply
する。
プログラミング
Lambda@Edgeがトリガされた時に、CloudFrontがLambda@Edgeにわたすイベントオブジェクト及びレスポンスオブジェクトを元にLambdaのコードを書いていけばいい。
ビューワーリクエスト及びオリジンリクエストの際にLambda@Edgeに渡されるイベント及び個々のパラメータについての説明はLambda@Edge イベント構造を参照するとよい。
以下のコードは、URIからパスを削除する時のコードの例。
def lambda_handler(event: dict, context):
request = event["Records"][0]["cf"]["request"]
request["uri"] = "/"
return request
トラブルシュート
Lambda@Edgeを呼ぶリクエストで503エラーが出力された場合
503 ERROR
The request could not be satisfied.
The Lambda function associated with the CloudFront distribution is invalid or doesn't have the required permissions. We can't connect to the server for this app or website at this time. There might be too much traffic or a configuration error. Try again later, or contact the app or website owner.
If you provide content to customers through CloudFront, you can find steps to troubleshoot and help prevent this error by reviewing the CloudFront documentation.
Lambda@Edgeの実行が失敗した場合にもこのエラーがブラウザに表示される。CloudWatch Logsを参照してエラーの原因調査をおこなう必要がある。