AWS Lambda를 이용한 API 서비스 배포 (2/2) – API Gateway

지난 글에 이어서 AWS Lambda와 API Gateway를 연동하여 서비스 배포하는 과정을 소개합니다. 이 글에서는 AWS Lambda 보다는 API Gateway 사용에 포인트를 두고 있습니다. AWS Lambda가 더 궁금하신 분들은 이전 글을 봐주세요. 링크:[AWS Lambda를 이용한 API 서비스 배포 (1/2)]

API GateWay는 무엇인가?

AWS에서는 다음과 같이 설명하고 있습니다.
“Amazon API Gateway는 어떤 규모에서든 개발자가 API를 손쉽게 생성, 게시, 유지 관리, 모니터링 및 보안할 수 있게 해주는 완전관리형 서비스입니다.”

API GateWay를 사용하면 어떤 장점들이 있을까요?

AWS콘솔을 통해서 트래픽관리와 모니터링을 쉽게 할 수 있습니다.

트래픽 제어도 콘솔에서 비교적 간단하게 처리할수 있습니다. 또한 제공되는 대시보드를 통해서 API호출, 오류발생률, 응답시간등을 시각화된 UI로 쉽게 볼수 있습니다. 제 견해로는 이 부분이 사실 비용면에서도 유리하다고 생각합니다. 관리인원에 대한 비용, 시간비용을 절약할 수 있다고 봅니다.

기존 서비스를 위한 RESTful 엔드포인트 생성할 수 있습니다.

AWS콘솔에서 다뤄보면 아시겠지만 RESTFul API 서비스를 배포하기 쉽게 구성이 되어 있습니다.
개발자로서 주목할만한 점은 기존에는 웹프로그래밍으로 구현했던 GET, POST, PUT, DELETE등의 메서드들을 쉽게 콘솔조작으로 적용할 수 있다는 점이었습니다.

매우 쉽게 한개의 도메인(예: api.algopie.com)으로 엔드포인트를 만들고 실제로는 각 메서드들 혹은 각 리소스마다 다른 서버로 분산처리 할 수 있습니다.
AWS 사용 이전에 트래픽 분산처리를 위해 사용했던 시간과 기술비용등을 고려해 볼때 이 부분은 매우 큰 장점입니다.

AWS 서비스들과 쉽게 연동할 수 있습니다.

자사 제품을의 사용률을 높이기 위해 AWS에서 당연히 설계시 반영되었겠지만 그래도 쉽게 연동할 수 있다는점도 또한 장점입니다. AWS Lambda, CloudFront등 연동 작업을 매우 간결하게 할 수 있습니다.

 

API Gateway 시작하기

위와 같이 New API를 체크하고 API name과 Description을 쓰고 Create API 버튼을 누릅니다.

REST의 3요소

계속해서 진행하려면 먼저 Resource를 만들어야 하는데 RESTful API에 관심이 없으신 분들은 Resource 라는 단어는 갖고 있는 광범위한 의미때문에 약한 헷갈릴 수도 있는 단어입니다. REST는 HTTP 스펙 본연의 디자인에 충실하게 API를 구현하기 위하여 제안된  아키텍쳐입니다.  간단하게 REST는 Resource, Method, Message 이렇게 3가지 요소가 있습니다. API Gateway를 사용하기 위해 매우 간단하게만 다루겠습니다.

Resource

사용하고 행위(?)하고자 하는 목적이 되는 대상입니다. https://api.algopie.com/products 와 같은 형태의 URI로 표현합니다.

Method

대상 (Resource)에 대한 행동 방법입니다. 대상 Resource를 생성, 삭제, 수정, 불러오기(보기)등에 대한 행동 방법입니다. HTTP의 method를 그대로 사용합니다. GET (불러오기, 보기등), POST(생성), PUT(수정), DELETE(삭제)등의 HTTP method. 기존 구형의 레거시 스타일에서는 HTTP 요청시에 GET, POST만 주로 사용했었으며 생성, 삭제, 수정, 읽기등 모든 행동을 GET과 POST로 사용하거나 심지어 POST 하나만으로도 사용하는 경우도 있었습니다. REST 아키텍쳐에서는 똑같은 http URL 호출일지라도 method에 따라서 그 결과가 달라집니다.

