Google Cloud Platform에서는 여러가지 형태의 Serverless 서비스들을 지원하고 있다.
이번 포스팅에서는 그 중에서도 Google Cloud Function에 대해서 알아본다.
Google Cloud Function은 Google Cloud Platform 이 제공하는 서비스 중에서 가장 AWS의 Lambda와 유사한 서비스다.실제로 검색해보면 Azure의 Function과 함께 종종 비교되는 글을 볼 수 있다. Spec적인 부분에 대해서는 어느정도 차이가 있으나 사용 방식에 대해서는 전부 비슷하다.
사용하기
프로젝트 Market Place의 서버리스 항목 중에서 Cloud Function을 선택한다.
사전에 만들어놓은 Function이 없다면 위와 같이 간단한 설명이 출력된다. 함수 만들기를 클릭한다.
각 항목을 입력한다.
함수 이름: 함수 이름을 입력한다. 영문 기준 62자 제한이 있고 소문자, 숫자, 하이픈, 밑줄만 사용가능하고 마지막 글자는 문자나 숫자여야한다는 제한이 있다.
리전: 데이터센터 위치를 선택한다. 한국은 asia-northeast3이다.
트리거 유형: 이 함수가 트리거될 방법을 선택한다. Default로 HTTP가 선택되어 있다.
그 외에 Cloud Pub/Sub, Cloud Firestore, Cloud Storage과 기타 Firebase 용 설정이 있다.
HTTP를 선택할 시 트리거를 발생시킬 수 있는 http 주소 및 발생 주체의 인증 여부를 선택할 수 있다
기타 추가 설정탭을 확인한다.
런타임 항목에서는 Function이 동작하기 위한 리소스 설정을 할 수 있다.
기본으로 할당 메모리가 256MB으로 설정되어 있고 2의 배수로 추가 설정할 수 있으며 최대 8GB까지 설정가능하다. 일부 메모리 자원이 많이 필요한 동작이 있다면 미리 추가로 설정 해놓는다.
시간 제한은 이 함수가 이 시간 내에 마무리되는 timeout으로, 기본 60초로 설정되어 있다.
Auto Scaling은 최대 1000개 까지 자동 설정되어 있다.
런타임 환경변수는 런타임 중에 사용할 환경 변수를 정의하는 부분으로, 필요한 값이 있다면 별도로 설정한다.
각각의 설정들이 끝나면 저장을 클릭하고 다음을 선택한다.
트리거를 받으면 동작할 코드를 작성하는 부분이다.
런타임으로는 Nodejs, Golang, Python, Ruby, .NET이 지원된다. 처음 Serverless Function 기능을 접한 사람은 제공되는 런타임이 적은 이유에 대해서 의아할 수 있는데, Function 기능 특성 상 설정한 런타임이 동작하기 위해 이미 환경이 구축된 서버 위에서 동작을 해야한다.
따라서 제공 환경이 구축된 서버를 안정적으로 제공하기 위해서는 버전 업그레이드 등의 이슈로 인해 환경 유지 보수하는 부분에 있어 상당한 제약이 따를 수 밖에 없다. 이때문에 언어의 버전 업데이트도 제한적이고, 많은 언어를 제공하는 것에도 제약이 따른다(서비스 되는 언어가 늘어나면 그만큼 서버 유지보수가 늘어날 수 밖에 없다). 이런 부분을 개선하기 위해 컨테이너 기반 서버리스 서비스들을 제공하기도 한다.
아래는 golang 선택 시 보여지는 기본 코드다.
// Package p contains an HTTP Cloud Function.
package p
import (
"encoding/json"
"fmt"
"html"
"io"
"log"
"net/http"
)
// HelloWorld prints the JSON encoded "message" field in the body
// of the request or "Hello, World!" if there isn't one.
func HelloWorld(w http.ResponseWriter, r *http.Request) {
var d struct {
Message string `json:"message"`
}
if err := json.NewDecoder(r.Body).Decode(&d); err != nil {
switch err {
case io.EOF:
fmt.Fprint(w, "Hello World!")
return
default:
log.Printf("json.NewDecoder: %v", err)
http.Error(w, http.StatusText(http.StatusBadRequest), http.StatusBadRequest)
return
}
}
if d.Message == "" {
fmt.Fprint(w, "Hello World!")
return
}
fmt.Fprint(w, html.EscapeString(d.Message))
}
로컬에서 구축하면 handleFunc에서 등록될 서비스를 작성하는 것과 유사하게 http.ResponseWriter와 *http.Request 인자를 가진 함수를 정의하는 것을 알 수 있다. 즉 서버의 구성 같은 부분은 상관없이 순수하게 동작할 로직만 구현하는 것이다.
배포를 클릭해서 함수를 생성한다.
함수를 생성하면 아래와 같이 함수 목록에 생성한 함수가 표시된다.
작업을 클릭해서 함수 테스트를 해본다.
아래와 같이 트리거 이벤트 항목을 공란으로 두고 함수 테스트를 클릭한다.
그 결과로 Hello World!가 출력되는 것을 볼 수 있다. 이는 위 코드에서 알 수 있듯이 HelloWorld 함수에서 트리거가 들어오면 별다른 동작없이 Hello World!만을 출력하게 구성되어 있기 때문이다.
서버리스 자체가 쿨 스타트 존재로 인해 헤비한 서비스를 다루기는 어려우나, 주기적인 Job이나 이벤트 트리거를 위한 동작으로 사용하기엔 상당이 용이하다.