JD의 블로그

CDK(Cloud Development Kit) 개념 본문

클라우드/AWS

CDK(Cloud Development Kit) 개념

GDong 2020. 5. 18. 23:09

CDK가 무엇인지에 대해서 설명한 글은 이미 많기 때문에 CDK에 대해서 잘 모른다면 아래의 글을 참고하길 바랍니다.

AWS CDK란?

앱 현대화 | 코드 기반 인프라(IaC)를 활용한 현대 애플리케이션 개발 가속화, 우리도 할 수 있어요.

AWS CDK(Cloud Development Kit)를 소개합니다

 

CDK에 대해서 알아보게 된 계기는 IaC(Infrastuscutre as Code)로 인프라의 변경 이력을 추적하고 실수를 막고자 하여 CloudFormation을 사용해보았으나 이는 YAML이나 JSON 같은 파일로 관리해야하기 때문에 작성할 때 많은 레퍼런스 문서를 참고해야했고, 꽤 관리가 복잡하다는 인상을 받았기 때문입니다. 

 

이 글에서는 CDK를 좀 더 이해하기 위해 CDK가 어떤 구조로 되어 있고, 어떻게 동작하는지에 대해서 알아보고자 합니다. 

 

CDK는 크게 App, Stack, Construct으로 구성이 된다고 볼 수 있습니다.

 

출처 : Boost your infrastructure with the AWS SDK

App은 CDK CLI를 통해 AWS CloudFormation 템플릿을 렌더링하고 배포할 수 있는 기능을 제공해줍니다. 

 

그리고 App은 리전 및 계정에 대한 정보가 포함된 하나 이상의 Stack으로 구성됩니다.

 

Stack은 여러 DynamoDB 테이블 또는 AWS Lambda 기능과 같이 AWS 리소스를 나타내는 Construct로 구성됩니다.

 

각각의 구성 요소를 조금 더 깊게 살펴보자면,

Construct

Construct는 CDK 앱을 만들기 위해 가장 기본적인 블록이라고 할 수 있습니다. AWS 리소스를 템플릿으로 만들기 위한 AWS CloudFormation을 보다 추상화한 형태라고 볼 수 있습니다.

Construct는 Amazon Simple Storage Serivce(Amazon S3)의 버킷이 될 수도 있으며, 복수의 AWS CDK 리소스로 구성된 보다 고 수준의 리소스 단위가 될 수도 있습니다. AWS Construct Library에서 어떤 Construct가 있는지 확인할 수 있습니다. AWS Construct Library에는 pattern이라는 것도 있는데 이는 AWS에서 자주 같이 쓰이는 리소스를 합쳐놓은 것이라고 할 수 있습니다. 예를 들어, aws-ecs-pattern에는 ApplicationLoadBalancedFargateService가 있는데 이는 Application Load Balancer(ALB)와 함께 Fargate 컨테이너 클러스터를 포함하는 아키텍쳐를 쉽게 만들 수 있게 해줍니다. 

 

Construct의 경우 다른 Construct를 기반으로 정의될 수 있는데, 이러한 방식으로 계층적인 트리 구조를 가짐으로써 높은 수준의 추상화를 가진 패턴을 만들 수 있습니다. 이러한 패턴으로 Construct를 만드는 방식을 composition이라고 합니다. 이렇게 Construct를 통해 composition을 구성하게 되면 재사용 가능한 구성요소가 된다는 것을 의미하고 이는 타인과 공유가 가능함을 뜻하게 됩니다. 예를 들어, A라는 개발 팀에서 DynamoDB 테이블에 백업, 글로벌 복제 및 자동 스케일링과 모니터링을 할 수 있는 Construct를 정의내렸다면 이는 다른 팀 B와 공유할 수 있으며 B는 테이블을 정의하기 위해 기존에 정의했던 Construct를 사용할 수 있습니다. 

 

