AWS Serverless 로 간단한 Web Application 만들기 (AWS Builders Korea)

LEE EUI JOO·2023년 6월 22일
0

Amazon Web Service

목록 보기
9/9

1. 소개

서버리스 어플리케이션에 관심이 있어서 AWS Builders Korea Program AWS Serverless 로 간단한 Web Application 만들기 (AWS Builders Korea) 트랙에 신청하였다.

서버리스 라고 해서 어려운 개념들도 수반될거 같았지만, AWS 솔루션 아키텍트 분께서 친절하게 강의를 해주셔서 별 문제없이 트랙을 마칠 수 있었다.

향후 AWS 서버리스 서비스나 프로젝트를 만들때 많은 도움이 될것같다.

  • 내가 실습할 Simple Architecture 이다.


2. Hello World! Function Test

1. Create Lambda Function

  • 여기서 블루프린트는 AWS 에서 기본적으로 제공하는 템플릿이라고 생각하면 된다.

import json

print('Loading function')


def lambda_handler(event, context):
    #print("Received event: " + json.dumps(event, indent=2))
    print("value1 = " + event['key1'])
    print("value2 = " + event['key2'])
    print("value3 = " + event['key3'])
    return event['key1']  # Echo back the first key value
    #raise Exception('Something went wrong')
  • json 파일을 받게 되면 key1 을 출력해주는 간단한 Lambda 함수이다

2. Lambda Function Test

  • 이벤트 작업 테스트 로 .json 파일을 넣어서 함수를 테스트 해볼 수 있다.

{
  "key1": "Hello!",
  "key2": "value2",
  "key3": "value3"
}
  • key1 의 value 값인 Hello! 가 리턴됨을 확인할 수 있다.


3. Web Page Lambda

1. Create Lambda Function

  • 함수이름 : simple-webpage

  • 런타임 : python 3.9

  • 아키텍처 : x86_64

  • 실행역할 : 기본 Lambda 권한을 가진 새 역할 생성

  • URL 로 테스트하기 위해서 함수 URL 활성화 체크 후 함수 생성

2. Lamda 코드 소스 작성

import json

def lambda_handler(event, context):
    response = {
        "statusCode": 200,
        "statusDescription": "200 OK",
        "Access-Control-Allow-Origin" : "*",
        "isBase64Encoded": False,
        "headers": {
            "Content-Type": "text/html; charset=utf-8"
        }
    }

    response['body'] = """<html>
    <head>
    <meta charset="utf-8" name="viewport" content="width=device-width, height=device-height, minimum-scale=1.0, maximum-scale=1.0, initial-scale=1.0">
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
    <title>Hello World!</title>
    <style>
        #title {
            font-family: arial; font-size: 2em;color: #eb971a; margin-top:50px;
            text-align: center;
        }
        button {
                background-color: #eb971a;
                border:none;
                color:white;
                border-radius: 5px;
                width:40%;
                height:35px;
                font-size: 13pt;
                margin-top:30px;
                text-align: center;
        }
        #sentence {
                font-size: 17pt;
                margin-top:30px;
                font-weight: bold;
                color: #eb971a;
        }
    </style>
        </head>
        <body>
            <p id="title">Hello World From <b>Lambda</b></p>
            <hr id="lambda-line" width="800px" align="center" color="#eb971a;">
            <center><button>Who are you?</button></center>
            <center><div id="sentence"></div></center>
        </body>
        <script type="text/javascript">
        
            function checkEvent(){
                $.ajax({ type: "GET", 
                        url: "URL을입력하세요", 
                        dataType:'json',
                        success: function(data){ 
                        document.getElementById('sentence').innerHTML = data.status + "&nbsp;&nbsp;" + data.name
                        }, 
                        error: function (error){
                        alert('ERROR::');
                        console.log(error)
                        }

                });
            }

        </script>
        </html>
            
        """
        
    return response
  • 코드 소스를 복사했으면 생성된 URL 을 크롬브라우저에서 호출

  • 서버리스 즉, 서버(EC2) 없이 정상적으로 배포가 된다. 이것이 서버리스 애플리케이션의 큰 장점이다.

  • 이전에는 Tomcat 설치하고 웹서버 설치하고 했어야함 5분만에 작업이 끝났다. 결국, 개발자는 코드에만 집중할 수 있다!!

  • html 페이지는 보통 S3에 올려놓고 서비스한다

  • 페이지의 "Who are you?" 버튼을 누르면 에러를 뿜는다

  • 왜냐하면 방금 lambda 애플리케이션의 코드소스에는
