GoLang, DynamoDB를 이용해 Lambda 서버리스 구축해보기

오동재·2022년 7월 17일
2
post-thumbnail

서버가 없으면 CSR같은 느낌인가요?

서버 리스? Server Less. 서버가 없다니, 그냥 백엔드 없고 프론트엔드만 있는 건가? 라고 생각할 수도 있다. 나도 처음 '서버리스'라는 용어를 들었을 때, 'IPFS처럼 분산된 네트워크느낌인가?'라고 생각했으니 무리도 아니다.
하지만 서버리스는 그런 개념이 아니다.

서버를 관리하지 않아도 서비스할 수 있는 기술. 서버에 대한 고민없이 애플리케이션을 구축하고 실행할 수 있도록 설계한 Faas이다.

Faas

Function as a service
함수가 실행 될 때만 서비스를 제공한다는 의미이다.
즉 서버에 우리가 함수를 등록해놓고 함수가 실행될 트리거를 설정해놓으면, 해당 함수가 호출될 때만 잠깐 서버를 사용하고, 그러지 않을 때에는 서버를 사용하지 않는다.

서버리스의 장점

1. 비용 절감

  • 기존 서버 : 24시간 가동 => 그에 따른 비용이 청구됨
  • Faas : 특정 이벤트에 의해 실행 => 실행 횟수에 따라 비용이 청구됨
    그렇기 때문에 서버 호출이 그리 많지 않은 소규모 서비스, 혹은 신생 서비스 등은 Faas를 사용하는 것이 비용을 절약해줄 수 있다.

2. 개발 시간 단축

위에서 언급했듯이 서버를 관리하지 않아도 되기 때문에, 서버 환경을 구축할 필요 없이 그냥 함수만 설계하면 배포할 수 있다. 실제로 Coca-Cola Freestyle은 서버리스 기술을 이용해 개발에 착수하고 100여일만에 출시했다고 한다.

3. 자동 확장

이 또한 서버를 관리하지 않아도 되기 때문에 나오는 장점이다. 호출이 많아도 자동으로 트래픽에 따라 확장/축소를 해준다.

AWS의 서버리스

AWS에서 서버리스를 구현하기 위해서는 세 가지 개념에 대해 집고 넘어갈 필요가 있다.

1. API GateWay

인증과 인가

Authentication : 사용자가 누구인지 확인(로그인, 회원가입 등이 여기에 포함)
Authorization : 사용자가 접근권한이 있는 지 확인

API 라우팅

하나의 Client에서 온 요청을 여러개의 lambda로 연결시켜줄 수 있음

메시지 포맷 변환

JSON 요청을 받고 처리함

2. Lambda

서버를 프로비저닝하거나 관리하지 않고 코드를 실행할 수 있게 해주는 컴퓨팅 서비스

3. DynamoDB

AWS에서 제공하는 NoSQL 형식에 데이터베이스

partition key

필수, 고유한 값

sort key

안 필수, partition key와 sort key가 모두 있는 경우, 같은 partition key끼리는 sort key가 달라야 한다.

예약어

예약어란 사전에 약속되고 사용할 수 없는 변수명으로 예를 들면 Go언어의 for, if 등과 같다.
DynamoDB의 예약어에는 name. comment, date, number등이 있다. 생긴 건 예약어처럼 안 생겼는데, 예약어란다. 헷갈리기 딱 좋다.

실습 : 갤러리를 만들어보자

혹시 AWS 회원가입에 대해서도 포스팅이 있으면 좋을까요??
일단 계정은 모두 있다고 생각하고 스킵하겠습니다.

aws 계정에 접속해주자. API GateWay를 만들었는데 없어요~ DB도 아까 분명 만들었는데 없어졌어요~ 있는데 연동이 안되요~ 할 수 있다. 그럴 땐 지역을 확인하자. '서울'로 설정하자

API GateWay 생성

  1. aws console에서 'APIGateWay'를 검색하여 들어간 후 REST API를 구축하자

  2. 큰 특이사항 없이 아래와 스크린샷과 같이 빈칸을 채워주면 API GateWay가 생성된다.

DynamoDB 테이블 생성

  1. aws console에서 'DynamoDB' 검색 후, 들어가서 테이블을 생성하자. 나는 Gallery라는 이름의 Table을 만들었고, Partition key는 id로 설정해줬다. 간단한 데이터베이스기 때문에 Sort key는 따로 설정하지 않았다.

Lambda 함수 생성

  1. aws console에 'lambda'를 검색한 후, '함수 생성' 버튼으로 함수를 생성한다.
    함수이름은 편하게 지어주면 되고, 언어는 Go로 설정한다.
    그냥 생성하면 DynamoDB에 대한 권한이 없기 때문에 [기본 실행 역할 변경]을 해줘야 한다. '기본 실행 역할 변경'을 누르고 'IAM 콘솔'로 이동한다.나는 콘솔?

  2. 나는 콘솔에서는 'AWS 서비스'와 'Lambda'를 선택하고 다음으로 넘어간다.

  3. 그럼 권한정책을 선택할 수 있는데 다음 2개를 선택하자 DynamoDBFullAccess는 DynamoDB에 대한 모든 권한을 부여해주고 LambdaBasicExecutionRoles는 Cloud Watch에 로그를 남겨 확인할 수 있게 해준다.

  4. 태그는 설정하지 않고 넘어가고 이름은 좋을 대로 작성해주자. 그 후 IAM > 역할에 들어가면 생성한 역할을 확인할 수 있다.

  5. 이제 다시 돌아와서 '기존 역할 사용'을 선택한 후 방금 생성한 역할을 적용해주고 함수를 생성해버리자.

  6. 함수가 잘 생성된 것을 확인할 수 있다. 이제 한번 함수를 작성해보자.

