반응형
AWS Lambda@edge로 실시간 이미지 리사이징
Lambda@Edge는 Amazon CloudFront의 기능 중 하나로서, 서버를 프로비저닝하고, 코드를 AWS Lambda에 업로드하고 요청에 대한 응답으로 함수가 사용자에게 좀 더 가까운 위치(리전)에서 트리거 되도록 구성할 수 있다.
프로비저닝: 사용자의 요구에 맞게 시스템 자원을 할당, 배치, 배포해 두었다가 필요 시 시스템을 즉시 사용할 수 있는 상태로 미리 준비해 두는 것
이러한 Lambda@Edge를 이용해서 쿼리스트링으로 옵션을 받아 실시간으로 이미지 크기(width, height)와 품질(quality), 파일 형식(format)등을 변경할 수 있도록 구성하고자 한다.
구현하고자 하는 기능
- width, height 값으로 이미지 크기 조절 가능
- 원본의 비율을 유지한 채 입력된 값으로 최대 이미지 크기 생성
- 해당 옵션 중 하나만 입력하면 그 값을 기준으로 이미지 비율 유지한 응답
- 옵션 둘 다 미입력 시, 원본 사이즈 그대로 퀄리티만 조정
- quality 조절 가능
- default 90으로 설정하여 퀄리티 옵션이 오지 않을 경우에도 90%의 품질로 응답
- format변경 가능
- format=webp로 주게 되면 webp형식으로 변환해서 반환
정책 생성: 람다를 CloudFront 배포와 연결하기 위해
- 정책 생성 선택
- Json을 선택하고 아래 정책 입력
- 정책 이름과 설명 작성
- 정책 생성
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "VisualEditor0",
"Effect": "Allow",
"Action": [
"iam:CreateServiceLinkedRole",
"lambda:GetFunction",
"lambda:EnableReplication",
"cloudfront:UpdateDistribution",
"s3:GetObject",
"logs:CreateLogGroup",
"logs:CreateLogStream",
"logs:PutLogEvents",
"logs:DescribeLogStreams"
],
"Resource": "*"
}
]
}
역할 생성
- 역할 만들기 선택
- '이 역할을 사용할 서비스'로 Lambda선택
- 목록 중 위에서 생성한 정책 선택
- 역할의 이름과 설명 작성
- 역할 만들기
역할의 신뢰 관계 수정
- 나의 역할 목록에서 방금 생성한 역할(ResizingImages) 선택
- 신뢰 관계 탭 - 신뢰 관계 편집 선택
- 아래의 신뢰 관계 정보 입력
- 신뢰 정책 업데이트
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Service": [
"edgelambda.amazonaws.com",
"lambda.amazonaws.com"
]
},
"Action": "sts:AssumeRole"
}
]
}
Lambda 함수 생성
- Lambda@Edge의 리전은 미국 동부(버지니아 북부)(us-east-1)만 허용되므로 리전 선택 주의
- 함수 생성 선택
- 함수 이름 입력
- 런타임(Node.js 최신버전) 선택
- 실행 역할 - 기존 역할 사용 선택
- 앞에서 만든 역할 선택
- 함수 생성
Cloud 9을 이용한 Lambda 함수 작성
- sharp 패키지를 설치해주어야 하기때문에 클라우드나인을 이용
람다에서 불러온 index.js에 코드 작성
'use strict';
const querystring = require('querystring');
const AWS = require('aws-sdk');
const Sharp = require('sharp');
const S3 = new AWS.S3({region: 'ap-northeast-2'});
const BUCKET = 'resize-imgage';
const allowedExtension = [ "jpg", "jpeg", "png", "webp" ];
const MAX_WIDTH = 1200;
const MAX_HEIGHT = 1200;
const DEFULT_QUALITY = 90;
exports.handler = async (event, context, callback) => {
const { request, response } = event.Records[0].cf;
const params = querystring.parse(request.querystring);
const { uri } = request;
const [, imageName, extension] = uri.match(/\/?(.*)\.(.*)/);
if (!allowedExtension.includes(extension)) {
console.log(`${extension} is not allowed`);
response.status = 400;
response.headers['content-type'] = [{ key: 'Content-Type', value: 'text/plain' }];
response.body = `${extension} is not allowed`;
return callback(null, response);
}
let s3Object;
let KEY = decodeURI(imageName + '.' + extension)
try {
s3Object = await S3.getObject({
Bucket: BUCKET,
Key: KEY
}).promise();
} catch (error) {
response.status = 404;
response.headers['content-type'] = [{ key: 'Content-Type', value: 'text/plain' }];
response.body = `Bad Request: contents is not found`;
return callback(null, response);
}
let resizedImage;
let quality = parseInt(params.quality, 10) ? parseInt(params.quality, 10) : DEFULT_QUALITY;
let format = params.format ? params.format : extension;
format = format === 'jpg' ? 'jpeg' : format;
quality = format === 'webp' ? 100 : quality;
let width = parseInt(params.width, 10) ? parseInt(params.width, 10) : null;
let height = parseInt(params.height, 10) ? parseInt(params.height, 10) : null;
try {
resizedImage = await Sharp(s3Object.Body)
.resize(width, height, {fit: 'inside'})
.toFormat(format, {quality, alphaQuality: 90})
.toBuffer();
} catch (error) {
console.log('Sharp: ', error);
return callback(error);
}
response.status = 200;
response.body = resizedImage.toString('base64');
response.bodyEncoding = 'base64';
response.headers['content-type'] = [{ key: 'Content-Type', value: `image/${format}` }];
return callback(null, response);
};
sharp 패키지 설치
- 람다 폴더로 이동 후 패키지 설치
$ cd ResizeImage
$ npm init -y
$ npm install sharp
작성한 함수 람다로 업로드
- 폴더 우클릭 - 임포트 람다 클릭
ColudFront 배포 생성
Lambda@Edge 배포
- 상단 메뉴에 작업 > Lambda@edge 배포를 클릭
- cloudfront arn으로 찾아 선택 후 아래와 같이 세팅
테스트
- {cloudFont host}/{s3 image 경로}?width=800&height=600
반응형
'기타 공부들' 카테고리의 다른 글
리팩토링 시점과 절차, 리팩토링이 필요한 이유 (2) | 2024.01.04 |
---|---|
Mac OS에서 JDK 11 설치 & Error: `brew cask` is no longer a `brew` command. 해결 (0) | 2022.03.22 |
Mac 에 brew 설치하기 & warning: /opt/homebrew/bin is not in your path. 해결 (0) | 2022.03.22 |
Web Server, WAS 차이점 (0) | 2021.11.29 |
행렬 기본 연산(덧셈, 뺄셈, 곱셈, 전치행렬, 역행렬) 정리 (0) | 2021.11.10 |