Lambda Layerを使ってSharpを使用した画像リサイズ機能を作る方法を学ぼう

Lambda Layerは、Lambda機能の世界で真の宝石です。ライブラリやその他の依存関係をパッケージングする便利な方法を提供し、Lambda関数で使用することができます。GitHubで50,000以上のダウンロードと5,500のスターを持つオープンソースプロジェクトのWebinyは、Lambda Layerを使用しています。これによって我々のLambda機能のサイズを12MB削減し、すべてのWebinyデプロイメントで画像処理ライブラリsharpを共有することができます。

この記事を読み終える頃には、Lambda Layerの作成と使用方法を学べるでしょう。例として、SharpライブラリLayerを作成し、サムネイル画像を作成するためにLambda関数でそれを使用します。
このチュートリアルでは、sharpライブラリを使用してサムネイル画像を作成するLambda関数を作成します。このライブラリは、Lambda Layerを使用してLambda関数にパッケージ化されます。

ワークフローはこのようになります。S3バケット(ソースバケット)に画像ファイルがアップロードされるたびに、Lambda関数が呼び出されます。ソースS3バケットから画像オブジェクトを読み取り、サムネイル画像を作成し、ターゲットS3バケットに保存します。

前提条件

  • AWSアカウント - 様々なAWSサービスを使用するには、AWSアカウントが必要です。AWSアカウントを作成するにはこのリンクに従ってください。
  • AWSコマンドライン - Lambda関数とLambda Layerを作成するために、AWSコマンドラインを使用します。AWS CLIのインストールガイドはこちらです。

ステップ1 - 2つのS3バケットを作成する

まず、ソースとターゲットの2つのバケットを作成しましょう。前述したように、ソースバケットに画像ファイルがアップロードされるたびに、Lambda関数は対応するサムネイル画像を作成し、ターゲットS3バケットに保存します。

S3バケットを作成するための手順は以下の通りです。

1.) Amazon S3コンソールを開きます。
2.) 2つのS3バケットを作成する - ソースとターゲット。

ターゲットバケット名は、source-bucket-nameと後ろに-resizedを接尾辞として付ける必要があります。例えば、ソースバケットがmybucketという名前なら、ターゲットバケットはmybucket-resizedと命名します。この命名規則に従ってください。なぜなら、この命名ロジックをLambda関数で使用するからです。

ステップ2 - IAMポリシーを作成する

次に、Lambda関数のための権限を指定するIAMポリシーを作成しましょう。Lambda関数は、次の操作の権限を持っている必要があります:

  • ソースS3バケットからオブジェクトを取得する。
  • ターゲットS3バケットにリサイズされたオブジェクトを配置する。
  • Amazon CloudWatch Logsにログを書き込む。

IAMポリシーを作成するには

1.) IAMコンソールのポリシーのページを開きます。
2.) ポリシーの作成を選びます。
3.) JSONタブを選び、次のポリシーを貼り付けます。事前に作成したソースバケットの名前でmybucketを置き換えてください。

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "logs:PutLogEvents",
                "logs:CreateLogGroup",
                "logs:CreateLogStream"
            ],
            "Resource": "arn:aws:logs:*:*:*"
        },
        {
            "Effect": "Allow",
            "Action": [
                "s3:GetObject"
            ],
            "Resource": "arn:aws:s3:::mybucket/*"
        },
        {
            "Effect": "Allow",
            "Action": [
                "s3:PutObject"
            ],
            "Resource": "arn:aws:s3:::mybucket-resized/*"
        }
    ]
}

4.) Next: Tagsを選びます。
5.) Next: Reviewを選びます。
6.) Review policyのもとで、NameAWSLambdaS3Policyを入力します。
7.) Create policyを選びます。

ステップ3 - 実行ロールを作成する

AWSリソースにアクセスする権限をLambda関数に与える実行ロールを作成します。

実行ロールを作成するには

1.) IAMコンソールのロールのページを開きます。
2.) ロールの作成を選びます。
3.) 次のプロパティを持つロールを作成します:
- 信頼されたエンティティタイプ - AWSサービス(EC2、LambdaなどのAWSサービスがこのアカウントでアクションを実行できるようにします。)
- ユースケース - Lambda(Lambda関数がAWSサービスを代わって呼び出せるようにします。)
- パーミッションポリシーAWSLambdaS3Policy
- ロール名lambda-s3-role

ステップ4 - Sharp Lambda Layerを作成する

このチュートリアルの特別な部分に来ました。このセクションでsharp Lambda Layerを作成します。

このチュートリアルのこの部分は、あなたのマシンで実行されます。npmがインストールされていることを確認してください(sharpパッケージをインストールするためにnpmが必要です)。

1.) nodejsという名前のディレクトリを作成します。
2.) 次のコマンドを実行してnodejsディレクトリにsharp依存関係をインストールします:

npm install
SHARP_IGNORE_GLOBAL_LIBVIPS=1 npm install --arch=x64 --platform=linux sharp

このステップ後、以下のディレクトリ構造が得られます:

nodejs
|- node_modules
|- package-lock.json

3.) nodejsディレクトリの.zipファイルアーカイブを作成します。

zip -r nodejs.zip nodejs

4.) レイヤーを公開しましょう。レイヤーを作成して公開するために、次のコマンドを実行します:

aws lambda publish-layer-version --layer-name sharp --description "Sharp dependency for image transformation" --zip-file fileb://nodejs.zip --compatible-runtimes "nodejs14.x" --region "us-east-1" --output "json"

