본문 바로가기

클라우드/AWS

SAM 환경에서 이미지 리사이징 람다 함수 사용하기

mac os에서 brew를 이용한 SAM CLI 설치 - docker, AWS CLI가 설치되어 있어야 한다.

brew tap aws/tap
brew install aws-sam-cli

sam 버전 확인

sam --version

 

SAM은 serverless application model의 약자. AWS에서 서버리스 앱을 만들게 해준다. 서버리스 앱은 람다 함수, 이벤트 소스 등의 조합이다. SAM 템플릿에 AWS 서비스들을 명세할 수 있고, CLI에서 빌드, 배포를 할 수 있다.

 

터미널에서 aws configure를 치고 aws access key id, aws secret access key 등을 입력한다. 도커 환경에서 사용해야 한다면 cd ~/ 를 치고 홈으로 진입해서 mkdir .aws로 디렉토리를 생성하고 cd .aws로 진입해서 vi config, vi credentials로 값을 넣어준다.

 

in config

[default]
region = ap-northeast-2  # your aws region

 

in credentials

[default]
aws_access_key_id = your_access_key_id
aws_secret_access_key = your_secret_access_key

 

AWS SAM CLI로 AWS에 서버리스 앱 생성, 빌드, 배포하기

서버리스 앱을 설치하고 싶은 디렉토리로 가서

sam init 입력 후 값 설정

앱 디렉토리로 이동 후

sam build 입력해서 앱 빌드

sam deploy --guided 입력해서 배포 초기화

이후 코드 수정 후 배포를 원하면

sam build

sam deploy

 

로컬에서 앱을 테스트하고 싶다면 도커도 있어야 함.

sam local invoke 로 람다 핸들러 호출하면 도커 이미지 기반 컨테이너 뜨면서 실행됨.

 

템플릿 생성 후 유효한 것인지 확인

sam validate 입력

 

S3 이벤트 발생 시 Lambda 함수 호출하는 템플릿

AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Description: >
  CreateThumbnail

  Sample SAM Template for CreateThumbnail

Resources:
  CreateThumbnail:
    Type: AWS::Serverless::Function
    Properties:
      CodeUri: create_thumbnail/
      Handler: app.handler
      Runtime: python3.7
      Timeout: 60
      Policies: AWSLambdaExecute
      Events:
        CreateThumbnailEvent:
          Type: S3
          Properties:
            Bucket: !Ref testbucket
            Events: s3:ObjectCreated:*
  testbucket:
    Type: AWS::S3::Bucket

S3 버킷에서 객체 생성 이벤트 발생 시 create_thumbnail 디렉토리 내 app.py의 handler 함수가 호출된다. app 디렉토리를 create_thumbnail로 바꿔준다.

 

빌드, 배포하면 AWS Cloudformation에 스택이 생기고 S3 버킷에도 SAM 스택 버킷이 생성된다.

 

create_thumbnail의 app.py에서 handler 메서드를 수정해준다.

import os

import boto3
from PIL import Image

s3_client = boto3.client('s3')


def resize_image(image_path, resized_path):
    with Image.open(image_path) as image:
        image.thumbnail((100, 100))
        image.save(resized_path)


def handler(event, context):
    for record in event['Records']:
        bucket = record['s3']['bucket']['name']
        key = record['s3']['object']['key']

        file_name = key.split('/')[-1]

        download_path = '/tmp/{}'.format(file_name)
        upload_path = '/tmp/resized-{}'.format(file_name)

        s3_client.download_file(bucket, key, download_path)
        resize_image(download_path, upload_path)
        bucket_to_upload = '{}-resized'.format(bucket)

        s3_client.upload_file(upload_path, bucket_to_upload, key)

 

S3에서 이벤트가 발생하면 그게 트리거(trigger)이므로 handler가 호출된다.

S3에서 발생한 이벤트를 객체로 묶어서 람다 함수에서 event로써 사용할 수 있게 된다.

event['Records'] 안에는 s3관련 정보가 있다. 버킷 이름, 버킷 key를 추출한다.

key는 객체라고 볼 수 있는데 S3는 디렉토리 내부 파일, 디렉토리에 속하지 않은 파일 모두를 key로 표현한다.

'dir1/dir2/hello.jpg', 'hello.jpg' 모두 key다.

file_name에 key에서 뽑아낸 파일명을 할당해준다.

 

람다는 tmp라는 임시 저장공간이 있는데 512MB다. 아마도 핸들러 호출 시에 캐시용으로 사용되는 것 같다.

download_path는 이벤트가 발생한 S3 버킷의 객체를 tmp에 넣는 용도로 지정해주고, upload_path는 썸네일용 S3 버킷에 썸네일을 업로드하는 용도로 지정해준다.

 

