サーバーレスファイル処理アプリケーションを作成する - AWS Lambda

サーバーレスファイル処理アプリケーションを作成する

Lambda の最も一般的なユースケースの 1 つは、ファイル処理タスクを実行することです。例えば、Lambda 関数を使用して、HTML ファイルまたは画像から PDF ファイルを自動的に作成したり、ユーザーが画像をアップロードしたときにサムネイルを作成したりできます。

この例では、PDF ファイルが Amazon Simple Storage Service (Amazon S3) バケットにアップロードされると自動的に暗号化されるアプリケーションを作成します。このアプリを実装するには、以下のリソースを作成する必要があります。

  • ユーザーが PDF ファイルをアップロードするための S3 バケット

  • アップロードされたファイルを読み取り、暗号化されたパスワードで保護されたバージョンのファイルを作成する Python の Lambda 関数

  • Lambda が暗号化されたファイルに保存するための 2 番目の S3 バケット

また、AWS Identity and Access Management (IAM) ポリシーを作成して、S3 バケットで読み取りおよび書き込みオペレーションを実行するアクセス許可を Lambda 関数に付与します。

S3 バケット、Lambda 関数、および別の S3 バケット間のデータフローを示す図
ヒント

Lambda を初めて使用する場合は、このサンプルアプリを作成する前にチュートリアル 最初の Lambda 関数を作成する から始めることをお勧めします。

AWS Management Console または AWS Command Line Interface (AWS CLI) を使用してリソースを作成して設定することで、アプリケーションを手動でデプロイできます。AWS Serverless Application Model (AWS SAM) を使用してアプリケーションをデプロイすることもできます。AWS SAM は、Infrastructure as Code (IaC) ツールです。IaC では、リソースを手動で作成するのではなく、コードに定義して自動的にデプロイします。

このサンプルアプリケーションをデプロイする前に、IaC で Lambda を使用する方法の詳細については、「Lambda と Infrastructure as code (IaC) の使用」を参照してください。

Lambda 関数のソースコードファイルを作成する

プロジェクトディレクトリに次のファイルを作成します。

  • lambda_function.py - ファイル暗号化を実行する Lambda 関数の Python 関数コード

  • requirements.txt - Python 関数コードに必要な依存関係を定義するマニフェストファイル

以下のセクションを展開してコードを表示し、各ファイルの役割の詳細を確認してください。ローカルマシンにファイルを作成するには、以下のコードをコピーして貼り付けるか、aws-lambda-developer-guide GitHub レポジトリからファイルをダウンロードします。

次のコードをコピーし、lambda_function.py という名前のファイルに貼り付けます。

from pypdf import PdfReader, PdfWriter import uuid import os from urllib.parse import unquote_plus import boto3 # Create the S3 client to download and upload objects from S3 s3_client = boto3.client('s3') def lambda_handler(event, context): # Iterate over the S3 event object and get the key for all uploaded files for record in event['Records']: bucket = record['s3']['bucket']['name'] key = unquote_plus(record['s3']['object']['key']) # Decode the S3 object key to remove any URL-encoded characters download_path = f'/tmp/{uuid.uuid4()}.pdf' # Create a path in the Lambda tmp directory to save the file to upload_path = f'/tmp/converted-{uuid.uuid4()}.pdf' # Create another path to save the encrypted file to # If the file is a PDF, encrypt it and upload it to the destination S3 bucket if key.lower().endswith('.pdf'): s3_client.download_file(bucket, key, download_path) encrypt_pdf(download_path, upload_path) encrypted_key = add_encrypted_suffix(key) s3_client.upload_file(upload_path, f'{bucket}-encrypted', encrypted_key) # Define the function to encrypt the PDF file with a password def encrypt_pdf(file_path, encrypted_file_path): reader = PdfReader(file_path) writer = PdfWriter() for page in reader.pages: writer.add_page(page) # Add a password to the new PDF writer.encrypt("my-secret-password") # Save the new PDF to a file with open(encrypted_file_path, "wb") as file: writer.write(file) # Define a function to add a suffix to the original filename after encryption def add_encrypted_suffix(original_key): filename, extension = original_key.rsplit('.', 1) return f'{filename}_encrypted.{extension}'
注記

このサンプルコードでは、暗号化されたファイル (my-secret-password) のパスワードが関数コードにハードコードされます。本番環境のアプリケーションでは、関数コードにパスワードなどの機密情報を含めないでください。AWS Secrets Manager を使用して、機密性の高いパラメータを安全に保存します。

Python 関数コードには 3 つの関数が含まれています。1 つは関数が呼び出されたときに Lambda が実行するハンドラー関数、他の 2 つは PDF 暗号化を実行するためにハンドラーが 呼び出す add_encrypted_suffixencrypt_pdf という名前の別個の関数です。

