Rust AXUM+MongoDB로 RestAPI 서버 개발하기 - AWS Lambda 활용 이미지 리사이징
AWS Lambda를 활용하여 Amazon S3에 업로드된 이미지를 자동으로 리사이징하는 과정을 자세히 다룹니다. 이 기능은 서버리스 아키텍처를 통해 이미지 처리를 자동화하여 리소스 사용을 최적화하고, 응용 프로그램의 성능을 향상시킬 수 있습니다. AWS Lambda와 S3 버킷 간의 연동 방법부터 실제 이미지 처리 로직의 구현까지, 단계별로 알아보겠습니다.
0. 리소스 최적화의 중요성
이번 편에서는 AWS Lambda를 이용해 S3 버킷에 업로드된 이미지 파일을 자동으로 리사이징하는 방법을 살펴봅니다. 이 과정은 효율적인 이미지 관리를 가능하게 하며, 웹사이트의 로딩 시간을 줄이고 사용자 경험을 향상시키는 데 중요한 역할을 합니다.
1. AWS Lambda와 S3 트리거 설정, S3 권한 부여
AWS Lambda는 서버리스 컴퓨팅 서비스로, 서버 관리 없이 코드를 실행할 수 있습니다. Amazon S3와 Lambda를 연동하면, S3 버킷에 파일이 업로드되거나 변경될 때마다 자동으로 Lambda 함수가 트리거됩니다.
- Lambda 함수 생성: AWS Management Console에서 Lambda 함수를 생성합니다. 함수 생성 시, Node.js 환경을 선택하여 생성합니다.
- S3 트리거 설정: 생성한 Lambda 함수에 S3 트리거를 추가합니다. 트리거 설정 시 소스는 S3, 버킷은 이전에 생성해둔 버킷을 선택하고 이벤트 유형은 PUT을 선택합니다. 이렇게 설정하면, 해당 버킷에 새 이미지가 업로드될 때마다 Lambda 함수가 호출됩니다.
raw/ 폴더에 대해서 PUT이벤트가 발생했을 때만 실행하도록 트리거를 설정합니다.
- Lambda에 S3권한 부여: [구성] - [권한]에서 역할 이름을 클릭하여 S3 정책을 추가합니다.
s3fullaccess를 검색하여 권한을 추가해줍니다.
3. Lambda 함수 구현
Lambda 함수는 Node.js로 구현되며, 이미지 처리를 위한 로직을 포함합니다. (Node.JS 환경 구성 필요)
npm init
: lambda 폴더를 만들고 해당 폴더 내부에서 터미널에npm init
커맨드로 package.json을 생성합니다.
관련 의존성 라이브러리를 설치하기 위해 다음 명령어를 입력합니다.
npm install --platform=linux --arch=x64 sharp
npm install --os=linux --cpu=x64 aws-sdk
- `index.js` 파일을 생성한 뒤 다음의 내용을 입력합니다.
- 이미지 처리 라이브러리:
sharp
라이브러리를 사용하여 이미지를 리사이징하고 최적화할 수 있습니다. - 함수 로직 구현: 업로드된 이미지를 읽어서 리사이징 후, 같은 S3 버킷 내 w140과 w600에 저장하는 로직을 작성합니다.
- 참고: w140 로직은 이미지를 원형으로 마스킹한 뒤 배경을 없애는 로직이기 때문에 필요없다면 지우셔도 됩니다.
const sharp = require("sharp");
const AWS = require("aws-sdk");
const s3 = new AWS.S3();
const transformationOptions = [
{ name: "w140", width: 140, circle: true },
{ name: "w600", width: 600, circle: false },
];
exports.handler = async (event) => {
try {
const Key = event.Records[0].s3.object.key;
const keyOnly = Key.split("/")[1];
console.log(`Image Resizing: ${keyOnly}`);
const image = await s3
.getObject({ Bucket: "travelers-companion", Key })
.promise();
await Promise.all(
transformationOptions.map(async ({ name, width, circle }) => {
const newKey = `${name}/${keyOnly}`;
let resizedImage = sharp(image.Body, { failOn: "truncated" })
.png()
.rotate();
if (circle) {
const radius = width / 2;
const circleSVG = Buffer.from(
`<svg><circle cx="${radius}" cy="${radius}" r="${radius}" fill="#fff"/></svg>`
);
resizedImage = resizedImage
.resize({ width, height: width, fit: "cover" })
.composite([{ input: circleSVG, blend: "dest-in" }]);
} else {
resizedImage = resizedImage.resize({
width,
height: width,
fit: "cover",
});
}
const output = await resizedImage.toBuffer();
await s3
.putObject({
Bucket: "travelers-companion",
Body: output,
Key: newKey,
})
.promise();
})
);
return {
statusCode: 200,
body: event,
};
} catch (err) {
console.error(err);
return {
statusCode: 500,
body: JSON.stringify(err),
};
}
};
- 압축: node_modules, index.js, package.json, package-lock.json 을 압축하여 하나의 파일로 만듭니다.
- Lambda에 업로드: 에서 업로드를 클릭하고, zip파일로 업로드를 통해 코드를 업로드합니다.
4. 테스트 및 검증
함수의 정상 작동을 확인하기 위해, S3 버킷에 다양한 크기와 형식의 이미지 파일을 업로드해보고, 리사이징된 이미지가 올바르게 저장되었는지 검사합니다.
raw폴더에 이미지를 업로드한 뒤, lambda가 올바르게 실행되었는지 확인합니다.
Lambda 함수 내 모니터링에서 CloudWatch Logs 보기를 통해 실행 결과를 확인할 수 있습니다.
여기서 이미지가 업로드될 때마다 로그로 남게 되고, 해당 부분을 확인하면서 디버깅하면 됩니다.
5. 결론
AWS Lambda를 사용한 이미지 리사이징은 서버리스 아키텍처를 활용하여 비용을 절감하고 애플리케이션의 성능을 향상시킬 수 있는 효과적인 방법입니다. 다음 편에서는 사용자 관리 및 JWT 기반 인증을 구현하는 방법을 알아볼 예정입니다.
추가적으로, 업로드되는 이미지의 크기가 너무 큰 경우에 제한시간이나 메모리가 부족해서 람다가 정상적으로 실행되지 않을 수 있습니다.
[구성] - [일반 구성]에서 편집을 통해 제한시간과 메모리, 임시스토리지 등등을 늘려주면서 확인하시면 됩니다.
저는 메모리는 512MB까지 늘렸고 제한시간을 30초 정도로 늘려놓았습니다.
frontend에서 이미지를 불러올 때 기본적으로 제공하는 버킷 URL이 아닌 cloudfront 설정 후 해당 URL로 접속할 수 있도록 하여 보안성과 캐싱을 통한 효율적인 비용관리를 할 수 있습니다.
문제가 있는 부분이 있다면 댓글 남겨주세요.