1. HOME
  2. ブログ
  3. AWS
  4. AWS Lambdaで画像ファイル加工

BLOG

ブログ

AWS

AWS Lambdaで画像ファイル加工

AWS Lambda関数を利用してAmazon S3バケットにアップロードされた画像ファイルのサムネイルを作成します。
本記事はAWSのチュートリアルとPythonのサンプルコードをベースに実践しております。
チュートリアル: Amazon S3 で AWS Lambda を使用する
サンプル Amazon S3 関数コード – Python3

動作概要

ざっくりとした流れですが、動作概要です。
①”S3バケットに画像ファイルをアップロード”をトリガーにLambda関数が起動。
②Lambda関数が画像ファイルを読取→サムネイル作成→ターゲットバケットにアップロード。

以下はLambda関数作成後の動作全体図です。

作成環境

今回はdocker-lambdaを利用するため、以下の環境となります。
・Windows 10 バージョン2004 ビルド19041(May 2020 Update)以降
・WSL2
 -ディストリビューションはUbuntu-20.04 LTSを使用
・Docker Desktop for Windows v20.10.3

バケットを作成し、サンプルオブジェクトをアップロードする

ソースバケットとオブジェクトを指定するサンプルイベントデータをLambda関数に渡すため、
サンプルオブジェクトを作成していきます。

1.Amazon S3コンソールを開きます。
2.バケットを2つ作成します。
  バケットは「ソースバケット」と「ターゲットバケット」の2つが必要になります。
  各バケット名を下記の通りに設定してます。
  ーソースバケット:lambda-mybucket001
  ーターゲットバケット:lambda-mybucket001-resized
3.ソースバケットに.jpegオブジェクト”Kanazawa_Crab.jpeg”をアップロードします。

IAMポリシーを作成する

Lambda関数のアクセス権限を定義するIAMポリシーを作成します。
・S3ソースバケットからオブジェクトを取得する。
・サイズ変更されたオブジェクトをS3ターゲットバケットに入れる。
・CloudWatchログに関連するアクセス許可

1.IAMコンソールを開きます。
2.[ポリシーの作成]を選択します。
3.[JSON]タブで、下記のポリシーをコピーします。
ソースバケット名とターゲットバケット名が先ほど作成した名前と一致するよう編集してください。

{
    "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:::lambda-mybucket001/*"
        },
        {
            "Effect": "Allow",
            "Action": [
                "s3:PutObject"
            ],
            "Resource": "arn:aws:s3:::lambda-mybucket001-resized/*"
        }
    ]
}         
        


4.ポリシーの確認にて、名前を入力後に[ポリシーの作成]を選択します。
今回はIAMポリシー名を”AWSLambdaPolicy”としています。

実行ロールを作成する

1.IAMコンソールのロールを開きます。
2.[ロールの作成]を選択します。
3.次のプロパティでロールを作成します。
・[信頼されたエンティティの種類を選択]で[Lambda]を選択します。
・[Attach アクセス権限ポリシー]で[AWSLambdaPolicy]を選択します。
・[ロール名]を入力後に[ロールの作成]を選択します。
今回、IAMロール名を”lambda-s3-role”としています。

関数を作成する

現在のディレクトリを確認します。

$ pwd
/home/crs/lambda-s3-test


“requirements.txt”に依存するインポート群を記載します。

$ sudo vi requirements.txt
pillow
boto3


“lambda_function.py”にPythonコードを記載します。

$ vi lambda_function.py
import boto3
import os
import sys
import uuid
from urllib.parse import unquote_plus
from PIL import Image
import PIL.Image

s3_client = boto3.client('s3')

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)

def lambda_handler(event, context):
    for record in event['Records']:
        bucket = record['s3']['bucket']['name']
        key = unquote_plus(record['s3']['object']['key'])
        tmpkey = key.replace('/', '')
        download_path = '/tmp/{}{}'.format(uuid.uuid4(), tmpkey)
        upload_path = '/tmp/resized-{}'.format(tmpkey)
        s3_client.download_file(bucket, key, download_path)
        resize_image(download_path, upload_path)
        s3_client.upload_file(upload_path, '{}-resized'.format(bucket), key)


“Dockerfile”にDockerイメージに対する実行内容を記載します。

$ sudo vi Dockerfile
FROM lambci/lambda:build-python3.8
ENV AWS_DEFAULT_REGION ap-northeast-1

ADD . .

CMD pip3 install -r requirements.txt -t /var/task && \
  zip -9 lambda_function.zip lambda_function.py && \
  zip -r9 lambda_function.zip *


Dockerイメージを作成します。

$ docker build -t lambda-s3-test .


作成したDockerイメージを確認します。

$ docker images
REPOSITORY                                     TAG            IMAGE ID       CREATED        SIZE
lambda-s3-test                                 latest         df3174ddf05d   1 minutes ago  1.96GB
lambci/lambda                                  python3.8      094248252696   4 weeks ago    524MB


