Amazon Web Services 한국 블로그

AWS Solutions Constructs – AWS CDK에 대한 아키텍처 패턴 라이브러리

클라우드 애플리케이션은 가상 서버, 컨테이너, 서버리스 함수, 스토리지 버킷 및 데이터베이스 등 다수의 구성 요소를 사용하여 구축됩니다. 이러한 리소스를 안전하고 반복 가능한 방법으로 프로비저닝하고 구성하는 기능은 프로세스를 자동화하여 구현의 고유한 부분에 집중하는 데 매우 중요합니다.

AWS Cloud Development Kit를 사용하면 자주 사용하는 프로그래밍 언어의 표현 기능을 활용하여 애플리케이션을 모델링할 수 있습니다. “적절한 기본값”으로 미리 구성되는 고급 구성 요소인 구문을 사용자 지정하여 새 애플리케이션을 빠르게 구축할 수 있습니다. CDK는 AWS CloudFormation을 사용하여 리소스를 프로비저닝함으로써 인프라를 코드로 관리할 때의 모든 이점을 활용합니다. 제가 CDK를 좋아하는 이유 중 하나는 자체 사용자 지정 구성 요소를 상위 수준의 구문으로 작성하고 공유할 수 있다는 것입니다.

예상하듯이 여기에는 다수의 고객에게 유용할 수 있는 반복적인 패턴이 있습니다. 오늘 발표되는 AWS Solutions Constructs는 이러한 이유로 출시되었습니다. CDK를 위한 오픈 소스 확장 라이브러리로서 고유한 솔루션을 구축하는 데 도움이 되는 Well-Architected 패턴을 제공합니다. CDK 구문은 대부분 단일 서비스를 다룹니다. AWS Solutions Constructs는 둘 이상의 CDK 리소스를 결합하고 로깅 및 암호화 같은 모범 사례를 구현하는 다중 서비스 패턴을 제공합니다.

AWS Solutions Constructs 사용하기
패턴 기반 접근 방식의 강력함을 확인하기 위해 새 애플리케이션을 구축할 때 이 접근 방식이 어떻게 작용하는지 알아봅시다. 예를 들어 Amazon DynamoDB 테이블에 데이터를 저장하는 HTTP API를 구축하려고 합니다. 테이블의 콘텐츠를 작게 유지하려면 DynamoDB TTL(Time to Live)을 사용하여 며칠 후에 항목이 만료되도록 합니다. TTL이 만료되면 테이블에서 데이터가 삭제되고 DynamoDB 스트림을 통해 AWS Lambda 함수로 전송됩니다. 함수는 만료된 데이터를 Amazon Simple Storage Service(S3)에 아카이브합니다.

몇 가지 구성 요소를 사용하여 이 애플리케이션을 구축할 수 있습니다.

  • API용 Amazon API Gateway 엔드포인트
  • 데이터를 저장할 DynamoDB 테이블
  • API 요청을 처리하고 데이터를 DynamoDB 테이블에 저장하는 Lambda 함수
  • 데이터 변경을 캡처하는 DynamoDB 스트림
  • 데이터 변경을 처리하여 만료된 데이터를 아카이브하는 Lambda 함수

좀 더 간단하게 할 수 있을까요? AWS Solutions Constructs의 사용 가능한 패턴을 보면 앱 구축에 도움이 될 수 있는 두 가지 패턴이 있습니다.

  • aws-apigateway-lambda는 Lambda 함수에 연결된 API Gateway REST API를 구현하는 구문입니다. AWS Solutions Constructs에 사용되는 “적절한 기본값”의 한 예인 이 패턴은 API Gateway에 대한 CloudWatch 로깅을 가능하게 합니다.
  • aws-dynamodb-stream-lambda 구문은 최소 권한으로 데이터 변경을 Lambda 함수로 스트리밍하는 DynamoDB 테이블을 구현합니다.

최종 아키텍처를 구축하려면 이 두 구문을 하나로 연결하기만 하면 됩니다.