コマンドを正常に実行した後、このような出力が表示されます。

LayerVersionArnを注目してください。Lambda関数の作成時に使用します。

{
    "LayerArn": "arn:aws:lambda:us-east-1:400803493251:layer:sharp",
    "LayerVersionArn": "arn:aws:lambda:us-east-1:400803493251:layer:sharp:1",
    ...
}

ステップ5 - Lambda関数を作成する

sharp Lambda Layerを使用するLambda関数を作成しましょう。以前に話したように、このLambda関数は、オブジェクトがソースバケットに作成されるときに呼び出されます。それから、それぞれのサムネイル画像を作成し、ターゲットバケットに保存します。以下のコード例は、ステップ1で述べたS3バケット名の規則に従っていることを前提としています。

ステップ5.1 関数コードを作成する

index.jsという名前のファイルに次のコード例をコピーします。

// 依存関係
const AWS = require('aws-sdk');
const util = require('util');
const sharp = require('sharp');

// S3クライアントへの参照を取得
const s3 = new AWS.S3();

exports.handler = async (event, context, callback) => {
    // イベントパラメータからオプションを読み取ります。
    console.log("Reading options from event:\n", util.inspect(event, {depth: 5}));
    const srcBucket = event.Records[0].s3.bucket.name;
    // オブジェクトキーはスペースやユニコード非ASCII文字を含むことがあります。
    const srcKey = decodeURIComponent(event.Records[0].s3.object.key.replace(/\+/g, " "));
    const dstBucket = srcBucket + "-resized";
    const dstKey = "resized-" + srcKey;
    
    // ...(中略)...
    
    try {
        var buffer = await sharp(origimage.Body).resize(width).toBuffer();
        
        // ...(中略)...
        
        console.log('Successfully resized ' + srcBucket + '/' + srcKey +
            ' and uploaded to ' + dstBucket + '/' + dstKey);
    } catch (error) {
        console.log(error);
        return;
    }
};

ステップ5.2 配置パッケージを作成する

配置パッケージは、Lambda関数コードとその依存関係を含む.zipファイルアーカイブです。

1.) Linux環境でコマンドライン端末またはシェルを開きます。
2.) lambda-s3という名前のディレクトリにindex.js関数コードを保存します。
このステップ後、以下のディレクトリ構造が得られます:

lambda-s3
|- index.js

3.) zipコマンドに-r(再帰的)オプションを設定して、関数コードとその依存関係を含む配置パッケージを作成します。
このコマンドをlambda-s3ディレクトリで実行します。

zip -r function.zip .

ステップ5.3 Lambda関数を作成する

AWS CLIコマンド(aws lambda create-function)を使用してLambda関数を作成します。

以下のコマンドにあるロールパラメータ123456789012をあなたのAWSアカウントIDに、ステップ4で得たレイヤーARN(LayerVersionArn)と置き換えてください。

aws lambda create-function --function-name CreateThumbnail \
--zip-file fileb://function.zip --handler index.handler --runtime nodejs14.x \
--timeout 30 --memory-size 1024 \
--role arn:aws:iam::123456789012:role/lambda-s3-role \
--region "us-east-1" \
--layers "arn:aws:lambda:us-east-1:400803493251:layer:sharp:1"

上記コマンドの実行に成功すると、以下のような出力が表示されます:

{
    "FunctionName": "CreateThumbnail",
    "FunctionArn": "arn:aws:lambda:us-east-1:400803493251:function:CreateThumbnail",
    ...
}

ステップ6 - Amazon S3トリガーを設定する

これまでに作成したすべての構成要素があります。最後の部品を加え、Amazon S3トリガーを設定してLambda関数を呼び出すようにしましょう。
S3ファイルがアップロードされると、サムネイルを作成し、ターゲットS3バケットにアップロードするLambda関数がトリガーされるはずです。

Amazon S3トリガーを作成するには

1.) AWSコンソールのLambdaページを開きます。
2.) CreateThumbnail関数を開きます。
3.) Function overviewセクションでAdd triggerを選択します。
4.) 以下のプロパティでトリガーを作成します:
- トリガーを選択 - S3
- バケット - mybucket(あなたのソースバケット名)
- イベントタイプ - PUT

ステップ7 - すべての設定が完了したので、テストしましょう!

素晴らしいですね。サムネイル画像を作成するsharp Layerを使用するLambda関数の準備が整いました。ソースS3バケットに画像(jpgまたはpng)をアップロードしてください。アップロードが完了すると、ターゲットS3バケットで画像のサムネイルバージョンを見ることができるはずです。

Lambda Layerは、Lambda関数と共に使用するライブラリやその他の依存関係をパッケージ化する非常に効率的で便利な方法です。デプロイアーカイブのサイズを小さくし、デプロイを早める大きなメリットがあります。Layersはコードの共有と責任の分離を可能にし、保守可能なLambda関数を作ります。

Lambdaに関連するベストプラクティスやコード例についてさらに探求して学びたい場合は、Webinyのコードリポジトリをチェックしてください。WebinyはオープンソースのエンタープライズグレードのサーバーレスCMSです。

このチュートリアルやフィ

こちらの記事はdev.toの良い記事を日本人向けに翻訳しています。
https://dev.to/webiny/learn-how-to-use-lambda-layers-by-building-an-image-resize-function-using-sharp-bj4