【大阪 / 横浜】インフラ / サーバーサイドエンジニア募集中!

【大阪 / 横浜】インフラ / サーバーサイドエンジニア募集中!

【25卒向け】AI×バーチャル面接の募集を開始いたしました!

【25卒向け】AI×バーチャル面接の募集を開始いたしました!

【導入実績 500社以上】AWS 構築・運用保守・監視サービス

【導入実績 500社以上】AWS 構築・運用保守・監視サービス

【CentOS 後継】AlmaLinux OS サーバー構築・移行サービス

【CentOS 後継】AlmaLinux OS サーバー構築・移行サービス

【WordPress 専用】クラウドサーバー『ウェブスピード』

【WordPress 専用】クラウドサーバー『ウェブスピード』

【格安】Webサイト セキュリティ自動診断「クイックスキャナー」

【格安】Webサイト セキュリティ自動診断「クイックスキャナー」

【低コスト】Wasabi オブジェクトストレージ 構築・運用サービス

【低コスト】Wasabi オブジェクトストレージ 構築・運用サービス

【予約システム開発】EDISONE カスタマイズ開発サービス

【予約システム開発】EDISONE カスタマイズ開発サービス

【100URLの登録が0円】Webサイト監視サービス『Appmill』

【100URLの登録が0円】Webサイト監視サービス『Appmill』

【中国現地企業に対応】中国クラウド / サーバー構築・運用保守

【中国現地企業に対応】中国クラウド / サーバー構築・運用保守

【YouTube】ビヨンド公式チャンネル「びよまるチャンネル」

【YouTube】ビヨンド公式チャンネル「びよまるチャンネル」

AWS lambdaを利用してS3の画像アップロードをトリガーにサムネイル画像を自動生成する

インフラエンジニアの寺岡です。

今回のテーマはAWSのサービスの中の一つの「lambda」です。
AWS Lambda (サーバーレスでコードを実行・自動管理) | AWS

ちなみに読み方は「ラムダ」です。間の「b」はどこに行ったのか。
ということは置いておいて・・・
この手の記事はすでにたくさん存在していてもはや何番煎じになるかもわかりませんが
自主的な勉強も兼ねて少し触ってみました。
今回はlambdaを利用してサムネイル画像を作ります。詳細は以下をご覧ください↓

■そもそも「lambda」って何ですか?

