이번 포스트는 CloudFront ( AWS CDN )과 Lambda 그리고 S3를 이용해서 온디맨드 이미지 서버를 만드는 과정을 기록하려고 한다.
온디맨드 이미지 서버란?
기존 이미지 서버에서는 이미지를 업로드하는 프로세스 중에 리사이징을 하고 각 사이즈의 이미지 파일도 저장을 하였다.
그 결과는 S3의 저장 증가와 새로운 사이즈의 타입이 추가되었을때 문제가 되었다.
그래서 이미지를 저장할때, 원본의 이미지를 바로 저장하고. GEt 요청할 때마다 원하는 타입의 사이즈로 리사이징 하여 이미지를 제공한다.
단, 매 요청마다 리사이징을 하게 되면 서버의 연산 과부화가 발생하기에 CloudFront와 같은 CND 캐싱 기능을 통해 최초 1회 리사이징 하여 응답한 이미지는 캐싱 처리한다.
순서는 아래와 같다.
1. IAM 정책 및 역할 생성
2. S3 생성
3. Lambda 함수 생성
4.Cloud9 AWS IDE로 Lambda함수 작성 및 업로드
5. Lambda함수 새 버전 게시 및 Edge배포(CloudFront)
1. IAM 정책 및 역할 생성
IAM이란?
AWS Identity and Access Management(IAM)은 AWS 리소스에 대한 액세스를 안전하게 제어할 수 있는 웹 서비스입니다. IAM을 사용하여 리소스를 사용하도록 인증(로그인) 및 권한 부여(권한 있음)된 대상을 제어합니다.
1-1. 정책 생성
1. AWS IAM 콘솔에서 사이드 바 메뉴 "액세스 관리" - "정책" 메뉴로 이동.
2. 정책 생성
3. 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": "*" } ] } |
3. "다음:태그" 버튼으로 다음 이동.
4. 태그는 생략.
5. 정책 이름 "ResizingImagePolicy"
6. 정책 생성.
1-2. 역할 생성
1. AWS IAM 콘솔에서 사이드 바 메뉴 "액세스 관리" - "역할" 메뉴로 이동.
2. "역할 만들기" 버튼 클릭
3. 신뢰할 수 있는 엔터티 유형 "AWS 서비스" 선택, 사용 사례 Lambda 선택 후 "다음"
4. 권한 추가 화면에서 이전에 생성한 정책 선택 후 오른쪽 아래 "다음"
5. 역할 이름 "ResizingImageRole", 1단계 신뢰할 수 있는 엔터티 아래와 같이 편집해서 작성
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Service": [
"edgelambda.amazonaws.com",
"lambda.amazonaws.com"
]
},
"Action": "sts:AssumeRole"
}
]
}
6. 오른쪽 아래 "역할 생성" 버튼
2. S3 생성
1. AWS S3 콘솔에서 S3 버킷 만들기
2. 버켓 이름 입력
3. 리전은 서울!
4. 이 버킷의 퍼블릭 액세스 차단 설정 체크 다 풀기
5. 버킷 만들기.
6. 버킷에 "dev", "prod" 폴더 만들기
3. CloudFront 생성 및 동작 생성
3-1. CloudFront 배포
1. AWS CloudFront 콘솔로 이동
2. 배포 생성 아래와 같이 세팅
3. 배포 생성
4. 배포된 CloudFront 상세 화면에서 "원본" 탭 - 원본 선택 후 편집
5. 정책 복사 (CloudFront에서 S3로 액세스 할 수 있도록 정책을 복사하고 S3에 등록해야 한다. S3 액세스 권한을 아까 모두 해제했기 때문에.)
6. S3 콘솔로 이동하여 버킷 상세 화면에서 "권한" 탭에 버킷 정책에 붙여 넣는다.
3-2. 동작 생성
1. CloudFront 배포한 상세 페이지에 동작 탭으로 이동하여 동작을 생성해준다.
2. ClounFront 배포할 때와 정말 동일하다 단, 경로 패턴만 제외! 아래와 같이 작성하고 동작 생성한다.
3. dev/* 에 대한 동작을 생성하였으니 prod/*에 대한 동작도 생성해준다.!!
4. S3 버킷 "dev"에 이미지를 업로드하고 CloudFront 주소로 S3 이미지에 접근해본다.
ex) https://cloudfront_domain/dev/test.jpg
4. Lambda 함수 생성
중요! 반드시 버지니아 북부(us-east-1)에서 생성할 것!! ( Lambda@Edge 가 버지니아 북부에서만 지원! )
1. AWS Lambda 콘솔로 이동
2. 함수 생성
3. 새로 작성 박스 선택
4. 함수 이름 "resize-image"
5. 런타임 "Node.js 14.x" 선택
6. 기본 실행 역할 변경 - 기존 역할 사용 - 이전에 생성한 역할 규칙 선택
7. 함수 생성
8. 생성된 함수 상세 화면에서 "구성" 탭 - "일반 구성" 편집으로 제한 시간은 10초 변경
5.Cloud9 AWS IDE로 Lambda함수 작성 및 업로드
5-1. Cloud9 Ec2 인스턴스 생성
1. AWS Cloud9 콘솔로 이동
2. Create Environment 버튼으로 환경 생성
3. 이름 "resize-image"
4. 모두 기본으로 생성
5. 잠시 기다리면 Cloud9이 실행됩니다.
5-2. 생성된 Cloud9 인스턴스로 Lambda로 실행될 함수를 작성
1. 실행된 Cloud9 왼쪽 사이드 메뉴에 AWS 선택 - US East - Lambda - resize-image - 오른쪽 클릭 - 다운로드
2. 디렉터리 선택은 기본으로 resize-image
** Cloud9는 EC2이다 그래서 Cloud9 서버에 다운로드할 건데 어느 디렉터리인지를 물어보는 것
3. 사이드 메뉴 폴더 누르면 resize-image 폴더에 뭔가가 다운로드됨. ( 저는 node-modules, package.json 등 몇 가지 파일이 더 있습니다. -> 4번 진행하면 됨. )
4. 아래 콘솔에 아래 명령어 입력
cd resize-image
npm init -y
위 명령어 중 npm init -y 입력하시면 3번 절차와 같이 node_modules, package~ 등 파일이 생성됩니다.
5. 아래 명령어로 sharp 라이브러리 설치 sharp 라이브러리가 이미지를 리사이징 해주는 아주 좋은 라이브러리입니다.
npm i sharp
6. index.js 파일을 아래 소스로 수정 후 컨트롤 S로 저장 ( 주의!!!*** 10번 라인에는 자신이 생성한 S3 이름으로 수정할 것 )
'use strict';
const querystring = require('querystring'); // Don't install.
const AWS = require('aws-sdk'); // Don't install.
const Sharp = require('sharp');
const S3 = new AWS.S3({
region: 'ap-northeast-2'
});
const BUCKET = 's3 name';
exports.handler = async (event, context, callback) => {
const { request, response } = event.Records[0].cf;
// Parameters are w, h, f, q and indicate width, height, format and quality.
const params = querystring.parse(request.querystring);
// Required width or height value.
if (!params.w && !params.h) {
return callback(null, response);
}
// Extract name and format.
const { uri } = request;
const [, imageName, extension] = uri.match(/\/?(.*)\.(.*)/);
// Init variables
let width;
let height;
let format;
let quality; // Sharp는 이미지 포맷에 따라서 품질(quality)의 기본값이 다릅니다.
let s3Object;
let resizedImage;
// Init sizes.
width = parseInt(params.w, 10) ? parseInt(params.w, 10) : null;
height = parseInt(params.h, 10) ? parseInt(params.h, 10) : null;
// Init quality.
if (parseInt(params.q, 10)) {
quality = parseInt(params.q, 10);
}
// Init format.
format = params.f ? params.f : extension;
format = format === 'jpg' ? 'jpeg' : format;
// For AWS CloudWatch.
console.log(`parmas: ${JSON.stringify(params)}`); // Cannot convert object to primitive value.
console.log(`name: ${imageName}.${extension}`); // Favicon error, if name is `favicon.ico`.
try {
s3Object = await S3.getObject({
Bucket: BUCKET,
Key: decodeURI(imageName + '.' + extension)
}).promise();
} catch (error) {
console.log('S3.getObject: ', error);
return callback(error);
}
try {
resizedImage = await Sharp(s3Object.Body)
.resize(width, height)
.toFormat(format, {
quality
})
.toBuffer();
} catch (error) {
console.log('Sharp: ', error);
return callback(error);
}
const resizedImageByteLength = Buffer.byteLength(resizedImage, 'base64');
console.log('byteLength: ', resizedImageByteLength);
// `response.body`가 변경된 경우 1MB까지만 허용됩니다.
if (resizedImageByteLength >= 1 * 1024 * 1024) {
return callback(null, response);
}
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);
};
7. 왼쪽 메뉴 AWS - US East - Lambda - resize-image 오른쪽 클릭 Upload Lambda 클릭
8. 이후에 나오는 팝업 전부 Yes
6. Lambda함수 새 버전 게시 및 Edge배포(CloudFront)
Lambda 함수 작성 후 Upload Lambda를 하게 되면 알아서 최신 새 버전의 Lambda가 게시가 된다.
확인하는 방법은 Lambda 콘솔로 이동하여 "resize-image" 함수 상세 화면에 버전 탭이 있다.
1. Lambda@Edge 배포하기 resize-image 함수 상세화면에서 아래 이미지와 같이 작업- Lambda@Edge 배포를 한다.
주의할 점은 CloudFront event가 응답이라는 것이다. 추가로 Cache behavior는 입력하는 게 아닌 CloudFront에서 생성해준 동작을 선택하는 것이다 리스트가 안 뜬다면 CloudFront 동작 생성 부분이 이상한 것..
2. dev/*, prod/* 둘 다 배포를 해주고 나면 resize-image 버전에 들어가서 해당 버전의 상세 화면에 아래와 같이 CloudFront 트리거가 추가된 것들 확인할 수 있다.
3. 이제 https://cloudfront_domain/dev/test.jpg? h=200&w=200을 호출해서 제대로 리사이징 되고 다시 호출했을 때 캐싱되었는지도 확인.!!
끝...
'인프라' 카테고리의 다른 글
GitHub 계정 액세스 토큰 발급 받기. (0) | 2023.10.27 |
---|---|
Jenkins + git/bitbucket + docker CI/CD 구축 이야기 (0) | 2022.06.22 |