デプロイパッケージを作成します。

$ docker run -v "$PWD":/var/task lambda-s3-test


作成後はこんな感じになります。
“lambda_function.zip”が作成されました。

$ ls -a
.           Pillow-8.1.1.dist-info  bin                      botocore-1.20.18.dist-info       lambda_function.py               s3transfer                  urllib3
..          Pillow.libs             boto3                    dateutil                         lambda_function.zip              s3transfer-0.3.4.dist-info  urllib3-1.26.3.dist-info
Dockerfile  boto3-1.17.18.dist-info jmespath                 python_dateutil-2.8.1.dist-info  six-1.15.0.dist-info
PIL         __pycache__             botocore                 jmespath-0.10.0.dist-info        requirements.txt                 six.py

AWS Lambda関数を作成する

デプロイパッケージファイルをLambda関数にアップロードします。

$ aws lambda create-function --function-name lambda-s3-test --profile [ユーザ名] \
--cli-binary-format raw-in-base64-out \
--zip-file  fileb://lambda_function.zip --handler lambda_function.lambda_handler \
 --runtime python3.8 --timeout 30 --memory-size 1024 \
 --role arn:aws:iam::[アカウントID]:role/lambda-s3-role


以下のようなメッセージが表示されていることを確認します。

{
    "FunctionName": "lambda-s3-test",
    "FunctionArn": "arn:aws:lambda:ap-northeast-1:[アカウントID]:function:lambda-s3-test",
    "Runtime": "python3.8",
    "Role": "arn:aws:iam::[アカウントID]:role/lambda-s3-role",
    "Handler": "lambda_function.lambda_handler",
    "CodeSize": 11283277,
    "Description": "",
    "Timeout": 30,
    "MemorySize": 1024,
    "LastModified": "2021-03-02T07:45:47.494+0000",
    "CodeSha256": "UF51ZaI77xckPPE8bpjx9MCVfNbxWNImHXFcAuSJCtk=",
    "Version": "$LATEST",
    "TracingConfig": {
        "Mode": "PassThrough"
    },
    "RevisionId": "0fa5ec24-5f88-4363-9ef5-b36d75619537",
    "State": "Active",
    "LastUpdateStatus": "Successful",
    "PackageType": "Zip"
}

Lambda関数をテストする

Amazon S3 サンプルイベントデータを元に”inputFile.txt”を作成します。
作成時は”lambda-test-mybucket001″と”Kanazawa_Crab.jpeg”を書き換えてください。

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


invokeコマンドで関数のテストを実行します。

$ aws lambda invoke --function-name lambda-s3-test --invocation-type Event --profile [ユーザ名] \
--payload file://inputFile.txt outputfile.txt \
--cli-binary-format raw-in-base64-out 


実行後に以下の表示がされていることを確認します。

{
    "StatusCode": 202
}


AWS CLIでS3のターゲットバケットにサムネイルが作成されたことを確認します。

$ aws s3 ls s3://lambda-test-mybucket001-resized --profile [ユーザ名]
2021-03-02 16:54:24      64212 Kanazawa_Crab.jpeg

Lambda関数のトリガーを設定する

S3がオブジェクト作成イベントをAWS Lambdaに発行し、Lambda関数を呼び出せるようにします。

$ aws lambda add-permission --function-name lambda-s3-test --principal s3.amazonaws.com --profile [ユーザ名] \
--statement-id s3invoke --action "lambda:InvokeFunction" \
--source-arn arn:aws:s3:::lambda-test-mybucket001 \
--source-account [アカウントID]


以下のような表示がされていることを確認します。

{
    "Policy": "{\"Version\":\"2012-10-17\",\"Id\":\"default\",\"Statement\":[{\"Sid\":\"s3invoke\",\"Effect\":\"Allow\",\"Principal\":{\"Service\":\"s3.amazonaws.com\"},\"Action\":\"lambda:InvokeFunction\",\"Resource\":\"arn:aws:lambda:ap-northeast-1:[アカウントID]:function:lambda-s3-test\",\"Condition\":{\"StringEquals\":{\"AWS:SourceAccount\":\"[アカウントID]\"},\"ArnLike\":{\"AWS:SourceArn\":\"arn:aws:s3:::lambda-test-mybucket001\"}}}]}",
    "RevisionId": "8b70bfd7-6646-487b-81ce-ed964369d6b8"
}

セットアップをテストする

S3コンソールを使って、.jpegオブジェクトをソースバケットにアップロードします。

Lambda関数を使用してサムネイルがターゲットバケットに作成されたことを確認します。

CloudWatch コンソールでログを表示します。

以上でAWS Lambdaを利用した画像ファイルの加工が完了しました!

関連記事