AWSで画像リサイズAPIを作ろう
2023/12/14(金) AWS Gameday
石塚 崚斗© R.Ishizuka 2023.

お題:
AWSで画像リサイズAPIを作成せよ
要件:
1. 画像はS3に保存する
2. CloudFrontでキャッシュする
3. リサイズ後の画像はS3に保存しない※ 保守性の観点

設計案

2

1. Lambda@Edgeの利用 [2018年3月7日の公式ブログ]

Viewer Request

ClientOrigin Request

Viewer Response

Origin Response
CloudFront

Lambda@Edge

S3

リサイズ後の画像保存（必須）※ Lambda@EdgeではOrigin ResponseのBodyを編集できないため© R.Ishizuka 2023.

設計案

3

2. CloudFront Functionsの利用

Viewer Request

ClientViewer Response

Functions

Origin Request

Origin ResponseCloudFront

CloudFront FunctionsはOrigin側に配置できないうえ
画像を扱うヘビーな処理に向いていない© R.Ishizuka 2023.

S3

設計案

43. Object Lambdaの利用 [2023年3月17日の公式ブログ]

Viewer Request

Origin Request
Origin Response

ClientViewerResponse

CloudFront

Object Lambda
Access Point
Alias© R.Ishizuka 2023.

LambdaS3
Access Point

S3

設計案

5

3案の比較検討

キャッシュ

リサイズ後の画像保存不要性

Lambda@Edge◎✖

CloudFront
Functions✖

-S3 Object Lambda◎◎※ 実はLambda Function URLsを使う手もありますが、今回は割愛© R.Ishizuka 2023.

デプロイ容易性✖

CloudFrontへのデプロイ(10分かかることも)◎Lambdaのデプロイ(長くても数分)

実装してみようTerraformに落とし込むだけ！

…と思っていたのですがTerraformを用いた実装

9Object Lambda Access Pointのalias attributeがない…
Viewer Request

Origin Request
Origin Response

ClientViewerResponse

CloudFront

Object Lambda
Access Point
Alias※ v5.16.1時点© R.Ishizuka 2023.

LambdaS3
Access Point

S3

二段階でapplyするという回避策はありますがTerraformのAWS ProviderにContributeしてみようと決心Terraform AWS ProviderへのContribute

13

1

2

3

そもそも何から
ハジメレバヨイノカ

Go言語
ナニモワカラン

終わりがナニモミエナイ

公式ドキュメントが懇切丁寧

A tour of Goを1日で完走

タイムボックスを切って自分に鞭を打つ© R.Ishizuka 2023.

Terraform AWS ProviderへのContribute© R.Ishizuka 2023.

14

Terraform AWS ProviderへのContribute

学んだことはブログに即時アウトプット© R.Ishizuka 2023.

15

Terraform AWS ProviderへのContribute

🎉© R.Ishizuka 2023.

16

Terraform AWS ProviderへのContribute17🥰

© R.Ishizuka 2023.

Terraform AWS ProviderへのContribute18🥰🥰

※ v5.16.2以降© R.Ishizuka 2023.

Terraformを用いた実装

19

無事実装完了！

Viewer Request

Origin Request
Origin Response

ClientViewerResponse

CloudFront

Object Lambda
Access Point
Alias© R.Ishizuka 2023.

LambdaS3
Access Point

S3Terraformを用いた実装

20

コイツ気になりますよね
コイツ

Viewer Request

Origin Request
Origin Response

ClientViewerResponse

CloudFront

Object Lambda
Access PointAlias© R.Ishizuka 2023.

LambdaS3
Access Point

S3Terraformを用いた実装

21
const { S3Client, WriteGetObjectResponseCommand } = require("@aws-sdk/client-s3");
const s3 = new S3Client({ region: "ap-northeast-1" })const axios = require("axios").default;
const sharp = require("sharp");

Nodeで実装してみました (超省略コード)
仕様
MethodQueryType

ExampleGETwint

https://{domain}/{ファイル名}?w=500エラーハンドリング後の世界
Status

Body

Example200

バイナリキャッシュヒット/ミスに拘らず200を返す

400

空Query Paramsが不正指定されたobjectのcontent-typeが不正404

空指定されたパスに画像が存在しない

500

空

内部エラー

exports.handler = async (event) => {// object lambdaのeventから必要なフィールドを抽出する
const {
getObjectContext: { inputS3Url, outputRoute, outputToken },userRequest: { url },} = event;// S3 originからレスポンスを受け取る
const axiosResponse = await axios.get(inputS3Url, { responseType: "arraybuffer" });// レスポンスから画像データを抽出する
let data = axiosResponse.data;// クエリパラメータからリサイズ後のwidthを取得
const { searchParams } = new URL(url);
const width = parseInt(searchParams.get("w"));// リサイズ実行
data = await sharp(data).resize(width).toBuffer();// クライアントに画像を返す
let response200 = {StatusCode: 200,
RequestRoute: outputRoute,
RequestToken: outputToken,
ContentType: axiosResponse.headers["content-type"],Body: data,};// GetObjectResponseを書き換える
await s3.send(new WriteGetObjectResponseCommand(response200));
return { statusCode: 200 };}© R.Ishizuka 2023.

まとめ
1. 画像リサイズAPIにはS3 Object Lambdaが便利
2. Terraformは最新のAWSに追従しているとは限らない