0. 실습 아키텍처
- User ⮕ S3 Static Website: 사용자는 브라우저에서 웹 애플리케이션을 열면, S3 버킷에 저장된 정적 웹사이트가 로드된다.
- S3 Static Website ⮕ Amazon API Gateway: 웹 애플리케이션의 JavaScript 코드가 데이터를 저장하거나 조회할 때, Amazon API Gateway로 API 요청을 보낸다.
- Amazon API Gateway ⮕ Lambda: API Gateway는 사용자의 요청을 받아 Lambda 함수로 전달한다.
- Lambda ⮕ DynamoDB: Lambda 함수는 DynamoDB와 직접 상호작용하여 데이터를 저장하거나 조회한다. 그 후, Lambda 함수는 처리된 결과를 API Gateway를 통해 다시 사용자에게 반환한다.
1. DynamoDB 테이블 생성
- DynamoDB는 Serverless형태의 NoSQL 데이터베이스이다.
- 테이블 생성 시 테이블 이름과 기본 키만 정의하면 된다. (스키마를 정의할 필요 없음)
- key-value 형태 이므로 쿼리 속도가 빠르다. (10ms 이하의 읽기 및 쓰기 성능)
- 실시간 서비스인 금융 서비스, 게임 애플리케이션, 스트리밍 애플리케이션 등에 많이 사용된다. (빠른 읽기 및 쓰기 성능, 확장성, 손쉬운 운영등의 장점)
- DynamoDB가 지원하는 2가지 primary keys (PK)
- 파티션키(Partition Key): 실제 데이터가 들어가는 위치를 결정한다. (데이터가 들어오면 데이터가 어디로 저장될지 파티션키의 해시함수를 돌리고, 해시 함수 출력에 따라 항목을 저장할 파티션이 결정됨)
- 복합키(Composite Key)=파티션키(Partition Key) + 정렬키(Sort Key): 파티션 키 값이 동일한 모든 항목은 정렬 키 값을 기준으로 정렬되어 함께 저장
1) DynamoDB 테이블 생성
- 하기와 같은 정보를 입력한 후 DynamoDB 테이블을 생성한다.
- 테이블 이름: mywebapp-dynamodb (※ 테이블 이름을 다른 것으로 사용할 경우 이어지는 Lambda 함수 코드도 변경 필요)
- 파티션 키: id (문자열)
- 나머지 값은 기본값으로 설정
2. AWS Lambda 함수 생성
- Lambda란 AWS 에서 제공하는 서버리스 컴퓨팅 서비스다.
- Lambda를 통해 서버를 프로비저닝하거나 관리할 필요 없이 코드를 실행할 수 있다.
- Lambda가 지원하는 언어 런타임 중 하나로 코드를 구성하면 필요할 때만 함수를 실행하고 자동으로 확장이 가능하다.
- 지원되는 런타임: https://docs.aws.amazon.com/ko_kr/lambda/latest/dg/lambda-runtimes.html#runtimes-supported
1) Lambda 함수 생성
- 하기와 같은 정보를 입력한 후 Lambda 함수를 생성한다.
- 함수 이름: mywebapp-lambda
- 런타임: Python 3.11
- 아키텍처: x86_64
- 나머지 값은 기본값으로 설정
2) Lambda 함수 생성 시 함께 생성된 IAM role에 DynamoDB에 대한 추가 권한 부여
- 생성한 함수로 이동 > [구성] > [권한] > "mywebapp-lambda-role-XXXX" 로 생성된 역할 클릭 > [권한 추가] 클릭
- 하기 정책 검색 후 추가
- 정책 이름: AmazonDynamoDBFullAccess
3) Lambda 함수에 코드 입력
- 생성한 함수로 이동 > [코드]에 하기 코드 입력 후 [Deploy] 클릭
더보기
## DynamoDB에 데이터를 저장하고, 조회하는 기능
import json
import boto3
from boto3.dynamodb.conditions import Key
dynamodb = boto3.resource('dynamodb')
table = dynamodb.Table('mywebapp-dynamodb') # DynamoDB table 이름
def lambda_handler(event, context):
# 이벤트 로그 출력
print(f"Received event: {json.dumps(event)}")
headers = {
'Access-Control-Allow-Origin': '*',
'Access-Control-Allow-Methods': 'GET, POST, OPTIONS',
'Access-Control-Allow-Headers': 'Content-Type'
}
# httpMethod가 존재하는지 확인
if 'httpMethod' not in event:
return {
'statusCode': 400,
'headers': headers,
'body': json.dumps('Invalid request: httpMethod not found.')
}
if event['httpMethod'] == 'POST':
# POST 요청: 데이터 저장
data = json.loads(event['body'])
table.put_item(Item={
'id': data['id'],
'name': data['name'],
'message': data['message']
})
return {
'statusCode': 200,
'headers': headers,
'body': json.dumps('Data saved successfully!')
}
elif event['httpMethod'] == 'GET':
# GET 요청: 데이터 조회
response = table.query(
KeyConditionExpression=Key('id').eq(event['queryStringParameters']['id'])
)
return {
'statusCode': 200,
'headers': headers,
'body': json.dumps(response['Items'])
}
elif event['httpMethod'] == 'OPTIONS':
# OPTIONS 요청 처리 (CORS preflight)
return {
'statusCode': 200,
'headers': headers,
'body': json.dumps('CORS preflight successful')
}
else:
return {
'statusCode': 405,
'headers': headers,
'body': json.dumps('Method Not Allowed')
}
- Boto3 - DynamoDB: https://boto3.amazonaws.com/v1/documentation/api/latest/guide/dynamodb.html
- Python에서 Lambda 함수 핸들러 정의: https://docs.aws.amazon.com/ko_kr/lambda/latest/dg/python-handler.html
- 이벤트를 처리하는 함수 코드의 메서드이다.
- 함수가 호출되면 Lambda는 핸들러 메서드를 실행한다.
- 함수는 핸들러가 응답을 반환하거나 종료하거나 제한 시간이 초과될 때까지 실행된다.
3. API Gateway 생성
- API Gateway는 규모와 관계없이 REST 및 WebSocket API를 생성, 게시, 유지, 모니터링 및 보호하기 위한 AWS 서비스이다.
- API Gateway는 상태 저장(WebSocket API) 및 상태 비저장(HTTP API 및 REST API) API를 지원한다.
- API Gateway는 AWS Lambda, AWS Step Functions, Amazon EC2, Amazon S3, Amazon DynamoDB 등과 쉽게 통합된다.
1) API Gateway 생성
- REST API [구축] 선택 > [새 API] 를 선택한다.
- 하기와 같은 정보를 입력한 후 API Gateway를 생성한다.
- API 이름: mywebapp-apigw
- 나머지 값은 기본값으로 설정
2) API Gateway에서 리소스 생성
- 리소스는 API의 각 엔드포인트를 정의하는 구성 요소로 경로, HTTP 메소드, 통합 백엔드, 매개변수, 응답 등을 포함하며, API의 구조를 계층적으로 구성할 수 있다. 각 리소스는 URI를 통해 고유하게 식별된다.
- 리소스 경로: API의 URL 경로에서 특정 엔드포인트를 나타낸다.
- 메서드: GET(리소스 조회), POST(리소스 생성), PUT(리소스 업데이트), DELETE(리소스 삭제)
- 통합 유형: API Gateway의 리소스는 다양한 백엔드 서비스와 연결될 수 있다. (Lambda 통합, HTTP 통합, Mock 통합, AWS 서비스 통합 등)
- 생성된 API Gateway에서 [리소스 생성]을 클릭하여 리소스를 생성한다.
- 리소스 경로: /
- 리소스 이름: items
3) 리소스에서 메서드 생성
- GET, POST 요청을 Lambda 함수로 전달 하기 위해서 메서드를 생성한다.
- 새로 생성한 /items 경로에서 [메서드 생성]을 클릭한 후 하기와 같이 설정한다.
- 매서드 유형: GET
- 통합 유형: Lambda 함수
- Lambda 프록시 통합: 활성화
- Lambda 함수: 사전에 생성한 Lambda 함수 클릭
- 새로 생성한 /items 경로에서 [메서드 생성]을 클릭한 후 하기와 같이 설정한다.
- 매서드 유형: POST
- 통합 유형: Lambda 함수
- Lambda 프록시 통합: 활성화
- Lambda 함수: 사전에 생성한 Lambda 함수 클릭
4) API 배포
- [API 배포]를 클릭하고, 스테이지 이름을 입력한 후 배포한다.
- 배포가 완료되면 API 호출 URL을 복사한다.
5) CORS 활성화
- CORS란? (출처: https://hannut91.github.io/blogs/infra/cors)
- 브라우저에서는 보안적인 이유로 cross-origin HTTP 요청들을 제한한다. 그래서 cross-origin 요청을 하려면 서버의 동의가 필요하다. 만약 서버가 동의한다면 브라우저에서는 요청을 허락하고, 동의하지 않는다면 브라우저에서 거절한다.
- 허락을 구하고 거절하는 메커니즘을 HTTP-header를 이용해서 가능한데, 이를 CORS(Cross-origin Resource Shargin)라고 한다.
- cross-origin이란 다음 중 한 가지라도 다른 경우를 말한다.
- 프로토콜 - http와 https는 프로토콜이 다르다.
- 도메인 - domain.com과 other-domain.com은 다르다.
- 포트 번호 - 8080포트와 3000포트는 다르다.
- 브라우저에서 실행하는 스크립트의 요청을 허용하기 위해 API에 대한 CORS를 활성화한다.
- API Gateway 리소스에서 [CORS 활성화]를 클릭한 후 하기와 같이 설정한다.
- Access-Control-Allow-Methods: GET, POST, OPTIONS
- Access-Control-Allow-Headers: Content-Type
- Access-Control-Allow-Origin: *
6) CORS 설정 완료 후 API 배포
- 설정이 완료되면 [API 배포]를 클릭하여 변경 사항이 적용되도록 한다.
- 이때, 스테이지는 기존에 생성한 스테이지를 클릭한다.
4. 프론트엔드 생성
- Amazon S3버킷은 정적 웹 호스팅을 지원하여 웹사이트를 간편하게 배포할 수 있도록 해준다.
- S3 버킷을 정적 웹 호스팅으로 설정하면 HTML, CSS, JavaScript 및 이미지 파일과 같은 정적 파일을 호스팅할 수 있다.
1) S3 버킷 생성
- 하기와 같은 정보를 입력한 후 S3 버킷을 생성한다.
- 버킷 이름: mywebapp-bucket-{your name}
- 모든 퍼블릭 액세스 차단: 모두 해제 (※ S3 버킷을 웹사이트로 호스팅하기 위해서 해제 필요)
- 나머지 값은 기본 값으로 둔 뒤 생성합니다.
2) 버킷 정책 수정
- 생성한 버킷으로 이동한 뒤 [권한] > [버킷 정책]을 클릭한다.
- 하기 코드에서 bucket-name을 수정한 뒤 버킷 정책에 입력하고 변경 사항을 저장한다.
- 이를 통해, 모든 사용자가 해당 버킷의 객체에 접근할 수 있다.
더보기
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": "*",
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::your-bucket-name/*"
}
]
}
3) S3 버킷 정적 웹 호스팅 설정
- 생성한 버킷으로 이동한 뒤 [속성] > [정적 웹 사이트 호스팅]을 클릭한다.
- [활성화]를 선택하고 인덱스 문서에서 업로드할 HTML 파일 이름을 입력한다.
4) S3 버킷에 html 파일 업로드
- 하기 스크립트로 html 파일을 생성 한 후 버킷에 업로드한다.
- 스크립트 중 const apiEndpoint 줄의 API Gateway 엔드포인트 URL를 이전에 복사한 API Gateway 스테이지의 URL 호출 주소로 변경한다.
더보기
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>DynamoDB 웹 앱</title>
</head>
<body>
<h1>DynamoDB 웹 앱</h1>
<div>
<h2>데이터 저장</h2>
<!-- 데이터를 저장하기 위한 입력 필드 -->
<input type="text" id="id" placeholder="ID"> <!-- ID 입력 필드 -->
<input type="text" id="name" placeholder="이름"> <!-- 이름 입력 필드 -->
<textarea id="message" placeholder="메시지"></textarea> <!-- 메시지를 위한 텍스트 영역 -->
<button onclick="saveData()">저장</button> <!-- saveData 함수를 호출하는 버튼 -->
</div>
<div>
<h2>데이터 조회</h2>
<!-- 데이터를 조회하기 위한 입력 필드 -->
<input type="text" id="retrieveId" placeholder="ID"> <!-- 조회할 ID 입력 필드 -->
<button onclick="retrieveData()">조회</button> <!-- retrieveData 함수를 호출하는 버튼 -->
<p id="result"></p> <!-- 데이터 조회 결과를 표시할 단락 -->
</div>
<script>
// DynamoDB와의 상호작용을 위한 Amazon API GATEWAY 엔드포인트
const apiEndpoint = 'https://YOUR_API_GATEWAY_ENDPOINT/items';
// DynamoDB에 데이터를 저장하는 함수
async function saveData() {
// 입력 필드에서 값 가져오기
const id = document.getElementById('id').value;
const name = document.getElementById('name').value;
const message = document.getElementById('message').value;
// 데이터를 저장하기 위해 POST 요청 보내기
const response = await fetch(apiEndpoint, {
method: 'POST', // HTTP 메서드
headers: { 'Content-Type': 'application/json' }, // 콘텐츠 타입을 JSON으로 설정
body: JSON.stringify({ id, name, message }) // 데이터를 JSON 형식으로 변환
});
const result = await response.json(); // JSON 응답을 파싱
alert(result); // 결과(보통 성공 메시지)를 알림으로 표시
}
// DynamoDB에서 데이터를 조회하는 함수
async function retrieveData() {
const id = document.getElementById('retrieveId').value; // 입력 필드에서 ID 가져오기
// 데이터를 조회하기 위해 GET 요청 보내기
const response = await fetch(`${apiEndpoint}?id=${id}`, { method: 'GET' });
const result = await response.json(); // JSON 응답을 파싱
document.getElementById('result').textContent = JSON.stringify(result); // 결과 표시
}
</script>
</body>
</html>
5) 웹사이트 접속
- 생성한 버킷으로 이동한 뒤 [속성] > [정적 웹 사이트 호스팅]에서 버킷 웹사이트 엔드포인트를 확인할 수 있다.
- 해당 엔드포인트로 웹사이트에 접속한다.
4. 최종 테스트
1) 샘플 정보 입력
- 웹사이트에서 정보 입력 시 Dynamo DB에 저장 되는지 확인한다.
2) Dynamo DB에서 데이터 저장 되었는지 확인
- 생성한 Dynamo DB > [표 항목 탐색] 클릭
- Dynamo DB에서 테이블 스캔 시 입력된 정보가 저장된 것을 확인할 수 있다.
참고
1. Amazon S3에서 정적 웹 사이트 구성: https://docs.aws.amazon.com/ko_kr/AmazonS3/latest/userguide/HostingWebsiteOnS3Setup.html
2. CORS 개념: https://hannut91.github.io/blogs/infra/cors
3. Boto3 - DynamoDB: https://boto3.amazonaws.com/v1/documentation/api/latest/guide/dynamodb.html
4. Python에서 Lambda 함수 핸들러 정의: https://docs.aws.amazon.com/ko_kr/lambda/latest/dg/python-handler.html
'Cloud > AWS' 카테고리의 다른 글
[AWS] EKS에서 ExternalDNS 구성하기 (1) | 2024.11.16 |
---|---|
[AWS] EKS에서 Ingress 및 AWS Load Balancer Controller (0) | 2024.08.06 |
[AWS] IAM 기초 (0) | 2024.07.28 |