https://api.algopie.com/products 라는 하나의 URI로도 GET으로 요청하면 product의 리스트를 응답하고 POST로 요청하면 새로운 product를 추가할 수 있습니다. 마찬가지로 DELETE로 요청하면 해당 product를 삭제하게 됩니다.

Message

대상에 대한 내용 입니다. 최근 트렌드는 JSON을 많이 사용합니다. XML로 통칭되는 확장된 마크업랭기지의 경우 JSON에 비하여 사용되는 패킷량도 많고 복잡도도 증가하여 요즈음에는 거의 JSON이 대세가 되었습니다. 위 예에서 https://api.algopie.com/proudcts 리소스를 GET으로 요청하면 product에 대한 아래와 같은 내용을 응답합니다.


[{\"url\": \"https://algopie.com\", \"name\": \"Algorithm Pie\", \"idx\": 1, \"description\": \"\\uc5ec\\ub7ec\\uac00\\uc9c0 \\ubb38\\uc81c\\ub97c \\ub2e4\\uc591\\ud558\\uace0 \\uc7ac\\ubc0c\\uac8c \\ud574\\uacb0\\ud558\\ub294 \\uc54c\\uace0\\ub9ac\\uc998 \\ud30c\\uc774\"}, {\"url\": \"https://biblepuzzle.algopie.com\", \"name\": \"Bible Puzzle\", \"idx\": 2, \"description\": \"\\uac00\\ub85c\\uc138\\ub85c \\uc131\\uacbd \\ud37c\\uc990!\"}]

REST에 대한 설명은 매우 부족하지면 본편을 위하여 이정도로 마무리 합니다. 이 글에서 주로 다루는 것은 Resource와 Method 입니다.

Resource 생성하기

다시 본편으로 돌아와서 아래 이미지와 같이 Resource를 생성합니다.

이 예제에서는 products 라는 리소스를 사용하겠습니다. 리소스 이름을 적어주시면 path는 자동으로 지정되는데 path는 수정 가능합니다. Create Resource 버튼을 눌러서 마무리 합니다.

Method 생성하기

Method를 아래와 같이 생성합니다.

이 글에서는 간단하게 GET 메서드만 배포하겠습니다. 메서드 생성시에 아래와 같이 GET을 선택하여 생성합니다.

우리는 API Gateway를 AWS Lambda와 연동 할 것이기 때문에 GET 메서드에 대한 셋팅을 AWS Lambda 사용을 휘한 셋팅으로 아래와 같이 합니다. 미리 만들어 놓은 lambda function을 아래와 같이 선택합니다. 참고로 저는 서울 region을 사용하기 때문에 Lambda Region은 ap-northeast-2 입니다.

먼저  AWS Lambda 에서 제대로 동작하는 function이 준비되어야 Lambda function을 사용할 수 있습니다. 이전 글에서 만든 function은 디비에 테이블을 생성하고 insert 하는 부분까지 있어서 그대로 사용하기엔 약간의 무리가 있지만 귀찮으신 분들은 그대로 사용하셔도 작동하긴 합니다. 다만 RESTful 하지 않을 뿐입니다. 되도록이면 이전 글을 보시고 응용하셔서 새로은 function을 만들어 보시는 것을 추천합니다. 링크:[AWS Lambda를 이용한 API 서비스 배포 (1/2)]

API 테스트

메서드 생성이 완료되면 아래와 같은 화면을 볼 수 있습니다. Request 부터 Response 까의 경로를 보여주고 있습니다.

가운데 TEST (번개표)를 누르시면 제대로 동작하는지 테스트 할 수 있습니다. 아래와 같이 잘 동작하는 군요. Response body 부분을 보시면 Json으로 된 body 응답을 보 실 수 있습니다. 레이턴시가 116 ms 로 나오는데 저의 경우 그때 그때 다릅니다. 이 경우는 매우 빠른 경우이고 느릴때도 있습니다. 추후 API 분산 처리를 위하여 CloudFront 연동시 보다 나은 퍼포먼스를 기대해 봅니다.

 

아직 끝이 아닙니다. 중요한 과정 하나가 더 남아 있습니다.

Deploy 하기

마지막 과정으로 우리가 생성한 API를 배포 하는 과정이 남았습니다. 리소스를 선택하고 메서드를 선택하고 Action 버튼을 눌러서 아래와 같이 Deploy 합니다.

Stage는 없으실 경우 New Stage로 새로 만들어 주세요. 제 기억이 가물가물해서 prod 스테이지가 위 과정중에 생성이 되었는지 제가 만들었는지 기억이 잘 나지 않네요.  필요한경우 추후에 업데이트 하겠습니다.

제대로 사용 하려면 Usage Plan, dl인증키관리 등도 함께 다뤄야겠지만 이번 글은 여기서 마치도록 하겠습니다.

AWS Lambda를 이용한 API 서비스 배포 (1/2)

AWS Lambda가 무엇 인가요?

AWS에서 설명하는 Lambda는 “이벤트에 응답하여 코드를 실행하고 자동으로 기본 컴퓨팅 리소스를 관리하는 서버 없는 컴퓨팅 서비스입니다.” (이전 AWS관련 글에도 적었지만 매번 씁니다. ^^ AWS에서 제공하는 문서를 보시면 더 자세한 내용이 있습니다. https://aws.amazon.com/ko/lambda/details/)여러 가지 특징중에 특히 강조할 만한 것은 서버없는 서비스(serverless services)가 가능하다는 것 입니다. 좀 더 구체적으로 말하면 내가 관리해야할 서버가 없이도 서비스를 제공할 수 있다 입니다. 서버 상태를 관리하지 않아도 되면 많은 비용과 스트레스를 줄일 수 있습니다. AWS Lambda를 사용해서 서버 관리에 필요한 당연히 예상되는 비용(시간, 돈, 사람등)을 획기적으로 줄일 수 있다면 거기에 포인트를 두고 서비스를 설계 개발 하는것이 필요합니다.

그럼 AWS Lambda는 어디에 쓰는 물건 인가요?

AWS의 서비스들과 관계가 적은 복잡한 기능을 수행해야만 하는 특별한 나만의 맞춤 서버가 필요하다면 AWS Lambda 보다는 EC2를 활용하는 것을 권장합니다. AWS Lambda에서 제공 하는 Lambda Trigger를 이용하여 AWS 서비스와 연계된 이벤트를 처리할 때 사용하기에 유용합니다. 그 외에 API 기능을 API서버 없이 구현하기에도 유용합니다. 물론 API 서버로서 활용하고 싶다면 AWS Lambda 뿐만 아니라 API Gateway와 연계하여 설계하는 것이 더 효율적입니다. (이 내용은 다음 포스팅에서 다룹니다.)

AWS 서비스 내의 이벤트에서 트리거를 만들어서 처리할 수 있는 서비스들은 아래와 같습니다.(스크롤로 안보이는 S3, SNS 서비스도 포함되어 있습니다.)

구글링해서 보통 많이 볼 수 있는 사용 예는 http api 서버 기능 제공, S3를 활용한 이미지 자동 처리, SNS를 활용한 notification에 대한 자동 처리, CloudWatch 특정 이벤트 발생시 원하는 액션 처리등이 있습니다. 이 글에서는 비교적 구현하기 간단하고 많이 사용하는 http api 서비스를 배포하는 것을 목적으로 아래의 4가지 내용을 다루겠습니다.

1. Python으로 function 작성하기 및 패키징
2. S3를 활용한 function 배포
3. AWS Lambda 설정
4. Testing

1. Python으로 function을 작성하고 패키징 하기

Lambda function 코드를 업로드 하는 방법중 S3을 이용한 방법이기 때문에 AWS Lambda 서비스를 설정하기 전에 코드를 작성하여 S3 버킷에 올려 놓겠습니다.

시행착오를 줄이고자 먼저 두 가지 유의 사항을 알려드립니다.

  • Lambda function 코드를 작성할때 추가로 사용하는 python 모듈이 있을경우 해당 모듈을 모두 함께 패키징 해서 zip파일로 올려야 합니다.
  • 높은 확률로 Linux 에서 패키징을 해야 정상 작동 합니다.

각각의 Lambda function은  논리적으로 독립된 공간에서 실행 된다고 가정하는 것이 맞을 듯 합니다. 그래서 다른 function을 작성할때 이전에 이미 필요한 모듈을 같이 올렸다고 하더라도 import 에러가 발생하는 것을 볼 수 있습니다. 또한 AWS Lambda는 Linux 기반에서 실행되니 Windows 파일 시스템에서 패키징 한것은 제대로 돌아 가지 않을 확률이 매우 높습니다.

이번 예제에서는 MariaDB 혹은 MySQL을 사용하기 때문에 pymysql 모듈을 함께 패키징 해야 합니다. EC2 우분투 에서 패키징하고 awscli를 이용하여 S3으로 바로 업로드 하는 방법을 사용하겠습니다.

코드는 Windows 용 IDE 와 같은 편하신 환경에서 작성하시고 ec2 에 올려서 패키징 하겠습니다. 코드가 간단해서 vim 에디터 사용 가능하시면 직접 vim으로 작성하셔도 좋습니다. 코드는 aws에서 제공하는 example을 사용하겠습니다.
(http://docs.aws.amazon.com/lambda/latest/dg/vpc-rds-deployment-pkg.html)

예제에 나온대로 2개의 파일을 작성합니다. 먼저 메인 fuction인 getProducts.py 파일 입니다.

# getProducts.py
import sys
import logging
import rds_config
import pymysql

# rds settings
rds_host = "rds-instance-endpoint"
name = rds_config.db_username
password = rds_config.db_password
db_name = rds_config.db_name

logger = logging.getLogger()
logger.setLevel(logging.INFO)

try:
    conn = pymysql.connect(rds_host, user=name, passwd=password, db=db_name, connect_timeout=5)
except:
    logger.error("ERROR: Unexpected error: Could not connect to MySql instance.")
    sys.exit()

logger.info("SUCCESS: Connection to RDS mysql instance succeeded")


def handler(event, context):

    item_count = 0

    with conn.cursor() as cur:
        cur.execute("create table IF NOT EXISTS employee ( EmpID  int NOT NULL, Name varchar(255) NOT NULL, "
                    "PRIMARY KEY (EmpID))")
        cur.execute('insert into employee (EmpID, Name) values(1, "Joe")')
        cur.execute('insert into employee (EmpID, Name) values(2, "Bob")')
        cur.execute('insert into employee (EmpID, Name) values(3, "Mary")')
        conn.commit()

        cur.execute("select * from employee")
        for row in cur:
            item_count += 1
            logger.info(row)
            print(row)

    return "Added %d items from RDS MySQL table" % (item_count)

def handler 의 arguments 를보시면 단박에 감 잡으실 것 같은데 그것 맞습니다!  다른 부분은 python 언어의 일반적인 내용인데 여기서 handler, event, context에 대한 개념은 꼭 이혀두시길 권장 합니다.

handler

Lambda funtion이 호출될때 실행하는 handler를 위와 같은 형식으로 정의 해놓고  c나 java의 Main 함수 처럼 사용합니다. handler라는 이름은 당연히 수정하셔도 됩니다. main으로 실행할 함수를 정의하시고 추후 aws Lambda 콘솔에서 handler로 지정합니다. handler (event, context)의 포맷만 기억하시면 됩니다.

event

Lambda function을 실행할때 넘겨주는 파라메터들을 이 event로 받아서 처리 할 수 있습니다. http로 lambda를 실행할때 get, post, put, delete 등의 메서드를 통해서 전달 할 수 있습니다. JAVA servlet 에서 doGet, doPost 등에 있는 requst 와 같은 역할을 합니다.

context

Lambda function이 실행완료 하고 context를 통해 return 할 수 있습니다. 성공 메시지, 실패 메시지등을 리턴 할 수 있습니다. JAVA Servlet으로 보면 doGet doPost등의 response와 같은 역할을 합니다.

해당 내용은 튜토리얼에 자세하게 나와 있으니 그냥 넘어가지 마시고 꼭 보시기를 권장합니다.
(http://docs.aws.amazon.com/ko_kr/lambda/latest/dg/python-programming-model-handler-types.html)

다음은 rds 계정정보가 있는 rds_config.py 파일 입니다.

rds_config.
db_username = "db_user_name"
db_password= "db_password"
db_name = "algopie"

저는 임시로 ubuntu 계정 디렉터리 하위로 repo/lambda/getProudcts 라는 디렉터리를 생성하고 그 하위에 위 2개의 파일을 위치 시켰습니다. 이제 패키징 합니다.

python module installation

앞서 설명 했듯이 패키징시 필요한 외부 모듈들이 모두 함께 포함되어야 실제 function 실행시 import 에러가 나지 않습니다. 그래서 외부 모듈들을 같은 디렉토리에 인스톨 하는 과정이 필요합니다. 본인이 작성한 모듈을 다른곳에 배포하기 위해 setup.py를 작성하는 작업도 필요합니다.

aws 튜토리얼에 다 나와 있습니다.
(http://docs.aws.amazon.com/ko_kr/lambda/latest/dg/lambda-python-how-to-create-deployment-package.html)

ec2-shell> cd /home/repo/lambda/getProducts
ec2-shell> vi setup.py

아래는 setup.py 내용입니다. py_module 부분과 setup.name 부분이 중요합니다. 외부 모듈을 사용하므로 아래 예시처럼 pymysql을 명시해주세요.

from distutils.core import setup

py_modules = [
 'pymysql',
]

setup(
    name='getProducts',
    version='0.1',
    packages=[''],
    url='',
    license='',
    author='YourName',
    author_email='',
    description=''
)

이제  pip install 로 외부 모듈을 같은 위치에 인스톨 합니다. 명령어 패턴은 aws 튜토리얼에 나온대로 pip install module-name -t /path/to/project-dir 입니다. 이미 change directory로 소스가 위치한 root 디렉터리에 와 있으므로 아래와 같이 typing  합니다.

 ec2-shell> pip install pymysql -t ./ 

성공적으로 모듈이 설치되면 아래와 같은 메시지가 나옵니다.

zip 으로 압축

하위디렉터리까지 몽땅 압축합니다.

ec2-shell> zip -r getProducts.zip *

2. S3를 활용한 function 배포

s3 버킷으로 업로드

awscli를 설치하신 상태라면 아래 커맨드라인으로 업로드 하시면 됩니다. 혹시 awscli가 무엇인지 모르시거나 아직 설치 하지 못하신 분들께서는 이전 포스트에 상세히 작성해 놓았으니 보시고 awscli를 설치해주신 다음에 아래 순서를 진행해 주세요. s3를 관리하는 cli 명령어 옵션에 대한 설명도 링크로 걸어둡니다.

링크1: AWS ec2 우분투(ubuntu)에 awscli 설치 하기

링크2: AWS CLI를 사용하여 ec2에서 s3로 업로드/다운로드 하기 (우분투 Ubuntu)

ec2-shell> aws s3 mb s3://algopie-functions
make_bucket: algopie-functions

ec2-shell> aws s3 cp ./getProducts.zip s3://algopie-functions/
upload: ./getProducts.zip to s3://algopie-functions/getProducts.zip

이제 가장 긴 고비를 넘기셨으니 얼마 안남았네요

3. AWS Lambda 설정

AWS 콘솔에서 AWS Lambda를 선택하면 제일 처음 대시보드가 나옵니다. Create Function 버튼을 누르고 새로운 funtion을 생성합니다. (저는 이미 2개의 사용중인 funtion이 있어서 아래와 같이 나오네요)

다음으로 넘어가면 각종 예제들이 포함되어 있는 Blueprint 항목이 나옵니다. 하지만 여기서는 그냥 그대로 따라하기 보다는 RDS와 연동하여 테이블 데이터를 쿼리하여 Json 포맷으로 뿌려주는 HTTP API를 만들기로 했으니 왼쪽 메뉴에서 “Configure Function” 버튼을 눌러줍니다. 아래와 같이 지원하는 언어는 5가지 입니다. 이 중에서 저는 Python으로 코드를 작성하겠습니다. (Python은 저도 몇번 접해 보기만 한 언어입니다. 이 참에 제대로 익혀 보자는 생각으로 골랐습니다. )

일단 이번 예제에서는 짧게 넘어가겠지만 AWS Lambda로 API 서비스를 구현하실 분들께서는 생각을 좀 해보셔야 하는 것이 있습니다. 바로 위 화면중 “Name”에 넣어야 할 Function Name 입니다. HTTP API 설계를 생각하시는 분들은 이미 머리속에 RESTful 이라는 단어가 있을 것 입니다. AWS Lambda 로 직접 API 서비스를 하실 계획을 가지신 분들은 별로 없을 것 같습니다. AWS에서도 API Gateway와 연동할 것을 권장하고 있습니다. 저도 API Gateway를 활용하여 RESTful한 멋진 API 서비스를 만들어 보시는 것을 추천합니다. 물론 이 AWS Lambda function을 direct로 HTTP API 서비스로 배포할 생각이 없으셔도 AWS Lambda Funtion naming 관련하여 시간을 내서 검색도 해보시고 본인에게 가장 설득력 있는 Naming 규칙을 사용하실 것을 권장합니다.

Name* : getProducts

네 그렇습니다. 전혀 RESTful 한 함수 이름이 아니야! 라고 할 수 있습니다. RESTful 한 naming 은 추후 API Gateway를 다룰 때 사용합니다!

Runtime*: Python 2.7

그리고 다음 아래로 내려 갑니다. 다음은 코드를 어디서 업로드할지 선택해주는 화면 입니다. 아래 화면과 같이 Upload a file from Amazon S3을 선택하시고 아래 s3 link URL에 아까 만들어준 s3 URL을 적어줍니다. 저와 동일하게 하셨다면 link url은  https://s3.amazonaws.com/algopie-functions/getProducts.zip 입니다.

환경변수를 셋팅하는 기능도 제공합니다. key-value 페어형태로 해당 functon 전역에서 사용할 수 있는 환경 변수를 셋팅할 수 있습니다. 이 예제에서는 넘어갑니다.

아래는 중요한 셋팅 내용들이 있으니 이왕 해보시는 김에 확실히 익혀두시기를 권장합니다. 위에 한번 중요하게 handler에 대한 부분을 작성했습니다. 드디어 여기에 나오는군요.

 

Handler*: 위 python 코드에서 handler(event, context) 를 정의 하였는데 Handler에 위에 정의해 놓은 함수명을 적어줍니다. 예시의 getProducts.py의 handler 이므로 getProducts.handler 입니다. 일종의 네임스페이스 개념이라고 생각하시면 될듯 합니다.

Advanced setting: 메모리나 타임아웃등에 대하여 셋팅할 수 있고 저는 기본으로 두고 진행했습니다. 튜토리얼을 보면 설명이 나옵니다. 간단하게 설명하면 디테일하게 셋팅하여 퍼포먼스를 높일 때 사용합니다.

Roll*: AWS의 IAM롤에서 lambd 전용 롤을 만들고 적용하겠습니다. 위 예시와 같이 new roll을 선택하시고 roll name을 적으시면 새로운 롤을 만드는 창이 오픈됩니다.

lambda basic execution 을 선택하고 policy name도 제공해주는 것을 사용하였습니다. IAM 관련하여서는 추후에 깊게 다룰 예정입니다. 이전 포스팅에서 awscli 의 access key id와 secret key를 발급 할때 다룬 내용을 참고하셔도 됩니다.

링크: IAM  유저생성

다시 Lambda 설정으로 돌아옵니다. 드디어 끝이 보이네요.
VPC는 virtual private cloud 로 쉽게 설명하면 가상 개인 네트워크 정도로 말 할 수 있습니다. vpc 셋팅을 통해서 aws 내부 접근과 외부접근에 대한 제어를 할 수 있습니다. 자세한 설명은 aws docs링크를 보시는 것을 권장합니다. http://docs.aws.amazon.com/ko_kr/AmazonVPC/latest/UserGuide/VPC_Introduction.html

Secret Group*: 저의 경우 Lambda 전용으로 하느를 만들었고 inbound, outbound 모두 모든 포트를 anywhere 로 오픈했습니다. Next 버튼을 누르면 review 화면이 나오고 마지막으로 creating 버튼을 누르면 약간의 시간을 대기하고 모든 과정이 완료됩니다. “Save and Test” 버튼을 누르시고 다음 과정으로 넘어 갑니다.

자 드디어 대망의 테스팅 입니다. 과연 잘 작동할까요? 두근두근!

4. Testing

Test 버튼을 누르시면 잠시후 테스트 결과가 나옵니다.

위에 우리가 작성한 대로 employee 라는 테이블을 생성하고 3개의 row를 insert 하여 위와 같은 결과가 리턴 되었습니다.  Lambda function 셋팅 자체보다는 선행해야할 셋팅들이 많아서 예상보다 긴 길이 되었습니다. 긴글 따라 오시느라 수고 많으셨습니다.