프로세스는 간단하다. 하지만 부하가 많아질 경우 웹 서버의 성능에 심각한 부작용이 있을 수 있다. 왜냐하면 미디어 업로드는 일반적으로 크기 때문에 I/O 및 서버 CPU 시간의 많은 부분을 나타낼 수 있다. 또한 트래픽 패턴이 급증하는 애플리케이션의 경우 터질수도 있다.
이러한 파일을 S3에 직접 업로드하면 애플리케이션 서버를 통해 이러한 요청을 프록시 하는 것을 방지할 수 있다. 이렇게 하면 네트워크 트래픽과 서버 CPU 사용량을 크게 줄이고 응용 프로그램 서버가 사용량이 많을 동안 다른 작업을 수행할 수 있다.
S3 버킷에 직접 업로드 하는 경우 먼저 Amazon S3 서비스에서 서명된 URL ( preSigned URL)을 요청해야 한다. 그런 다음 서명된 URL을 사용하여 직접 업로드 할 수 있다.
웹 어플리케이션에서 S3로 객체를 업로드 할 때 CORS 에 대해 S3를 구성해야 한다.
S3UploadBucket:
Type: AWS::S3::Bucket
Properties:
CorsConfiguration:
CorsRules:
- AllowedHeaders:
- "*"
AllowedMethods:
- GET
- PUT
- HEAD
AllowedOrigins:
- "*"
SignedURL 을 호출하는 람다 함수
const AWS = require('aws-sdk')
AWS.config.update({ region: process.env.AWS_REGION })
const s3 = new AWS.S3()
const URL_EXPIRATION_SECONDS = 300
// Main Lambda entry point
exports.handler = async (event) => {
return await getUploadURL(event)
}
const getUploadURL = async function(event) {
const randomID = parseInt(Math.random() * 10000000)
const Key = `${randomID}.jpg`
// Get signed URL from S3
const s3Params = {
Bucket: process.env.UploadBucket,
Key,
Expires: URL_EXPIRATION_SECONDS,
ContentType: 'image/jpeg'
}
const uploadURL = await s3.getSignedUrlPromise('putObject', s3Params)
return JSON.stringify({
uploadURL: uploadURL,
Key
})
}
업로드 프로세스에 인증 추가
현재 API 엔드포인트가 열려 있으며 인터넷의 모든 서비스에서 사용할 수 있다.
즉 SignedURL을 받으면 누구나 JPG 파일을 업로드할 수 있다. 대부분의 프로덕션 시스템에서 개발자는 인증을 사용하여 API에 액세스 할 수 있는 사람과 S3 버킷에 파일을 업로드 할 수 있는 사람을 제어
권한 부여자를 사용하자 JWT 권한 부여자 Amazon Cognito, Auth0과 같은 서비스가 될 수 있는 자격 증명 공급자를 통해 API 에 대한 액세스를 제어할 수 있다.
MyApi:
Type: AWS::Serverless::HttpApi
Properties:
Auth:
Authorizers:
MyAuthorizer:
JwtConfiguration:
issuer: !Ref Auth0issuer
audience:
- https://auth0-jwt-authorizer // 여기서 이 URL은 우리 프로젝트의 JWT URL이 되는 건가?
IdentitySource: "$request.header.Authorization"
DefaultAuthorizer: MyAuthorizer
ACL 수정 및 공개적으로 읽을 수 있는 객체 생성
s3Params에 넣어주면 되나보다
현재 구현에서 업로드된 객체는 공개적으로 액세스 할 수 없다.
업로드된 객체를 공개적으로 읽을 수 있도록 하려면 해당 ACL(액세스 제어 목록)을 설정해야 한다.
const s3Params = {
Bucket: process.env.UploadBucket,
Key,
Expires: URL_EXPIRATION_SECONDS,
ContentType: 'image/jpeg',
ACL: 'public-read'
}
요청에 서명할 수 있는 적절한 버킷 권한이 있어야 한다
함수에 PutObjectAcl 권한이 있는지 확인
- Statement:
- Effect: Allow
Resource: !Sub 'arn:aws:s3:::${S3UploadBucket}/'
Action:
- s3:putObjectAcl
서버리스 패턴은 서비스에서 네트워크 부하를 줄여줄 수 있다. 그래서 애플리케이션을 훨씬 더 확장 가능하게 만들고 급증하는 트래픽을 처리할 수 있다.
Lambda(preSignedURL) > S3 > SQS(이벤트 알림) > Lamda(이벤트 받아서 Dynamo에 넣기) > DynamoDB 형태로 구현
1번 과정인 Lambda(Presigned Url) > S3
2번 S3 에서 SQS로 Polling 하여 값 넣기
3번 Lamda > DynamoDB
Lambda용 S3 이벤트 소스 (S3에서 SQS로)
Lambda용 SQS 이벤트 소스 (SQS에서 DynamoDB로)
Lambda용 API 게이트웨이 이벤트 소스 (Dynamo에 대한 API 게이트웨이)
Lambda용 S3 이벤트 소스
파일이 대상 S3 버킷에 복사될 때마다 S3 이벤트 알림이 Lambda 의 비동기식 호출을 트리거합니다.AWS에 따르면 함수를 비동기식으로 호출하면 Lambda가 이벤트를 SQS대기열로 보냅니다. 별도의 프로세스가 대기열에서 이벤트를 읽고 Lambda 함수를 실행합니다.
Python으로 작성된 Lambda의 함수 핸들러는 이벤트에 파일 이름이 포함된 webm 파일을 읽습니다. Lambda는 webm 파일의 url을 추출하고 각 메시지를 SQS로 푸시합니다.
참고링크
https://aws.amazon.com/ko/blogs/compute/uploading-to-amazon-s3-directly-from-a-web-or-mobile-application/
https://dev.classmethod.jp/articles/lim-lambda-s3-sqs/
https://dev.classmethod.jp/articles/lim-lambda-s3-2021/