Infra

S3, CloudFront, Lambda@Edge를 이용한 이미지 리사이즈(5) - Lambda@Edge 배포 셋팅 및 로그 확인

연_우리 2023. 5. 28. 20:45
반응형

목차

     

     

     

     

    이 게시글은 시리즈물입니다!
    아래 목차를 먼저 확인해주세요

    1. Lambda@Edge란?
    2. S3, CloudFront 셋팅
    3. CloudFront 쿼리스트링 캐시 셋팅
    4. IAM 역할 생성
    5. Lambda@Edge 배포 셋팅 및 로그 확인
    6. 리사이징 로직 작성 및 테스트

     

     

     

     

    프로젝트 셋팅

    • serverless framework를 사용하여 람다를 배포할 예정입니다.
    • 이미 존재하는 S3와 CloudFront에 Lambda@Edge를 연결하므로
      serverless-lambda-edge-pre-existing-cloudfront 플러그인을 사용합니다.
     

    Serverless Framework: Plugins

    The Serverless Framework Plugin Registry. Search thousands of Serverless Framework plugins.

    www.serverless.com

    링크를 참조해서도 설정할 수 있는데,
    CloudFront 배포 구성단계에서 사용하는 "resources: Resources:" 설정을 사용하면
    람다를 배포함과 동시에 클라우드프론트도 제거되었다가 새로 생성되는 것 같습니다....
    자세한 원인은 모르겠다...

     

     

     

     

     

    Serverless 설치

    1. 명령어 입력

    npm install -g serverless

     

     

    프로젝트 폴더 생성

    serverless
    • 템플릿 : AWS - Node.js - Starter
    • 프로젝트명 : serverless-lambda-edge-image-resize

    서버리스 프로젝트를 만들고나면 아래와 같이 4개의 파일이 생성됩니다.

    index.js : 람다에서 수행될 비즈니스 로직이 작성될 파일

    serverless.yml : 람다 배포 시 필요한 셋팅 파일

     

     

    node 모듈 관리를 위해 npm init 수행

    npm init

     

     

     

     

     

     

     

    배포 셋팅

    람다와 클라우드 프론트가 잘 연결되는지 확인하기 위해 람다에 console.log()만 찍어서 배포해봅니다.

     

     

    index.js 수정

    serverless.yml파일의 provider.runtime이 nodejs18.x로 되어있다면

    index.js에 module.exports.handler, require는 더이상 사용할 수 없습니다.

    또한 package.json에 type필드가 module로 지정되어야만 ES6방식으로 처리됩니다.

     

     

    1. 링크 참고하여 index.js 수정

    2. 어떤 함수인지 명확히 나타내기 위해 함수명 handler → imageResize로 수정

    //node 16 : CommonJS 방식
    exports.imageResize = async function (event, context) { ~ };
    
    //node 18 : ES6 방식
    export const imageResize = async (event, context) => { ~ };

    3. 링크 참고하여 package.json에 type:module 추가

    //package.json
    {
      "name": "serverless-lambda-edge-image-resize",
      "version": "1.0.0",
      "type": "module",
      "description": "<!-- title: 'AWS Simple HTTP Endpoint example in NodeJS' description: 'This template demonstrates how to make a simple HTTP API with Node.js running on AWS Lambda and API Gateway using the Serverless Framework.' layout: Doc framework: v3 platform: AWS language: nodeJS authorLink: 'https://github.com/serverless' authorName: 'Serverless, inc.' authorAvatar: 'https://avatars1.githubusercontent.com/u/13742415?s=200&v=4' -->",
      "main": "index.js",
      "scripts": {
        "test": "echo \"Error: no test specified\" && exit 1"
      },
      "author": "",
      "license": "ISC",
      "devDependencies": {
        "serverless-lambda-edge-pre-existing-cloudfront": "^1.2.0"
      }
    }

    4. 람다함수에 console.log문 작성

    실제로 event객체에 어떤 값이 들어오는지 클라우드 워치에서 확인할 예정입니다.

    여기에서도 확인할 수 있다.

    export const imageResize = async (event, context) => {
        console.log("serverless-lambda-edge-image-resize 실행!");
        console.log(JSON.stringify(event));
        const res = event.Records[0].cf.response;
    
        return res;
    };

     

     

    플러그인 설치

    • 명령어 입력하여 설치
    npm install --save-dev serverless-lambda-edge-pre-existing-cloudfront

    #serverless.yml
    
    service: serverless-lambda-edge-image-resize
    frameworkVersion: '3'
    plugins:
      - serverless-lambda-edge-pre-existing-cloudfront
    
    provider:
      name: aws
      runtime: nodejs18.x
      region: us-east-1 #lambda@edge는 북미서버에만 등록 가능하다.
      iam:
        role: 'arn:aws:iam::~'
    
    functions:
      imageResize:
        name: 'serverless-lambda-edge-image-resize'
        handler: index.imageResize #index.js 파일의 imageResize 함수를 바라본다
        events:
          - preExistingCloudFront:
              distributionId: E3AICXLJSBYDFW #s3-lambda-edge-image-resize의 cloudfront id값 입력
              eventType: origin-response
              pathPattern: '*'
              includeBody: false
    • provider > iam > role : 람다가 실행될 수 있도록 이전에 만들었던 iam의 arn을 입력합니다.
    • handler > index.Resize : index.js파일의 imageResize함수를 바라보도록 입력합니다.
    • events > preExistingCloudFront
      • distributionId : 이전에 만들었던 cloudfront의 id값을 입력합니다.
      • eventType: origin-response를 입력해두었으니 캐싱처리되지 않은 이미지를 호출할때 람다가 호출됩니다.                              eventType에 대한 더 자세한 내용은 링크를 참조해주세요.

     

     

     

     

     

     

    배포

    • 배포 명령어를 입력하고 기다리면 2번째 사진처럼 성공 메시지가 출력됩니다.
    serverless deploy

     

    • 버지니아 북부리전 > Lambda > 함수 > serverless-lambda-edge-image-resize

    • 버전 > 최신버전 클릭

     

    • 가장 최신버전에 트리거로 CloudFront가 잡혀있는지 확인

     

     

     

     

     

    테스트

    F12를 눌러 개발자도구를 켜놓고, 우리가 연결한 클라우드 프론트로 이미지 파일을 호출하면 람다가 수행되는지 확인해봅시다.

    * 만약 X-Cache가 Hit from cloudfront로 되어있다면, 클라우드프론트로 한번도 호출하지 않은 이미지 파일을 호출해주세요. 

    Miss로 응답받았으니 클라우드워치에서 로그를 확인합니다.

     

     

     

     

     

    클라우드워치 로그 확인

    제가 가장 해맨 부분 중 하나입니다,... 눈 크게 뜨고 봐주세요

     

     

    로그 저장되는 리전 주의

    기존에 람다를 사용해보신 분들이라면 람다 함수의 "테스트" 메뉴에 대해 알고계실겁니다.

    위처럼 템플릿을 cloudfront-modify-querystring으로 선택하고 테스트버튼을 누르면

    실행 성공으로 뜨며 로그를 볼수있는 링크가 나오는데, 해당 로그는 버지니아 리전에 저장된 것을 볼 수 있습니다.

    (이벤트 JSON에 있는 uri도 /test로 동일함)

     

     

    하지만 CloudFront를 통해 수행된 람다의 로그는... 서울리전에 저장됩니다.

     

    생각해보면 당연합니다

    람다엣지는 버지니아 리전에 만들어두면 AWS가 전 세계 리전에 자동으로 복사해주고, 

    클라우드 프론트는 내 위치에서 가장 가까운 리전에서 실행될테니..

    람다엣지도 내 위치에서 가장 가까운 리전에서 실행되겠죠!

     

    공식문서 에도 나와있습니다

     

     

    Miss와 Hit에 따른 로그 출력 확인

    어쨋든 위에서 호출한 /lucy.jpg에 대한 로그가 찍혀있으면 람다가 잘 수행된것입니다.

     

    혹시 모르니 다시한번 /lucy.jpg를 호출해봅시다

     

    이번엔 Hit이 떴으니 람다가 수행되면 안됩니다. 클라우드 워치에 로그가 찍혔는지 봅시다.

     

    Miss일때만 람다가 실행되고, Hit일때는 람다가 실행되지 않는 것을 보니 이벤트 타입에 맞게 잘 동작하네요! 

     

     

     

     

     

     

     

    반응형
    • 네이버 블러그 공유하기
    • 페이스북 공유하기
    • 트위터 공유하기
    • 구글 플러스 공유하기
    • 카카오톡 공유하기