AWS Lambda 함수 호출 - Amazon Simple Storage Service

AWS Lambda 함수 호출

AWS Lambda 함수 호출은 매니페스트에 나열된 객체에 대한 사용자 지정 작업을 수행할 AWS Lambda 함수를 시작합니다. 이 단원에서는 S3 배치 작업에 사용할 Lambda 함수 생성 방법과 함수 호출 작업 생성 방법을 설명합니다. S3 Batch Operations 작업은 LambdaInvoke 작업을 사용하여 매니페스트에 나열된 모든 객체에 대해 Lambda 함수를 실행합니다.

AWS Management Console, AWS Command Line Interface(AWS CLI), AWS SDK 또는 REST API를 사용하여 Lambda에 대한 S3 Batch Operations를 수행할 수 있습니다. Lambda 사용에 대한 자세한 내용은 AWS Lambda 개발자 안내서AWS Lambda 시작하기를 참조하세요.

다음 단원에서는 S3 배치 작업을 Lambda와 함께 사용하여 시작할 수 있는 방법에 대해 설명합니다.

Amazon S3 배치 작업에 Lambda 사용

S3 Batch Operations를 AWS Lambda와 함께 사용할 때 특별히 S3 Batch Operations에 사용할 새로운 Lambda 함수를 생성해야 합니다. 기존의 Amazon S3 이벤트 기반 함수를 S3 배치 작업에 재사용할 수는 없습니다. 이벤트 함수는 메시지만 받을 수 있습니다. 메시지를 반환하지 않습니다. S3 배치 작업에 사용되는 Lambda 함수는 메시지를 수락하고 반환해야 합니다. Amazon S3 이벤트와 함께 Lambda를 사용하는 방법에 대한 자세한 내용은 AWS Lambda 개발자 안내서Amazon S3에서 AWS Lambda 사용 섹션을 참조하세요.

Lambda 함수를 호출하는 S3 배치 처리 작업을 생성합니다. 이 작업은 매니페스트에 나열된 모든 객체에 대해 동일한 Lambda 함수를 실행합니다. 매니페스트의 객체를 처리하는 동안 사용할 Lambda 함수의 버전을 제어할 수 있습니다. S3 배치 작업은 정규화되지 않은 Amazon 리소스 이름(ARN), 별칭 및 특정 버전을 지원합니다. 자세한 내용은 AWS Lambda 개발자 안내서AWS Lambda 버전 관리 소개를 참조하세요.

별칭 또는 $LATEST 한정어를 사용하는 함수 ARN에 S3 배치 작업을 제공하고 해당 버전 중 하나를 업데이트하면 S3 배치 작업에서 Lambda 함수의 새 버전 호출을 시작합니다. 이는 라지 작업을 통해 기능 부분을 업데이트하고자 할 때 유용할 수 있습니다. S3 배치 작업에서 사용되는 버전을 변경하지 않으려면 작업을 생성할 때 FunctionARN 파라미터에 특정 버전을 제공합니다.

응답 및 결과 코드

S3 배치 작업이 Lambda 함수에서 기대하는 코드에는 두 가지 레벨이 있습니다. 첫 번째는 전체 요청에 대한 응답 코드이고 두 번째는 작업별 결과 코드입니다. 다음 표는 응답 코드를 포함합니다.

응답 코드 설명
Succeeded 작업이 정상적으로 완료되었습니다. 작업 완료 보고서를 요청한 경우 작업의 결과 문자열이 보고서에 포함됩니다.
TemporaryFailure 작업이 일시적으로 실패하여 작업이 완료되기 전에 리드라이브됩니다. 결과 문자열은 무시됩니다. 이것이 최종 리드라이브인 경우 오류 메시지가 최종 보고서에 포함됩니다.
PermanentFailure 작업에 영구 실패가 발생했습니다. 작업 완료 보고서를 요청한 경우 작업은 Failed로 표시되고 오류 메시지 문자열을 포함합니다. 실패한 작업의 결과 문자열은 무시됩니다.

S3 배치 작업에서 사용할 Lambda 함수 생성

이 섹션에서는 Lambda 함수와 함께 사용해야 하는 AWS Identity and Access Management(IAM) 권한 예제를 제공합니다. 또한 S3 배치 작업에 사용할 예제 Lambda 함수도 포함되어 있습니다. 이전에 Lambda 함수를 생성한 적이 없다면 AWS Lambda 개발자 안내서자습서: Amazon S3에서 AWS Lambda 사용을 참조하세요.

