Amazon Web Services 한국 블로그

[AWS Heroes 특집] 스타트업이라면 이제 서버리스(Serverless)로 시작하자!

AWS 서버리스 히어로인 Slobodan StojanovićServerless Applications with Node.js의 공동 저자이며 소프트웨어 개발 스튜디오인 Cloud Horizon의 CTO이자 Slack 기반 휴가 관리 앱인 Vacation Tracker의 CTO입니다. 더 빠른 속도와 더 저렴한 비용으로 소프트웨어를 구축할 수 있다는 점에서 서버리스에 열광하는 Slobodan 는 종종 서버리스에 대한 글을 기고하고 컨퍼런스에서 서버리스를 주제로 발표합니다.

서버리스(Serverless)는 스타트업을 위한 완벽한 기술인 듯합니다. 사용량 기반 요금 모델 및 인프라를 기반으로 하기 때문에 앱을 사용하는 사용자가 한 명도 없다면 비용이 전혀 발생하지 않으므로 초기 단계의 스타트업에서 비용을 절감하는 데 도움이 됩니다.

뿐만 아니라 자동으로 조정되는 완전관리형 서비스이기 때문에 대규모 마케팅 캠페인이나 예기치 못한 트래픽을 염려할 필요가 없습니다. 우리가 회사의 첫 번째 제품인 Vacation Tracker에 대한 작업을 시작할 때 서버리스를 사용하기로 결정한 이유도 여기에 있습니다.

Vacation Tracker는 팀의 휴가 및 연차를 추적하고 관리할 수 있는 Slack 기반 앱입니다. 회사의 Slack 앱과 웹 기반 대시보드 모두에 API가 필요했기 때문에 Amazon API Gateway로 트리거되는 AWS Lambda 함수에서 시작하는 게 논리적으로 적절했습니다. API Gateway는 퍼블릭 API를 제공합니다. API가 요청을 수신할 때마다 Lambda 함수가 트리거되어 요청에 응답합니다.

이 앱은 중소 규모 팀에 중점을 두고 개발되었으며 하루에 몇 번 밖에 사용되지 않습니다. 사용량에 따라 요금을 지불하는 서버리스 요금 모델은 주기적인 사용량 패턴에 큰 이점을 제공합니다. 처음에는 API Gateway와 Lambda의 사용 요금이 (프리티어 안에서) 무료이기 때문입니다.

소규모로 시작해서 확장하기

우리는 단순한 프로토타입을 사용해 소규모로 시작하기로 결정했습니다. 하드코딩된 작업 몇 개와 작은 캘린더가 포함된 실제 Slack 앱을 프로토타입으로 만들고, Claudia.js 및 봇 빌더를 사용해 앱을 구축했습니다. Claudia.js는 Lambda 및 API Gateway에 Node.js 서버리스 함수를 배포할 수 있는 단순한 도구입니다.

프로토타입을 완성한 후에는 시작 페이지를 게시했습니다. 그러나 사용자가 비공개 베타 액세스에 등록하는 동안에도 제품 구축은 계속되었습니다.

단 몇 달 만에 챗봇, 대시보드 API, Slack 알림, Stripe Billing용 작업 몇 개 등을 비롯한 다수의 서버리스 함수를 프로덕션 환경에 적용할 수 있었습니다. 이러한 각 함수에는 자체 트리거와 역할이 지정되었습니다. 앱은 문제 없이 작동했지만 새 단계를 배포하기가 점점 더 어려워졌습니다.

앱을 좀 더 체계화할 필요가 있었습니다. 그래서 Vacation Tracker에 AWS SAM을 적용하게 되었습니다.

Lambda 함수로 이동하기

먼저, 모든 서비스를 매핑하고 플로우로 그룹화한 후 AWS에서 서버리스 앱을 구축할 때 사용할 수 있는 오픈 소스 프레임워크인 AWS Serverless Application Model(AWS SAM)로 하나씩 마이그레이션하기로 했습니다. AWS SAM은 언어 중립적이므로 Node.js 종속성을 처리할 방법이 없습니다. 그래서 Claudia의 pack 명령을 빌드 단계로 사용했습니다.