関数が Amazon S3 によって呼び出されると、Lambda は呼び出しの原因となったイベントの詳細を含む JSON 形式のイベント引数を関数に渡します。この場合、情報には S3 バケットの名前と、アップロードされたファイルのオブジェクトキーが含まれます。Amazon S3 のイベントオブジェクトの形式の詳細については、「Lambda を使用した Amazon S3 イベント通知の処理」を参照してください。

次に、関数は AWS SDK for Python (Boto3) を使用して、イベントオブジェクトで指定された PDF ファイルをローカル一時ストレージディレクトリにダウンロードしてから、pypdf ライブラリを使用して暗号化します。

最後に、この関数は Boto3 SDK を使用して暗号化されたファイルを S3 送信先バケットに保存します。

次のコードをコピーし、requirements.txt という名前のファイルに貼り付けます。

boto3 pypdf

この例では、関数コードには、標準の Python ライブラリに含まれていない依存関係が 2 つしかありません。SDK for Python (Boto3) と、関数が PDF 暗号化の実行に使用する pypdf パッケージです。

注記

SDK for Python (Boto3) のバージョンは Lambda ランタイムの一部として含まれているため、Boto3 を関数のデプロイパッケージに追加せずにコードが実行されます。ただし、関数の依存関係を完全に制御し、バージョン不一致による問題を回避するには、Python のベストプラクティスとして、関数のデプロイパッケージにすべての関数の依存関係を含めることをお勧めします。詳細については、「Python でのランタイム依存関係」を参照してください。

アプリをデプロイする

このサンプルアプリケーションのリソースは、手動または AWS SAM を使用して作成およびデプロイできます。実稼働環境では、AWS SAM のような IaC ツールを使用して、手動プロセスを使用せずにサーバーレスアプリケーション全体を迅速かつ繰り返しデプロイすることをお勧めします。

アプリを手動でデプロイするには:

  • ソースと送信先の Amazon S3 バケットを作成する

  • PDF ファイルを暗号化し、暗号化されたバージョンを S3 バケットに保存する Lambda 関数を作成する

  • オブジェクトがソースバケットにアップロードされたときに、関数を呼び出す Lambda トリガーを設定します。

開始する前に、ビルドマシンに Python がインストールされていることを確認してください。

2 つの S3 バケットを作成する

まず、2 つの S3 バケットを作成します。1 つ目のバケットは、PDF ファイルをアップロードするソース バケットです。2 つ目のバケットは、関数を呼び出すときに暗号化されたファイルを保存するために Lambda が使用するバケットです。

Console
S3 バケットを作成するには (コンソール)
  1. Amazon S3 コンソールの [汎用バケット] ページを開きます。

  2. 住まいの地域に最も近い AWS リージョン を選択してください。画面上部にあるドロップダウンリストを使用して、リージョンを変更できます。

    S3 コンソールのドロップダウンリージョンメニューを示す画像
  3. [バケットを作成する] を選択します。

  4. [全般設定] で、次の操作を行います。

    1. [バケットタイプ] で、[汎用] が選択されていることを確認してください。

    2. [バケット名] には、Amazon S3 バケットの命名規則を満たすグローバルに一意な名前を入力します。バケット名は、小文字、数字、ドット (.)、およびハイフン (-) のみで構成できます。

  5. 他のすべてのオプションはデフォルト設定値のままにしておき、[バケットの作成] を選択します。

  6. ステップ 1 ~ 4 を繰り返して、送信先のバケットを作成します。[バケット名] には amzn-s3-demo-bucket-encrypted と入力します。amzn-s3-demo-bucket は先ほど作成したソース元バケットの名前です。

AWS CLI

開始する前に、ビルドマシンに AWS CLI がインストールされていることを確認してください。

Amazon S3 バケットを作成する方法 (AWS CLI)
  1. 次の CLI コマンドを実行して、ソース元のバケットを作成します。バケットに付ける名前は、グローバルに一意で、Amazon S3 バケットの命名規則に従ったものである必要があります。名前には、小文字、数字、ドット (.)、およびハイフン (-) のみを使用できます。region および LocationConstraint については、お住まいの地域に最も近い AWS リージョン を選択してください。

    aws s3api create-bucket --bucket amzn-s3-demo-bucket --region us-east-2 \ --create-bucket-configuration LocationConstraint=us-east-2

    チュートリアルの後半では、ソース元バケットと同じ AWS リージョン で Lambda 関数を作成する必要があるため、選択したリージョンを書き留めておいてください。

  2. 次のコマンドを実行して、送信先のバケットを作成します。バケット名には amzn-s3-demo-bucket-encrypted を使用する必要があります。amzn-s3-demo-bucket はステップ 1 で作成したソース元バケットの名前です。region および LocationConstraint については、ソース元バケットを作成するときに使用したものと同じ AWS リージョン を選択してください。

    aws s3api create-bucket --bucket amzn-s3-demo-bucket-encrypted --region us-east-2 \ --create-bucket-configuration LocationConstraint=us-east-2

