오늘의 작업
- 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):
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 = []
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))
return text_data
def handler(event, context):
print("Received event: " + json.dumps(event, indent=2))
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최소권한 부여