【AWS】Lambda@Edgeの基本とTerraformを使った構築

Posted on
AWS Lambda

業務で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を削除

Ref:Lambda@Edge 関数とレプリカの削除

サポートしているランタイム

  • (2021年3月現在)サポートしているランタイムはPythonNodeのみ
  • 環境変数は使用不可

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-1regionにデプロイされる必要がある(mulitu-prividerを用いる)
resource "aws_lambda_function" "cf_verifixation_fix_path" {
・・・
  publish = true
}

aws_cloudfront_distribution

  • lambda_function_associationcache_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.

Ref:LambdaFunctionAssociation

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を参照してエラーの原因調査をおこなう必要がある。