본문 바로가기
프로젝트 개발 기록/[개발] java | spring

[AWS S3+Lambda] 이미지 처리 2탄: Image Resizing으로 썸네일 이미지 만들기

by HelloJudy 2023. 6. 28.

📷 이미지 처리

1탄에서는 pre-signed URL을 이용해서 이미지 업로드를 구현했다.
근데 실제로 우리가 화면에서 이미지를 보여줄 때 원본 이미지 파일을 전부 보여주기엔 파일이 너무 크다.
그래서 리사이징을 함으로써 데이터를 전송하는 과정에서도 더 효율적으로 서버를 운영하고, 프론트에서
이미지를 렌더링 할 때의 시간도 줄여보자.
 

📑 목차

[AWS S3] 이미지 처리 1탄: Pre-signed URL로 파일 업로드 구현
[AWS S3+Lambda] 이미지 처리 2탄: Image Resizing으로 썸네일 이미지 만들기 - 현재 포스팅

 

 

 

💭 고민

이미지 리사이징을 어떻게 구현할지 고민했다.
 

[ 리사이징 시기 ]

  1. Resize during Upload
  2. On-demand Resize

 
이미지를 요청할 때 리사이즈해 줄지, 업로드하는 요청이 트리거 됐을 때 리사이즈해 줄지 고민됐다.
근데 저장할 때 리사이즈해서 저장하면 용량이 두 배가 돼~~ 두두두배가 돼~~
 
 
[ Amazon S3 이미지 온디맨드 리사이징을 통한 70% 서버 비용 줄이기 - AWS Summit Seoul 2017 ]
 
해당 글에서는 원본 파일을 가지고 있다가 이미지 요청(GET) 시 리사이징해서 보내주었다. 이렇게 하면 썸네일 이미지를 따로 저장할 필요가 없다. 하지만 고민 끝에 현재 서비스 피드에서는 대부분의 경우 썸네일 이미지를 사용하고, 기본 사이즈가 정해져 있다.
여러 가지 크기로 썸네일을 만드는 경우에는 온디맨드 리사이징이 효율적이겠지만, 현재 한 가지의 크기로 리사이징 할 것이기 때문에 일단 썸네일 이미지를 저장하는 것으로 결정했다. (추후에 바꿀 수도~)
 

 
 

🪄 AWS Lambda

AWS Lambda는 서버를 프로비저닝 또는 관리하지 않고도 실제로 모든 유형의 애플리케이션 또는 백엔드 서비스에 대한 코드를 실행할 수 있는 이벤트 중심의 서버리스 컴퓨팅 서비스

 
람다를 활용해서 이미지 리사이징을 구현하려고 한다.
전체적인 Flow는 'S3 버킷에 이미지가 업로드되면 Lambda에 Trigger 돼서 함수를 실행해서 썸네일 이미지를 생성해서 업로드'이다.
 
1. S3 버킷에 이미지 업로드 (original/ 경로에 업로드)
2. S3 오브젝트 업로드 이벤트 발생
3. S3 Trigger가 발생해서 람다 함수 실행
4. 람다 함수에서 이미지를 리사이징 한 다음 thumb/ 경로에 이미지 업로드
 

 

1. 리사이징 코드 작성

간편하게 코드를 작성하기 위해서 리사이징 코드는 node.js로 작성했다.
 
🐰 : 아아 만능 토끼🐰 스프링과 노드를 넘나 든다~
🤖 : 하나라도 제대로 하지?
 
코드 작성은 해당 레포를 참고해서 작성했다.
 

[ 모듈 설치 ]

우선 필요한 모듈을 설치하자!

npm install aws-sdk
npm install --platform=linux --arch=x64 sharp

 

[ index.js ]

경로를 수정해서 리사이징 이미지를 저장했다.

const AWS = require('aws-sdk');
const sharp = require('sharp');

const s3 = new AWS.S3();

exports.handler = async (event, context, callback) => {
   const Bucket = event.Records[0].s3.bucket.name;
   const Key = event.Records[0].s3.object.key;
   const s3obj = { Bucket, Key };

   const newKey = Key.replace("original/", "thumb/"); // 리사이징 된 이미지를 thumb 폴더에 저장

   try {
      //* 객체 불러오기
      const s3Object = await s3.getObject(s3obj).promise(); // 버퍼로 가져오기
      console.log('original size', s3Object.Body.length);

      //* 리사이징
      const resizedImage = await sharp(s3Object.Body)
         .resize(200, 200, { fit: 'inside' })
         .toFormat(requiredFormat)
         .toBuffer();

      //* 객체 넣기
      await s3
         .putObject({
            Bucket,
            Key: newKey,
            Body: resizedImage,
         })
         .promise();
      console.log('put', resizedImage.length);

      // //* 기존 객체 삭제
      // await s3.deleteObject(s3obj).promise();
      // console.log('del origin img');

      // Lambda 함수 내부에서 모든 작업을 수행한 후에는 그에 대한 결과(또는 오류)와 함께 callback 함수를 호출하고 이를 AWS가 HTTP 요청에 대한 응답으로 처리한다.
      return callback(null, newKey);
   } catch (error) {
      console.error(error);
      return callback(error);
   }
};

 
node_modules까지 압축한다.

zip -r img_resizing_function.zip .

 
 

2. Lambda 설정

1) 함수 생성

우선 AWS Lambda로 가서 함수를 생성한다.

 

2) 함수 코드 파일 업로드

 
node_modules까지 압축해서 용량이 커서 S3에 업로드하고 람다에서 업로드했다.

 

3) 트리거 추가

 
트리거는 S3에서 연결할 수도 있고, 람다에서 연결할 수도 있다.
난 람다에서 추가해 보겠다.

 
람다 함수 인풋 아웃풋 버킷을 같이 쓸거라 경로를 나눠줬다. original에 업로드 트리거됐을 때 함수 실행되도록 한다.
같은 버킷을 사용하기 때문에 original/ 트리거를 걸었다.
접두사를 안 두면 같은 버킷을 쓰고 있기 때문에 썸네일 이미지가 업로드 됐을 때도 트리거가 걸려서 재귀에 빠질 수 있다.
 

 
다음과 같이 thumb 폴더 아래 이미지가 생성된 것을 확인할 수 있다.

 
 


번외 : 🐛 Error 해결

 
sharp 설치 이거 좀 화난다^^..
설치해 줬는데 계속 에러 나서 npm install sharp가 아니라 아래 형태로 설치해서 해결했다..! 총총총

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

 
 


📌 Reference

 

반응형

댓글