1. 개요
AWS의 Lambda Function 을 이용한 Serverless 환경을 구축하는 것은 이제 많이 대중화가 된 것 같습니다.
Lambda Function을 사용하게 되면 서버의 관리 필요성도 없어지고, 사용자가 급격하게 증가할 때 발생하는 문제들도 고민이 줄어들게 됩니다.
CloudFront를 사용하는 경우 Edge Location에서 Lambda@Edge를 사용하여 로직 처리가 가능합니다.
주로 Static 파일들을 서비스하는 CloudFront에 Lambda@Edge를 연결하여, 사용자의 지역과 가까운 Edge Location에서 더욱 빠르게 로직 처리가 가능한 장점이 있습니다. 이 글에서는 CloudFront+S3 환경에서 S3에 저장된 이미지를 Lambda@Edge를 통해서 사용자의 화면에 맞는 사이즈로 리사이즈하는 Lambda@Edge Function을 구성합니다. Lambda@Edge Function 구성과 CI/CD Pipeline 구축 방법에 대해서 알아보겠습니다.
2. 구성 방안
2.1 아키텍처
참고 : https://docs.aws.amazon.com/ko_kr/lambda/latest/dg/lambda-edge.html
Lambda@Edge 가 실행되는 이벤트는 4가지가 있습니다. Origin은 CloudFront에 Cache 될 대상으로 여기서는 S3가 해당됩니다.
● Viewer Request
● Viewer Response
● Origin Request
● Origin Response
이번 구성에서는 Origin Response 이벤트에 Lambda@Edge가 동작하도록 설정하였습니다.
Resize를 할 대상 이미지는 Origin(S3)에 있고, 해당 이미지를 S3에서 Load 하여 Resize 후 CloudFront에 Cache로 저장하게 됩니다.
Cache가 되고 나면, 다음 호출부터는 빠르게 응답할 수 있습니다.
2.2 CloudFront Function vs Lambda@Edge
참고 : https://docs.aws.amazon.com/ko_kr/AmazonCloudFront/latest/DeveloperGuide/edge-functions.html
Lambda@Edge 와 유사한 CloudFront Function이라는 서비스도 있는데요.
CloudFront Function 은 밀리초 미만의 시작 시간을 제공하고, 더 작고 가벼운 함수에 최적화되어있습니다.
최대 메모리 지원과 함수 지속 시간을 고려하여, Lambda@Edge를 사용하게 되었습니다.
큰 이미지 리사이즈 시 함수 지속 시간 제약으로 실행이 제대로 되지 않을 수 있습니다.
Lambda 코드 구성 시 지속시간(timeout)을 30초로 설정하였습니다.
2.3 Lambda@Edge 제약사항
제약사항 리스트는 CloudFront Document에서 가져왔습니다.
• VPC 내부 리소스에 액세스하도록 Lambda 함수 구성
• Lambda 함수 DLQ(Dead Letter Queue)
• Lambda 환경 변수
• AWS Lambda 계층이 있는 Lambda 함수
• AWS X-Ray 사용
• Lambda 예약된 동시성 및 프로비저닝된 동시성
• 컨테이너 이미지로 정의된 Lambda 함수
• arm64 아키텍처를 사용하는 Lambda 함수
• 512MB를 초과하는 임시 스토리지가 있는 Lambda 함수
Lambda@Edge 를 지원하는 언어와 버전은 아래와 같습니다.
• Node.js 16
• Node.js 14
• Node.js 12 이전 버전은 사용이 중지되었고, 12 버전은 곧 중지될 예정입니다.
• Python 3.9
• Python 3.8
CI/CD Pipeline으로 구성할 때 Lambda 함수에서 Import 해야 되는 module들을 Layer로 구성하면 좀 더 쉽게 만들 수 있는데요.
Lambda@Edge 구성할 때는 Lambda 계층(Layer)와 컨테이너 이미지로 Lambda 함수를 정의할 수 없습니다.
Lambda와 비슷한 환경의 컨테이너에서 npm install 을 통해 필요한 모듈들을 설치 후 압축하여 배포하는 방식으로 해결했습니다.
상세한 내용은 CI/CD Pipeline 코드에서 확인하실 수 있습니다.
2.4 Lambda@Edge Resize 코드
Node.js 16버전으로 코드를 구성하였습니다.
w(=width), h(=height), q(=quality), f(=format) 을 파라미터로 사용하여 리사이즈를 합니다.
sharp 모듈의 설치가 필요합니다.
2.5 인프라 구성
인프라의 구성은 terraform 1.2.8 을 이용하였습니다.
디렉토리의 구성은 아래와 같습니다.
2.5.1 Lambda@Edge 구성
Lambda@Edge 는 us-east-1 리전에 구성이 되어야 합니다.
Lambda에서 사용할 Role을 정의하고 할당해 주었습니다.
timeout은 30초로 설정하여 큰 이미지 리사이즈가 가능하도록 했습니다.
2.5.2 CloudFront 구성
origin access identity를 구성하고 CloudFront에 설정합니다.
Lambda@Edge에 전달할 파라미터로 h, w를 설정했습니다.
2.5.3 S3 구성
CloudFront에서 origin access identity를 통해서 접근할 수 있도록 Policy 구성이 필요합니다.
2.6 Gitlab CI/CD Pipeline 구성
Lambda@Edge에서 사용하는 sharp 모듈 설치가 필요합니다.
Lambda@Edge에서 Layer나 container image를 지원하지 않기 때문에
Ubuntu 이미지를 사용한 컨테이너에서 npm install 실행 및 lambda function을 압축하여 deploy 하도록 했습니다.
Alpine 이미지를 사용할 경우 sharp 모듈이 달라서 Lambda@Edge가 제대로 동작하지 않았습니다.
아래의 코드는 .gitlab-ci.yml에 작성합니다.
위와 같이 구성된 코드들을 Gitlab CI/CD Pipeline을 통해서 실행을 하면
lambda_function.zip 파일 생성 후 Terraform으로 인프라 환경을 구성하게 됩니다.
2.7 결과
웹브라우저를 통해서 실행해 보도록 하겠습니다.
w와 h 파라미터로 사이즈를 지정할 수 있습니다.
Cache 되지 않은 요청일 경우에는 Response Header에 “X-Cache: Miss from cloudfront”라고 표시됩니다.
Cache가 된 이후에는 “X-Cache: Hit from cloudfront”를 확인할 수 있습니다.
3. 마무리
지금까지 Lambda@Edge를 통해서 이미지 리사이즈 처리를 해봤습니다.
Lambda보다 제약사항이 많은 관계로 구성이 조금 더 힘들었는데요.
Lambda@Edge를 통해서 최종 사용자와 가까운 영역에서 로직 처리를 하고
CloudFront의 Cache 기능을 이용하기 때문에 더욱 빠른 응답을 받을 수 있었습니다.
글로벌 사용자를 대상으로 하는 시스템이라면 더욱 큰 도움이 될 것 같습니다.