Construct는 class를 통해 구현되며, class를 인스턴스화 함으로써 Construct를 정의내릴 수 있습니다. 그리고 Construct는 초기화되기 위해 3가지 파라미터를 가지게 됩니다. 

 

  • Scope : Construct가 정의되는 범위를 나타내게 됩니다. 그래서 super 또는 this를 통해 Construct 자기 자신을 Scope로 넘겨줘야 합니다. 그래야 Construct가 정의되는 현재 Scope를 나타낼 수 있기 때문입니다.
  • Id : Scope 내에서 유일한 식별자이며 Scope의 하위 트리 내에 캡슐화된 모든 리소스에 대한 네임 스페이스 역할을 합니다. 그래서 AWS CloudFormation의 논리적인 ID나 리소스 이름과 같은 고유한 식별자를 할당할 때 사용되게 됩니다. 
  • Props : 리소스의 구성을 정의하는 속성이나 키워드 집합이라고 볼 수 있습니다. 예를 들어, s3.Bucket의 경우 "versioned=True" 라는 옵션을 추가할 때 Props에 이를 적용시킨다고 생각할 수 있습니다. 
from aws_cdk.core import App, Stack
from aws_cdk import aws_s3 as s3

class HelloCdkStack(core.Stack):
	
    def __init__(self, scope: core.Construct, id: str, **kwargs) -> None:
    	super().__init__(scope, id, **kwargs)
       
        s3.Bucket(self, "MyFirstBucket", versioned=True)
        
app = core.App()
HelloCdkStack(app, "HelloCdkStack")

이 예제 코드는 버전을 관리하는 옵션을 가지는 Amazon S3 버킷을 생성하는 단일한 Stack을 가지는 App을 정의하고 있습니다. Scope내에 버킷이 정의되어 있으며, 이러한 리소스는 Stack을 통해 AWS CloudFormation으로 특정 AWS 계정 및 AWS 영역을 포함하는 AWS 환경에 배포될 수 있습니다. 

 

Construct는 인스턴스화가 된 후에, 다른 시스템의 일부에 참조로 전달되어 다른 Construct와 상호작용할 수 있습니다. 

raw_data = s3.Bucket(self, 'raw-data')
data_science = iam.Group(self, 'data-science')
raw_data.grand_read(data_science)

예를 들어, 거의 모든 AWS Construct에는 해당 Construct에 대한 IAM 허용을 위한 방법을 제공하며 여기서는 "data-science"라는 그룹에, 지정된 S3 Bucket의 데이터를 읽을 수 있는 권한을 제공해줍니다. 

 

Stack

AWS CDK에서 배포 단위를 Stack이라고 합니다. 모든 AWS 리소스는 Stack의 범위 내에서 정의되고 단일한 단위로 프로비저닝됩니다. 또한 AWS CDK App 안에는 여러 개의 Stack을 정의할 수 있습니다. 

 

app = App()

MyFirstStack(app, 'stack1')
MySecondStack(app, 'stack2')

app.synth()

cdk ls 명령어를 통해 AWS CDK App 내부에 있는 stack의 리스트를 출력할 수 있는데, 명령어를 입력하면 'stack1' 과 'stack2' 모두 출력이 됩니다. 그리고 cdk synth 명령어를 통해 CloudFormation 템플릿을 생성할 수 있는데 이 경우 각각의 Stack 인스턴스에 대해 다른 템플릿이 생성됩니다. 그래서 cdk synth 명령어를 입력할 때 하나의 Stack 이름을 지정해줘야 하나의 템플릿만 만들게 됩니다. 

 

$ cdk synth stack1

이러한 접근방식은 AWS CloudFormation 템플릿이 사용되는 방식과 조금 다른데, AWS CloudFormation의 경우 파라미터를 통해 템플릿 구성을 다양하게 만들어 여러 번 배포하고 재사용할 수 있습니다. AWS CloudFormation 파라미터를 AWS CDK에서 정의될 수 있지만 이는 추천되는 방식이 아닙니다. 왜냐하면 CloudFormation의 파라미터 값은 배포 중에 선택해야하기 때문에, 코드만을 가지고 배포를 할 수 없게 만들기 때문입니다. 그래서 AWS SDK의 경우 여러가지 케이스를 if와 같은 조건문을 통해서 분기시킴으로써 배포 시에 구체적인 템플릿이 생성되는 방식을 이용하길 권장합니다. 

 

