본문 바로가기

개발/AWS

[AWS] 컨테이너 기반 Lambda 생성하기, Lambda에서 S3업로드

반응형

프로젝트 내에서 음성파일 분석을 위해 파이썬 Librosa 라이브러리를 활용해야 했는데요,

전체프로젝트를 서버리스로 구성할 계획이어서 이 부분도 람다로 추가해보았습니다. 

 

일반적으로 람다에 외부 라이브러리를 활용하려면 Lambda layers를 이용하면 되지만,

librosa는 패키지 사이즈가 커서 이 방법으로는 업로드가 어려웠습니다. 

EFS에 패키지를 설치하고 람다에 EFS를 마운트하는 방법도 있었지만 제가 시도해보니 잘 안되어서..

람다 전체를 도커로 컨테이너화 해서 올리는 방법을 택했습니다. 

 

01. 람다 핸들러 소스코드 작성

람다 핸들러 소스코드를 작성해줍니다.

아래 코드는 쿼리패러미터로 입력받은 url에 대해서 librosa의 split(묵음 구간 식별)를 수행하고 

결과를 boto3라이브러리를 이용해서 S3버킷에 업로드 하는 함수입니다.

import json
import requests
import librosa
import boto3
import io
from urllib.request import urlopen
import os
os.environ[ 'NUMBA_CACHE_DIR' ] = '/tmp/'

def handler(event, context):
    print(event)
    if event['queryStringParameters'] and event['queryStringParameters']['url']:
        url = event['queryStringParameters']['url']
        name = event['queryStringParameters']['name'] if 'name' in event['queryStringParameters'] else url.split('/')[-1].split('.')[0]
        top_db = event['queryStringParameters']['top_db'] if 'top_db' in event['queryStringParameters'] else 40
        print(url, top_db)
        data, samplerate = librosa.load(io.BytesIO(urlopen(url).read()))
        print(data[:10], samplerate)
        ll = librosa.effects.split(y=data, frame_length=samplerate, top_db=top_db)

        start_of_speech = []
        for l in ll:
            start_of_speech.append("%.3f" % (l[0]/samplerate))
        
        result = {
                    "origin": event['queryStringParameters']['url'],
                    "name": name,
                    "start_of_speech": start_of_speech,
                    "ll": ll.tolist()
                }

        s3 = boto3.resource("s3").Bucket("{{버킷이름}}")
        json.dump_s3 = lambda obj, f: s3.Object(key=f).put(Body=json.dumps(obj))
        json.dump_s3(result, name)

        return {
            'headers': {'Content-Type' : 'application/json'},
            'statusCode': 200,
            'body': json.dumps(result)
            }
    else:
        return {
            'headers': {'Content-Type' : 'application/json'},
            'statusCode': 400,
            'body': json.dumps({"message": "url is necessary"})
        }

 

02. 필요한 라이브러리를 requirements.txt에 작성 

이 프로젝트에서 사용할 라이브러리만 requirements.txt에 작성해주어야 합니다. 

파이썬에서 새로운 실행환경을 만들어줍니다. 

python3 -m venv .venv
source .venv/bin/activate

실행된 환경에서 필요한 라이브러리를 pip install로 설치하고,

pip의 내용을 requirements.txt에 저장해줍니다. 

pip install librosa
pip insall boto3
pip freeze > requirements.txt

 

03. 도커파일 작성 

아래와 같이 aws/lambda/python:3.8 기반으로 하는 Dockerfile을 루트에 작성해줍니다. 

# python3.8 lambda base image
FROM public.ecr.aws/lambda/python:3.8

# copy requirements.txt to container
COPY requirements.txt ./

# installing dependencies
RUN pip3 install -r requirements.txt

# Copy function code to container
COPY app.py ./

# handling librosa error
RUN mkdir -m 777 /tmp/NUMBA_CACHE_DIR /tmp/MPLCONFIGDIR
ENV NUMBA_CACHE_DIR=/tmp/NUMBA_CACHE_DIR/
ENV MPLCONFIGDIR=/tmp/MPLCONFIGDIR/
# handling sndfile not found error
RUN yum -y update && \
    yum -y install libsndfile && \
    yum clean all
		
# setting the CMD to your handler file_name.function_name
CMD [ "app.handler" ]

 

04. AWS Elastic Container Repository 생성 

AWS ECS서비스에서 ECR메뉴로 들어갑니다. 

새로운 리포지토리를 하나 생성해줍니다. 

 

 

05. 도커 이미지 빌드 및 푸시

리포지토리 리스트로 돌아가서 '푸시 명령 보기'를 클릭하면 해당 ECR 리포지토리로 푸시하기 위한 명령어를 확인할 수 있습니다.

해당 명령어를 통해 작성한 람다 핸들러와 도커파일을 빌드하고 푸시해줍니다.  

푸시까지 완료되면 리포지토리에서 도커 이미지를 확인할 수 있습니다.

 

 

06. 컨테이너 이미지 기반 람다 함수 생성

새로운 람다 함수를 생성해줍니다.

옵션으로 '컨테이너 이미지'를 선택하고 위에서 업로드한 컨테이너 이미지를 찾아서 선택해줍니다.

 

음성 파일 분석은 시간이 오래 걸리므로 람다 기본 설정의 제한시간을 늘려줍니다.

저는 제한시간을 3초에서 3분으로 늘렸습니다. 

테스트하다보니 메모리도 부족하다는 에러메시지가 나서 메모리도 512MB로 늘려주었습니다. 

 

 

07. 결과를 S3에 업로드하는 권한 추가

람다 실행 권한에 S3FullAccess를 추가하여 결과 파일이 S3에 정상적으로 업로드 될 수 있도록 합니다.

(더 강력한 보안을 위해서는 파일이 업로드될 버킷의 put권한만 주는게 좋지만 여기서는 테스트를 위함이므로 전체 권한을 넣어줍니다)

 

08. 테스트 

람다의 테스트 탭을 통해 만들어진 함수를 테스트해봅니다.

테스트 탭의 이벤트 JSON 부분이 핸들러의 event 패러미터로 들어간다고 보면 됩니다. 

저는 아래와 같이 이벤트를 작성해주었습니다.

{
  "queryStringParameters": {
    "url": "{{타겟url}} "
  }
}

 

테스트해보면 성공적으로 response가 오고 S3에도 결과물이 잘 생성된 것을 확인할 수 있습니다. 

반응형