서비스를 서버리스 앱으로 그룹화하자 배포가 쉬워졌습니다. 단일 명령을 사용하여 테스터를 위한 새 환경을 준비할 수 있었습니다.

곧이어 Slack 챗봇, API, Stripe-Billing 기반 결제 플로우, 알림 플로우 및 앱의 기타 플로우 몇 개를 위한 AWS CloudFormation 템플릿이 준비되었습니다.

다른 스타트업과 마찬가지로 Vacation Tracker의 목표는 신속한 변경을 통해 사용자 요구 사항에 적응하는 것입니다. 그렇게 하려면 실험을 수행하고 즉시 변경 사항을 적용할 수 있어야 합니다. 이를 염두에 두고 우리는 앱 플로우에서 몇 가지 일반적인 기능을 재사용 가능한 구성 요소로 추출하는 것을 목표로 설정했습니다.

예를 들어 일부 실험에서 다수의 Slack slash 명령을 사용할 때 Slack 챗봇 플로우의 명령을 재사용 가능한 구성 요소로 추출했습니다.

Slack slash 명령 구성 요소는 다음 요소로 구성됩니다.

  • Slack slash 명령 및 메시지 작업 웹훅에 대한 경로를 포함하는 API Gateway API
  • slash 명령을 처리하는 Lambda 함수
  • 메시지 작업을 처리하는 Lambda 함수
  • 구문 분석된 Slack 데이터에 대한 Amazon SNS 주제

이 구성 요소를 사용하면 slash 명령 실험을 더 빠르게 실행할 수 있습니다. 새로운 Slack slash 명령을 앱에 추가하려면 slash 명령을 배포해야 합니다. 또한 SNS 주제로 트리거되거나 비즈니스 논리를 처리하는 몇 가지 Lambda 함수도 작성했습니다.

Vacation Tracker를 작업하는 동안 재사용 가능한 구성 요소의 잠재적 가치를 인식하게 되었는데 다른 사람이 구축한 표준 구성 요소를 사용할 수 있다면 MVP를 훨씬 더 빠르게 어셈블할 수 있을 것입니다. 앱을 구축할 때는 앱을 고유하게 하는 비즈니스 논리를 중심으로 재사용되는 부분 간에 글루를 작성해야 합니다.

오픈 소스 서버리스 구성 요소를 위한 리포지토리인 AWS Serverless Application Repository를 사용하면 이 꿈을 현실로 만들 수 있습니다.

우리는 Slack slash 명령 앱을 시작으로 몇 가지 재사용 가능한 구성 요소를 Serverless Application Repository에 게시하기로 결정했습니다. 그러나 이 작업을 수행하려면 제대로 테스트된 앱이 필요했는데, 여기서 재사용 가능한 서버리스 앱의 아키텍처를 설계하고 테스트해야 하는 과제에 직면했습니다.

육각형 아키텍처에서 해답을 얻다

답은 간단했습니다. 육각형 아키텍처 또는 포트 및 어댑터를 사용하는 것이었습니다. 이 패턴을 사용하면 사용자, 프로그램, 자동화된 테스트 또는 배치 스크립트를 통해 앱을 동일하게 구동할 수 있습니다. 또한 최종 런타임 디바이스 및 데이터베이스와 분리된 상태에서 앱을 개발하고 테스트할 수 있습니다. 이러한 이유로 육각형 아키텍처는 마이크로서비스 및 서버리스 앱에 매우 적합합니다.

이 아키텍처를 Vacation Tracker에 적용한 후의 설정은 다음 다이어그램과 유사합니다. 이 설정은 다음으로 구성됩니다.

  • lambda.js 및 main.js 파일. lambda.js에는 테스트가 없으며 이 파일은 sns-notification-repository.js 같은 종속 관계를 구성하고 main.js를 호출합니다.
  • main.js에는 자체 단위 및 통합 테스트가 포함됩니다. 통합 테스트에는 로컬 통합이 사용됩니다.
  • 각 리포지토리에는 자체 단위 및 통합 테스트가 포함됩니다. 통합 테스트에서 리포지토리는 AWS 서비스에 연결합니다. 예를 들어 sns-notification-repository.js 통합 테스트는 Amazon SNS에 연결합니다.