実行ロールを作成する

実行ロールとは、AWS のサービス とリソースにアクセスする許可を Lambda 関数に付与する IAM ロールです。関数に Amazon S3 への読み取りおよび書き込みアクセスを許可するには、 AWS管理ポリシー AmazonS3FullAccess をアタッチします。

Console
実行ロールを作成して AmazonS3FullAccess 管理ポリシーをアタッチするには (コンソール)
  1. IAM コンソールの [Roles (ロール)] ページを開きます。

  2. [ロールの作成] を選択します。

  3. [信頼されたエンティティタイプ][AWS サービス] を選択し、[ユースケース][Lambda] を選択します。

  4. [Next] を選択します。

  5. 次の手順を実行して AmazonS3FullAccess 管理ポリシーを追加します。

    1. [許可ポリシー] で、検索ボックスに AmazonS3FullAccess と入力します。

    2. ポリシーの横にあるチェックボックスを選択します。

    3. [Next] を選択します。

  6. [ロールの詳細] の [ロール名] には LambdaS3Role を入力します。

  7. [ロールの作成] を選択します。

AWS CLI
実行ロールを作成して AmazonS3FullAccess 管理ポリシー (AWS CLI) をアタッチするには
  1. 次の JSON を trust-policy.json という名のファイルに保存します。この信頼ポリシーは、AWS Security Token Service (AWS STS) AssumeRole アクションを呼び出すサービスプリンシパルの lambda.amazonaws.com アクセス許可を付与することで、Lambda がロールのアクセス許可を使用できるようにします。

    { "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Principal": { "Service": "lambda.amazonaws.com" }, "Action": "sts:AssumeRole" } ] }
  2. JSON 信頼ポリシードキュメントを保存したディレクトリから、次の CLI コマンドを実行して実行ロールを作成します。

    aws iam create-role --role-name LambdaS3Role --assume-role-policy-document file://trust-policy.json
  3. AmazonS3FullAccess 管理ポリシーをアタッチするには、次の CLI コマンドを実行します。

    aws iam attach-role-policy --role-name LambdaS3Role --policy-arn arn:aws:iam::aws:policy/AmazonS3FullAccess

関数デプロイパッケージを作成する

関数を作成するには、関数コードとその依存関係を含むデプロイパッケージを作成します。このアプリケーションでは、関数コードは PDF 暗号化に別のライブラリを使用します。

デプロイパッケージを作成するには
  1. 以前に GitHub から作成またはダウンロードした lambda_function.py および requirements.txt ファイルを含むプロジェクトディレクトリに移動し、package という名前の新しいディレクトリを作成します。

  2. 次のコマンドを実行して、 package ディレクトリの requirements.txt ファイルで指定された依存関係をインストールします。

    pip install -r requirements.txt --target ./package/
  3. アプリケーション コードとその依存関係を含む .zip ファイルを作成します。Linux または MacOS では、コマンドラインインターフェイスから次のコマンドを実行します。

    cd package zip -r ../lambda_function.zip . cd .. zip lambda_function.zip lambda_function.py

    Windows では、任意の zip ツールを使用して、lambda_function.zip ファイルを作成します。lambda_function.py ファイルと依存関係が含まれるフォルダは、.zip ファイルのルートにインストールする必要があります。

また、Python 仮想環境を使用してデプロイパッケージを作成することもできます。「Python Lambda 関数で .zip ファイルアーカイブを使用する」を参照してください。

Lambda 関数を作成する

これで、前のステップで作成したデプロイパッケージを使用して Lambda 関数をデプロイします。

Console
関数を作成するには (コンソール)

コンソールを使用して Lambda 関数を作成するには、まず「Hello world」コードが含まれるベーシックな関数を作成します。次に、前のステップで作成した .zip ファイルをアップロードして、、このコードを自身で作成した関数コードへと置き換えます。

