1. S3 버킷 생성하기
- 이름 : sample-lambda-image-resize
- 설정 : 기본값
원하는 버킷 이름을 설정하고 아래 설정은 모두 기본값으로 둔 채, 버킷을 생성한다.
2. CloudFront 생성하기
CloudFront 에서 좌측 네비게이션 바에서 원본 엑세스를 클릭한다.
제어 설정 생성을 누른 다음, 이름과 설명을 입력한 후 생성을 클릭한다.
- 이름 : s3-lambda-edge-image-resize
- 설정 : 기본
3. CloudFront 배포하기
좌측 탭에서 배포를 눌러서 배포 생성을 클릭한다.
원본 도메인에서 아까 만든 S3를 선택한다.
원본 엑세스 설정은 공개에서 원본 액세스 제어 설정(권장)으로 바꿔서 선택한다.
방화벽은 다음과 같이 보안 보호 비활성화로 선택한다.
4. S3 버킷 정책 수정하기
위에서 배포를 하고 나면 상단에 다음과 같이 경고가 뜬다.
S3 버킷 정책을 본격적으로 수정해보자
그전에, cloudfront 배포에서 원본을 선택한 다음, 내 원본을 클릭 후 편집을 누른다.
아래로 내려가서 정책 복사를 눌러준다.
이제 다시 S3 버킷 권한으로 이동해보자.
위에서 s3 버킷 권한으로 이동을 클릭하면 다음과 같은 화면이 보인다.
편집을 눌러서 아까 복사한 정책을 붙여넣기로 넣어준다.
변경 사항 저장 클릭.
5. S3에 이미지 업로드하기
이제 S3에 이미지를 업로드 해 준다.
업로드 하면 다음과 같이 나타난다.
사진을 눌러서
객체 url 에 들어가보면 다음과 같이 AccessDenied 가 뜨면 성공이다.
6. CloudFront 도메인에서 이미지 잘 뜨는 지 확인하기
이제 다시 CloudFront 가서 배포 도메인을 복사한 뒤, 내 이미지 사진을 확인해본다.
이미지가 잘 뜬다. 성공!
7. CloudFront 캐시 정책 생성하기
cloudfront에서 정책을 눌러서 사용자 정의 정책을 생성해준다.
이름과 설명을 넣어준다.
캐시 키 설정에서 쿼리 문자열은 모두로 바꾸어 준다.
이렇게 하면, 나중에 q w h t 이렇게 따로 키 설정을 안해주어도 된다.
그리고 생성 클릭.
8. CloudFront 원본 요청 정책 생성
아까는 캐시 정책을 생성했다면, 바로 옆 탭을 눌러서 원본 요청 정책을 생성한다.
이름과 설명을 넣은 뒤, 아까와 동일하게 쿼리 문자열을 모두로 설정한다.
9. CloudFront 동작 편집
배포에서 동작을 클릭한 뒤, 편집을 눌러준다.
아까 설정한 캐시 및 원본 정책을 선택해 준다. (사용자 정의에 있는 것 선택)
아래 처럼 알맞게 선택 되었는 지 확인
10. IAM 권한 설정하기
IAM 에서 역할을 눌러 역할 만들기를 클릭한다.
신뢰할 수 있는 엔터티 유형은 AWS 서비스로,
사용 사례는 Lambda를 클릭한다.
검색창에 AWSLambdaExecute를 검색한 뒤, 선택한다.
권한이 잘 들어갔는 지 확인 한 다음,
역할 생성을 눌러준다.
11. IAM 역할 신뢰 정책 편집하기
엣지를 수행하기 위해서는 "edgelambda.amazonaws.com" 역할도 있어야 한다.
신뢰 정책 편집을 눌러 추가해준다.
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Service": [
"lambda.amazonaws.com",
"edgelambda.amazonaws.com"
]
},
"Action": "sts:AssumeRole"
}
]
}
12. 람다 함수 만들기
중요한 것은 버지니아 북부 지역에서 생성한다는 것이다. 람다 엣지는 버지니아 북부에서 배포해야지만 작동한다.
그리고 node 로 설정한다.
13. 이미지 resize 코드 작성 및 람다에 올리기
AWS 에서 제공하는 Cloud9을 IDE 를 사용할 수도 있지만,
나는 기존에 사용하던 Visual Studio Code 를 열어서 코드를 작성했다.
그리고 해당 프로젝트에서 node를 설치에 주었다.
아래는 내가 사용한 이미지 resize 코드이다.
const sharp = require('sharp');
const aws = require('aws-sdk');
const s3 = new aws.S3({
region: 'ap-northeast-2'
});
const BUCKET = 'S3_버킷_이름_대체';
exports.handler = async (event, _, callback) => {
const { request, response } = event.Records[0].cf;
/** 쿼리 설명
* w : width
* h : height
* f : format
* q : quality
* t : type (contain, cover, fill, inside, outside)
*/
const querystring = request.querystring;
const searchParams = new URLSearchParams(querystring);
if (!searchParams.get('w') && !searchParams.get('h')) {
return callback(null, response);
}
const { uri } = request;
const [, imageName, extension] = uri.match(/\/?(.*)\.(.*)/);
const width = parseInt(searchParams.get('w'), 10);
const height = parseInt(searchParams.get('h'), 10);
const quality = parseInt(searchParams.get('q'), 10) || DEFAULT_QUALITY;
const type = searchParams.get('t') || DEFAULT_TYPE;
const f = searchParams.get('f');
const format = (f === 'jpg' ? 'jpeg' : f) || extension;
try {
const s3Object = await getS3Object(s3, BUCKET, imageName, extension);
const resizedImage = await resizeImage(s3Object, width, height, format, type, quality);
response.status = 200;
response.body = resizedImage.toString('base64');
response.bodyEncoding = 'base64';
response.headers['content-type'] = [
{
key: 'Content-Type',
value: `image/${format}`
}
];
response.headers['cache-control'] = [{ key: 'cache-control', value: 'max-age=31536000' }];
return callback(null, response);
} catch (error) {
return callback(error);
}
};
const DEFAULT_QUALITY = 80;
const DEFAULT_TYPE = 'contain';
async function getS3Object(s3, bucket, imageName, extension) {
try {
const s3Object = await s3.getObject({
Bucket: bucket,
Key: decodeURI(imageName + '.' + extension)
}).promise();
return s3Object;
} catch (error) {
console.log('s3.getObject error: ', error);
throw new Error(error);
}
}
async function resizeImage(s3Object, width, height, format, type, quality) {
try {
const resizedImage = await sharp(s3Object.Body)
.resize(width, height, { fit: type })
.toFormat(format, {
quality
})
.toBuffer();
return resizedImage;
} catch (error) {
console.log('resizeImage error: ', error);
throw new Error(error);
}
}
이제 프로젝트를 압축해서 람다에 올리면 된다.
14. CloudFront 트리거 추가하기
이제 해당 람다 함수에 CloudFront 트리거를 추가한다.
그리고 Deploy to Lambda@Edge 를 클릭한다.
- distribution : 기존에 Cloudfront 에 배포한 것을 선택
- Cache behavior : 본인이 설정한 S3 이미지 경로
- CloudFront event : Origin response 로 설정
이렇게 설정한 뒤 배포를 눌러준다.
배포를 하면 이렇게 버전이 생긴다. 나는 4번의 수정, 배포를 거쳐서 네 개의 버젼이 있다.
15. 배포된 이미지 확인하기
이제 본인의 CloudFront 배포 도메인을 통해서 확인해보자
https://배포_도메인_이름t/images/105.png?w=29&h=60&t=outside
https://배포_도메인_이름t/images/105.png?w=118&h=244&t=outside
원하는 사이즈와 타입을 넣으면 그에 맞게 사진이 잘 변하는 것을 확인할 수 있다..!
이렇게 CloudFront 를 활용하면 S3에 가진 원본 이미지 하나로도 각 요청에 맞는 사이즈 이미지를 전달 가능하다
'AWS' 카테고리의 다른 글
[AWS] AWS RDS 인스턴스 생성 및 연결하기(PostgreSQL) (0) | 2023.10.30 |
---|---|
[AWS] EC2 인스턴스 생성하기 (2023 ver.) (1) | 2023.10.24 |