각 함수에는 lambda.jsmain.js의 최소 2개 파일이 포함됩니다. 첫 번째 파일은 크기가 작으며 모든 종속성을 포함하여 main.js를 호출합니다(어댑터). 이 파일에는 자동화된 테스트가 없으며 다음 코드 조각과 유사합니다.

const {
httpResponse,
SnsNotificationRepository
} = require('@serverless-slack-command/common')
const main = require('./main')
async function handler(event) {
const notification = new SnsNotificationRepository(process.env.notificationTopic)
await main(event.body, event.headers, event.requestContext, notification)
return httpResponse()
}

exports.handler = handler

두 번째 파일이자 각 함수에서 가장 중요한 파일은 main.js입니다. 이 파일에는 함수의 비즈니스 논리가 포함되므로 올바르게 테스트되어야 합니다. 이 사례에서 이 파일에는 자체 단위 및 통합 테스트가 포함됩니다. 그러나 비즈니스 논리에는 주로 외부 통합이 사용합니다(예: SNS 알림 보내기). 우리는 모든 외부 알림을 테스트하는 대신 이 파일을 다른 어댑터(예: 로컬 알림 리포지토리)로 테스트했습니다.

이 파일은 다음 코드 조각과 유사합니다.

const qs = require('querystring')

async function slashCommand(slackEvent, headers, requestContext, notification) {
const eventData = qs.parse(slackEvent);
return await notification.send({
type: 'SLASH_COMMAND',
payload: eventData,
metadata: {
headers,
requestContext
}
})
}

module.exports = slashCommand

외부 통합에 대한 어댑터에는 AWS 서비스 통합을 검사하는 테스트를 비롯한 자체 단위 및 통합 테스트가 포함됩니다. 우리는 이 방법으로 AWS 서비스를 사용하는 테스트 수를 최소화하면서 앱에서 필요한 모든 테스트를 수행했습니다.

행복한 결말에 도달하다!

AWS SAM으로 마이그레이션한 후 회사의 배포 프로세스가 간소화되고 개선되었습니다. 이제 새 환경을 단 몇 분 안에 설정할 수 있습니다. 향후에 AWS CloudFormation 스택을 중첩하면 이 시간을 추가로 단축할 수 있습니다. 육각형 아키텍처를 사용하여 구성 요소를 손쉽게 개발하고 테스트할 수 있습니다. 서버리스 앱의 최종 작업에는 재사용 가능한 구성 요소 및 Serverless Application Repository가 사용됩니다.

이러한 이점 덕에 서버리스는 스타트업의 좋은 친구가 될 수 있습니다. 서버리스를 사용하면 스타트업 인프라가 완벽하게 관리되며 앱을 사용하는 사용자가 있는 경우에만 요금을 지불합니다. 서버리스 요금 모델을 사용하면 적은 비용으로 시작할 수 있습니다. Serverless Application Repository를 사용하면 기존 구성 요소를 재사용해 MVP를 더 빠르게 구축할 수 있습니다. 이러한 이점을 활용하면 풍부한 예산을 바탕을 대규모 팀이 개발하는 다른 제품과 경쟁하는 데 필요한 힘과 속도를 얻을 수 있습니다.

Serverless Application Repository를 사용해 구축되고 아웃소싱되는 많은 스타트업 제품이 나오길 기대해 봅니다.

저희 회사의 첫 번째 오픈 소스 서버리스 구성 요소의 원본은 GitHub(https://github.com/vacationtracker/serverless-slack-slash-command-app)에서 확인할 수 있습니다.

Vacation Tracker를 체험하고 싶다면 https://vacationtracker.io를 방문하십시오. AWS_IS_AWESOME 프로모션 코드를 사용하면 무료 평가 기간이 두 배로 늘어납니다.

– Slobodan Stojanović;