220816

HyeonKi Jo·2022년 8월 16일
0

오늘의 작업

  • Lambda함수 재생성
  • S3 이벤트와 Lambda함수 연결
  • S3 업로드 후, 텍스트 반환 확인
  • S3암호화
  • S3의 ACL과 Lambda IAM최소권한 부여

Lambda함수 재생성

ECR 프라이빗 리포지토리 생성

  • Private repository를 사용해야 Lambda의 이미지로 사용할 수 있다.
  • 프라이빗으로 생성할 때, 암호화설정(KMS)을 고려할 수 있다.
  • 위 푸시명령을 따라 도커 이미지를 push해준다.
  • 이미지가 잘 push되었다.

Lambda 컨테이너이미지 업데이트



  • 위 이미지를 선택하고 저장을 눌러준다.

S3 버킷 생성 및 테스트용 파일 세팅

  • 새로 버킷을 만들어주고, GCP API Credential json파일을 넣어준다.
  • 또, nutrition_facts_label 디렉토리를 만들어주고 테스트용 영양성분표 이미지를 넣어준다.
  • 이때 두 파일 모두 퍼블릭액세스를 열어준다.

Lambda 환경변수 값 변경

  • Lambda를 구성할 때, 환경변수의 키로 credential과 이미지의 경로를 수정할 수 있도록 했다.
  • 이 환경변수 URL을 수정해준다.

Lambda 테스트


  • 에러없이 성공했다.

S3 이벤트와 Lambda함수 연결

AWS 에서 제공하는 Lambda blueprint 생성해보기

Blueprint Lambda 함수 생성

  • Blueprint 는 말 그대로 AWS에서 제공하는 특정기능의 템플릿이다.
  • 함수이름, 역할이름을 정해주고,
  • 정책 템플릿으로 AmazonS3 객체 읽기 전용 권한을 부여했다.
  • 방금 생성한 S3버킷을 선택해주고, 아래 체크해준다.
  • 함수 생성한다.
  • S3버킷에 이벤트 알림이 추가되엇다.

Test

  • 이벤트 이름을 넣어준다.
  • 이벤트 템플릿은 S3-put으로 생성한다.
  • 기본 코드
import json
import urllib.parse
import boto3

print('Loading function')

s3 = boto3.client('s3')

def lambda_handler(event, context):
    #print("Received event: " + json.dumps(event, indent=2))

    # Get the object from the event and show its content type
    bucket = event['Records'][0]['s3']['bucket']['name']
    key = urllib.parse.unquote_plus(event['Records'][0]['s3']['object']['key'], encoding='utf-8')
    try:
        response = s3.get_object(Bucket=bucket, Key=key)
        print("CONTENT TYPE: " + response['ContentType'])
        return response['ContentType']
    except Exception as e:
        print(e)
        print('Error getting object {} from bucket {}. Make sure they exist and your bucket is in the same region as this function.'.format(key, bucket))
        raise e
  • 테스트 이벤트
{
  "Records": [
    {
      "eventVersion": "2.0",
      "eventSource": "aws:s3",
      "awsRegion": "us-east-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": "example-bucket",
          "ownerIdentity": {
            "principalId": "EXAMPLE"
          },
          "arn": "arn:aws:s3:::example-bucket"
        },
        "object": {
          "key": "test%2Fkey",
          "size": 1024,
          "eTag": "0123456789abcdef0123456789abcdef",
          "sequencer": "0A1B2C3D4E5F678901"
        }
      }
    }
  ]
}

에러

Blueprint 내 S3이벤트로 테스트 성공시키기

S3 Event Json 형식

{  
   "Records":[  
      {  
         "eventVersion":"2.2",
         "eventSource":"aws:s3",
         "awsRegion":"us-west-2",
         "eventTime":"The time, in ISO-8601 format, for example, 1970-01-01T00:00:00.000Z, when Amazon S3 finished processing the request",
         "eventName":"event-type",
         "userIdentity":{  
            "principalId":"Amazon-customer-ID-of-the-user-who-caused-the-event"
         },
         "requestParameters":{  
            "sourceIPAddress":"ip-address-where-request-came-from"
         },
         "responseElements":{  
            "x-amz-request-id":"Amazon S3 generated request ID",
            "x-amz-id-2":"Amazon S3 host that processed the request"
         },
         "s3":{  
            "s3SchemaVersion":"1.0",
            "configurationId":"ID found in the bucket notification configuration",
            "bucket":{  
               "name":"bucket-name",
               "ownerIdentity":{  
                  "principalId":"Amazon-customer-ID-of-the-bucket-owner"
               },
               "arn":"bucket-ARN"
            },
            "object":{  
               "key":"object-key",
               "size":"object-size in bytes",
               "eTag":"object eTag",
               "versionId":"object version if bucket is versioning-enabled, otherwise null",
               "sequencer": "a string representation of a hexadecimal value used to determine event sequence, only used with PUTs and DELETEs"
            }
         },
         "glacierEventData": {
            "restoreEventData": {
               "lifecycleRestorationExpiryTime": "The time, in ISO-8601 format, for example, 1970-01-01T00:00:00.000Z, of Restore Expiry",
               "lifecycleRestoreStorageClass": "Source storage class for restore"
            }
         }
      }
   ]
}