함수 작성

굳이 Go로 Lambda를 이용하려고 이 글을 찾아보는 독자들이기에 GoLang을 기본적으로 한다고 전제하고, 코드에 대한 설명은 생략하겠다.

  1. 아래의 두 공식문서를 참고하여 DB에 subject, Image_url을 등록하는 Create함수를 작성하였다.
    https://docs.aws.amazon.com/ko_kr/lambda/latest/dg/golang-handler.html
    https://docs.aws.amazon.com/ko_kr/sdk-for-go/v1/developer-guide/dynamo-example-create-table-item.html
//main.go
package main

import (
	"context"
	"fmt"
	"log"
	"time"

	"github.com/aws/aws-lambda-go/lambda"
	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/aws/session"
	"github.com/aws/aws-sdk-go/service/dynamodb"
	"github.com/aws/aws-sdk-go/service/dynamodb/dynamodbattribute"
)

type MyEvent struct {
	Subject   string `json:"subject"`
	Image_url string `json:"image_url"`
}

type Picture struct {
	Id        int64  `json:"id"`
	Subject   string `json:"subject"`
	Image_url string `json:"image_url"`
}

func HandleRequest(ctx context.Context, myInput MyEvent) (string, error) {
	sess := session.Must(session.NewSessionWithOptions(session.Options{
		SharedConfigState: session.SharedConfigEnable,
	}))

	// Create DynamoDB client
	svc := dynamodb.New(sess)

	picture := Picture{
		Id:        time.Now().UnixNano() / 1000000,
		Subject:   myInput.Subject,
		Image_url: myInput.Image_url,
	}

	av, err := dynamodbattribute.MarshalMap(picture)
	if err != nil {
		log.Fatalf("Got error marshalling new movie item: %s", err)
	}

	// Create item in table Movies
	tableName := "Gallery"

	input := &dynamodb.PutItemInput{
		Item:      av,
		TableName: aws.String(tableName),
	}

	_, err = svc.PutItem(input)
	if err != nil {
		log.Fatalf("Got error calling PutItem: %s", err)
	}

	return fmt.Sprintln("Successfully added '" + picture.Subject + " to table " + tableName), nil
}

func main() {
	lambda.Start(HandleRequest)
}
  1. 함수를 작성한 후, linux 환경으로 빌드해준 후 이를 압축해주자.
GOOS=linux GOARCH=amd64 CGO_ENABLED=0 go build -o main main.go
zip function.zip main
  1. 압축한 zip파일을 업로드하고 핸들러를 main으로 입력해준다.

  2. 테스트를 해보자.

    테스트를 누르면 성공적으로 실행된 것을 확인할 수 있고

    DynamoDB에서 확인해보면 데이터가 성공적으로 생성된 것을 볼 수 있다!

  3. 이와 같은 방법으로 나머지 함수들도 생성해주었다. 함수 내용은 https://github.com/donggni0712/ServerLess_Go 에서 확인할 수 있다.

API GateWay 연결

  1. 생성했던 API GateWay에 접속해서 [작업] -> [메서드 생성]으로 메서드를 생성하자

  2. 생성한 Lambda함수들을 연결해주자.

  3. get, put, post, delete를 모두 연결해주자. put에는 update함수를 연결해준다.

  4. 그리고 POST의 메서드 요청을 수정해주자. [요청 검사기]는 '본문 검사'로 입력하고 [요청 본문]에 모델을 추가해 줘야 한다. 모델을 만들고 와보자.

  5. [모델 생성]에서 [콘텐츠 유형]은 'application/json'으로 하고 스키마는 아래와 같이 적어주자. 이름은 뭐 마음대로 해도 된다.

  6. 다시 돌아와서 [모델 이름]은 방금 만든 모델을 선택해주고 콘텐츠 유형은 'application/json'으로 입력하자.

  7. 아래와 같은 request body로 테스트해주면 테스트가 잘 되는 것을 확인할 수 있다.

  8. CORS를 활성화 시켜줘야 다른 웹페이지에서도 권한 문제 없이 API를 호출할 수 있다. AWS API GateWay에서는 [CORS 활성화]버튼으로 모든 메서드에 간단하게 권한을 허용해줄 수 있다.

    버튼을 누르면 아래와 같이 적용된다.

  9. 이제 테스트가 아니라 외부에서도 호출할 수 있도록 배포해주자.

  10. 배포된 URL을 확인할 수 있다.
    업로드중..

profile
https://donggni0712.tistory.com 로 이사했습니다~

0개의 댓글