サイズの大きい PDF ファイルを暗号化するときに関数がタイムアウトしないようにするには、関数のメモリとタイムアウトの設定が必要です。また、関数のログ形式を JSON に設定します。提供されたテストスクリプトを使用するときは、CloudWatch Logs から関数の呼び出しステータスを読み取って呼び出しが成功したことを確認するために、JSON 形式のログを設定する必要があります。

  1. Lambda コンソールの [関数ページ] を開きます。

  2. S3 バケットを作成したときと同じ AWS リージョン で操作していることを確認してください。画面上部にあるドロップダウンリストを使用して、リージョンを変更できます。

    Lambda コンソールのドロップダウンリージョンメニューを示す画像
  3. [関数の作成] を選択します。

  4. Author from scratch を選択します。

  5. 基本的な情報 で、以下の作業を行います。

    1. [関数名] に「EncryptPDF」と入力します。

    2. ランタイム には、[Python 3.12] を選択します。

    3. [アーキテクチャ] で [x86_64] を選択します。

  6. 次の手順を実行して、前のステップで作成した実行ロールをアタッチします。

    1. [デフォルト実行ロールの変更] セクションを展開します。

    2. [既存のロールを使用] を選択します。

    3. [既存のロール] で、ロール (LambdaS3Role) を選択します。

  7. [Create function (関数の作成)] を選択します。

関数コードをアップロードする方法 (コンソール)
  1. [コードソース] ペインで、[アップロード元] をクリックします。

  2. [.zip ファイル] をクリックします。

  3. [アップロード] を選択します。

  4. ファイルセレクターで .zip ファイルを選択し、[開く] を選択します。

  5. [Save] を選択します。

関数のメモリとタイムアウトを設定するには (コンソール)
  1. 関数の [設定] タブを選択します。

  2. [一般設定] ペインで、[編集] を選択します。

  3. [メモリ] を 256 MB に設定し、[タイムアウト]を 15 秒に設定します。

  4. [Save] を選択します。

ログ形式を設定するには (コンソール)
  1. 関数の [設定] タブを選択します。

  2. [モニタリングおよび運用ツール] を選択します。

  3. [ログ記録設定] ペインで、[編集] を選択します。

  4. [ログ記録設定] で、[JSON]を選択します。

  5. [Save] を選択します。

AWS CLI
関数を作成する方法 (AWS CLI)
  • lambda_function.zip ファイルを含むディレクトリから次のコマンドを実行します。region パラメータの場合は、us-east-2 を S3 バケットを作成したリージョンに置き換えます。

    aws lambda create-function --function-name EncryptPDF \ --zip-file fileb://lambda_function.zip --handler lambda_function.lambda_handler \ --runtime python3.12 --timeout 15 --memory-size 256 \ --role arn:aws:iam::123456789012:role/LambdaS3Role --region us-east-2 \ --logging-config LogFormat=JSON

関数を呼び出すように Amazon S3 トリガーを設定する

ファイルをソース元のバケットにアップロードするときに Lambda 関数が実行されるようにするには、関数のトリガーを設定する必要があります。Amazon S3 トリガーは、コンソールまたは AWS CLI を使用して設定できます。

重要

この手順では、オブジェクトが S3 バケット内に作成されるたびに、関数を呼び出すようにバケットを設定します。この設定は、ソース元バケットのみで行うようにしてください。Lambda 関数が自身を呼び出した同じバケットにオブジェクトを作成する場合、関数が連続的にループして呼び出される可能性があります。その結果、予期しない請求がお客様の AWS アカウント に請求される可能性があります。

Console
Amazon S3 トリガーを設定する方法 (コンソール)
  1. Lambda コンソールの [関数] ページを開き、関数を選択します (EncryptPDF)。

  2. [Add trigger] を選択します。

  3. [S3] を選択します。

  4. [バケット] で、ソース元のバケットを選択します。

  5. [イベントタイプ] で、[すべてのオブジェクト作成イベント] を選択します。

  6. [再帰呼び出し] でチェックボックスをオンにすると、入力と出力に同じ S3 バケットを使用することは推奨されないことを認識できます。Lambda の再帰呼び出しパターンについて詳しくは、Serverless Land の「Lambda 関数が暴走する原因となる再帰パターン」を参照してください。

  7. [追加] を選択します。

    Lambda コンソールを使用してトリガーを作成すると、Lambda はリソースベースのポリシーを自動的に作成し、選択したサービスに関数を呼び出すアクセス許可を付与します。

