serverless-image-handler 적용하기
Serverless-image-handler 에 대해서
먼저 현재 진행하고있는 사이드 프로젝트에서 이미지 업로드에 대해서 생각하게 되었는데, 이전 회사에서 사용하던 서비스에서 서버리스 이미지 핸들러를 사용한적 있어서, 이 AWS에서 제공하는 서비스에 대해서 알아보고자 합니다.
서버리스 이미지 핸들러는 AWS 클라우드 서비스로, 오픈 소스 이미지 라이브러리인 Sharp 를 사용하여서 동적 이미지로 변환해서 url을 통해서 보여주어서 cloudfront를 통해서 캐싱 처리도 진행해 비용 효율적인 서비스로 알고 있습니다.
실제적인 서비스의 구조는 아래 그림과 같습니다.
먼저 위의 방식을 설명하자면 CloudFormation의 스택을 통해서 구현되어진 CloudFront, API Gateway, Lambda, Secrets Manager, S3, Rekognition으로 자동화되어서 만들어집니다.
Serverless image handelr 방식 설명
1. 이미지 처리비용, 후속 이미지 전송 지연 시간을 줄여주는 캐싱 계층을 이용한 CloudFront를 이용하게 되고 이 CloudFront의 도메인을 이용해서 이미지의 캐싱된 정보를 제공하고 확인할 수 있게 됩니다.
2. API Gateway를 통해 정해진 엔드포인트에 접근하게 되고, 서버리스 이미지 핸들러 템플릿 스택을 통해서 만들어진 Lambda를 실행합니다.
3. 기존 S3 버킷의 이미지를 정해진 포맷형식으로 받게 되어 (버킷네임, 리전, 속성(리사이징 정보, Cropping 등.. )) 수정된 버전의 이미지를 Lambda를 통해서 처리하게 됩니다.
4. 로그 스토리용 S3 버킷이 존재하게 되고, 템플릿 생성시에 선택적으로 데모 S3도 생성합니다.
5. 템플릿에서 이미지 서명 선택 작업까지 한다면, AWS Secrets Manager를 통해서 보안 검색을 통해 서명인증까지 진행합니다. 저는 이 옵션은 선택하지 않았습니다.
6. 선택된 이미지가 콘텐츠에 적합한지 (성인 관련, 이상한 이미지들) Rekognition을 통해 이미지 분석을 하고 반환합니다.
실제 적용 과정
실제로 위의 편한 서비스를 이용하기 위해서 제가 겪으면서 배포햇던 경험을 공유할려 합니다.
1. 먼저 템플릿을 사용하기 위해서 aws 계정을 통해서 CloudFormation 페이지로 이동하고 스택 생성을 진행했습니다.
2. 스택 생성 페이지에서 Serverless-image-handler의 템플릿의 URL의 경우 다음과 같고 이 URL을 복사해서 아래와 같이 넣으면 됩니다.
https://s3.amazonaws.com/solutions-reference/serverless-image-handler/latest/serverless-image-handler.template
3. 그 이후 세부 옵션의 경우 저는 기존 그대로 사용하였고 CloudFront PriceClass의 경우 서울을 제공하는 PriceClass_200 을 사용하였습니다.
4. 생성을 완료하고 스택 실행을 하게 되는데 자동적으로 위의 구조의 모든 구조를 생성해줍니다. 저희가 따로 할거는 없습니다..
5. 성공적으로 배포가 되었다면 Demo 페이지까지 설정해서 한 경우, CloudFront로 이동하게 된다면 아래와 같은 데모 UI까지 생성되고 직접 테스트도 진행할 수 있습니다.
6. 데모페이지에서 버킷네임, 이미지 키값을 넣고 에디터부분에 원하는 속성을 적용하면 원하는 이미지로 반환해줍니다.
실제 사용하기 위한 클라이언트 단에서의 추가적인 작업
실제로 서비스에 적용하기 위해서 S3 버킷에 이미지를 올리는 작업을 진행하였고 저의 클라이언트 스택 환경의 경우,
리액트 네이티브를 사용중에 있어서, 이미지를 올리는 작업으로
1. react-native-image-picker를 통해서 이미지를 가져옵니다.
2. 서버단에서 presignedPost 또는 presignedUrl의 정보를 요청합니다.
* 저의 경우 presignedPost를 사용합니다.(presginedUrl의 경우 formData를 사용못하고 이미지를 따로 읽고 Buffer를 통해서 전송해야하는 이중적인 방법이라 생각됨)
3. 받은 정보를 통해서 Post 방식으로 formData와 함께 S3에 업로드 진행합니다.
const {result: presigned} = await getPresignedS3Url(
token,
file.fileName.slice(0, file.fileName.length - 4),
ext,
);
for (const key in presigned.fields) {
// presigned의 fields를 모두 formData 추가
formData.append(key, presigned.fields[key]);
}
formData.append('file', file);
...
await fetch(presigned.url, {
headers: {
'Content-Type': 'multipart/form-data',
},
method: 'POST',
body: formData,
});
...
4. 이미지 업로드 방식이 끝나고 그 이미지의 url을 가지고 화면에 보여줍니다.
https://petwalk-image.s3.ap-northeast-2.amazonaws.com/pet/2/705C8AFD-924B-456E-BDFE-DA36BAE1BAF0.jpg
위와 같은 형식으로 이루어져있었고 위의 url을 통해서 serverless-image-handler를 통해서 생성한 cloudFront의 도메인을 이용해서 이미지를 가공해서 보여줍니다.
5. 위의 url을 가공하는 코드를 이용하는데 저는 아래와 regex로 같이 커스터마이징해서 사용합니다.
function parseS3Url(url: string) {
// Regular expression to extract region, bucket, and key from S3 URL
const regex = /https:\/\/([^.]+)\.s3\.([^.]+)\.amazonaws\.com\/(.+)/;
const match = url.match(regex);
if (match && match.length > 3) {
return {
region: match[2], // Extracts the region
bucket: match[1], // Extracts the bucket name
key: match[3], // Extracts the key
};
} else {
// Return null or an appropriate error/response if the URL doesn't match
return null;
}
}
6. 그리고 이제 마지막으로 cloudfront url로 접근하고 base64로 변환하여서 아래와 같이 사용합니다.
클라우드프런트도메인 + '/' + Buffer.from(JSON.stringify(버킷,키,서버리스이미지 핸들러 변환옵션)).toString('base64')