AWS

AWS API Gateway - Lambda 를 활용한 동적 이미지 프로세싱

kyuuuun 2025. 4. 25. 00:30
728x90

근래 사내 프로젝트로 AWS Lambda 를 활용하여 on-the-fly 방식으로 동적 이미지 프로세싱 프로젝트를 진행하게 되었습니다. 

프로젝트를 진행하며 겪었던 이슈와 과정들을 간략하게 정리해보려 합니다.

 

배경

저희 회사는 이커머스 업계 특성상 굉장히 많은 상품 이미지를 AWS S3로 관리하고 있습니다. 

당시 이미 동적 이미지 프로세싱 및 캐싱 기능의 역할을 하는 외부 솔루션을 도입하여 Image 서버가 구축되어 있었고 월마다 고정 비용이 나가고 있었는데요. 클라이언트에서 이미지 요청의 경우 flow 를 자세히 보니 조금 의아한 부분이 있었습니다.

기존 이미지 요청 flow 를 간략하게 도식화한 이미지입니다. 이미 AWS CloudFront가 제일 앞 단에서 url 을 key 값으로 캐싱을 잘해주고 있었고 실제 Image Server 의 캐싱 히트율은 2-3%대에 지나지 않았습니다. 

 

그럼 이미지 프로세싱만 잘 구현하면 굳이 Image Server 솔루션 사용할 이유가 있을까 ? 에서 시작된 PoC 였습니다. 초기에는 nest.js를 기반으로 sharp 라이브러리를 활용하여 Image Server 를 대체할 서버를 구축하려 했으나 구글링을 해보니 AWS Lambda 를 활용하여 비교적 더 간단한게 구현한 선례들이 많아 API Gateway + Lambda로 우회하게 되었습니다. Lambda에 대해 간략하게 설명하면 AWS 에서 제공하는 serverless 함수 기반 서비스로 작성된 코드를 aws 가 알아서 실행해주는 저렴한 가격의 훌륭한 서비스입니다.

 

그리하여 AWS API Gateway + Lambda 를 도입한 이미지 요청 flow 는 아래와 같습니다.

왜 CloudFront 가 바라보는 origin(원본)이 두개일까?

이유는 Lambda의 응답 용량 한계에 있습니다. 처음에는 AWS Lamda@Edge 를 생각했지만 response limit 이 1mb 밖에 되지 않아 고민하였습니다. 실제 사용자들이 올리는 리뷰 이미지의 경우는 스마트폰의 카메라 기술 발전에 따라 굉장히 고화질이라 1mb 가 넘는 이미지가 수두룩하였기 때문입니다... 이미지를 리사이징하여 용량을 낮추면 되지 않나 ? 라고 생각하면 또 그럴수 있겠지만 원본이미지 요청인 경우 1mb가 넘어가면 불필요한 이미지 리사이징이 필요하기에 용량 제한이 6mb 인 일반 Lambda로 변경 하였고 이미지 프로세싱이 필요없는 원본 이미지 요청은 바로 S3를 찌르도록 구성하였습니다. API Gateway는 CloudFront에 직접 붙일수 있는 Lambda@Edge 와 다르게 일반 Lambda는 직접 붙일수가 없어 CloudFront에서 Lambdad를 사용하기위해서는 API Gateway를 엔드포인트처럼 함께 사용하여야 합니다.

 

Lambda 배포 방법

사내에서는 여러 Lambda 함수를 Serverless 프레임워크를 통해 관리 및 배포를 하고 있었습니다. serverless 프레임워크는 serverless.yml 파일 하나로 Lambda 함수, API Gateway, S3, IAM 권한 등을 손쉽게 관리하고 배포할수 있는 툴로 생각하시면 됩니다.

AWS 권한만 있다면 serverless deploy 명령어 하나로 serverless.yml에 작성된 설정대로 AWS 에 바로 배포되니 정말 편리하긴 합니다. 저 같은 경우는 사내 보안상? 모든 권한을 다 받지는 못했습니다.. 그리 하여 코드 수정이 필요할때는 수동 배포를 진행했는데serverless deploy 에 비해 조금 번거롭긴 하지만 나름 적응되면 또 괜찮습니다. 

방법은 아래와 같습니다. 

serverless package --stage dev // 개발 환경으로 패키징
serverless package --stage prod // 운영 환경으로 패키징

위 명령어들을 실행하면 local에 설치된 node_mouduls 와 코드를 가지고 패키징을 하여 위 이미지처럼 .serverless 폴더 아래에 zip 파일을 만들어줍니다.

* 여기서 정말 주의 해야하는 점은 AWS Lambda는 linux 환경에서 실행되기 때문에 반드시 linux 환경에서 호환이되는 모듈을 설치해야 합니다.

