BLOG
잘 설계된 서버리스 애플리케이션은 상호 종속성이 낮고 상태 비보존(stateless) 형태이며 최소한의 코드를 사용합니다. 프로젝트가 발전함에 따라 개발 관리자의 목표는 간단한 디자인과 코드 구현을 유지하는 것입니다. 오늘 블로그 포스팅으로는 대규모 서버리스 프로젝트에서 코드 리포지토리를 설계 및 관리하기 위한 권장 사항과 프로덕션 시스템 릴리스 배포를 위한 모범 사례를 소개해 드리겠습니다.
코드 리포지토리 구성
많은 서버리스 애플리케이션은 단일 애플리케이션에서 시작됩니다. 이는 간단한 애플리케이션이 시간이 지남에 따라 더욱 복잡해지거나 개발자가 기존 개발 방식을 따르고 있기 때문에 발생할 수 있습니다. 단일 애플리케이션은 여러 작업을 수행하는 단일 AWS Lambda 함수로 표현되며 단일 리포지토리는 전체 애플리케이션 로직을 포함하는 단일 리포지토리입니다.
모놀리식 작업은 단일 목적 기능을 수행하는 가장 단순한 서버리스 애플리케이션에 적합합니다. 이는 크론 작업, 데이터 처리 작업 및 일부 비동기 프로세스와 같은 소규모 애플리케이션입니다. 이러한 애플리케이션이 워크 플로우로 발전하거나 새로운 기능을 개발함에 따라 코드를 더 작은 서비스로 리팩터링하는 것이 중요합니다.
AWS Serverless Application Model (SAM) 또는 Serverless Framework 와 같은 프레임 워크를 사용하면 일반적인 기능을 더 작은 서비스로 쉽게 그룹화할 수 있습니다. 이들 각각은 별도의 코드 저장소를 가질 수 있습니다. SAM의 경우 template.yaml 파일에는 응용 프로그램에 필요한 모든 리소스 및 함수 정의가 포함됩니다. 따라서 별도의 템플릿을 사용하여 응용 프로그램을 마이크로 서비스로 나누는 것은 저장소와 리소스 그룹을 분리하는 간단한 방법입니다.
서버리스 애플리케이션의 가장 작은 단위에서 기능 당 하나의 저장소를 작성할 수도 있습니다. 이러한 기능이 독립적이며 다른 AWS 리소스를 공유하지 않는 경우 적절할 수 있습니다. 헬퍼 함수와 간단한 이벤트 처리 코드는 이러한 종류의 리포지토리 구조에 대한 후보의 예시입니다.
대부분의 경우 마이크로 서비스를 정의하는 기능 및 자원 그룹 주위에 저장소를 작성하는 것이 좋습니다. 전자 상거래 예에서 “지불 처리”는 공통 자원을 공유하는 여러 개의 작은 관련 기능이 있는 마이크로 서비스입니다.
다른 소프트웨어와 마찬가지로 repo 디자인은 개발 팀의 사용 사례 및 구조에 따라 다릅니다. 하나의 큰 저장소에서는 다른 기능에 대해 작업하고 테스트 및 배포가 어려울 수 있습니다. 저장소가 너무 많으면 코드가 중복되어 저장소간에 리소스를 공유하기가 어려울 수 있습니다. 프로젝트의 균형을 찾는 것은 응용 프로그램 아키텍처를 디자인하는 중요한 단계입니다.
코드 라이브러리 대신 AWS 서비스 사용
AWS 서비스는 서버리스 애플리케이션을 위한 중요한 빌딩 블록입니다. 이들은 유사한 기능을 가진 번들 코드 패키지보다 더 큰 규모, 성능 및 안정성을 제공할 수 있습니다.
예를 들어 Lambda로 마이그레이션 된 많은 웹 응용 프로그램은 Flask (Python) 또는 Express (Node.js) 와 같은 웹 프레임 워크를 사용합니다. 두 패키지 모두 애플리케이션 웹 서버에서 실행중인 경우 적합한 라우팅 및 개별 사용자 컨텍스트를 지원합니다. Lambda 함수에서 이러한 패키지를 사용하면 다음과 같은 아키텍처가 생성됩니다.
이 경우 Amazon API Gateway는 모든 요청을 Lambda 함수에 프록시하여 라우팅을 처리합니다. 애플리케이션이 더 많은 경로를 개발함에 따라 Lambda 기능의 크기가 커지고 새로운 버전의 배포가 전체 기능을 대체합니다. 이 상황에서 여러 개발자가 동일한 프로젝트에서 작업하기가 더 어려워집니다.
이 방법은 일반적으로 불필요하며 API Gateway에서 사용 가능한 기본 라우팅 기능을 활용하는 것이 좋습니다. 대부분의 경우 Lambda 함수에서 웹 프레임 워크가 필요하지 않으므로 배포 패키지의 크기가 증가합니다. API Gateway는 또한 매개 변수의 유효성을 검사할 수 있으므로 사용자 지정 코드로 매개 변수를 확인할 필요가 없습니다. 또한 무단 액세스로부터 서비스를 보호하고 서비스 수준에서 처리하기에 더 적합한 다양한 기능을 제공 할 수 있습니다. 이 방법으로 API Gateway를 사용하면 새로운 아키텍처는 다음과 같습니다.
또한 Lambda 함수는 더 적은 코드와 더 적은 패키지 종속성으로 구성됩니다. 따라서 테스트가 쉬워지고 코드 라이브러리 버전을 유지 관리할 필요가 줄어 듭니다. 팀의 다른 개발자는 별도의 라우팅 기능을 독립적으로 사용할 수 있으며 향후 프로젝트에서 코드를 재사용하는 것이 더 간단해집니다. 애플리케이션의 SAM 템플릿에서 API Gateway의 경로를 구성할 수 있습니다.
Resources: GetProducts: Type: AWS::Serverless::Function Properties: CodeUri: getProducts/ Handler: app.handler Runtime: nodejs12.x Events: GetProductsAPI: Type: Api Properties: Path: /getProducts
Method: get
마찬가지로 Lambda 함수 내에서 워크 플로 오케스트레이션을 수행하지 않아야 합니다. 이들은 다른 서비스 및 기능을 호출하고 성공적인 실행 또는 실패에 따라 후속 조치를 수행하는 코드 섹션입니다.
이러한 워크 플로우는 빠르게 깨지기 쉬우며 새로운 요구 사항을 수정하기가 어렵습니다. Lambda 함수에서 유휴 상태가 발생할 수 있습니다. 즉, 함수가 외부 소스로부터의 반환 값을 기다리고 있음에 따라 실행 비용이 증가합니다.
더 나은 방법은 애플리케이션의 SAM 템플릿에서 복잡한 워크 플로우를 JSON 정의로 나타낼 수 있는 AWS Step Functions 를 사용하는 것입니다. 이 서비스는 필요한 사용자 지정 코드의 양을 줄이고 Lambda 함수의 유휴를 최소화하는 오래 지속되는 워크 플로우를 가능하게 합니다. 또한 워크 플로우가 업그레이드됨에 따라 기내 실행을 관리합니다. Step Functions 워크 플로우로 재구성된 예시는 다음과 같습니다.
개발 팀에 여러 AWS 계정 사용
서버리스 애플리케이션을 프로덕션에 배치하는 방법에는 여러 가지가 있습니다. 애플리케이션이 향상되고 비즈니스에 중요해짐에 따라 개발 관리자는 배포 프로세스의 견고성을 향상시키고자 합니다. AWS 는 서버리스 애플리케이션의 개발 및 배포를 관리를 위한 다양한 옵션을 제공합니다.
먼저 둘 이상의 AWS 계정을 사용할 것을 권장합니다. AWS Organizations를 사용하면 이러한 계정의 청구, 규정 준수 및 보안을 중앙에서 관리할 수 있습니다. 사용자 지정 스크립트 및 수동 프로세스를 피하기 위해 계정 그룹에 정책을 연결할 수 있습니다. 간단한 방법 중 하나는 각 개발자에게 AWS 계정을 제공한 다음 베타 배포 단계 및 프로덕션에 별도의 계정을 사용하는 것입니다.
개발자 계정에는 프로덕션 리소스의 복사본이 포함되어 있으며 개발자에게 이러한 리소스에 대한 관리자 수준 권한을 제공할 수 있습니다. 각 개발자는 계정에 대해 고유한 한도를 가지므로 사용법은 프로덕션 환경에 영향을 미치지 않습니다. 개별 개발자는 프로덕션 자산에 대한 위험을 최소화하면서 이러한 계정에 CloudFormation 스택 및 SAM 템플릿을 배포할 수 있습니다.
이 접근 방식을 통해 개발자는 개별 계정의 라이브 클라우드 리소스에 대해 개발 컴퓨터에서 Lambda 함수를 로컬로 테스트할 수 있습니다. 강력한 단위 테스트 프로세스를 만드는 데 도움이 될 수 있으며 개발자는 준비가 되면 AWS CodeCommit 과 같은 리포지토리에 코드를 푸시할 수 있습니다.
AWS Secrets Manager 와 통합하면 각 환경에 서로 다른 비밀 세트를 저장하고 코드에 저장된 자격 증명이 필요하지 않습니다. 개발자 계정에서 베타 및 프로덕션 계정으로 코드가 승격되면 올바른 자격 증명 세트가 자동으로 사용됩니다. 개별 개발자와 환경 수준의 자격 증명을 공유할 필요는 없습니다.
코드가 배포될 때 빌드 파이프 라인을 시작하기 위해 CI / CD 프로세스를 구현할 수도 있습니다. 다중 계정 배포 흐름을 사용하여 샘플 응용 프로그램을 배포하려면 이 서버리스 CI / CD 자습서를 확인하세요.
서버리스 애플리케이션에서 기능 릴리스 관리
프로덕션 서버리스 애플리케이션에 CI / CD 파이프 라인을 구현할 때는 전체 애플리케이션 업그레이드에 대해 안전한 배치를 우선순위에 두는 것이 가장 좋습니다. 기존 소프트웨어 배포와 달리 서버리스 애플리케이션은 Lambda 기능과 AWS 서비스 구성에서 사용자 지정 코드의 조합입니다.
기능 릴리스는 Lambda 함수의 버전 변경으로 구성될 수 있습니다. API Gateway에 엔드 포인트가 다르거나 DynamoDB 테이블과 같은 새로운 리소스를 사용할 수 있습니다. 배포된 기능에 대한 액세스는 애플리케이션에 따라 사용자 구성 및 기능 토글을 통해 제어될 수 있습니다. AWS SAM에는 AWS CodeDeploy가 내장되어있어 YAML 구성에서 카나리아 배포를 구성할 수 있습니다.
Resources: GetProducts: Type: AWS::Serverless::Function Properties: CodeUri: getProducts/ Handler: app.handler Runtime: nodejs12.x AutoPublishAlias: live DeploymentPreference: Type: Canary10Percent10Minutes Alarms: # A list of alarms that you want to monitor – !Ref AliasErrorMetricGreaterThanZeroAlarm – !Ref LatestVersionErrorMetricGreaterThanZeroAlarm Hooks: # Validation Lambda functions run before/after traffic shifting PreTraffic: !Ref PreTrafficLambdaFunction PostTraffic: !Ref PostTrafficLambdaFunction
CodeDeploy는 이전 및 버전의 함수를 가리키는 별칭을 자동으로 만듭니다. 카나리아 배포를 사용하면 새 버전이 예상대로 작동한다고 확신하면서 트래픽을 점진적으로 이전 별칭에서 새 별칭으로 옮길 수 있습니다. 또는 필요한 경우 업데이트를 롤백할 수 있습니다. 트래픽 이동 전후에 Lambda 함수를 호출하도록 PreTraffic 및 PostTraffic 후크를 설정할 수도 있습니다.
결론
소프트웨어 응용 프로그램의 크기가 커짐에 따라 개발 관리자는 코드 리포지토리를 구성하고 릴리스를 관리해야 합니다. 서버리스에는 규모가 더 큰 애플리케이션을 관리하기 위해 구축된 패턴이 있습니다. 일반적으로 모놀리식 함수 및 단일 리포지토리는 피하는 것이 좋으며 리포지토리를 마이크로 서비스 또는 함수 수준으로 범위를 지정해야 합니다.
잘 설계된 서버리스 애플리케이션은 Lambda 함수의 사용자 정의 코드를 사용하여 관리 서비스와 연결합니다. 배포 크기를 최소화하고 코드 기반을 단순화하기 위해 서비스로 대체 할 수 있는 라이브러리 및 패키지를 식별하는 것이 중요합니다. 서버 기반 환경에서 마이그레이션 된 애플리케이션에서 더욱 그렇습니다.
AWS Organizations를 사용하면 개발자가 개발을 위해 자체 AWS 계정을 가질 수 있도록 계정 그룹을 관리합니다. 이를 통해 엔지니어는 코드를 작성하고 디버깅 할 때 프로덕션 자산을 복제하고 AWS 클라우드에 대해 테스트할 수 있습니다. CI / CD 파이프 라인을 사용하여 Secrets Manager를 사용하여 비밀을 보호하면서 베타 환경을 통해 코드를 프로덕션 환경으로 푸시할 수 있습니다. CodeDeploy를 사용하여 카나리아 배포를 쉽게 관리 할 수도 있습니다.
SAM 및 CodeDeploy로 Lambda 함수를 배포하는 방법에 대한 자세한 내용은 이 자습서의 단계를 따르십시오.
** 메가존 클라우드 TechBlog는 AWS BLOG 영문 게재 글 중에서 한국 사용자들에게 유용한 정보 및 콘텐츠를 우선적으로 번역하여 내부 엔지니어 검수를 받아서, 정기적으로 게재하고 있습니다. 추가로 번역 및 게재를 희망하는 글에 대해서 관리자에게 메일 또는 SNS 페이지에 댓글을 남겨주시면, 우선적으로 번역해서 전달해드리도록 하겠습니다.