function checkEvent(){
                $.ajax({ type: "GET", 
                        url: "URL을입력하세요", 
                        dataType:'json',
                        success: function(data){ 
                        document.getElementById('sentence').innerHTML = data.status + "&nbsp;&nbsp;" + data.name
                        }, 
                        error: function (error){
                        alert('ERROR::');
                        console.log(error)
  • Who are you? 버튼의 이벤트에 GET 메서드 즉, API에서 데이터를 가져오는 코드가 있기 때문이고, 우리는 아직 API 를 구현하지 않았기 때문이다. 다음 과정에서 Lambda 로 API 를 만들고 Amazon API GateWay 로 생성한 API 엔드포인트 를 코드소스에 기입할 예정이다.

3. API Service Lambda 생성

1. Create Lambda Function

  • 함수이름 : api-service-create

  • 런타임 : python 3.9

  • 아키텍처 : x86_64

  • 권한 : AWS 정책 템플릿에서 새역할 생성

    • 역할 이름 : my-lambda-role
    • 단순 마이크로서비스 권한 체크
  • URL 생성은 딱히 필요 없다.

  • Lambda Function
import json
import boto3
import random
import json

def lambda_handler(event, context):
    
    member_name = ['Ama','Jone','Zon','Penny','Jessie']
    member_status = ['Happy','Sad','Serious','Satisfied','Free']
    
    dynamodb = boto3.resource('dynamodb',endpoint_url='http://dynamodb.ap-northeast-2.amazonaws.com')
    member_table = dynamodb.Table('hello-member')
    
    name = member_name[random.randint(0,4)]
    status = member_status[random.randint(0, 4)]
    
    member_table.put_item(
       Item={
            'name': name,
            'status': status,
        }
    )
    
    documents = {'name':name,'status':status}
    
    print(documents)
    
    return {
        'statusCode': 200,
        'headers': {'Access-Control-Allow-Origin': '*'},
        'body': json.dumps(documents)
    }
  • dynamo db 에 member_table(hello-member) 을 만들고 테이블에 랜덤한 member_name 데이터와 member_status 데이터를 넣는 함수이다.

2. 코드 소스 Deploy & TEST

  • 테스트 이벤트를 작성

  • 테스트를 해보면 DB 가 생성되지 않았기 때문에 put_item 메서드가 실행되지 않아 오류를 뿜는다
Test Event Name
my-api-test

Response
{
  "errorMessage": "An error occurred (ResourceNotFoundException) when calling the PutItem operation: Requested resource not found",
  "errorType": "ResourceNotFoundException",
  "requestId": "4e3aa377-881a-443b-b6b6-897a983d413a",
  "stackTrace": [
    "  File \"/var/task/lambda_function.py\", line 17, in lambda_handler\n    member_table.put_item(\n",
    "  File \"/var/runtime/boto3/resources/factory.py\", line 580, in do_action\n    response = action(self, *args, **kwargs)\n",
    "  File \"/var/runtime/boto3/resources/action.py\", line 88, in __call__\n    response = getattr(parent.meta.client, operation_name)(*args, **params)\n",
    "  File \"/var/runtime/botocore/client.py\", line 530, in _api_call\n    return self._make_api_call(operation_name, kwargs)\n",
    "  File \"/var/runtime/botocore/client.py\", line 960, in _make_api_call\n    raise error_class(parsed_response, operation_name)\n"
  ]
}

Function Logs
START RequestId: 4e3aa377-881a-443b-b6b6-897a983d413a Version: $LATEST
[ERROR] ResourceNotFoundException: An error occurred (ResourceNotFoundException) when calling the PutItem operation: Requested resource not found
Traceback (most recent call last):
  File "/var/task/lambda_function.py", line 17, in lambda_handler
    member_table.put_item(
  File "/var/runtime/boto3/resources/factory.py", line 580, in do_action
    response = action(self, *args, **kwargs)
  File "/var/runtime/boto3/resources/action.py", line 88, in __call__
    response = getattr(parent.meta.client, operation_name)(*args, **params)
  File "/var/runtime/botocore/client.py", line 530, in _api_call
    return self._make_api_call(operation_name, kwargs)
  File "/var/runtime/botocore/client.py", line 960, in _make_api_call
    raise error_class(parsed_response, operation_name)END RequestId: 4e3aa377-881a-443b-b6b6-897a983d413a
REPORT RequestId: 4e3aa377-881a-443b-b6b6-897a983d413a	Duration: 1545.42 ms	Billed Duration: 1546 ms	Memory Size: 128 MB	Max Memory Used: 69 MB	Init Duration: 249.72 ms

Request ID
4e3aa377-881a-443b-b6b6-897a983d413a

3. DynamDB 생성

AWS 솔루션 아키텍트분이 말하길 Amazon DynamoDB는 DBA 가 필요고, 파티션 키에 대한 설정을 잘하면 누구나 쉽게 다룰 수 있다고 하셨다. 또한, 액세스 패턴이 정해져 있으면 성능이 매우 좋다고 한다.

  • 테이블 이름 : hell-member

  • 파티션 키 : name

  • create table
    • hello-member 이름을 가지고 name 이라는 기본키를 가진 테이블을 생성했다.


4. API GateWay 생성

1. REST API 생성

  • HTTP API 보다 API 관리 기능이 더 추가되어 있는 REST API 로 생성 (not private)

  • 프로토콜 : REST

  • 새 API생성 : 새 API

  • API 이름 : my-api

2. 작업에서 메서드 생성 및 설정

  • create method : GET

  • 통합 유형 : Lambda 함수

  • Lambda 프록시 통합 사용 : check

  • 리전 : ap-northeast-2

  • Lambda 함수 : 이전에 생성했던 api-service-create

  • 아까 lambda에 dynamoDB 권한만 넣었고, 여기에 api gateway 권한을 또 추가해주는 창이 뜨는데 OK 버튼을 눌러서 api gateway 에서 lambda 를 부를 수 있도록 구성한다.

3. TEST

  • 이제 권한도 완성했으니, 부를 수 있는 준비가 됐다. Method Execution 창에서 TEST 버튼을 눌러 테스트를 준비한다.

  • Test 버튼을 다시 눌러준다. 서비스가 더 복잡해지면 여기에서 Request Body 에 값을 추가하고 Headers 에도 추가할 수도 있지만, 지금은 아무 값도 넣지 말자

  • 테스트 결과 상태코드 200을 반환하면 성공한것이고, 응답 본문을 보면 랜덤하게 테이블에서 데이터를 가져온 것을 볼 수 있다.

4. API Gateway 추가 설정 (CORS Issue)

정말 강력하다 예전 Django 프로젝트중에 CORS 에러로 애를 많이 먹은적이 있었는데 클릭 한번으로 해결이 가능하다!!!

  • CORS 활성화 클릭

  • CORS를 활성화 했다면, API 를 배포

  • 배포가 완료됐다면 Invoke URL 이 생성되는데 기록해두자

  • Swagger로 내보낼 수도 있어 문서화도 가능하다


5. Lambda 와 API Gateway 와의 연결

  • 그 전에 만들었던 simple-webpage function으로 접속

  • 소스 코드를 들여다 보면 GET 메서드에 대해 EVENT 를 발생할 URL을 API Gate Way URL 을 입력

  • Deploy 후 Function URL 에 있는 URL 로 다시 접속

  • 누를때마다 랜덤하게 생기며 Dynamo DB에도 데이터가 저장된다.


6. 리소스 삭제

1. Lambda

2. Dynamo DB

3. Api Gateway


profile
무럭무럭 자라볼까

0개의 댓글