AWS CLI
Amazon S3 トリガーを設定する方法 (AWS CLI)
  1. ファイルを追加するときに Amazon S3 のソースバケットが関数を呼び出すことを許可する [リソースベースのポリシー] を関数に追加します。リソースベースのポリシーステートメントが、他の AWS のサービス に関数を呼び出す権限を付与します。Amazon S3 に関数を呼び出す権限を付与するには、次の CLI コマンドを実行します。source-account パラメータは必ず自分自身の AWS アカウント ID に置き換えて、自分自身のソース元バケット名を使用するようにしてください。

    aws lambda add-permission --function-name EncryptPDF \ --principal s3.amazonaws.com --statement-id s3invoke --action "lambda:InvokeFunction" \ --source-arn arn:aws:s3:::amzn-s3-demo-bucket \ --source-account 123456789012

    このコマンドで定義するポリシーにより、Amazon S3 はソース元バケットでアクションが発生した場合にのみ、関数を呼び出すことができるようになります。

    注記

    S3 バケットの名前はグローバルに一意ですが、リソースベースのポリシーを使用する場合には、バケットがアカウントに属していなければならないことを指定するのがベストプラクティスです。これは、バケットを削除したときに、別の AWS アカウント が同じ Amazon リソースネーム (ARN) でバケットを作成する可能性があるからです。

  2. 次の JSON を notification.json という名のファイルに保存します。この JSON をソースバケットに適用すると、新しいオブジェクトが追加されるたびに Lambda 関数に通知を送信するようにバケットが設定されます。Lambda 関数 ARN の AWS アカウント 番号と AWS リージョン を、自分自身のアカウント番号とリージョンへと置き換えます。

    { "LambdaFunctionConfigurations": [ { "Id": "EncryptPDFEventConfiguration", "LambdaFunctionArn": "arn:aws:lambda:us-east-2:123456789012:function:EncryptPDF", "Events": [ "s3:ObjectCreated:Put" ] } ] }
  3. 次の CLI コマンドを実行して、JSON ファイル内に作成した通知設定をソース元のバケットに適用します。amzn-s3-demo-bucket を自分自身のソース元バケットの名前へと置き換えます。

    aws s3api put-bucket-notification-configuration --bucket amzn-s3-demo-bucket \ --notification-configuration file://notification.json

    put-bucket-notification-configuration コマンドと notification-configuration オプションの詳細については、「AWS CLI コマンドリファレンス」の「put-bucket-notification-configuration」を参照してください。

開始する前に、DockerAWS SAMCLI の最新バージョンがビルドマシンにインストールされていることを確認してください。

  1. プロジェクトディレクトリで、次のコードをコピーして template.yaml という名前のファイルに貼り付けます。プレースホルダーバケット名を置き換えます。

    • ソースバケットの場合は、amzn-s3-demo-bucketS3 バケットの命名規則に準拠した任意の名前に置き換えます。

    • レプリケート先バケットの場合は、amzn-s3-demo-bucket-encrypted<source-bucket-name>-encrypted に置き換えます。ここで、 <source-bucket> はレプリケート元バケットに選択した名前です。

    AWSTemplateFormatVersion: '2010-09-09' Transform: AWS::Serverless-2016-10-31 Resources: EncryptPDFFunction: Type: AWS::Serverless::Function Properties: FunctionName: EncryptPDF Architectures: [x86_64] CodeUri: ./ Handler: lambda_function.lambda_handler Runtime: python3.12 Timeout: 15 MemorySize: 256 LoggingConfig: LogFormat: JSON Policies: - AmazonS3FullAccess Events: S3Event: Type: S3 Properties: Bucket: !Ref PDFSourceBucket Events: s3:ObjectCreated:* PDFSourceBucket: Type: AWS::S3::Bucket Properties: BucketName: amzn-s3-demo-bucket EncryptedPDFBucket: Type: AWS::S3::Bucket Properties: BucketName: amzn-s3-demo-bucket-encrypted

    AWS SAM テンプレートは、アプリケーション用に作成するリソースを定義します。この例では、テンプレートは AWS::Serverless::Function タイプを使用して Lambda 関数を定義し、AWS::S3::Bucket タイプを使用して 2 つの S3 バケットを定義します。テンプレートで指定されたバケット名はプレースホルダーです。AWS SAM を使用してアプリケーションをデプロイする前に、テンプレートを編集して、S3 バケットの命名規則を満たすグローバルに一意の名前でバケットの名前を変更する必要があります。このステップについては、「AWS SAM を使用してリソースをデプロイする」で詳しく説明します。

    Lambda 関数リソースの定義は、S3Event イベントプロパティを使用して関数のトリガーを設定します。このトリガーにより、ソースバケットにオブジェクトが作成されるたびに関数が呼び出されます。

    関数定義は、関数の実行ロールにアタッチする AWS Identity and Access Management (IAM) ポリシーも指定します。AWS 管理ポリシーAmazonS3FullAccessは、Amazon S3 へのオブジェクトの読み取りと書き込みに必要なアクセス許可を関数に付与します。

  2. lambda_function.pyrequirements.txt、および template.yaml ファイルを保存したディレクトリで、次のコマンドを実行します。

    sam build --use-container

    このコマンドによって、アプリケーションのビルドアーティファクトが収集され、それらをデプロイする場所を適切な形式で配置します。--use-container オプションを指定すると、Lambda のような Docker コンテナ内に関数がビルドされます。ここではこれを使用するため、ビルドを実行するためにローカルマシンに Python 3.12 をインストールする必要はありません。

    ビルドプロセス中に、AWS SAM はテンプレートの CodeUri プロパティで指定した場所で Lambda 関数コードを検索します。この場合、現在のディレクトリをロケーション (./) として指定しました。

    requirements.txt ファイルが存在する場合、AWS SAM はそれを使用して指定された依存関係を収集します。デフォルトでは、AWS SAM は関数コードと依存関係を含む .zip デプロイパッケージを作成します。PackageType プロパティを使用して、関数をコンテナイメージとしてデプロイすることもできます。

  3. アプリケーションをデプロイし、AWS SAM テンプレートで指定された Lambda リソースと Amazon S3 リソースを作成するには、次のコマンドを実行します。

    sam deploy --guided

    --guided フラグを使用すると、AWS SAM にデプロイプロセスの手順が示されます。このデプロイでは、Enter キーを押してデフォルトのオプションをそのまま使用してください。

