ドキュメントを通してre:Invent 2016キーノートで発表されたLambda@Edgeを理解する #reinvent

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

はじめに

こんにちは、中山です。

re:Invent 2016に参加中です。現地時間12/1(木)の8:30から実施されたWerner Vogels氏によるキーノートの中で発表された新サービス、Lambda@Edgeについてまとめます。残念ながらまだプレビュー版で利用するには申請が必要です。まずは実際に利用する前にドキュメントを参照してどういったものなのかをまとめたいと思います。今回参照するドキュメントは以下のとおりです。

Lambda@Edgeとは何か

ドキュメントにずばり書かれています。

Lambda@Edge (preview) allows you to run Lambda functions at the AWS Edge locations in response to CloudFront events, without provisioning or managing servers, by using the AWS Lambda serverless programming model.

つまり、CloudFrontのエッジロケーション上でLambda関数を実行可能、かつCloudFrontの各種イベントに基づきイベントドリブンに実行されるよ、しかもサーバーレスなのでサーバのお守りしなくてもいいよということです。至れり尽くせり感すごい。

Lambda@Edge登場以前でもCloudFrontへの特定の情報を契機に(ヘッダの情報など)オリジン側で変更を加えるといったことは可能でした。が、これではオリジンまでトラフィックが届く必要があるためネットワークレイテンシ上の問題がありました。Lambda@Edgeの登場により高速にかつサーバーレスな形でこういった問題点に対して対応可能になったというわけです。

Lambda@Edgeのユースケース

Lambda関数が実行可能なので自分にあった動作に調整可能ですが、主なユースケースとしては以下のようなものがあります。

  • A/Bテストを実施するためにクッキーを解析/挿入してクライアント毎に異なるURLを返す
  • ユーザエージェントに基いてレスポンスとして返すオブジェクトをクライアント毎に変更する
    • 例えば、クライアントのデバイスに最適化された画像を返却する
  • ヘッダやトークンを解析して、それらに対応するヘッダを挿入し、オリジンへリクエストが届く前にアクセスコントロールとして利用する
  • エッジロケーションでキャッシュされているオブジェクトについて、ヘッダに対し各種操作(追加/削除/変更)を実施し、URLを変更して異なるオブジェクトを返す

CloudFrontのイベントにはどういったものがあるのか

こちらのドキュメントに詳しいです。まとめると現状以下の4つのイベントがあります。

CloudFront Viewer Request

  • クライアントからのリクエストがCloudFrontに届く前かつCloudFrontのキャッシュ検索が実施される前

viewer-request

CloudFront Origin Request

  • クライアントからのリクエストがCloudFrontからオリジンへ転送される前に発生するイベント
  • CloudFrontがリクエストをオリジンに転送する際にのみ発生する
  • つまり、オブジェクトのフェッチなどエッジロケーション起源のリクエストに関してこのイベントは発生しない

origin-request

CloudFront Origin Response

  • オリジンからのレスポンスがCloudFrontで受信された後かつCloudFrontによってこのレスポンスがキャッシュされる前に発生するイベント
  • このイベントはCloudFrontがリクエストをオリジンに転送する際にのみ発生する
  • つまり、オブジェクトのフェッチなどエッジロケーション起源のリクエストに関してこのイベントは発生しない

origin-response

CloudFront Viewer Response

  • CloudFrontからクライアントへレスポンスを返す前に発生するイベント
  • レスポンスとして返すコンテンツはエッジロケーションにすでにキャッシュされているオブジェクトでも、キャッシュがなくオリジンからフェッチしたものでも両方共このイベントは発生可能

viewer-response

イベント発生時にLambda@Edgeへはどういった情報が渡されるのか

レスポンスとリクエストで異なるようです。

  • リクエストの場合
{
"Records":[
          {
              "cf": {
                  "configuration": {
                      "distributionId": "EXAMPLE"
                  },
                  "request": {
                      "uri": "/me.pic",
                      "method": "GET",
                      "httpVersion": "2.0",
                      "clientIp": "2001:cdba::3257:9652",
                      "headers": {
                          "User-Agent": ["Test Agent"],
                          "Host" : ["d2fadu0nynjpfn.cloudfront.net"]
                      }
                  }
              }
          }
      ]
}
キー バリュー 読み書き
uri CloudFrontからリクエストされたコンテンツの相対パス。このバリューを更新することで提供するオブジェクトを変更できる。 両方可
method リクエストのHTTPメソッド。 読み込みのみ
httpVersion リクエストのHTTPバージョン。 読み込みのみ
clientIp リクエストの送信元IPアドレス。 読み込みのみ
headers リクエストのヘッダ。ヘッダはリストの中にキーペア形式で表現される。現状全てのヘッダが操作可能というわけではなくいくつか制限がある。 両方可
  • レスポンスの場合
{
    "Records":[
          {
              "cf": {
                  "configuration": {
                      "distributionId": "EDFDVBD6EXAMPLE "
                  },
                  "response": {
                      "status": "200",
                      "statusDescription": "HTTP OK",
                      "httpVersion": "2.0",
                      "headers": {
                          "User-agent": [ "mozilla", "safari" ],
                          "Vary": [ "*" ]
                      }
                  }
              }
          }
      ]
  }
キー バリュー 読み書き
status クライアントへ返すHTTPステータスコード。 読み込みのみ
statusDescription クライアントへ返すHTTPステータスコード。 読み込みのみ
httpVersion クライアントへのレスポンスで利用されるHTTPプロトコルバージョン。 読み込みのみ
headers レスポンス内のHTTPヘッダ。ヘッダはリストの中にキーペア形式で表現される。現状全てのヘッダが操作可能というわけではなくいくつか制限がある。 両方可

ヘッダの制限はどういったものがあるのか

読み書き両方共不可能な「blacklisted headers」と、読み込みのみ可能な「read-only headers」の2つのタイプがあります。それぞれのヘッダにはどういった種類があるのかについてはこちらのドキュメントを参照してください。ここに記載されていないヘッダについては読み書き可能ということです。

実際のところどんな感じで使えるの?

現地時間の今日プレビューに応募したのでまだ実際には使えてないですが、こちらのドキュメントなどにサンプルコードがまとめられています。また、Lambda関数のブループリントにも複数のサンプルコードが上がっている模様です。次回以降で使ってみた内容をレポートしたいと思います。

まとめ

いかがだったでしょうか。

まだプレビュー段階ですが個人的にはかなり期待できる機能だと思いました。もう少し使い込んでからより詳細なレポートにまとめたいと思います。

本エントリがみなさんの参考になれば幸いです。