TypeScript를 사용하여 CDK 스택과 Lambda 함수에 대한 Node.js를 정의합니다. CDK 스택부터 시작합시다.

 

import * as cdk from '@aws-cdk/core';
import * as lambda from '@aws-cdk/aws-lambda';
import * as apigw from '@aws-cdk/aws-apigateway';
import * as dynamodb from '@aws-cdk/aws-dynamodb';
import { ApiGatewayToLambda } from '@aws-solutions-constructs/aws-apigateway-lambda';
import { DynamoDBStreamToLambda } from '@aws-solutions-constructs/aws-dynamodb-stream-lambda';

export class DemoConstructsStack extends cdk.Stack {
  constructor(scope: cdk.Construct, id: string, props?: cdk.StackProps) {
    super(scope, id, props);

    const apiGatewayToLambda = new ApiGatewayToLambda(this, 'ApiGatewayToLambda', {
      deployLambda: true,
      lambdaFunctionProps: {
        code: lambda.Code.fromAsset('lambda'),
        runtime: lambda.Runtime.NODEJS_12_X,
        handler: 'restApi.handler'
      },
      apiGatewayProps: {
        defaultMethodOptions: {
          authorizationType: apigw.AuthorizationType.NONE
        }
      }
    });

    const dynamoDBStreamToLambda = new DynamoDBStreamToLambda(this, 'DynamoDBStreamToLambda', {
      deployLambda: true,
      lambdaFunctionProps: {
        code: lambda.Code.fromAsset('lambda'),
        runtime: lambda.Runtime.NODEJS_12_X,
        handler: 'processStream.handler'
      },
      dynamoTableProps: {
        tableName: 'my-table',
        partitionKey: { name: 'id', type: dynamodb.AttributeType.STRING },
        timeToLiveAttribute: 'ttl'
      }
    });

    const apiFunction = apiGatewayToLambda.lambdaFunction;
    const dynamoTable = dynamoDBStreamToLambda.dynamoTable;

    dynamoTable.grantReadWriteData(apiFunction);
    apiFunction.addEnvironment('TABLE_NAME', dynamoTable.tableName);
  }
}

스택의 시작에서 Lambda 함수, API Gateway 엔드포인트 및 DynamoDB 테이블에 대한 표준 CDK 구문을 가져옵니다. 그런 다음 AWS Solutions Constructs에서 ApiGatewayToLambdaDynamoDBStreamToLambda의 패턴 2개를 추가합니다.

ApiGatewayToLambdaDynamoDBStreamToLambda 구문 2개를 선언한 후 ApiGatewayToLambda 구문으로 생성된 Lambda 함수와 DynamoDBStreamToLambda로 생성된 DynamoDB 테이블을 두 변수에 저장합니다.

스택의 끝에서 DynamoDB 테이블을 읽고 쓸 수 있는 권한을 Lambda 함수에 부여하여 두 패턴을 “연결”하고 DynamoDB 테이블의 이름을 Lambda 함수의 환경에 추가하여 데이터를 테이블에 저장하는 함수 코드에 사용될 수 있도록 합니다.

두 Lambda 함수의 코드는 CDK 애플리케이션의 lambda 폴더에 있습니다. Node.js 12 런타임을 사용합니다.

restApi.js 함수는 API를 구현하고 DynamoDB 테이블에 데이터를 씁니다. URL 경로는 파티션 키로 사용되며 URL의 모든 쿼리 문자열 파라미터는 속성으로 저장됩니다. 항목의 TTL은 현재 시간에 7일의 시간 기간을 더하는 방법으로 계산됩니다.

const { DynamoDB } = require("aws-sdk");

const docClient = new DynamoDB.DocumentClient();

const TABLE_NAME = process.env.TABLE_NAME;
const TTL_WINDOW = 7 * 24 * 60 * 60; // 7 days expressed in seconds