S3 배치 작업 전용으로 Lambda 함수를 만들어야 합니다. 기존 Amazon S3 이벤트 기반 Lambda 함수를 재사용할 수는 없습니다. S3 배치 작업에 사용되는 Lambda 함수는 특수 데이터 필드를 수락 및 반환해야 하기 때문입니다.

중요

Java로 작성된 AWS Lambda 함수는 RequestHandler 또는 RequestStreamHandler 핸들러 인터페이스를 수락합니다. 그러나 S3 Batch Operations 요청 및 응답 형식을 지원하려면 AWS Lambda에 요청 및 응답의 사용자 지정 직렬화 및 역직렬화를 위한 RequestStreamHandler 인터페이스가 필요합니다. 이 인터페이스를 통해 Lambda에서 InputStream 및 OutputStream을 Java handleRequest 메서드에 전달할 수 있습니다.

S3 배치 작업에 Lambda 함수를 사용할 때는 반드시 RequestStreamHandler 인터페이스를 사용해야 합니다. RequestHandler 인터페이스를 사용하는 경우 배치 작업이 실패하고 완료 보고서에 “잘못된 JSON이 Lambda 페이로드로 반환됨”이라고 표시됩니다.

자세한 내용은 AWS Lambda 사용 설명서핸들러 인터페이스를 참조하세요.

예제 IAM 권한

다음은 Lambda 함수를 S3 배치 작업에 사용하는 데 필요한 IAM 권한의 예제입니다.

예 - S3 배치 작업 신뢰 정책

다음은 배치 작업 IAM 역할에서 사용할 수 있는 신뢰 정책의 예제입니다. 이 IAM 역할은 작업을 생성할 때 지정되며 IAM 역할을 수임할 배치 작업 권한을 부여합니다.

{ "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Principal": { "Service": "batchoperations.s3.amazonaws.com" }, "Action": "sts:AssumeRole" } ] }

예 - Lambda IAM 정책

다음은 Lambda 함수를 호출하고 입력 매니페스트를 읽을 수 있는 S3 배치 작업 권한을 부여하는 IAM 정책의 예제입니다.

{ "Version": "2012-10-17", "Statement": [ { "Sid": "BatchOperationsLambdaPolicy", "Effect": "Allow", "Action": [ "s3:GetObject", "s3:GetObjectVersion", "s3:PutObject", "lambda:InvokeFunction" ], "Resource": "*" } ] }

예제 요청 및 응답

이 섹션에는 Lambda 함수에 대한 요청 및 응답 예제가 나와 있습니다.

예 Request

다음은 Lambda 함수 요청에 대한 JSON 예제입니다.

{ "invocationSchemaVersion": "1.0", "invocationId": "YXNkbGZqYWRmaiBhc2RmdW9hZHNmZGpmaGFzbGtkaGZza2RmaAo", "job": { "id": "f3cc4f60-61f6-4a2b-8a21-d07600c373ce" }, "tasks": [ { "taskId": "dGFza2lkZ29lc2hlcmUK", "s3Key": "customerImage1.jpg", "s3VersionId": "1", "s3BucketArn": "arn:aws:s3:us-east-1:0123456788:awsexamplebucket1" } ] }

예 Response

다음은 Lambda 함수에 대한 JSON 응답의 예제입니다.

{ "invocationSchemaVersion": "1.0", "treatMissingKeysAs" : "PermanentFailure", "invocationId" : "YXNkbGZqYWRmaiBhc2RmdW9hZHNmZGpmaGFzbGtkaGZza2RmaAo", "results": [ { "taskId": "dGFza2lkZ29lc2hlcmUK", "resultCode": "Succeeded", "resultString": "[\"Mary Major", \"John Stiles\"]" } ] }

S3 배치 작업에 대한 Lambda 함수 예제

다음 예제 Python Lambda는 버전이 지정된 객체에서 삭제 마커를 제거합니다.

예제에서 볼 수 있듯이 S3 배치 작업의 키는 URL로 인코딩됩니다. Amazon S3를 다른 AWS 서비스와 함께 사용하려면 S3 Batch Operations에서 전달된 키를 URL로 디코딩해야 합니다.

