- 이미지를 압축하는 역할이기 때문에 S3에서 파일을 get합니다.
- cloudfront와 연결해야 합니다.
- 잘 작동했는지 log 확인해야 합니다.
결론적으로 이런 정책을 만들어야합니다.
{
"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": "*"
}
]
}
1번을 위해 s3: GetObject
2번을 위해 cloudfront:UpdateDistribution,lambda:GetFunction, lambda:EnableReplication
3번을 위해 log관련 정책을 넣었습니다.
조금만 자세히 설명드리면
lambda:GetFunction 에서는 cloudfront 이벤트 발생 시 ARN을 지정하는 역할을 하고
lambda:EnableReplication 에서는 복제 서비스의 구성을 가져올 수 있는 권한을 부여합니다.
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Service": [
"lambda.amazonaws.com",
"edgelambda.amazonaws.com"
]
},
"Action": "sts:AssumeRole"
}
]
}
이렇게 바꿔주도록 합니다. 역할 부분이 끝이 났습니다.
⭐ lambda@edge는 버지니아 북부에서 생성해야합니다.
🙄 여기서 용량이 커 오래걸리게 된다면 제한 시간을 늘려가면서 컨트롤해야 합니다.
⭐ 저는 이미지 압축으로 sharp라는 모듈을 사용할 것입니다.
여기서 문제점이 하나 있습니다.
lambda는 linux기반이기 때문에 linux용 sharp를 설치해야합니다.
window 기준으로 아래의 코드를 이용하시면 됩니다.😎
npm install
SHARP_IGNORE_GLOBAL_LIBVIPS=1 npm install --arch=x64 --platform=linux sharp
index.js
"use strict";
const querystring = require("querystring"); // Don't install
const AWS = require("aws-sdk"); // Don't install
const Sharp = require("sharp"); //Linux용 install
const convert = require("heic-convert"); //heic 파일 jpeg로 변환용
const allowedExtension = [
"jpg",
"jpeg",
"png",
"webp",
"heic"
];
const MAX_WIDTH = 1280;
const MAX_HEIGHT = 720;
// 버킷 찾기
const S3 = new AWS.S3({
region: "ap-northeast-2",
});
const BUCKET = "u-market";
exports.handler = (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);
// query로 받은 이미지 압축 크기와 높이
if (!params.w && !params.h) {
return callback(null, response);
}
// uri와 이름, 확장자찾기
const { uri } = request;
const [, imageName, extension] = uri.match(/\/?(.*)\.(.*)/);
// Init variables
let width;
let height;
let format;
let quality; // Sharp는 이미지 포맷에 따라서 품질(quality)의 기본값이 다릅니다.
let resizedImage;
// 사이즈 구별
width = parseInt(params.w, 10) ? parseInt(params.w, 10) : MAX_WIDTH;
height = parseInt(params.h, 10) ? parseInt(params.h, 10) : MAX_HEIGHT;
// Init quality.
if (parseInt(params.q, 10)) {
quality = parseInt(params.q, 10);
}
// 확장자 바꾸는 코드
format = params.f ? params.f : extension;
format = format === "jpg" ? "jpeg" : format;
format = format === "HEIC" ? "jpeg" : format;
// 이미지 파일이 아니라면 500 error
if (!allowedExtension.includes(extension)) {
response.status = "500";
response.headers["content-type"] = [
{ key: "Content-Type", value: "text/plain" },
];
response.body = `${extension} is not allowed`;
callback(null, response);
return;
}
// 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`.
// S3에서 이미지 받아오는 코드
S3.getObject({
Bucket: BUCKET,
Key: decodeURI(imageName + "." + extension),
})
.promise()
.then((data) => {
// HEIC 파일 JPEG로 convert
if (extension === "HEIC" || extension === "heic") {
return convert({
buffer: data.Body,
format: "JPEG",
quality: 1,
});
} else {
return data.Body;
}
})
.then((input) => {
resizedImage = Sharp(input);
resizedImage
.metadata()
.then((meta) => {
return resizedImage
.resize(width, height)
.toFormat(format, {
quality,
})
.toBuffer();
})
.then((buffer) => {
// response에 리사이징 한 이미지를 담아서 반환
response.status = 200;
response.body = buffer.toString("base64");
response.bodyEncoding = "base64";
response.headers["content-type"] = [
{ key: "Content-Type", value: `image/${format}` },
];
callback(null, response);
});
})
.catch((error) => {
response.status = "404";
response.headers["content-type"] = [
{ key: "Content-Type", value: "text/plain" },
];
response.body = `${request.uri} is not found. and ${error}`;
callback(null, response);
});
};
sharp를 설치하고 나면 index.js, package.json, package-lock.json, node_modules
이 4가지 파일,폴더를 압축하여 lambda에 올려줍니다.
저는 index.js에 handler를 넣었기 때문에 핸들러를 index.handler로 설정해주었습니다.
아까 선택한 동작의 주소에 들어가서 함수 연결에 lambda@edge의 주소가 적혀있다면 성공입니다!
Hit from cloudfront까지 뜬다면 성공적으로 cloudfront에 배포된 것입니다. 🙇♂️