exports.handler = async function (event) {

  const item = event.queryStringParameters;
  item.id = event.pathParameters.proxy;

  const now = new Date(); 
  item.ttl = Math.round(now.getTime() / 1000) + TTL_WINDOW;

  const response = await docClient.put({
    TableName: TABLE_NAME,
    Item: item
  }).promise();

  let statusCode = 204;
  
  if (response.err != null) {
    console.error('request: ', JSON.stringify(event, undefined, 2));
    console.error('error: ', response.err);
    statusCode = 500
  }

  return {
    statusCode: statusCode
  };
};

processStream.js 함수는 TTL로 삭제된 항목을 조회하여 DynamoDB 스트림의 데이터 캡처 레코드를 처리합니다. 이 샘플 코드에는 아카이브 기능이 구현되지 않았습니다.

exports.handler = async function (event) {
  event.Records.forEach((record) => {
    console.log('Stream record: ', JSON.stringify(record, null, 2));
    if (record.userIdentity.type == "Service" &&
      record.userIdentity.principalId == "dynamodb.amazonaws.com") {

      // Record deleted by DynamoDB Time to Live (TTL)
      
      // I can archive the record to S3, for example using Kinesis Data Firehose.
    }
  }
};

작동하는지 봅시다! 먼저, 모든 종속성을 설치해야 합니다. 종속성을 간소화하기 위해 각 AWS Solutions Constructs의 릴리스를 해당하는 버전의 CDK에 연결합니다. 이 예에서는 CDK와 AWS Solutions Constructs 패턴 모두에 버전 1.46.0을 사용합니다. 처음 세 개 명령은 일반 CDK 구문을 설치합니다. 마지막 두 개 명령은 이 애플리케이션에 사용되는 AWS Solutions Constructs 패턴을 설치합니다.

npm install @aws-cdk/aws-lambda@1.46.0
npm install @aws-cdk/aws-apigateway@1.46.0
npm install @aws-cdk/aws-dynamodb@1.46.0
npm install @aws-solutions-constructs/aws-apigateway-lambda@1.46.0
npm install @aws-solutions-constructs/aws-dynamodb-stream-lambda@1.46.0

이제, 애플리케이션을 구축하고 CDK를 사용하여 애플리케이션을 배포합니다.

npm run build
cdk deploy

cdk deploy 명령의 출력 끝에 있는 녹색 등은 스택 배포가 완료되었음을 나타냅니다. 바로 다음에 있는 Outputs에서 API Gateway의 엔드포인트를 찾을 수 있습니다.

 ✅  DemoConstructsStack

Outputs:
DemoConstructsStack.ApiGatewayToLambdaLambdaRestApiEndpoint9800D4B5 = https://1a2c3c4d.execute-api.eu-west-1.amazonaws.com/prod/

이제, curl을 사용하여 API를 테스트할 수 있습니다.

curl "https://1a2c3c4d.execute-api.eu-west-1.amazonaws.com/prod/danilop?name=Danilo&company=AWS"

이제, DynamoDB 테이블을 확인합시다.

항목이 저장되었고 TTL이 설정되었습니다. 일주일 후에는 항목이 삭제되고 DynamoDB 스트림을 통해 processStream.js 함수로 전송됩니다.

테스트를 완료한 후 CDK를 다시 사용하여 이 애플리케이션을 위해 생성한 모든 리소스를 빠르게 삭제합니다.

cdk destroy

정식 출시
AWS Solutions Constructs를 TypeScript와 Python에 사용할 수 있습니다. Java 및 C#에서 CDK를 사용할 때에도 이러한 구문을 사용할 수 있도록 AWS Solutions Builders 팀이 현재 작업 중입니다. AWS Solutions Constructs 또는 CDK 사용에는 요금이 부과되지 않으며 스택을 배포할 때 생성한 리소스에 대한 요금만 지불하면 됩니다.

이 첫 번째 릴리스에서는 다양한 사용 사례에 적용되는 25개 패턴이 포함되었습니다. 이제, 어떤 새로운 패턴과 기능에 집중하면 좋을까요? 오픈 소스 프로젝트 리포지토리에서 피드백을 남겨주십시오!

Danilo