「AWS Lambda」の基礎中の基礎、「Amazon S3」にアップロードした画像の自動補正――Lambda関数を「AWS Cloud9」で実装するAWSチートシート

AWS活用における便利な小技を簡潔に紹介する連載「AWSチートシート」。今回は、「AWS Cloud9」で「AWS Lambda」のイベント駆動処理の基本を紹介する。

» 2021年12月16日 05時00分 公開
[天野盛介株式会社システムシェアード]

この記事は会員限定です。会員登録(無料)すると全てご覧いただけます。

 「Amazon Web Services」(AWS)活用における便利な小技を簡潔に紹介する連載「AWSチートシート」。今回は、AWSのサーバレスサービス「AWS Lambda」の基本的で、よく紹介される利用方法の一つ、「Amazon S3」にアップロードした画像を自動で補正する方法を紹介します。併せて、サーバを自分で構築、設定することなくコードを実行できるLambdaの特徴について解説します。

S3にアップロードした画像の自動補正

 画像の自動補正として公式でも紹介されているLambdaのユースケースが「サムネイルの自動生成」。「SNSやブログなどの見出しに利用する画像をサムネイルとして利用するために一律のサイズにそろえたいといったケース」です。

 図1の構成例では、「オリジナル画像用バケット」に画像がアップロードされると、それをトリガーにLambdaで画像を補正し、補正後の画像を「サムネイル画像用バケット」に保存するといった流れが紹介されています。

図1 サムネイル自動生成アーキテクチャの構成例(「イベント駆動処理にLambdaを用いたサーバレス構成と料金試算例」から引用)

 このケースにある「画像がS3バケットにアップロードされるとLambdaを実行する」のようにLambdaによる処理を開始させるトリガーのことを「イベント」と呼びます。

 イベントには「データベースの更新」「APIとしての呼び出し」などがあります。このイベントをきっかけに処理を実行する「イベントドリブンな処理の実行(イベント駆動処理)」はLambdaの大きな特徴です。

今回紹介する構成と作業手順

 Lambdaを利用した画像の自動補正処理の構築方法を確認します。今回は手順を簡略化するために、公式で紹介されている構成から図2のようにS3バケットは1つのみ利用する構成に変更して紹介します。

図2 今回の構成

 また、今回紹介する手順はこのようになっています。

  1. 「Amazon DynamoDB」テーブルの作成
  2. S3バケットを作成しCSVファイルをアップロード
  3. Lambda関数が利用する「AWS Identity and Access Management」(IAM)ロールの作成
  4. DynamoDBにデータを登録するLambda関数の作成
  5. 作成したLambda関数のテスト
  6. S3バケットでイベントトリガーを設定

【ステップ1】S3バケットの作成

 アップロードおよび補正後の画像を保存するS3バケットを作成します。S3のコンソールから「バケットの作成」を選択し、任意のバケット名とリージョンを選択してバケットを作成します。

図3 S3バケットの作成

 バケットを作成したら、バケットの詳細画面から「フォルダの作成」をクリックして「input」と「output」の2つのフォルダを作成します。

図4 フォルダ作成後のS3バケットの詳細画面

【ステップ2】AWS Cloud9を利用したLambdaパッケージの作成

 Lambda関数を作成します。

 通常なら図5のようにLambdaのコンソール画面上で直接コーディングできます。

図5 Lambda関数の作成画面

 しかし、今回のケースでは画像を補正するために画像処理のライブラリを利用するので、外部ライブラリとLambda関数のコードをパッケージしたZipファイルを作成し、そのZipファイルをアップロードする形で関数を作成する必要があります。このパッケージングは、ローカルマシンや「Amazon EC2」を使って作業することもできますが、今回は分かりやすくするためにブラウザ上のIDE(統合開発環境)「AWS Cloud9」を利用します。

 Cloud9のコンソール画面に遷移し「Create Environment」をクリックします。

図6 Cloud9のコンソール画面

 任意の名前を設定し、その他の設定は全てデフォルトのまま「Next step」をクリックして進んでいき、「Create environment」をクリックします。

 数分待つと、Cloud9のセットアップが完了してIDEの画面が表示されます。今回は赤枠で示したターミナルの部分にコマンドを入力して操作していきます。

図7 セットアップ完了後のCloud9の画面

 下記コマンドを実行して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

図8  S3バケットにZipファイルがアップロードされたことを確認

【ステップ3】Lambda関数が利用するIAMロールの作成

 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」といった任意のポリシー名を指定して「ポリシーの作成」をクリックします。

図9 IAMポリシーの確認画面

 ポリシーの作成が完了したら、IAMコンソールから「ロール」→「ロールの作成」と遷移し、一般的なユースケースで「Lambda」を選択して「次のステップ:アクセス権限」をクリックします。

