本文為英文版的機器翻譯版本,如內容有任何歧義或不一致之處,概以英文版為準。
建立無伺服器檔案處理應用程式
Lambda 最常見的使用案例之一是執行檔案處理工作。例如,您可以使用 Lambda 函數從PDF檔案或影像自動建立HTML檔案,或在使用者上傳影像時建立縮圖。
在此範例中,您建立了一個應用程式,該應用程式會在PDF檔案上傳到 Amazon Simple Storage Service (Amazon S3) 貯體時自動加密檔案。要實現此應用程序,請創建以下資源:
-
供使用者上傳PDF檔案至的 S3 儲存貯體
-
Python 中的 Lambda 函數,用於讀取上傳的文件並創建一個加密的,受密碼保護的版本
-
Lambda 用來儲存加密檔案的第二個 S3 儲存貯體
您也可以建立 AWS Identity and Access Management (IAM) 政策,授與 Lambda 函數在 S3 儲存貯體上執行讀取和寫入操作的權限。
提示
如果您是 Lambda 的新手,建議您建立第一個 Lambda 函數在建立此範例應用程式之前先執行教學課程。
您可以使用 AWS Management Console 或 AWS Command Line Interface (AWS CLI) 建立和設定資源,以手動方式部署應用程式。您也可以使用 AWS Serverless Application Model (AWS SAM) 部署應用程式。 AWS SAM 是一個基礎架構作為代碼(IaC)工具。使用 IaC,您不會手動創建資源,而是在代碼中定義它們,然後自動部署它們。
如果您想在部署此範例應用程式之前,進一步了解如何將 Lambda 與 IaC 搭配使用,請參閱將 Lambda 搭配基礎設施即程式碼 (IaC)。
必要條件
在建立範例應用程式之前,請確定已安裝必要的命令列工具。
-
AWS CLI
您可以使用 AWS Management Console 或手動部署應用程式的資源 AWS CLI。若要使用CLI,請依照《使用AWS Command Line Interface 者指南》中的安裝指示進行安裝。
-
AWS SAM CLI
如果您想要使用部署範例應用程式 AWS SAM,則必須同時安裝 AWS CLI 和 AWS SAM CLI. 若要安裝 AWS SAM CLI,請遵循使AWS SAM 用者指南中的安裝指示。
-
最火焰模塊
部署應用程序後,您可以使用我們提供的自動化 Python 測試腳本對其進行測試。若要使用此指令碼,請執行下列命令,在本機開發環境中安裝
pytest
套件:pip install pytest
若要使用部署應用程式 AWS SAM,Docker
下載範例應用程式檔案
若要建立並測試範例應用程式,請在專案目錄中建立下列檔案:
-
lambda_function.py
-執行檔案加密之 Lambda 函數的 Python 函數程式碼 -
requirements.txt
-資訊清單檔案,定義 Python 函數程式碼所需的相依性 -
template.yaml
-可用於部署應用程序的 AWS SAM 模板 -
test_pdf_encrypt.py
-可用於自動測試應用程序的測試腳本 -
pytest.ini
-測試腳本的配置文件
展開下列各節以檢視程式碼,並深入瞭解每個檔案在建立和測試應用程式時所扮演的角色。要在本地計算機上創建文件,請複製並粘貼下面的代碼,或從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 函數代碼包含三個函數-Lambda 在調用函數時運行的處理程序函數,以及兩個名為add_encrypted_suffix
和encrypt_pdf
處理程序調用以執行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 程式庫的相依性-SDK 適用於 Python (Boto3),以及函式用來執行加密的pypdf
PDF套件。
注意
Python 版本 (Boto3) 包含在 Lambda 執行階段的一部分,因此您的程式碼可以在不將 Boto3 新增至函數的部署套件的情況下執行。SDK但是,為了保持對函數依賴關係的完全控制並避免版本錯位可能出現的問題,Python 的最佳實踐是在函數的部署包中包含所有函數依賴關係。如需進一步了解,請參閱Python 中的執行期相依項。
將以下代碼複製並粘貼到名為的文件中template.yaml
。
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: EXAMPLE-BUCKET EncryptedPDFBucket: Type: AWS::S3::Bucket Properties: BucketName: EXAMPLE-BUCKET-encrypted
AWS SAM 範本會定義您為應用程式建立的資源。在此範例中,範本使用類型定義 Lambda 函數,並使用該AWS::Serverless::Function
類型定義兩個 S3 儲存貯體。AWS::S3::Bucket
範本中指定的值區名稱為預留位置。在使用部署應用程式之前 AWS SAM,您需要編輯範本,以使用符合 S3 儲存貯體命名規則的全域唯一名稱重新命名值區。此步驟將在中進一步說明使用部署資源 AWS SAM。
Lambda 函數資源的定義會使用S3Event
事件屬性來設定函數的觸發程序。每當在源存儲桶中創建對象時,此觸發器都會調用您的函數。
函數定義也會指定要附加至函數執行角色的 AWS Identity and Access Management (IAM) 原則。受AWS 管政策AmazonS3FullAccess
為您的函數提供讀取和寫入物件至 Amazon S3 所需的許可。
將以下代碼複製並粘貼到名為的文件中test_pdf_encrypt.py
。
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 = 'EXAMPLE-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 = 'EXAMPLE-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 = 'EXAMPLE-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 = 'EXAMPLE-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
自動化測試腳本執行三個測試功能,以確認應用程序的正確操作:
-
測試會將測試PDF檔案上傳至值區,以
test_source_bucket_available
確認您的來源值區已成功建立。 -
該測試會
test_lambda_invoked
詢問函數的最新 CloudWatch 日誌日誌流,以確認當您上傳測試文件時,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
腳本中的測試運行的順序。
部署應用程式
您可以手動建立和部署此範例應用程式的資源,也可以使用 AWS SAM. 在生產環境中,我們建議您使用 IaC 工具,例如 AWS SAM 快速且重複地部署整個無伺服器應用程式,而無需使用手動程序。
在此範例中,請依照主控台或 AWS CLI 指示操作,了解如何分別設定每個 AWS 資源,或略過以使用部署資源 AWS SAM使用幾個CLI命令快速部署應用程式。
手動部署資源
若要手動部署應用程式,請執行下列步驟:
-
建立來源和目的地 S3 儲存貯體
-
建立 Lambda 函數來加密PDF檔案,並將加密版本儲存至 S3 儲存貯體
-
設定 Lambda 觸發程序,以便在物件上傳至來源儲存貯體時叫用您的函數
請遵循以下段落中的指示來建立和配置資源。
建立兩個 S3 儲存貯體
首先創建兩個 S3 存儲桶。第一個值區是您要將PDF檔案上傳到的來源儲存貯體。當您呼叫函數時,Lambda 會使用第二個儲存貯體來儲存加密的檔案。
建立執行角色 (AWS CLI 僅限)
執行角色是授與 Lambda 函數存取 AWS 服務 和資源權限的IAM角色。當您使用 Lambda 主控台建立函數時,Lambda 會自動建立執行角色。如果您選擇使用部署應用程式,則只需手動建立角色 AWS CLI。若要提供 Amazon S3 的函數讀取和寫入存取權,請附加受AWS 管政策AmazonS3FullAccess
。
建立函數部署套件
要建立函數,需建立包含函數程式碼和其相依項的部署套件。對於此應用程序,您的函數代碼使用單獨的庫進行PDF加密。
建立部署套件
-
導航到包含您從 GitHub 之前創建或下載的
lambda_function.py
和requirements.txt
文件的項目目錄,並創建一個名為的新目錄package
。 -
執行下列命令,將
requirements.txt
檔案中指定的相依性安裝在package
目錄中。pip install -r requirements.txt --target ./package/
-
建立包含應用程式程式碼及其相依性的 .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 虛擬環境建立部署套件。請參閱使用 .zip 封存檔部署 Python Lambda 函數
建立 Lambda 函式
現在,您可以使用在上一步中建立的部署套件來部署 Lambda 函數。
設定 Amazon S3 觸發器以叫用函數
若要在將檔案上傳到來源儲存貯體時執行 Lambda 函數,您需要設定函數的觸發器。可以使用主控台或 AWS CLI來設定 Amazon S3 觸發條件。
重要
此程序會將 S3 儲存貯體設定為每次在儲存貯體中建立物件時即會調用您的函數。請務必僅在來源儲存貯體上進行設定。如果 Lambda 函數在進行調用的同一個儲存貯體中建立物件,則可以在一個迴圈中連續調用
使用部署資源 AWS SAM
若要使用部署範例應用程式 AWS SAM CLI,請執行下列步驟。
確保您已安裝最新版本的,CLI並且 Docker
-
編輯
template.yaml
檔案以指定 S3 儲存貯體的名稱。S3 儲存貯體必須具有符合 S3 儲存貯體命名規則的全域唯一名稱。將值區名稱
EXAMPLE-BUCKET
取代為您選擇的名稱,其中包含小寫字母、數字、點 (.) 和連字號 (-)。對於目標值區,請取代EXAMPLE-BUCKET-encrypted
為<source-bucket-name>-encrypted
,其中<source-bucket>
是您為來源值區選擇的名稱。 -
從儲存
template.yaml
、lambda_function.py
和requirements.txt
檔案的目錄執行下列命令。sam build --use-container
此命令會收集應用程式的建置成品,並將它們放置在適當的格式和位置以進行部署。指定該
--use-container
選項將在 Lambda 類似的 Docker 容器中構建您的函數。我們在這裡使用它,因此您不需要在本地計算機上安裝 Python 3.12 即可使構建工作。在建置程序期間,會在您使用範本中的
CodeUri
屬性指定的位置 AWS SAM 尋找 Lambda 函數程式碼。在這種情況下,我們指定當前目錄作為 location (./
)。如果存在
requirements.txt
檔案, AWS SAM 會使用它來收集指定的相依性。根據預設, AWS SAM 會使用函數程式碼和相依性建立 .zip 部署套件。您也可以選擇使用屬性將函數部署為PackageType容器映像檔。 -
若要部署應用程式並建立 AWS SAM 範本中指定的 Lambda 和 Amazon S3 資源,請執行下列命令。
sam deploy --guided
使用該
--guided
標誌意味著 AWS SAM 將顯示提示,以引導您完成部署過程。對於此部署,請按 Enter 接受預設選項。
在部署程序期間, AWS SAM 會在您的中建立下列資源 AWS 帳戶:
-
一個名為的 AWS CloudFormation 堆棧
sam-app
-
具有名稱的 Lambda 函數
EncryptPDF
-
兩個 S3 儲存貯體,其中包含您在編輯
template.yaml
AWS SAM 範本檔案時選擇的名稱 -
具有名稱格式的函數的IAM執行角色
sam-app-EncryptPDFFunctionRole-
2qGaapHFWOQ8
AWS SAM 完成建立資源後,您應該會看到下列訊息:
Successfully created/updated stack - sam-app in us-west-2
測試應用程式
若要測試應用程式,請將PDF檔案上傳到來源儲存貯體,並確認 Lambda 在目的地儲存貯體中建立檔案的加密版本。在此範例中,您可以使用主控台或使用提供的 AWS CLI測試指令碼手動測試此測試。
對於生產應用程式,您可以使用傳統的測試方法和技術 (例如單元測試) 來確認 Lambda 函數程式碼的正常運作。最佳做法也是在提供的測試腳本中進行測試,這些測試腳本使用真實的基於雲的資源進行集成測試。雲端中的整合測試可確認您的基礎結構已正確部署,且事件會如預期般在不同服務之間流動。如需進一步了解,請參閱 如何測試無伺服器功能和應用程式。
手動測試應用程式
您可以將PDF檔案新增至 Amazon S3 來源儲存貯體,以手動測試函數。將檔案新增至來源儲存貯體時,應自動叫用 Lambda 函數,並將檔案的加密版本儲存在目標儲存貯體中。
使用自動指令碼測試應用程式
要使用提供的測試腳本測試您的應用程序,請首先確保該pytest
模塊已安裝在本地環境中。您可以執pytest
行下列命令來進行安裝:
pip install pytest
您也需要編輯test_pdf_encrypt.py
檔案中的程式碼,以 Amazon S3 來源和目的地儲存貯體的名稱取代預留位置儲存貯體名稱。對 test_pdf_encrypt.py
進行下列變更:
-
在
test_source_bucket_available
函數中,EXAMPLE-BUCKET
替換為源存儲桶的名稱。 -
在
test_encrypted_file_in_bucket
函數中,EXAMPLE-BUCKET-encrypted
替換為<source-bucket>-encrypted
,其中<source-bucket>
是源存儲桶的名稱。 -
在
cleanup
函數中,EXAMPLE-BUCKET
替換為源存儲桶的名稱,並替換EXAMPLE-BUCKET-encrypted
為≪source-bucket>-encrypted
,其中<source-bucket>
是源存儲桶的名稱。
要運行測試,請執行以下操作:
-
在包含
test_pdf_encrypt.py
和PDF檔案的目錄test.pdf
中儲存一個名為的pytest.ini
檔案。 -
打開終端機或 shell 程序,並從包含測試文件的目錄運行以下命令。
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 EXAMPLE-BUCKET
Deleted test_encrypted.pdf from EXAMPLE-BUCKET
-encrypted
=============================================================== 4 passed in 7.32s ==========================================================
後續步驟
現在,您已經創建了這個示例應用程序,您可以使用提供的代碼作為基礎來創建其他類型的文件處理應用程序。修改lambda_function.py
檔案中的程式碼,以針對您的使用案例實作檔案處理邏輯。
許多典型的檔案處理使用案例都涉及影像處理。使用 Python 時,最流行的圖像處理庫(如枕頭
使用部署資源時 AWS SAM,您需要採取一些額外的步驟,在部署套件中包含正確的來源散發。因為 AWS SAM 不會針對與建置機器不同的平台安裝相依性,因此如果您的建置機器使用的作業系統或架構與 Lambda 執行環境不同,則在requirements.txt
檔案中指定正確的來源散發 (.whl
檔案) 將無法運作。相反,您應該執行以下操作之一:
-
運行時使用該
--use-container
選項sam build
。當您指定此選項時,會 AWS SAM 下載與 Lambda 執行環境相容的容器基礎映像,並使用該映像在 Docker 容器中建立函數的部署套件。若要深入了解,請參閱在提供的容器內建置 Lambda 函數。 -
使用正確的來源散發二進位檔自行建置函式的 .zip 部署套件,並將 .zip 檔案儲存在範本中指定的目錄
CodeUri
中 AWS SAM 。若要進一步瞭解如何使用二進位發行版為 Python 建置 .zip 部署套件,請參閱建立含相依項的 .zip 部署套件和建立含原生程式庫的 .zip 部署套件。