import logging from urllib import parse import boto3 from botocore.exceptions import ClientError logger = logging.getLogger(__name__) logger.setLevel('INFO') s3 = boto3.client('s3') def lambda_handler(event, context): """ Removes a delete marker from the specified versioned object. :param event: The S3 batch event that contains the ID of the delete marker to remove. :param context: Context about the event. :return: A result structure that Amazon S3 uses to interpret the result of the operation. When the result code is TemporaryFailure, S3 retries the operation. """ # Parse job parameters from Amazon S3 batch operations invocation_id = event['invocationId'] invocation_schema_version = event['invocationSchemaVersion'] results = [] result_code = None result_string = None task = event['tasks'][0] task_id = task['taskId'] try: obj_key = parse.unquote(task['s3Key'], encoding='utf-8') obj_version_id = task['s3VersionId'] bucket_name = task['s3BucketArn'].split(':')[-1] logger.info("Got task: remove delete marker %s from object %s.", obj_version_id, obj_key) try: # If this call does not raise an error, the object version is not a delete # marker and should not be deleted. response = s3.head_object( Bucket=bucket_name, Key=obj_key, VersionId=obj_version_id) result_code = 'PermanentFailure' result_string = f"Object {obj_key}, ID {obj_version_id} is not " \ f"a delete marker." logger.debug(response) logger.warning(result_string) except ClientError as error: delete_marker = error.response['ResponseMetadata']['HTTPHeaders'] \ .get('x-amz-delete-marker', 'false') if delete_marker == 'true': logger.info("Object %s, version %s is a delete marker.", obj_key, obj_version_id) try: s3.delete_object( Bucket=bucket_name, Key=obj_key, VersionId=obj_version_id) result_code = 'Succeeded' result_string = f"Successfully removed delete marker " \ f"{obj_version_id} from object {obj_key}." logger.info(result_string) except ClientError as error: # Mark request timeout as a temporary failure so it will be retried. if error.response['Error']['Code'] == 'RequestTimeout': result_code = 'TemporaryFailure' result_string = f"Attempt to remove delete marker from " \ f"object {obj_key} timed out." logger.info(result_string) else: raise else: raise ValueError(f"The x-amz-delete-marker header is either not " f"present or is not 'true'.") except Exception as error: # Mark all other exceptions as permanent failures. result_code = 'PermanentFailure' result_string = str(error) logger.exception(error) finally: results.append({ 'taskId': task_id, 'resultCode': result_code, 'resultString': result_string }) return { 'invocationSchemaVersion': invocation_schema_version, 'treatMissingKeysAs': 'PermanentFailure', 'invocationId': invocation_id, 'results': results }

Lambda 함수를 호출하는 S3 배치 작업 건 생성

Lambda 함수를 호출하기 위해 S3 배치 작업을 생성할 때 다음을 제공해야 합니다.

  • Lambda 함수의 ARN(함수 별칭 또는 특정 버전 번호를 포함할 수도 있음)

  • 함수 호출 권한이 있는 IAM 역할

  • 작업 파라미터 LambdaInvokeFunction

S3 배치 작업 생성에 대한 자세한 내용은 S3 배치 작업 건 생성S3 Batch Operations에서 지원하는 작업 단원을 참조하세요.

다음 예제에서는 AWS CLI를 사용하여 Lambda 함수를 호출하는 S3 Batch Operations 작업을 생성합니다.

aws s3control create-job --account-id <AccountID> --operation '{"LambdaInvoke": { "FunctionArn": "arn:aws:lambda:Region:AccountID:function:LambdaFunctionName" } }' --manifest '{"Spec":{"Format":"S3BatchOperations_CSV_20180820","Fields":["Bucket","Key"]},"Location":{"ObjectArn":"arn:aws:s3:::ManifestLocation","ETag":"ManifestETag"}}' --report '{"Bucket":"arn:aws:s3:::awsexamplebucket1","Format":"Report_CSV_20180820","Enabled":true,"Prefix":"ReportPrefix","ReportScope":"AllTasks"}' --priority 2 --role-arn arn:aws:iam::AccountID:role/BatchOperationsRole --region Region --description “Lambda Function"

Lambda 매니페스트에서 태스크 수준 정보 제공

S3 Batch Operations에서 AWS Lambda 함수를 사용할 때 작동하는 각 태스크/키를 포함하는 추가 데이터를 원할 수 있습니다. 예를 들어 원본 객체 키와 새로운 객체 키가 모두 제공되도록 하고 싶을 수 있습니다. 이렇게 하면 Lambda 함수는 새 S3 버킷에 원본을 새로운 이름으로 복사할 수 있습니다. 기본적으로 Amazon S3 배치 작업은 작업에 대해 입력 매니페스트의 대상 버킷과 원본 키 목록만 지정할 수 있도록 합니다. 아래에는 보다 복잡한 Lambda 함수를 실행할 수 있도록 매니페스트에 추가 데이터를 포함시킬 수 있는 방법이 나와 있습니다.