図10 IAMロールのユースケース選択画面

 ロールにアタッチするポリシーは先ほど作成した「s3-read-and-write」を検索してチェックを付け、「次のステップ: タグ」に遷移します。

図11 IAMロールに適用するポリシーのアタッチ

 タグの追加は特にせず、「次のステップ: 確認」に進んで「lambda-s3-read-and-write-role」などロール名を指定して「ロールの作成」をクリックします。

図12 IAMロールの確認画面

【ステップ4】Lambda関数の作成

 これまでに作成したデプロイパッケージとIAMロールを利用してLambdaを作成します。

 S3バケットを作成したのと同じリージョンかどうかを確認します。Lambdaコンソールから「関数の作成」をクリックし、以下の情報を選択します。

  • 作成オプション
    • 一から作成
  • 基本的な情報
    • 関数名:createThumbnailFunction
    • ランタイム:Python3.7(パッケージ作成時に利用したバージョンを選択)
    • アクセス権限:
      • 「デフォルト実行ロールの変更」>「既存のロールを使用する」と選択
      • lambda-s3-read-and-write-role

 設定が完了したら「関数の作成」をクリックします。

 Lambda関数の詳細ページに遷移したら、ソースコード欄の「アップロード元」→「Amazon S3 の場所」から作成したデプロイパッケージをアップロードします。

図13 Lambda関数にソースコードをアップロード

 ポップアップが表示されたらS3バケットにアップロードしたZipファイルのオブジェクトURLを貼り付けて「保存」をクリックします。

図14 アップロードするZipファイルの指定

 S3バケットに画像ファイルが追加されたら自動でLambda関数が呼び出されるようにするためにイベントを追加します。

 Lambda関数の画面上部にある「トリガーを追加」をクリックします。

図15 Lambda関数を起動するトリガーを追加

 トリガーを追加画面に遷移したら、このように情報を入力します。

  • バケット:自分が作成したバケットを選択
  • イベントタイプ:すべてのオブジェクト作成イベント
  • プレフィックス:input/
  • サフィックス:.jpg
  • 再帰呼び出し:チェックを付ける

図16 Lambda関数のトリガーにS3を追加

 このように指定することで、対象バケットの「input」ディレクトリ配下に.jpgファイルがアップロードされたときにLambda関数を呼び出すことができます。

※今回は「input」「output」で2つのディレクトリを用意していますが、ディレクトリを分けずにイベントを作成してしまうと、画像のアップロード⇒Lambda関数呼び出し⇒補正後の画像アップロード⇒Lambda関数の再呼び出し……といったように処理が無限ループしてしまい、高額な料金発生などにつながってしまうので注意してください。

【ステップ5】Lambda関数の実行

 作成したLambda関数が正しく動作するかどうかを確認します。

 S3バケットの「input」ディレクトリ内に画像をアップロードします。

図17 inputディレクトリに画像ファイルをアップロード

 「output」ディレクトリ内を確認すると、画像ファイルをアップロードしてから約3秒後にファイルが追加されていることが分かります。画像のサイズは5分の1程度の大きさになっています。

図18 outputディレクトリ内にアップロードされた画像ファイル

 2つのファイルをダウンロードして比べてみると、画像の大きさが半分になっていることを確認できます。

図19 画像ファイルのプロパティを比較

終わりに

 今回はLambdaを使ってS3にアップロードした画像ファイルを自動で補正する方法を紹介しました。

 今回紹介した内容はLambda関数の基本的なユースケースの一つです。コンソール上でのコーディングだけではなく、パッケージファイルをアップロードしたLambda関数の作成はぜひ押さえておきたいポイントなので、動作を確認してみてください。

筆者紹介

天野盛介(あまのせいすけ)

株式会社システムシェアード

マルチクラウドへの閉域接続サービスのサービスマネジメント業務に従事した後、AWS案件での基盤構築支援などを担当。社内では、検証・学習用にAWSを完全定額で利用できるサービス「安心サンドボックス」の立ち上げや東京ITスクールのAWS研修におけるコンテンツ開発、Java・AWS研修の講師などを歴任。


Copyright © ITmedia, Inc. All Rights Reserved.

スポンサーからのお知らせPR

注目のテーマ

Microsoft & Windows最前線2025
AI for エンジニアリング
ローコード/ノーコード セントラル by @IT - ITエンジニアがビジネスの中心で活躍する組織へ
Cloud Native Central by @IT - スケーラブルな能力を組織に
システム開発ノウハウ 【発注ナビ】PR
あなたにおすすめの記事PR

RSSについて

アイティメディアIDについて

メールマガジン登録

@ITのメールマガジンは、 もちろん、すべて無料です。ぜひメールマガジンをご購読ください。