from aws_cdk.core import App, Construct, Stack

# 아래의 Stack이 관련된 리소스들을 가지고 있다고 가정합니다.
class ControlPlane(Stack): pass
class DataPlane(Stack): pass
class Monitoring(Stack): pass

class MyService(Construct):
    def __init__(self, scope: Construct, id: str, *, prod=False):
    
        super().__init__(scope,id)
    
        # prod 파라미터는 서비스가 어떻게 구성될지, 변경될지 결정하는 역할을 합니다.
        ControlePlane(self, "cp")
        DataPlane(self, "data")
        Monitoring(self, "mon")

app = App();
MyService(app, "beta")
MyService(app, "prod", prod=True)

app.synth()

 

App

Stack를 정의하더라도, 이를 배치하기 위해 App을 정의할 필요가 있습니다. App은 정의된 Stack을 바탕으로 Stack을 인스턴스화하고 AWS CloudFormation 템플릿을 생성합니다. 

 

App 라이프사이클

위 그림은 cdk deploy 명령어를 입력했을 때 AWS CDK가 어떻게 동작하는지 보여줍니다.

참고: 이 명령어는 App이 정의한 리소스를 배포하는 데 사용됩니다. 

 

총 5 단계의 과정을 거치게 되는데 다음과 같습니다.

  1. 구축(Construction) : 앞서 정의한 모든 Construct를 인스턴스화하며 이를 다 함께 연결합니다. 대부분의 코드가 이 스테이지에서 실행됩니다.
  2. 준비(Preparation) : 준비 과정을 거친 Construct는 최종 상태로 가기 위해 마지막 수정을 겪게 되며 이때 사용자가 작업에 끼어들게 되면 결과에 영향을 줄 수 있으니 이 단계에서 생성되는 트리를 변경할 때는 각별히 주의해야 합니다.
  3. 검증(Validation) : 검증 단계에서 배포가 정상적으로 이뤄진 상태에 있는지 확인하게 되며, 이 단계에서 실패하게 되면 사용자에게 알림이 가게 됩니다. 가능한 빨리 검증 단계를 거쳐 예외 처리를 하는 것을 추천하며 이런 방식을 통해 코드가 지속적으로 안전하고 코드에 대한 진단 능력이 향상될 수 있습니다.
  4. 종합(Synthesis) : AWS CDK App의 마지막 실행 단계로 app.synth()에 의해 호출됩니다. 이는 Construct tree를 순회하며 모든 Construct에 대해 synthesize 메서드를 호출합니다. 이를 통해 CloudFomration 템플릿, Lambda 애플리케이션 번들, 파일 그리고 도커 이미지 등 배포를 위해 필요한 구성 요소들이 만들어집니다. 
  5. 배포(Deployment) : AWS CDK CLI가 생성된 구성 요소를 AWS 환경에 배포합니다. 이때 구성 요소는 Amazon S3 그리고 Amazon ECR(Elastic Container Repository)에 업로드 되며 AWS CloudFormation 배포 작업을 통해 애플리케이션이 배포되며 AWS 리소스들이 생성됩니다.

그리고 5단계가 시작할 때 이미 AWS CDK App의 모든 작업은 완료되고 끝난 상태라고 할 수 있습니다. 

 

 

마무리

이렇게 기본적으로 AWS CDK가 어떻게 구성되는지 알아보았습니다. 저는 AWS CDK에 대해서 알아보며, AWS CDK가 AWS 인프라를 좀 더 쉽게 관리하고 구성할 수 있게 해줄 수 있는 도구라고 믿게 되었습니다. 아직 발전하는 단계에 있어 기존에 CloudFormation이나 Terraform과 같은 IaC 툴을 이용하고 있다면 기존의 도구를 계속 사용하는 것이 더 좋을 수 있지만 CDK가 가지는 매력도 충분히 많다고 생각합니다. 앞으로 AWS CDK에 대해 더 많은 내용을 조금씩 정리해보고자 합니다. 읽어주셔서 감사합니다.