デプロイプロセス中に、AWS SAM でお使いの AWS アカウントに次のリソースが作成されます。

  • sam-app という名前の AWS CloudFormation スタック

  • EncryptPDF という名前の Lambda 関数

  • template.yaml AWS SAM テンプレートファイルを編集したときに選択した名前の 2 つの S3 バケット

  • 名前形式 sam-app-EncryptPDFFunctionRole-2qGaapHFWOQ8 の関数の IAM 実行ロール

AWS SAM がリソースの作成を完了すると、次のメッセージが表示されます。

Successfully created/updated stack - sam-app in us-east-2

アプリケーションをテストする

アプリをテストするには、PDF ファイルをソースバケットにアップロードし、Lambda が送信先バケットに暗号化されたバージョンのファイルを作成することを確認します。この例では、コンソールまたは AWS CLI を使用して手動でテストするか、提供されたテストスクリプトを使用してテストできます。

本番環境のアプリケーションでは、ユニットテストなどの従来のテスト方法や手法を使用して、Lambda 関数コードが正しく機能していることを確認できます。ベストプラクティスは、実際のクラウドベースのリソースとの統合テストを実行する、提供されているテストスクリプトのようなテストを実行することです。クラウド環境における統合テストでは、インフラストラクチャが適切にデプロイされ、イベントが期待どおりに異なるサービス間で流れることを確認します。詳細については、「サーバーレス関数とアプリケーションをテストする方法」を参照してください。

Amazon S3 ソースバケットに PDF ファイルを追加することで、関数を手動でテストできます。ファイルをソースバケットに追加すると、Lambda 関数が自動的に呼び出され、ファイルの暗号化されたバージョンが送信先のバケットに保存されます。

Console
ファイルをアップロードしてアプリケーションをテストするには (コンソール)
  1. PDF ファイルを S3 バケットにアップロードするには、次の手順を実行します。

    1. Amazon S3 コンソールの[バケット] ページを開き、ソース元のバケットを選択します。

    2. [アップロード] を選択します。

    3. [ファイルを追加] を選択し、ファイルセレクターを使用してアップロードする PDF ファイルを選択します。

    4. [開く][アップロード] の順に選択します。

  2. 次の手順を実行して、Lambda が PDF ファイルの暗号化されたバージョンを送信先のバケットに保存したことを確認します。

    1. Amazon S3 コンソールの [バケット] ページに戻り、送信先バケットを選択します。

    2. [オブジェクト] ペインに、名前形式 filename_encrypted.pdf (filename.pdf はソースバケットにアップロードしたファイルの名前) のファイルが表示されます。暗号化された PDF をダウンロードするには、ファイルを選択し、[ダウンロード] を選択します。

    3. ダウンロードしたファイルを、Lambda 関数で保護されたパスワード (my-secret-password) で開くことができることを確認します。

