AWS LambdaでのS3画像アップロードをトリガーとしたリサイズ(サムネイル作成) (1/2) ローカルPC上の準備
Androidからアップロードした画像ファイルのサムネイルを作成する目的でAWS Lambdaを使用してみましたので、簡単な動作確認までをご紹介。
[目次]
AWS Lambdaとは
AWS LambdaはNode.js(javascript)、python、javaでクラウド上の自動化処理の用途でプログラミングをすることができます。
AWS Lambda は、コードを AWS Lambda にアップロードすると、サービスが AWS インフラストラクチャを使用してコードの実行を代行するコンピューティングサービスです。コードをアップロードして、Lambda 関数と呼ばれる関数を作成することで、AWS Lambda がコードを実行するサーバーのプロビジョニングおよび管理を行います。AWS Lambda は次のように使用できます。 ・Amazon S3 バケットまたは Amazon DynamoDB テーブルのデータ変更などのイベントに対応して AWS Lambda がコードを実行するイベント駆動型コンピューティングサービスとして。 ・Amazon API Gateway を使用した HTTP リクエストまたは AWS SDK を使用した API 呼び出しに対応してコードを実行するコンピューティングサービスとして。
料金
遊ぶ分には無料で使えますな。
リクエストのうち毎月最初の 1,000,000 件は無料 その後は 0.20 USD/1,000,000 件のリクエスト(0.0000002 USD/リクエスト)
ローカルでのNode.js環境作成
今回はNode.jsベースで動かしてみたので、まずNode.jsをローカルのPCにインストールします。ちなみにAWSマニュアルにはNode.js v4.3で対応とありますので、Node.jsのサイトからv4.3をダウンロードします。
Note The code sample is compliant with the Node.js runtime v4.3. For more information, see Programming Model (Node.js)
Step 2.1: Create a Deployment Package - AWS Lambda
Node.jsのダンロード
https://nodejs.org/download/release/v4.3.2/
私の環境はwindows x64のPCなので「node-v4.3.2-x64.msi」をダウンロードました。
Node.jsのインストール
全てデフォルトの設定値で、インストールします。
Lambdaプログラムアップロード用ファイルを作成
どこでもいいので「createThumbnail」フォルダを作成して、配下で「npm install async gm」を実行して、asyncとgmモジュールをダウンロードし展開します。
C:\>mkdir createThumbnail C:\>cd createThumbnail C:\createThumbnail>npm install async gm gm@1.23.0 node_modules\gm ├── array-parallel@0.1.3 ├── array-series@0.1.5 ├── debug@2.2.0 (ms@0.7.1) └── cross-spawn@4.0.2 (lru-cache@4.0.1, which@1.2.12) async@2.1.4 node_modules\async └── lodash@4.17.2
「createThumbnail」フォルダ内に「index.js」というファイル名で以下のプログラムを貼り付けます。
「createThumbail.js」という風にAWSのマニュアルは書いてありますが、Lambdaファンクションを作成する際のハンドラのデフォルト値が「index.handler」なのでこれとファイル名がマッチする必要があります。マッチしない場合は以下のようにLambdaファンクション実行した際にエラーになります。
{ "errorMessage": "Cannot find module '/var/task/index'", "errorType": "Error", "stackTrace": [ "Function.Module._load (module.js:276:25)", "Module.require (module.js:353:17)", "require (internal/module.js:12:17)" ] }
コード(index.js)
// dependencies var async = require('async'); var AWS = require('aws-sdk'); var gm = require('gm') .subClass({ imageMagick: true }); // Enable ImageMagick integration. var util = require('util'); // constants var MAX_WIDTH = 100; var MAX_HEIGHT = 100; // get reference to S3 client var s3 = new AWS.S3(); exports.handler = function(event, context, callback) { // Read options from the event. console.log("Reading options from event:\n", util.inspect(event, {depth: 5})); var srcBucket = event.Records[0].s3.bucket.name; // Object key may have spaces or unicode non-ASCII characters. var srcKey = decodeURIComponent(event.Records[0].s3.object.key.replace(/\+/g, " ")); var dstBucket = srcBucket + "-resize"; var dstKey = "resized-" + srcKey; //★ // Sanity check: validate that source and destination are different buckets. if (srcBucket == dstBucket) { callback("Source and destination buckets are the same."); return; } // Infer the image type. var typeMatch = srcKey.match(/\.([^.]*)$/); if (!typeMatch) { callback("Could not determine the image type."); return; } var imageType = typeMatch[1]; if (imageType != "jpg" && imageType != "png") { callback('Unsupported image type: ${imageType}'); return; } // Download the image from S3, transform, and upload to a different S3 bucket. async.waterfall([ function download(next) { // Download the image from S3 into a buffer. s3.getObject({ Bucket: srcBucket, Key: srcKey }, next); }, function transform(response, next) { gm(response.Body).size(function(err, size) { // Infer the scaling factor to avoid stretching the image unnaturally. var scalingFactor = Math.min( MAX_WIDTH / size.width, MAX_HEIGHT / size.height ); var width = scalingFactor * size.width; var height = scalingFactor * size.height; // Transform the image buffer in memory. this.resize(width, height) .toBuffer(imageType, function(err, buffer) { if (err) { next(err); } else { next(null, response.ContentType, buffer); } }); }); }, function upload(contentType, data, next) { // Stream the transformed image to a different S3 bucket. s3.putObject({ Bucket: dstBucket, Key: dstKey, Body: data, ContentType: contentType }, next); } ], function (err) { if (err) { console.error( 'Unable to resize ' + srcBucket + '/' + srcKey + ' and upload to ' + dstBucket + '/' + dstKey + ' due to an error: ' + err ); } else { console.log( 'Successfully resized ' + srcBucket + '/' + srcKey + ' and uploaded to ' + dstBucket + '/' + dstKey ); } callback(null, "message"); } ); };
Step 2.1: Create a Deployment Package - AWS Lambdaのコードになりますが一部、バケット名などを個別に指定するために変更しています。★の部分。
ファイルの圧縮
index.jsとnode_modulesのフォルダをzipで圧縮します。
http://aws-mobile-development.hatenablog.com/AWS LambdaでのS3画像アップロードをトリガーとしたリサイズ(サムネイル作成) (2) AWSコンソールでの作業 - AWS Mobile Application Development へ続きます。