저의 경우 Lambda 런타임 환경이 리눅스, 아키텍처가 arm64로 아래 명령어를 통해 sharp 를 설치하였습니다.

npm install sharp --platform=linux --arch=arm64

 

이 zip 파일을 가지고 AWS Lambda 콘솔로 이동합니다. 

콘솔의 코드탭에서 코드 소스를 zip파일로 업로드하거나 S3 버킷에 올리고 버킷주소를 통해 업로드할 수 있습니다.

업로드 후에는 버전 탭으로 이동해서 새버전 발행으로 배포를 진행하면 완료입니다.

 

AWS Lambda Console 테스트

코드 업로드 후에는 테스트 탭에서 업로드된 코드로 AWS Lambda 콘솔에서 테스트를 진행해볼 수 있습니다.

테스트 탭에서 저장버튼을 클릭시 테스트했던 이벤트 Json을 테스트 이름과 같이 저장하고 추후에도 계속 세팅하여 테스트 할 수 있습니다.

이미지 프로세싱의 경우 대게 request url에 원본 파일경로나 어떻게 이미지를 가공할 것인지에 대한 옵션 정보 값들이 있을텐데 저 역시 request url 이 필요했고 Lambda 함수 실행시 진입점인 handler 함수에서는 event 객체를 인자로 받아 path 에서 request url 에서 꺼내서 사용하기 때문에 이벤트 JSON 에 위와 같이 cloudfront url을 제외한 나머지 경로를 path 프로퍼티에 넣어 테스트를 진행하면 아래와 같이 테스트 결과를 확인할 수 있습니다.

lambda 함수 내에서 찍은 log도 로그 출력에서 확인이 가능합니다. 물론 CloudWatch에서도 해당 lambda의 로그를 확인할 수 있습니다.

 

AWS CloudFront 설정

이제 lambda 를 만들었으니 API Gateway에 연결 후 마지막으로 CloudFront의 원본으로 API Gateway 설정하면 완료입니다.

API Gateway는 serverless.yml에 작성된 설정대로 배포하면 잘 배포되지만 CloudFront 설정에서 한가지 주의해야하는 점이 있습니다.

 

우선 CloudFront로 이동하여 원본탭으로 가보면 아래와 같은 화면이 나오는데 

이 탭에서는 cloudfront 의 캐시가 miss 났을때 바라볼 원본 origin 들을 설정할 수 있습니다. 도식에서 설명드렸던것과 같이 원본유형이 API Gateway, S3  두개가 있는 것을 확인할 수 있습니다.

이 탭에서는 크게 볼건 없고 람다 함수를 실행시키기 위한 API Gateway 도메인 이름과 원본 이미지가 저장된 S3 버킷 이름 정도만 알고 넘어가면 될 것 같습니다.

 

다음은 동작탭으로 이동해보면 request url 에서 패턴에 따라 어떤 원본(origin)을 가져올지 설정할 수 있습니다.

처음 요청이 들어오면 우선순위가 높은 순으로 먼저 패턴 체크를 하여 저희는 image processing 이 필요한 이미지의 경우 특정 예약어가 url 에 붙기때문에 해당 예약어가 url 포함되어 있으면 API Gateway 를 통해 람다를 실행시킵니다.

0번째 동작이 정상적인 응답을 반환했다면 다음 우선순위는 실행되지 않습니다.

 

동작을 새로 생성하거나 편집 버튼을 통해 수정하면  해당 동작의 캐시 키와 응답 헤더 정책 등을 설정할 수 있는데 cloudfront 원본(origin)을 기본적으로 헤더에 넣어주지는 않습니다.

origin 이 빠진 정책으로 설정하면 CORS 이슈가 발생하여 정상적으로 이미지가 불러와지지 않기에 CORS 에러 발생을 막기위해서는 반드시 요청정책과 응답 헤더 정책에 origin 이 포함된 정책을 넣어야합니다. 위 이미지의 요청정책과 응답헤더 정책은 보기 클릭시 origin이 포함되어 있습니다. (응답헤더는 보안상 가리긴했지만)

 

여기까지 모든 설정이 완료되었습니다. 현재는 운영에 배포되어 기존 이미지 서버는 걷어내고 Lambda를 통해 정상적으로 이미지 프로세싱이 되고 있습니다. 아무래도 AWS 인프라 설정은 Front end 개발자로서 자주 접해볼 기회가 많지 않아 매우 유익한 시간이였고 CloudFront와 이미지 캐싱 및 프로세싱 모두 Front end 측면에서는 알아두면 매우 좋은 경험이 될 것 같아 회고해보면서 뿌듯했습니다 ㅎㅎ.. 

 

긴 글 읽어주셔서 감사합니다!