AWS CLI
ファイルをアップロードしてアプリケーションをテストするには (AWS CLI)
  1. アップロードする PDF ファイルが含まれるディレクトリから、次の CLI コマンドを実行します。--bucket パラメータをソース元バケットの名前に置き換えます。--key および --body パラメータには、テスト ファイルのファイル名を使用します。

    aws s3api put-object --bucket amzn-s3-demo-bucket --key test.pdf --body ./test.pdf
  2. 関数によってファイルの暗号化されたバージョンが作成され、それが送信先の S3 バケットに保存されたことを確認します。amzn-s3-demo-bucket-encrypted を自分自身の送信先のバケットの名前へと置き換えて、次の CLI コマンドを実行します。

    aws s3api list-objects-v2 --bucket amzn-s3-demo-bucket-encrypted

    関数が正常に実行されると、以下に類似した出力が表示されます。送信先のバケットには、名前形式 <your_test_file>_encrypted.pdf のファイルが含まれている必要があります。<your_test_file> はアップロードしたファイル名です。

    { "Contents": [ { "Key": "test_encrypted.pdf", "LastModified": "2023-06-07T00:15:50+00:00", "ETag": "\"7781a43e765a8301713f533d70968a1e\"", "Size": 2763, "StorageClass": "STANDARD" } ] }
  3. Lambda が送信先のバケットに保存したファイルをダウンロードするには、次の CLI コマンドを実行します。--bucket パラメータを送信先のバケットの名前に置き換えます。--key パラメータには、ファイル名 <your_test_file>_encrypted.pdf を使用します。<your_test_file> はアップロードしたテストファイルの名前です。

    aws s3api get-object --bucket amzn-s3-demo-bucket-encrypted --key test_encrypted.pdf my_encrypted_file.pdf

    このコマンドは、ファイルを現在のディレクトリにダウンロードし、my_encrypted_file.pdf として保存します。

  4. ダウンロードしたファイルを、Lambda 関数で保護されたパスワード (my-secret-password) で開くことができることを確認します。

プロジェクトディレクトリに次のファイルを作成します。

  • test_pdf_encrypt.py - アプリケーションの自動テストに使用できるテストスクリプト

  • pytest.ini - テストスクリプトの設定ファイル

以下のセクションを展開してコードを表示し、各ファイルの役割の詳細を確認してください。

次のコードをコピーし、test_pdf_encrypt.py という名前のファイルに貼り付けます。プレースホルダーバケット名は必ず置き換えてください。

  • test_source_bucket_available 関数で、amzn-s3-demo-bucket をソースバケットの名前に置き換えます。

  • test_encrypted_file_in_bucket 関数で、amzn-s3-demo-bucket-encryptedsource-bucket-encrypted に置き換えます。source-bucket> はソースバケットの名前です。

  • cleanup 関数で、amzn-s3-demo-bucket をソースバケットの名前に置き換え、amzn-s3-demo-bucket-encrypted を送信先バケットの名前に置き換えます。

import boto3 import json import pytest import time import os @pytest.fixture def lambda_client(): return boto3.client('lambda') @pytest.fixture def s3_client(): return boto3.client('s3') @pytest.fixture def logs_client(): return boto3.client('logs') @pytest.fixture(scope='session') def cleanup(): # Create a new S3 client for cleanup s3_client = boto3.client('s3') yield # Cleanup code will be executed after all tests have finished # Delete test.pdf from the source bucket source_bucket = 'amzn-s3-demo-bucket' source_file_key = 'test.pdf' s3_client.delete_object(Bucket=source_bucket, Key=source_file_key) print(f"\nDeleted {source_file_key} from {source_bucket}") # Delete test_encrypted.pdf from the destination bucket destination_bucket = 'amzn-s3-demo-bucket-encrypted' destination_file_key = 'test_encrypted.pdf' s3_client.delete_object(Bucket=destination_bucket, Key=destination_file_key) print(f"Deleted {destination_file_key} from {destination_bucket}") @pytest.mark.order(1) def test_source_bucket_available(s3_client): s3_bucket_name = 'amzn-s3-demo-bucket' file_name = 'test.pdf' file_path = os.path.join(os.path.dirname(__file__), file_name) file_uploaded = False try: s3_client.upload_file(file_path, s3_bucket_name, file_name) file_uploaded = True except: print("Error: couldn't upload file") assert file_uploaded, "Could not upload file to S3 bucket" @pytest.mark.order(2) def test_lambda_invoked(logs_client): # Wait for a few seconds to make sure the logs are available time.sleep(5) # Get the latest log stream for the specified log group log_streams = logs_client.describe_log_streams( logGroupName='/aws/lambda/EncryptPDF', orderBy='LastEventTime', descending=True, limit=1 ) latest_log_stream_name = log_streams['logStreams'][0]['logStreamName'] # Retrieve the log events from the latest log stream log_events = logs_client.get_log_events( logGroupName='/aws/lambda/EncryptPDF', logStreamName=latest_log_stream_name ) success_found = False for event in log_events['events']: message = json.loads(event['message']) status = message.get('record', {}).get('status') if status == 'success': success_found = True break assert success_found, "Lambda function execution did not report 'success' status in logs." @pytest.mark.order(3) def test_encrypted_file_in_bucket(s3_client): # Specify the destination S3 bucket and the expected converted file key destination_bucket = 'amzn-s3-demo-bucket-encrypted' converted_file_key = 'test_encrypted.pdf' try: # Attempt to retrieve the metadata of the converted file from the destination S3 bucket s3_client.head_object(Bucket=destination_bucket, Key=converted_file_key) except s3_client.exceptions.ClientError as e: # If the file is not found, the test will fail pytest.fail(f"Converted file '{converted_file_key}' not found in the destination bucket: {str(e)}") def test_cleanup(cleanup): # This test uses the cleanup fixture and will be executed last pass