s3_client는 boto3 패키지를 써서 s3를 다룰 수 있게 해준다. 

download_file()은 최소 3개의 인수를 받는다.

첫번째는 객체를 가져올 이벤트가 발생한 버킷, 두번째는 그 버킷에서 생성된 객체 key(파일명 or 디렉토리 경로를 포함한 파일명), 세번째는 람다의 tmp에 저장할 파일 경로('/tmp/ABC.jpg')이다.

 

resize_image()를 호출해서 tmp에 다운로드된 원본 이미지를 썸네일로 만들어 tmp의 upload_path에 저장해둔다.

 

upload_file()을 호출해 tmp에 있는 썸네일을 썸네일용 버킷에 key라는 경로로 저장한다.

 

AWS 람다 콘솔에서 테스트하기

AWS console에 로그인하고 Lambda 서비스를 검색해서 함수 -> 생성한 람다 함수를 클릭한다.

테스트 버튼 왼쪽에 테스트 이벤트 구성 클릭 -> 새로운 테스트 이벤트 생성 -> 이벤트 템플릿 -> Amazon S3 Put 선택 -> 이벤트 이름 지정 -> 템플릿 수정

{
  "Records": [
    {
      "eventVersion": "2.0",
      "eventSource": "aws:s3",
      "awsRegion": "ap-northeast-2",
      "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/key",  // S3에 올라갈 key 지정
          "size": 1024,
          "eTag": "0123456789abcdef0123456789abcdef",
          "sequencer": "0A1B2C3D4E5F678901"
        }
      }
    }
  ]
}

SAM이 생성해준 버킷 이름을 복사해서 이름 뒤에 -resized를 붙여 썸네일용 버킷을 생성해준다.

 

테스트 이벤트가 생성되었으면 S3 버킷에 object : key에 설정해 준대로 이미지를 업로드해준다. 테스트 버튼 눌러서 응답값 확인. 정상이라면 S3의 이미지를 가져와서 썸네일로 만들고 썸네일용 버킷에 썸네일이 저장된다.

 

아니면 버킷에 이미지를 업로드하면 이벤트가 발생된 것이므로 람다 함수가 실행되어 썸네일이 생성된다.

 

403 뜨는 경우 IAM 설정, S3 권한 설정해줘야 함.

404 뜨는 경우 버킷에 저장된 객체를 못가져 오는 경우일 수 있음. 객체(이미지)가 디렉토리 내에 있다면 key를 제대로 명시해야 함.

 

key는 filename이 될 수 있지만 (key가 'hello.jpg'이고 filename이 'hello.jpg'인 경우)

filename은 key가 될 수 없다. (key가 'dir/hello.jpg')이고 filename이 'hello.jpg'인 경우)

 

Postman에서 S3에 이미지 올리는 서버 API 호출하고 람다 함수 내용 보고 싶으면 람다 함수에 print()로 로그 찍어야 함.

 

서버가 도커에 띄워져 있다면 도커 콘솔에 진입해서 config, credentials를 생성, 작성하면 되는데 안먹힐 수도 있다. 그러면 boto3 client에 aws_access_key_id, aws_access_secret_key를 명시해주고 커밋할 때는 빼주면 된다.

 

tip

현재 임시 디렉토리가 뭔지 보는 메서드

print(tempfile.gettempdir())

현재 임시 디렉토리에 무슨 객체가 있는지 확인하는 메서드

print(os.path.isfile('/tmp/' + filename))

 

print()는 로그용. 람다 콘솔 테스트 시 확인할 수 있다.

 

 

참고

https://docs.aws.amazon.com/ko_kr/lambda/latest/dg/with-s3-example-use-app-spec.html

 

https://docs.aws.amazon.com/ko_kr/lambda/latest/dg/with-s3-example-use-app-spec.html

Amazon S3 애플리케이션을 위한 AWS SAM 템플릿

docs.aws.amazon.com

https://docs.aws.amazon.com/ko_kr/lambda/latest/dg/with-s3-example-deployment-pkg.html#with-s3-example-deployment-pkg-python

 

https://docs.aws.amazon.com/ko_kr/lambda/latest/dg/with-s3-example-deployment-pkg.html#with-s3-example-deployment-pkg-python

샘플 Amazon S3 함수 코드

docs.aws.amazon.com

https://docs.aws.amazon.com/ko_kr/lambda/latest/dg/with-s3.html

 

https://docs.aws.amazon.com/ko_kr/lambda/latest/dg/with-s3.html

Amazon S3 이벤트와 함께 AWS Lambda 사용

docs.aws.amazon.com

https://www.youtube.com/watch?v=H_rRlnSw_5s

 

'클라우드 > AWS' 카테고리의 다른 글

운영 서버 환경 구성  (0) 2020.03.22
운영 서버, AWS  (0) 2020.03.22