AWS Lambda란?
Lambda는 AWS가 제공하는 서버리스 FaaS 솔루션으로, 함수의 인스턴스를 실행하여 이벤트를 처리합니다.
사용해야할것 API 게이트웨이, S3, SQS
추가적으로 Application LoadBalancer, cloudWatch 모니터링 부분에서 추가 사용
cloudWatch lamda 사용에 필수적 -로그확인
API Gateway를 사용하는 이유?
마이크로서비스의 사용 증가로 인해 API 게이트웨이가 더 많이 사용되고 있습니다. 각 마이크로서비스는 자체 기능을 필요로 하기 때문에 애플리케이션을 느슨하게 결합된 여러 서비스로 분해될 수 있습니다. 한편, 마이크로서비스를 사용하면 애플리케이션의 다양한 기능을 더 쉽게 개발, 배포 및 유지 관리할 수 있지만 고객이 애플리케이션에 빠르고 안전하게 액세스하기가 더 어려워질 수도 있습니다. 이 때 API 게이트웨이가 이 문제를 해결할 수 있습니다. 고객이 각 마이크로서비스에 대한 액세스를 개별적으로 요청하는 대신 게이트웨이는 요청에 대한 단일 진입점(entrypoint)으로, 해당 요청을 적절한 서비스에 연결하고 결과를 수집하여 요청자에게 다시 전달하게 도와줍니다. 이 기능을 라우팅이라고 하며, API Gateway의 주요 기능 중 하나입니다.
API Gateway 기능 :
API Gateway 장점 :
HTTP API, REST API 차이점 파악
SAM(serverless application model)
대표적인 기능
SAM이 제공하는 대표적인 기능으로는 다음과 같습니다.
SAM 대안
serverless 범용성이 좀 더 좋다 멀티 클라우드에
terraform 사용할 수 있지만 서버리스위한 툴은아님
실행 속도 문제
cold start/warm start
언제 Cold start가 발생하는가?
어떻게 하면 Warm 상태를 유지하는가?
SAM 설치(Mac 기준)
SAM 설치 전 사전 조건
brew tap aws/tap
brew install aws-sam-cli
설치 후 잘 깔려있는지 확인
sam --version
HelloWorld 출력하는 애플리케이션 배포
참고
https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/serverless-getting-started-hello-world.html#serverless-getting-started-hello-world-test-locally
sam local start-api
curl http://127.0.0.1:3000/hello
서버 실행 후 hello api 실행결과
API Gateway - Lambda - DyanmoDB 구조를 가지는 애플리케이션 배포 해보기
step 1: API Gateway - Lambda 배포 Instruction
git clone https://github.com/aws-samples/serverless-patterns/
cd serverless-patterns/lambda-dynamodb
Runtime: node.js14.x
변경사항 sam build
sam 으로 배포
sam deploy --guided
잘 동작 하는지 확인
aws lambda invoke --function-name arn:aws:lambda:ap-northeast-2:652217438494:function:sam-app-LambdaPutDynamoDB-gJozNWaUjUS5 --invocation-type Event \
--payload '{ "Metadata": "Hello" }' \ response.json --cli-binary-format raw-in-base64-out
202 state가 도착하면 성공!
step 2. lambda 추가 트리거 api 게이트웨이 생성
생성 확인
Step 3 : API 게이트웨이에 제한 추가
본문만 저장하도록 만들기
API 키를 이용한 인증 추가하기
참고
https://docs.aws.amazon.com/ko_kr/apigateway/latest/developerguide/api-gateway-create-usage-plans-with-console.html#api-gateway-usage-plan-create
순서
1. apigateway에서 apikey 자동 생성
2. 사용량 계획 생성
3. 리소스 메소드실행에서 apikey필요함 ture로 변경
4. postman에 헤더 x-api-key 벨류 값으로 생성된 apikey 입력 후 테스트
5. OK가 나오면 성공
순서
1. 함수생성
2. 함수값 입력 (aws공식문서)
// A simple token-based authorizer example to demonstrate how to use an authorization token
// to allow or deny a request. In this example, the caller named 'user' is allowed to invoke
// a request if the client-supplied token value is 'allow'. The caller is not allowed to invoke
// the request if the token value is 'deny'. If the token value is 'unauthorized' or an empty
// string, the authorizer function returns an HTTP 401 status code. For any other token value,
// the authorizer returns an HTTP 500 status code.
// Note that token values are case-sensitive.
exports.handler = function(event, context, callback) {
var token = event.authorizationToken;
switch (token) {
case 'allow':
callback(null, generatePolicy('user', 'Allow', event.methodArn));
break;
case 'deny':
callback(null, generatePolicy('user', 'Deny', event.methodArn));
break;
case 'unauthorized':
callback("Unauthorized"); // Return a 401 Unauthorized response
break;
default:
callback("Error: Invalid token"); // Return a 500 Invalid token response
}
};
// Help function to generate an IAM policy
var generatePolicy = function(principalId, effect, resource) {
var authResponse = {};
authResponse.principalId = principalId;
if (effect && resource) {
var policyDocument = {};
policyDocument.Version = '2012-10-17';
policyDocument.Statement = [];
var statementOne = {};
statementOne.Action = 'execute-api:Invoke';
statementOne.Effect = effect;
statementOne.Resource = resource;
policyDocument.Statement[0] = statementOne;
authResponse.policyDocument = policyDocument;
}
// Optional output with custom properties of the String, Number or Boolean type.
authResponse.context = {
"stringKey": "stringval",
"numberKey": 123,
"booleanKey": true
};
return authResponse;
}
우리가 만드려는 서버리스 사진첩 서비스는, 여느 클라우드 사진 저장 서비스들처럼 단순히 사진을 업로드하는 것 외에도, 인증 기능과 썸네일 생성 기능을 제공합니다.
S3->lambda->sns
Bare Minimum Requirements
썸네일 이미지는 가로 200px의 크기를 가집니다.
썸네일을 저장할 별도의 버킷은 람다 함수의 환경 설정으로 구성되어야 합니다.
Amazon SNS를 활용합니다
Setting
터미널에서 sam init 로 샘플 받아온 후 람다 함수 변경하고 빌드 후 배포
exports.helloFromLambdaHandler = async (event, context) => {
console.log(event)
console.log(context)
return 'Hello from Lambda!';
}
이후 s3 생성 후 트리거 추가로 연결 후(접미사: .jpeg추가) 람다함수 테스트 (s3.put)로 실행되는 함수 로그 확인하여 완성시키기
참고: https://docs.aws.amazon.com/ko_kr/lambda/latest/dg/with-s3-tutorial.html
로컬에서 테스트
JSON.stringify(event) 테스트 실행 로그를 가져와 json파일로 만들어 아래 명령어 실행
sam local invoke -e ./s3-event.json
사전 모듈 설치
aws-sdk: s3버킷을 불러오는데 필요
sharp: 썸네일을 만드는데 필요
npm install aws-sdk
npm install sharp
1) not find sharp : m1의 환경에서만 npm i sharp를 했음에도 모듈을 못찾는다고 나오는 현상
-> 패키지에서 sharp를 제거하니 해결
"dependencies": {
"aws-sdk" : "^2.1111.0",
"sharp": "^0.30.3" //<-제거
}
2) "errorType": "AccessDenied"
s3 정책에서 허용하지 못한다고 나오는 오류
3) 대상 버킷 환경변수 설정
구성 -> 환경 변수 -> 편집 -> 키, 값 입력
람다 함수에서 process.env.key값 입력
4) 람다함수 완성 후 sns서비스와 연결
sns주제 일반으로 생성 후 프로토콜 이메일 엔드포인트 : 이메일 주소
5)sns에 s3 url 주소 담아서보내기
const message = {
Message: "URL : "+`https://${process.env.s3resized}.s3.${region}.amazonaws.com/${uploadFileName}`,
Subject: "썸네일 도착",
TopicArn : process.env.topicArn
}
TopicArn : AWS-SNS:ARN
6) sns 메일 url이랑 빈메일 오는거 해결하기
람다와 sns를 추가 할 때 대상추가에서 조건을 성공시에서 실패시로 변경
Bare Mininum Requirements 완성!
s3에 jpeg업로드 했을때
/**
* A Lambda function that returns a static string
*/
const AWS = require('aws-sdk');
AWS.config.update({ region: 'ap-northeast-2'});
const s3 = new AWS.S3({apiVersion: '2006-03-01'});
const sharp = require('sharp');
exports.helloFromLambdaHandler = async (event, context) => {
const bucketName = event.Records[0].s3.bucket.name
const uploadFileName = event.Records[0].s3.object.key
const region = event.Records[0].awsRegion
console.log("*******"+JSON.stringify(event))
console.log("-------"+JSON.stringify(context))
// 원본 버킷으로부터 파일 읽기
const s3Object = await s3.getObject({
Bucket: bucketName,
Key: uploadFileName
}).promise()
// 이미지 리사이즈, sharp 라이브러리가 필요
const data = await sharp(s3Object.Body)
.resize(200)
.jpeg({ mozjpeg: true })
.toBuffer()
// 대상 버킷으로 파일 쓰기 (*일단 대상버킷 똑같이)
const result = await s3.putObject({
Bucket: process.env.s3resized,
Key: uploadFileName,
ContentType: 'image/jpeg',
Body: data,
ACL: 'public-read'
}).promise()
const sns = new AWS.SNS(region);
const massage = await sns.publish({
Message : "URL : "+`https://${process.env.s3resized}.s3.${region}.amazonaws.com/${uploadFileName}`,
Subject: "썸네일 도착",
TopicArn : process.env.topicArn
}).promise()
}
Advanced Challenge
과제를 달성하면, S3 이벤트가 SQS로 전송되게 만들고, SQS로부터 이벤트를 받아 람다가 실행하게 만들어봅시다.
S3의 Pre-signed URL 기능을 이용하여, 업로드 전용 URL을 획득하고, 이를 통해 이미지를 S3 업로드할 수 있게 만들어봅시다.
7) sqs 람다 트리거 연결
람다에서 sqs풀엑세스 역할 지정후 트리거 추가로 sqs연결
8) s3에서 sqs 대기열 이벤트 생성불가
Error: Unable to validate the following destination configurations
sqs 엑세스 정책 변경
"Principal": {
"AWS": "arn:aws:iam::652217438494:root",
"Service" : "s3.amazonaws.com"
}
Service 추가
9) 실패하는 메시지 처리
sqs에서 보내는 실패하는 메시지는 발신자를 찾지못해 무한 루프하게됨
(처리해주지 않으면 aws 과금발생)
해결법
sqs에서 실패하는 메시지 담을 대기열 생성 후 배달 못한 편지 대기열 활성화 후 대기열 추가
10) 에러메시지 : "Cannot read property 'bucket' of undefined"
sqs에서 오는 이벤트값이 json형태가 아니여서 bucket값을 찾지 못하는 상태 콘솔에서 에러메시지 확인 후 바디에 값있는걸 확인 후
event값을 json형으로 변경
event = JSON.parse(event.Records[0].body)
11) "errorMessage": "SyntaxError: Identifier 'event' has already been declared"
event를 상수로 2번 지정해서 난 오류
event값을 json으로 변경해주는 과정에서 event를 const event로 한번 더 지정해서 난 오류 였음.. (내 실수ㅜ)