はい、まず初めにlambdaの概要から。
お決まりの如くAWSの公式ドキュメントから引用します(
AWS Lambda とは - AWS Lambda - AWS Documentation

AWS Lambda はサーバーをプロビジョニングしたり管理しなくてもコードを実行できるコンピューティングサービスです。

・・・・なるほどですね。
lambdaは、何かしらの「イベント」をトリガーにして
予め登録しておいたコードを実行することができます。
また、このイベントをトリガーにして非同期に処理が実行されるので
常時EC2インスタンス等を起動しておく必要がなくなります。
サーバーをプロビジョニングしたり管理しなくても良いというのはこの部分のことですね。

さてさて、先ほどから「イベント」という言葉が出てきていますが
一言で申しますと以下のようなものです。

  • S3のバケットにファイルがアップロードされた

つまり、「S3のバケットにファイルがアップロードされたら何らかの処理を自動実行する」
ということが可能になります。
もちろんEC2インスタンス上のAPIを叩きに行くなんてことはしません。
S3とlambdaだけで完結します。

はい、ここまでの内容とブログタイトルをご覧になった方はピンときたと思いますが
今回は「S3のバケットにファイルがアップロードされたら画像のサムネイル画像を自動生成する」
・・・・・・・をやっていきたいと思います(

■サムネイル画像が出来るまでの道のり

  • 画像をアップロードするS3のバケットを用意
  • lambda関数の記述
  • 関数の動作テスト
  • lambdaトリガーの設定
  • 動作確認

①画像をアップロードするS3のバケットを用意

まずは、入れ物を用意しないと始まらないということでさくっとS3にバケットを作成します。
バケットの作成とポリシーの設定は以下の記事をご覧ください。
以前に私が書いたものですのでどさくさに紛れて宣伝します(

AWS S3で静的サイトの配信をやってみた

②lambda関数の記述

いよいよ本題、lambdaの関数を記述します。
「サムネイル画像を自動生成する」ためのコードを記述してlambdaに登録します。
コードに関しては、pythonやnode.jsベースで記述できるのですが
今回は個人的な好みを尊重してnode.jsで記述します(python好きな方は申し訳ございません
まずはLambda関数の作成というボタンをクリックします、すると以下のような画面になると思います。

この画面でlambda関数の設計図を選択します。
予め用途に併せてテンプレート的なものを用意してくれていますのでありがたく利用させてもらいます。
ますランタイムの選択から「Node.js6.10」を選択。
設計図に関してはs3周りの処理を行いたいので、「s3-get-object」というものを利用します。
設計図をクリックすると・・・

こんな感じでトリガーの設定画面になります。

バケット ①で作ったバケットを選択します。
イベントタイプ 今回は「画像がアップロードされたら」関数を実行したいのでPutを選択します。
プレフィックス 今回はバケット直下にアップロードを行うので省略します。
サフィックス ファイル名の末尾が「jpg」のファイルのみを関数の実行対象とします。

トリガーの有効化のチェックは入れません。
後程記述する関数の動作確認が終わってから手動で有効にします。
入力が終わったら次へをクリックします。

この画面で実際に関数を記述していきます。
関数名を記入する項目がありますがこの部分はお好きな名前で大丈夫です。
設計図の選択画面で「s3-get-object」を選択したので
S3からファイルを取得するためのコードが予め記述されています。

'use strict';

console.log('Loading function');

const aws = require('aws-sdk');

const s3 = new aws.S3({ apiVersion: '2006-03-01' });


exports.handler = (event, context, callback) => {
    //console.log('Received event:', JSON.stringify(event, null, 2));

    // Get the object from the event and show its content type
    const bucket = event.Records[0].s3.bucket.name;
    const key = decodeURIComponent(event.Records[0].s3.object.key.replace(/\+/g, ' '));
    const params = {
        Bucket: bucket,
        Key: key,
    };
    s3.getObject(params, (err, data) => {
        if (err) {
            console.log(err);
            const message = `Error getting object ${key} from bucket ${bucket}. Make sure they exist and your bucket is in the same region as this function.`;
            console.log(message);
            callback(message);
        } else {
            console.log('CONTENT TYPE:', data.ContentType);
            callback(null, data.ContentType);
        }
    });
};

しかし、このままだとS3からファイルを取得することはできますが
サムネイル画像を生成することが出来ません。
少しこのコードに追記します。

'use strict';
console.log('Loading function');

var fs = require('fs');
var im = require('imagemagick');
const aws = require('aws-sdk');
const s3 = new aws.S3({ apiVersion: '2006-03-01' });

exports.handler = (event, context, callback) => {
    const bucket = event.Records[0].s3.bucket.name;
    const key = decodeURIComponent(event.Records[0].s3.object.key.replace(/\+/g, ' '));
    const params = {
        Bucket: bucket,
        Key: key,
    };
    s3.getObject(params, (err, data) => {
        if (err) {
            console.log(err);
            const message = `Error getting object ${key} from bucket ${bucket}. Make sure they exist and your bucket is in the same region as this function.`;
            console.log(message);
            callback(message);
        } else {
            var contentType = data.ContentType;
            var extension = contentType.split('/').pop();
            console.log(extension);
            
            im.resize({
                srcData: data.Body,
                format: extension,
                width: 100
            }, function(err, stdout, stderr) {
                if (err) {
                    context.done('resize failed', err);
                } else {
                    
                    var thumbnailKey = key.split('.')[0] + "-thumbnail." + extension;
                   
                    s3.putObject({
                        Bucket: bucket,
                        Key: thumbnailKey,
                        Body: new Buffer(stdout, 'binary'),
                        ContentType: contentType
                    }, function(err, res) {
                        if (err) {
                            context.done('error putting object', err);
                        } else {
                            callback(null, "success putting object");
                        }
                    });
                }
            });
        }
    });
};

追記するとこんな感じになります。
S3からファイルを取得するまでは同じですが
取得した画像からimagemagickを利用してリサイズを行い
加工後の画像をサムネイル画像として再度S3にアップロードしています。

コードを記述したら、以下のようにIAM Roleの設定を行います
今回はこの部分は割愛してテンプレートから新しいRoleを自動で作成してしまいましょう。
ここで作ったロールに対してS3のオブジェクトを操作するポリシーがアタッチされる形になるので
正しく設定しないと関数がエラーになったりします。
(S3に対するアクセス権限がなくてAccess Deniedはよくあるお話です)

次へを押すと確認画面になりますので、「関数の作成」ボタンを押しましょう。
するとlambda関数が作成されます。

一覧に、先ほど作成した関数が表示されていますね!

③関数の動作テスト

作成した関数が正しく動作するかをテストします。

画面上部のアクションからテストイベントの設定を選択します。

すると、テストイベントの入力の画面になります。
テストイベントをjson形式で記述するのですが
このjsonをlambdaがS3から受け取って関数を実行するとお考えください。
今回は、test.jpgという画像ファイルを予めS3にバケットにアップロードしておき
その画像がアップロードされたことを想定してlambda関数が正常に動作するかをテストします。

このテストイベントにもテンプレートが用意されているので
S3 Putというテンプレートを利用しましょう。
以下を入力して、保存してテストをクリックします。

{
  "Records": [
    {
      "eventVersion": "2.0",
      "eventTime": "1970-01-01T00:00:00.000Z",
      "requestParameters": {
        "sourceIPAddress": "*"
      },
      "s3": {
        "configurationId": "testConfigRule",
        "object": {
          "eTag": "0123456789abcdef0123456789abcdef",
          "sequencer": "0A1B2C3D4E5F678901",
          "key": "test.jpg",
          "size": 1024
        },
        "bucket": {
          "arn": "arn:aws:s3:::lambda-img-resize",
          "name": "lambda-img-resize",
          "ownerIdentity": {
            "principalId": "EXAMPLE"
          }
        },
        "s3SchemaVersion": "1.0"
      },
      "responseElements": {
        "x-amz-id-2": "EXAMPLE123/5678abcdefghijklambdaisawesome/mnopqrstuvwxyzABCDEFGH",
        "x-amz-request-id": "EXAMPLE123456789"
      },
      "awsRegion": "ap-northeast-1",
      "eventName": "ObjectCreated:Put",
      "userIdentity": {
        "principalId": "EXAMPLE"
      },
      "eventSource": "aws:s3"
    }
  ]
}

実行結果として成功したときのメッセージが返ってきました!
S3バケットの中身に変化があったか確認してみましょう。

はい、何事もなかったかのようにサムネイル画像が生成されています。
関数の実行自体は問題なさそうですね。

④lambdaトリガーの設定

いよいよ終盤、トリガーの設定を行います。
先程まではあくまでテストなので
今の段階で新しく画像をアップロードしてもサムネイル画像は作成されません。
画像がアップロードされたら関数が自動実行されるようにトリガーの設定を行う必要があります。
作成したlambda関数からトリガータブをクリックします。

関数を作成する段階でトリガー自体は作成しているので、あとはこれを有効化するだけです。
有効化をクリックします。

⑤動作確認

では、実際に画像をS3にアップロードして確認してみましょう。

・・・・・・・作成されてますね、素晴らしい。。。

■まとめ

いかがでしたでしょうか。
コードを書く必要があるので少し複雑になってしまいますが
EC2いらずでここまで出来てしまうので便利ですしおもしろいですね。
今回は軽く触ってみただけですが、もう少し高度なこともやってみようと思います。
以上です、ありがとうございました。

この記事がお役に立てば【 いいね 】のご協力をお願いいたします!
0
読み込み中...
0 票, 平均: 0.00 / 10
8,151
X facebook はてなブックマーク pocket
【2024.6.30 CentOS サポート終了】CentOS サーバー移行ソリューション

【2024.6.30 CentOS サポート終了】CentOS サーバー移行ソリューション

【25卒向け】AI×バーチャル面接の募集を開始いたしました!

【25卒向け】AI×バーチャル面接の募集を開始いたしました!

【大阪 / 横浜】インフラエンジニア・サーバーサイドエンジニア 積極採用中!

【大阪 / 横浜】インフラエンジニア・サーバーサイドエンジニア 積極採用中!

この記事をかいた人

About the author

寺岡佑樹

2016年ビヨンド入社、現在6年目のインフラエンジニア
MSPの中の人として障害対応時のトラブルシューティングを行いながら
AWSなどのパブリッククラウドを用いたインフラの設計/構築も行っている。
最近はDockerやKubernetesなどのコンテナ基盤の構築や
運用自動化の一環としてTerraformやPackerなどのHashicorpツールを扱うことが多く
外部の勉強会やセミナーで登壇するEvangelistの役割も担っている。

・GitHub
https://github.com/nezumisannn

・登壇経歴
https://github.com/nezumisannn/my-profile

・発表資料(SpeakerDeck)
https://speakerdeck.com/nezumisannn

・所有資格
AWS Certified Solutions Architect - Associate
Google Cloud Professional Cloud Architect

Top Scroll �A�C�R��