내 S3 Event Json 가져오는 법

json 수정

{
  "Records": [
    {
      "eventVersion": "2.1",
      "eventSource": "aws:s3",
      "awsRegion": "ap-northeast-2",
      "eventTime": "2022-08-16T07:20:37.735Z",
      "eventName": "ObjectCreated:Put",
      "userIdentity": {
        "principalId": "[숨김]"
      },
      "requestParameters": {
        "sourceIPAddress": "[숨김]"
      },
      "responseElements": {
        "x-amz-request-id": "[숨김]",
        "x-amz-id-2": "[숨김]"
      },
      "s3": {
        "s3SchemaVersion": "1.0",
        "configurationId": "[숨김]",
        "bucket": {
          "name": "s3.cocudeny",
          "ownerIdentity": {
            "principalId": "[숨김]"
          },
          "arn": "arn:aws:s3:::s3.cocudeny"
        },
        "object": {
          "key": "nutrition_facts_label/3f8d0df9cb2b7.jpg",
          "size": 263910,
          "eTag": "10852e22b2fa01a99695f4924cdbc0c5",
          "sequencer": "0062FB4545AC7A94A6"
        }
      }
    }
  ]
}

결과

Blueprint를 따라서 Lambda 수정하기

import sys
import os
from struct import pack
import json
import urllib.parse
import boto3

print('Loading function')

s3 = boto3.client('s3')

def detect_document(path):
    """Detects document features in an image."""
    from google.cloud import vision
    import io
    client = vision.ImageAnnotatorClient()
    text_data = []

    # [START vision_python_migration_document_text_detection]
    with io.open(path, 'rb') as image_file:
        content = image_file.read()

    image = vision.Image(content=content)

    response = client.document_text_detection(image=image)

    for page in response.full_text_annotation.pages:
        for block in page.blocks:
            block_text = []
            print('\nBlock confidence: {}\n'.format(block.confidence))

            for paragraph in block.paragraphs:
                paragraph_text = ''
                print('Paragraph confidence: {}'.format(
                    paragraph.confidence))

                for word in paragraph.words:
                    word_text = ''.join([
                        symbol.text for symbol in word.symbols
                    ])
                    paragraph_text += word_text+''
                block_text.append(paragraph_text)
            text_data.append(block_text)

    if response.error.message:
        raise Exception(
            '{}\nFor more info on error messages, check: '
            'https://cloud.google.com/apis/design/errors'.format(
                response.error.message))
    # [END vision_python_migration_document_text_detection]
    return text_data

def handler(event, context):
    print("Received event: " + json.dumps(event, indent=2))

    # Get the object from the event and show its content type
    bucket = event['Records'][0]['s3']['bucket']['name']
    key = urllib.parse.unquote_plus(event['Records'][0]['s3']['object']['key'], encoding='utf-8')
    image_name = key.split('/')[-1]
    image_path = '/tmp/'+image_name

    credential_key = 'GCP_API_CREDENTIAL/fabled-meridian-352009-e226c97ba30a.json'
    credential_name = credential_key.split('/')[-1]
    credential_path = '/tmp/'+credential_name
os.environ['GOOGLE_APPLICATION_CREDENTIALS'] = credential_path

    try:
        response = s3.get_object(Bucket=bucket, Key=key)
        print("CONTENT TYPE: " + response['ContentType'])

        image_path = '/tmp/'+image_name
        s3.download_file(bucket, key, image_path)
        s3.download_file(bucket, credential_key, credential_path)
        text_data = detect_document(image_path)
        return text_data

    except Exception as e:
        print(e)
        print('Error getting object {} from bucket {}. Make sure they exist and your bucket is in the same region as this function.'.format(key, bucket))
        raise e

  • 테스트가 성공했다.
  • 텍스트 출력이 잘 완료되었다.

S3 이미지 업로드 테스트

  • 위와같이 로그가 잘 생성되었다.
  • 근데 출력어디서보지...?

이전 코드와 차이점

  • 이전 코드와 다른점은 환경변수를 아예 설정할 필요가 없어졌다.
  • 대신 S3이벤트알림에서 보내는 bucket과 key정보로 s3.download_file 기능을 이용해 credential과 이미지를 다운로드 받을 수 있게되었다.

앞으로 할 것

  • s3.download_file은 datatransfer 요금을 발생시키는가?
  • S3 업로드 후, 텍스트 반환 확인하기
  • S3암호화, lambda암호화
  • S3의 ACL과 Lambda IAM최소권한 부여
profile
Talking Potato

0개의 댓글