S3 배치 작업 매니페스트에 Lambda 함수 코드에서 사용할 키별 파라미터를 지정하려면 다음과 같이 URL 인코딩된 JSON 형식을 사용하세요. key 필드는 마치 Amazon S3 객체 키인 것처럼 Lambda 함수로 전달됩니다. 그러나 아래와 같이 다른 값이나 여러 키를 포함시키기 위해 Lambda 함수에 의해 해석될 수 있습니다.

참고

매니페스트에서 key 필드의 최대 문자 수는 1,024자입니다.

예 - “Amazon S3 키”를 JSON 문자열로 대체하는 매니페스트

URL 인코딩 버전을 S3 배치 작업에 제공해야 합니다.

my-bucket,{"origKey": "object1key", "newKey": "newObject1Key"} my-bucket,{"origKey": "object2key", "newKey": "newObject2Key"} my-bucket,{"origKey": "object3key", "newKey": "newObject3Key"}

예 - URL 인코딩된 매니페스트

이러한 URL 인코딩 버전을 S3 배치 작업에 제공해야 합니다. URL 인코딩 버전이 아니면 작동하지 않습니다.

my-bucket,%7B%22origKey%22%3A%20%22object1key%22%2C%20%22newKey%22%3A%20%22newObject1Key%22%7D my-bucket,%7B%22origKey%22%3A%20%22object2key%22%2C%20%22newKey%22%3A%20%22newObject2Key%22%7D my-bucket,%7B%22origKey%22%3A%20%22object3key%22%2C%20%22newKey%22%3A%20%22newObject3Key%22%7D

예 - 작업 보고서에 결과를 기록하는 매니페스트 형식을 지원하는 Lambda 함수

이 Lambda 함수는 S3 배치 작업 매니페스트로 인코딩되는, 파이프로 구분된 태스크를 구문 분석하는 방법을 보여 줍니다. 이 태스크는 지정된 객체에 적용되는 개정 작업을 나타냅니다.

import logging from urllib import parse import boto3 from botocore.exceptions import ClientError logger = logging.getLogger(__name__) logger.setLevel('INFO') s3 = boto3.resource('s3') def lambda_handler(event, context): """ Applies the specified revision to the specified object. :param event: The Amazon S3 batch event that contains the ID of the object to revise and the revision type to apply. :param context: Context about the event. :return: A result structure that Amazon S3 uses to interpret the result of the operation. """ # Parse job parameters from Amazon S3 batch operations invocation_id = event['invocationId'] invocation_schema_version = event['invocationSchemaVersion'] results = [] result_code = None result_string = None task = event['tasks'][0] task_id = task['taskId'] # The revision type is packed with the object key as a pipe-delimited string. obj_key, revision = \ parse.unquote(task['s3Key'], encoding='utf-8').split('|') bucket_name = task['s3BucketArn'].split(':')[-1] logger.info("Got task: apply revision %s to %s.", revision, obj_key) try: stanza_obj = s3.Bucket(bucket_name).Object(obj_key) stanza = stanza_obj.get()['Body'].read().decode('utf-8') if revision == 'lower': stanza = stanza.lower() elif revision == 'upper': stanza = stanza.upper() elif revision == 'reverse': stanza = stanza[::-1] elif revision == 'delete': pass else: raise TypeError(f"Can't handle revision type '{revision}'.") if revision == 'delete': stanza_obj.delete() result_string = f"Deleted stanza {stanza_obj.key}." else: stanza_obj.put(Body=bytes(stanza, 'utf-8')) result_string = f"Applied revision type '{revision}' to " \ f"stanza {stanza_obj.key}." logger.info(result_string) result_code = 'Succeeded' except ClientError as error: if error.response['Error']['Code'] == 'NoSuchKey': result_code = 'Succeeded' result_string = f"Stanza {obj_key} not found, assuming it was deleted " \ f"in an earlier revision." logger.info(result_string) else: result_code = 'PermanentFailure' result_string = f"Got exception when applying revision type '{revision}' " \ f"to {obj_key}: {error}." logger.exception(result_string) finally: results.append({ 'taskId': task_id, 'resultCode': result_code, 'resultString': result_string }) return { 'invocationSchemaVersion': invocation_schema_version, 'treatMissingKeysAs': 'PermanentFailure', 'invocationId': invocation_id, 'results': results }