web-dev-qa-db-ja.com

CloudFrontでオンザフライで画像のサイズを変更し、同じURLで即座に取得します:AWS CloudFront-> S3-> Lambda-> CloudFront

TLDR:Lambda関数からの応答に対して新しいキャッシュ動作を作成して、CloudFront 307リダイレクトキャッシュをだます必要があります。

私たちがこれを達成するのにどれほど近いか信じられないでしょう。私たちは最後のステップでひどくこだわっています。

ビジネスケース:

私たちのアプリケーションはS3に画像を保存し、世界中の地理的な速度低下を避けるためにCloudFrontでそれらを提供します。さて、私たちはデザインに本当に柔軟性があり、ChouldFront URLで直接新しい画像寸法をリクエストできるようにしたいと思います!新しい各イメージサイズはオンデマンドで作成され、S3に保存されるため、2回目にリクエストされたときに、S3に存在し、CloudFrontにもキャッシュされるため、非常に迅速に提供されます。

ユーザーが画像chucknorris.jpgをアップロードしたとしましょう。元の画像のみがS3に保存され、次のようにページに表示されます。

//xxxxx.cloudfront.net/chucknorris.jpg

200x200ピクセルのサムネイルを表示する必要があると計算しました。したがって、画像srcをテンプレートに配置します。

//xxxxx.cloudfront.net/chucknorris-200x200.jpg

この新しいサイズが要求されると、Amazon Webサービスは、同じバケット内で、要求されたキーを使用して、その場でサイズを提供する必要があります。これにより、CloudFrontの同じURLに画像が直接読み込まれます。

私はアーキテクチャの概要とAWSでこれを行う方法のワークフローを使って醜い図を作成しました。

enter image description here

Python Lambdaの終了方法は次のとおりです。

return {
    'statusCode': '301',
    'headers': {'location': redirect_url},
    'body': ''
}

問題:

Lambda関数をS3にリダイレクトすると、チャームのように機能します。 CloudFrontにリダイレクトすると、CloudFrontは307(および301、302、303と同様)をキャッシュするため、リダイレクトループに入ります。 Lambda関数がCloudFrontにリダイレクトするとすぐに、CloudFrontはS3から画像をフェッチする代わりにAPI Getaway URLを呼び出します。

enter image description here

CloudFrontのBehaviors設定タブで新しいキャッシュ動作を作成したいと思います。この動作では、LambdaまたはS3からの応答はキャッシュされません(内部で何が起こっているのか正確にはわかりません)が、この同じサイズ変更されたイメージに対する後続の要求はキャッシュされます。パスパターン-\d+x\d+\..+$を設定し、Lambda関数のARNをadd "Lambda Function Association"に追加して、イベントタイプOrigin Responseを設定しようとしています。次に、「デフォルトTTL」を0に設定します。

しかし、いくつかのエラーのために動作を保存できません:

enter image description here

私たちは正しい方向に進んでいますか、それともこの「ラムダ関数関連付け」の考え方はまったく異なりますか?

20
katericata

ようやく解決できました。これは実際には構造的な解決策ではありませんが、必要なことを行います。

まず、マイケルの回答のおかげで、すべてのメディアタイプに一致するパスパターンを使用しました。次に、キャッシュ動作ページは少し誤解を招きやすいものでした。実際、LambdaアソシエーションはLambda @ Edgeを対象としていますが、キャッシュ動作のすべてのツールチップにはこれが表示されていません。表示されるのはLambdaだけです。この特定の問題のために、AWSサービススコープをLambda @ Edgeで拡張したくないので、この機能は役に立ちません。

ソリューションアプローチは次のとおりです。
サポートするメディアタイプごとに1つ、複数のキャッシュ動作を定義しました:

enter image description here

キャッシュ動作ごとに、Default TTL0に設定しました。

そして最も重要な部分:Lambda関数で、S3に配置するときにサイズ変更された画像にCache-Controlヘッダーを追加しました:

s3_resource.Bucket(BUCKET).put_object(Key=new_key, 
                                      Body=edited_image_obj,
                                      CacheControl='max-age=12312312',
                                      ContentType=content_type)

すべてが機能することを検証するために、新しい画像ディメンションがCloudFrontのキャッシュヘッダーと共に提供されることがわかりました。

enter image description here

9
katericata

あなたは正しい軌道に乗っています...多分...しかし、少なくとも2つの問題があります。

ここで設定している「Lambda Function Association」はLambda @ Edgeと呼ばれ、まだ使用できません。アクセスできるユーザーは、限定プレビューへの参加を申し込んだユーザーのみです。 "maximum allowed is 0"エラーは、あなたがプレビュー参加者ではないことを意味します。これがすべてのアカウントで公開される時期に関連するアナウンスを見たことがありません。

しかし、それが利用可能になったとしても、Origin Responseトリガーを使用してCloudFrontをトリガーして別の宛先を試行し、リダイレクト。この主張に反するドキュメントを見つけた場合は、私にお知らせください。

ただし... Lambda @ Edgeは307にCache-Control: no-cacheを設定するのに役立つため、CloudFrontはそれをキャッシュしませんが、リダイレクト自体は引き続きブラウザーに戻る必要があります。

また、Lambda @ EdgeはPythonではなくNodeのみをサポートしているので、これはまだ計画の一部ではないかもしれません。質問からは、私には本当にわかりません。

Lambda @ Edge限定プレビューについてお読みください

2番目の問題:

パスパターン-\d+x\d+\..+$を設定しようとしています

それはできません。パスパターンは、*ワイルドカードをサポートする文字列の一致です。正規表現ではありません。 複数のワイルドカードがサポートされているように見える であるため、/*-*x*.jpgでうまくいくかもしれません。

1