自動テストスクリプトは、3 つのテスト関数を実行して、アプリの正しいオペレーションを確認します。

  • テスト test_source_bucket_available では、テスト PDF ファイルをバケットにアップロードすることで、ソースバケットが正常に作成されたことを確認します。

  • テスト test_lambda_invoked は、関数の最新の CloudWatch Logs ログストリームを調べて、テストファイルをアップロードしたときに Lambda 関数が実行され、成功が報告されていることを確認します。

  • テスト test_encrypted_file_in_bucket では、レプリケート先バケットに暗号化された test_encrypted.pdf ファイルが含まれていることを確認します。

これらのテストがすべて実行されると、スクリプトは追加のクリーンアップステップを実行して、送信元バケットと送信先バケットの両方から test.pdf および test_encrypted.pdf ファイルを削除します。

AWS SAM テンプレートと同様に、このファイルで指定されたバケット名はプレースホルダーです。テストを実行する前に、このファイルをアプリケーションの実際のバケット名で編集する必要があります。このステップについては、「自動スクリプトを使用したアプリケーションのテスト」で詳しく説明します。

次のコードをコピーし、pytest.ini という名前のファイルに貼り付けます。

[pytest] markers = order: specify test execution order

これは、test_pdf_encrypt.py スクリプト内のテストを実行する順序を指定するために必要です。

テストを実行するには、次の手順を実行します。

  1. pytest モジュールがローカル環境にインストールされていることを確認します。pytest は以下のコマンドを実行することでインストールできます。

    pip install pytest
  2. test.pdf という名前の PDF ファイルを、test_pdf_encrypt.py ファイルと pytest.ini ファイルがあるディレクトリに保存します。

  3. ターミナルまたはシェルプログラムを開き、テストファイルがあるディレクトリから次のコマンドを実行します。

    pytest -s -v

    テストが完了すると、次のようになります。

    ============================================================== test session starts ========================================================= platform linux -- Python 3.12.2, pytest-7.2.2, pluggy-1.0.0 -- /usr/bin/python3 cachedir: .pytest_cache hypothesis profile 'default' -> database=DirectoryBasedExampleDatabase('/home/pdf_encrypt_app/.hypothesis/examples') Test order randomisation NOT enabled. Enable with --random-order or --random-order-bucket=<bucket_type> rootdir: /home/pdf_encrypt_app, configfile: pytest.ini plugins: anyio-3.7.1, hypothesis-6.70.0, localserver-0.7.1, random-order-1.1.0 collected 4 items test_pdf_encrypt.py::test_source_bucket_available PASSED test_pdf_encrypt.py::test_lambda_invoked PASSED test_pdf_encrypt.py::test_encrypted_file_in_bucket PASSED test_pdf_encrypt.py::test_cleanup PASSED Deleted test.pdf from amzn-s3-demo-bucket Deleted test_encrypted.pdf from amzn-s3-demo-bucket-encrypted =============================================================== 4 passed in 7.32s ==========================================================

次のステップ

これで、サンプルアプリケーションを作成できました。このコードをベースにして、他の種類のファイル処理アプリケーションを作成することができます。lambda_function.py ファイル内のコードを変更して、ユースケースのファイル処理ロジックを実装します。

一般的なファイル処理のユースケースの多くには、画像処理が含まれます。Python で画像処理を行う場合、Pillow のような一般的な画像処理ライブラリは、通常 C 言語または C++ コンポーネントを含んでいます 関数のデプロイパッケージが Lambda 実行環境と互換性があることを確認するには、正しいソースディストリビューションバイナリを使用することが重要です。

AWS SAM を使用してリソースをデプロイする場合、デプロイパッケージに適切なソースディストリビューションを含めるための追加の手順を実行する必要があります。AWS SAM はビルドマシンとは異なるプラットフォームの依存関係をインストールしないため、ビルドマシンが Lambda 実行環境とは異なるオペレーティングシステムまたはアーキテクチャを使用している場合、requirements.txt ファイルに正しいソースディストリビューション (.whl ファイル) を指定しても機能しません。代わりに、次のいずれかの操作を行います。