AWS活用における便利な小技を簡潔に紹介する連載「AWSチートシート」。今回は、「AWS Cloud9」で「AWS Lambda」のイベント駆動処理の基本を紹介する。
この記事は会員限定です。会員登録(無料)すると全てご覧いただけます。
「Amazon Web Services」(AWS)活用における便利な小技を簡潔に紹介する連載「AWSチートシート」。今回は、AWSのサーバレスサービス「AWS Lambda」の基本的で、よく紹介される利用方法の一つ、「Amazon S3」にアップロードした画像を自動で補正する方法を紹介します。併せて、サーバを自分で構築、設定することなくコードを実行できるLambdaの特徴について解説します。
画像の自動補正として公式でも紹介されているLambdaのユースケースが「サムネイルの自動生成」。「SNSやブログなどの見出しに利用する画像をサムネイルとして利用するために一律のサイズにそろえたいといったケース」です。
図1の構成例では、「オリジナル画像用バケット」に画像がアップロードされると、それをトリガーにLambdaで画像を補正し、補正後の画像を「サムネイル画像用バケット」に保存するといった流れが紹介されています。
このケースにある「画像がS3バケットにアップロードされるとLambdaを実行する」のようにLambdaによる処理を開始させるトリガーのことを「イベント」と呼びます。
イベントには「データベースの更新」「APIとしての呼び出し」などがあります。このイベントをきっかけに処理を実行する「イベントドリブンな処理の実行(イベント駆動処理)」はLambdaの大きな特徴です。
Lambdaを利用した画像の自動補正処理の構築方法を確認します。今回は手順を簡略化するために、公式で紹介されている構成から図2のようにS3バケットは1つのみ利用する構成に変更して紹介します。
また、今回紹介する手順はこのようになっています。
アップロードおよび補正後の画像を保存するS3バケットを作成します。S3のコンソールから「バケットの作成」を選択し、任意のバケット名とリージョンを選択してバケットを作成します。
バケットを作成したら、バケットの詳細画面から「フォルダの作成」をクリックして「input」と「output」の2つのフォルダを作成します。
Lambda関数を作成します。
通常なら図5のようにLambdaのコンソール画面上で直接コーディングできます。
しかし、今回のケースでは画像を補正するために画像処理のライブラリを利用するので、外部ライブラリとLambda関数のコードをパッケージしたZipファイルを作成し、そのZipファイルをアップロードする形で関数を作成する必要があります。このパッケージングは、ローカルマシンや「Amazon EC2」を使って作業することもできますが、今回は分かりやすくするためにブラウザ上のIDE(統合開発環境)「AWS Cloud9」を利用します。
Cloud9のコンソール画面に遷移し「Create Environment」をクリックします。
任意の名前を設定し、その他の設定は全てデフォルトのまま「Next step」をクリックして進んでいき、「Create environment」をクリックします。
数分待つと、Cloud9のセットアップが完了してIDEの画面が表示されます。今回は赤枠で示したターミナルの部分にコマンドを入力して操作していきます。
下記コマンドを実行してPythonのバージョンが「3」であることを確認します。
$ python --version Python 3.7.10
Lambda関数のコードと外部ライブラリを管理する仮想環境を構築して、環境内に移動します。Pythonの仮想環境を構築するツールはいろいろありますが、今回はCloud9に最初から用意されている「venv」を利用しています。
$ python3 -m venv v-venv $ source v-venv/bin/activate
仮想環境内に移動すると下記のようにカレントディレクトリの最初に仮想環境の名前(v-env)が表示されます。
Lambda関数として実行するソースコードを作成します。
$ nanoLambda_function.py
エディタが開いたら、下記Pythonコードを貼り付けて「Ctrl」+「S」キーで保存し「Ctrl」+「X」キーでファイルを閉じます。
import boto3 import os import sys import uuid from urllib.parse import unquote_plus from PIL import Image import PIL.Image # S3クライアントを取得 s3_client = boto3.client('s3') # 画像のサイズを半分に縮小してLambdaの実行環境に一時保存する関数 def resize_image(image_path, resized_path): with Image.open(image_path) as image: image.thumbnail(tuple(x / 2 for x in image.size)) image.save(resized_path) #Lambda関数の実行時に最初に呼び出されるハンドラ関数 defLambda_handler(event, context): # 引数からLambda関数呼び出し時のイベント情報を取得 for record in event['Records']: # S3のバケット名とオブジェクトのKey情報(フォルダ名/ファイル名)を取得 bucket = record['s3']['bucket']['name'] key = unquote_plus(record['s3']['object']['key']) # Key情報のフォルダ名とファイル名を分離 splitkey = key.split('/') # 補正後の画像をS3にアップロードするパス newkey = key.replace(splitkey[0],'output') # Key情報をLambdaの実行環境内で利用するために加工 tmpkey = key.replace('/', '') # S3からLambdaの実行環境に画像をダウンロードするパス download_path = '/tmp/{}{}'.format(uuid.uuid4(), tmpkey) # ダウンロードした画像を補正後に保存しておくパス upload_path = '/tmp/resized-{}'.format(tmpkey) # S3からファイルをダウンロード s3_client.download_file(bucket, key, download_path) # 関数を呼び出して画像サイズを縮小 resize_image(download_path, upload_path) # 縮小後の関数をS3にアップロード s3_client.upload_file(upload_path, bucket, newkey)
下記コマンドを実行して、コード内で利用しているライブラリを仮想環境内にインストールします。
$ pip install pillow $ pip install boto3
インストールされたライブラリが保存されている「site-packages」ディレクトリに移動し、フォルダ内の全てのファイルをZip化します。
$ cd $VIRTUAL_ENV/lib/python3.7/site-packages $ zip -r ~/resize-function.zip .
最後にホームディレクトリに移動し、とZip化したライブラリとPythonのコードを1つにまとめます。
$ cd ~ $ zip -g resize-function.zipLambda_function.py
コードとライブラリのパッケージが完了したらLambda関数の作成時に利用するので、下記コマンドを実行して手順1で作成したS3バケットにZipファイルをアップロードします(※Cloud9はAWSマネジメントコンソールにログイン中のユーザーと同じ権限で「AWS CLI」のコマンドを実行できます)。
$ aws s3 cp resize-function.zip s3://create-thumbnail-sample-12345
Lambda関数がS3バケットに読み書きするためのIAMロールを作成します。
IAMコンソールから「ポリシー」→「ポリシーの作成」と遷移し、JSONを使用して下記のポリシーを設定したら「次のステップ: タグ」に進みます。
{ "Version": "2012-10-17", "Statement": [ { "Sid": "VisualEditor0", "Effect": "Allow", "Action": [ "s3:PutObject", "s3:GetObject" ], "Resource": "arn:aws:s3:::*" } ] }
タグは特に設定せず「次のステップ:確認」に遷移したら「s3-read-and-write」といった任意のポリシー名を指定して「ポリシーの作成」をクリックします。
ポリシーの作成が完了したら、IAMコンソールから「ロール」→「ロールの作成」と遷移し、一般的なユースケースで「Lambda」を選択して「次のステップ:アクセス権限」をクリックします。
ロールにアタッチするポリシーは先ほど作成した「s3-read-and-write」を検索してチェックを付け、「次のステップ: タグ」に遷移します。
タグの追加は特にせず、「次のステップ: 確認」に進んで「lambda-s3-read-and-write-role」などロール名を指定して「ロールの作成」をクリックします。
これまでに作成したデプロイパッケージとIAMロールを利用してLambdaを作成します。
S3バケットを作成したのと同じリージョンかどうかを確認します。Lambdaコンソールから「関数の作成」をクリックし、以下の情報を選択します。
設定が完了したら「関数の作成」をクリックします。
Lambda関数の詳細ページに遷移したら、ソースコード欄の「アップロード元」→「Amazon S3 の場所」から作成したデプロイパッケージをアップロードします。
ポップアップが表示されたらS3バケットにアップロードしたZipファイルのオブジェクトURLを貼り付けて「保存」をクリックします。
S3バケットに画像ファイルが追加されたら自動でLambda関数が呼び出されるようにするためにイベントを追加します。
Lambda関数の画面上部にある「トリガーを追加」をクリックします。
トリガーを追加画面に遷移したら、このように情報を入力します。
このように指定することで、対象バケットの「input」ディレクトリ配下に.jpgファイルがアップロードされたときにLambda関数を呼び出すことができます。
※今回は「input」「output」で2つのディレクトリを用意していますが、ディレクトリを分けずにイベントを作成してしまうと、画像のアップロード⇒Lambda関数呼び出し⇒補正後の画像アップロード⇒Lambda関数の再呼び出し……といったように処理が無限ループしてしまい、高額な料金発生などにつながってしまうので注意してください。
作成したLambda関数が正しく動作するかどうかを確認します。
S3バケットの「input」ディレクトリ内に画像をアップロードします。
「output」ディレクトリ内を確認すると、画像ファイルをアップロードしてから約3秒後にファイルが追加されていることが分かります。画像のサイズは5分の1程度の大きさになっています。
2つのファイルをダウンロードして比べてみると、画像の大きさが半分になっていることを確認できます。
今回はLambdaを使ってS3にアップロードした画像ファイルを自動で補正する方法を紹介しました。
今回紹介した内容はLambda関数の基本的なユースケースの一つです。コンソール上でのコーディングだけではなく、パッケージファイルをアップロードしたLambda関数の作成はぜひ押さえておきたいポイントなので、動作を確認してみてください。
マルチクラウドへの閉域接続サービスのサービスマネジメント業務に従事した後、AWS案件での基盤構築支援などを担当。社内では、検証・学習用にAWSを完全定額で利用できるサービス「安心サンドボックス」の立ち上げや東京ITスクールのAWS研修におけるコンテンツ開発、Java・AWS研修の講師などを歴任。
Copyright © ITmedia, Inc. All Rights Reserved.