Amazon Web Services 한국 블로그

Python으로 AWS Cloud Development Kit 시작하기

AWS Cloud Development Kit(AWS CDK)에 익숙한 프로그래밍 언어를 사용하여 클라우드 애플리케이션 리소스를 모델링 및 프로비저닝할 수 있는 오픈 소스 소프트웨어 개발 프레임워크입니다. 클라우드를 사용해 보신 분들은 Infra as a Code(코드 기반 인프라, IaC)라는 개념에는 익숙할 것입니다. IaC를 생각하면서 AWS CloudFormation라는 서비스를 통한 방식을 생각하셨을 것 같습니다.

AWS CloudFormation을 이용하면 AWS 인프라를 JSON 또는 YAML 파일로 정의할 수 있으며 일반 코드처럼 소스 코드 리포지토리에서 관리할 수 있습니다. 또한 풀 요청과 코드 검토를 수행할 수도 있습니다. 모든 것이 양호하면 이러한 파일을 인프라 변경 사항을 배포하는 자동화된 프로세스(CI/CD)에 대한 입력으로 사용할 수 있습니다.CDK는 실제 AWS CloudFormation에 구축되며, AWS 리소스를 프로비저닝하기 위한 엔진으로 이 서비스를 사용합니다. JSON 또는 YAML과 같은 선언적 언어를 사용하여 인프라를 정의하는 대신, CDK에서는 선호하는 명령형 프로그래밍 언어로 인프라를 정의할 수 있습니다. TypeScript, Java, C# 및 Python과 같은 언어가 이에 해당합니다.

인프라 구성에 선언적 언어보다 명령형 언어가 더 나은 이유는 무엇일까요? 항상은 아니지만 IDE 통합 및 구성 측면에서 몇 가지 실질적인 장점이 있습니다.

IDE 통합

  • 선호하는 프로그래밍 언어에 대해 선호하는 IDE가 있을 것입니다. IDE에서는 코드 완성, 통합 문서화 또는 리팩토링 도구와 같이 개발자의 생산성을 높일 수 있는 다양한 유형의 유용한 기능을 제공합니다.
  • CDK를 사용하면 AWS 인프라를 정의할 때 이러한 동일한 모든 장점을 자동으로 확보할 수 있습니다. 애플리케이션 코드에서 사용하는 동일한 언어로 수행하기 때문입니다.

구성

최신 프로그래밍 언어의 강점인 영역 중 하나가 바로 구성입니다. 즉, 진행되는 상황에 대한 세부 정보는 숨기고 훨씬 더 단순한 API를 공개하는 보다 향상된 새로운 상위 수준의 추상 환경을 구축할 수 있습니다. 개발자가 하는 주된 작업 중 하나가 바로, 향상된 상위 수준의 추상 환경을 구축하여 코드를 단순화하는 것입니다.

그러면 인프라를 정의할 때도 유용합니다. AWS 서비스에 대한 기존 API는 설계 측면에서 꽤 하위 수준에 해당합니다. 포괄적인 개발자를 대상으로 가능한 한 많은 기능을 공개하려고 하기 때문입니다. AWS CloudFormation과 같은 IaC 도구는 선언적 인터페이스를 공개하지만, 이러한 인터페이스는 API와 같은 수준이기 때문에 마찬가지로 복잡합니다.

반면, CDK에서는 세부 정보를 숨기고 공통 사용 사례를 단순화하는 새로운 추상 환경을 구성할 수 있습니다. 그리고 사용자가 선택한 언어를 사용하여 이러한 코드를 라이브러리로 패키지할 수 있어서, 다른 사람도 이러한 장점을 쉽게 활용할 수 있습니다.

CDK의 또 다른 강점은 여러 프로그래밍 언어를 지원하도록 설계되었다는 점입니다. 시스템의 핵심은 TypeScript로 작성되지만, 다른 언어의 바인딩을 추가할 수 있습니다.

이 글에서는 CDK를 Python으로 구성하는 방법을 샘플을 통해 살펴보고자 합니다. 먼저 몇 가지 요소를 설치해야 합니다. 자세한 것은 AWS CDK 시작하기를 참조하십시오.

1. 애플리케이션 생성

이제 샘플 애플리케이션을 생성합니다.

$ mkdir my_python_sample
$ cd my_python_sample
$ cdk init
Available templates:
* app: Template for a CDK Application
└─ cdk init app --language=[csharp|fsharp|java|python|typescript]
* lib: Template for a CDK Construct Library
└─ cdk init lib --language=typescript
sample-app: Example CDK Application with some constructs
└─ cdk init sample-app —language=[python|typescript]

먼저 Python CDK 샘플을 포함하는 디렉터리를 생성합니다. CDK에서는 많은 CDK 관련 작업을 쉽게 수행할 수 있는 CLI 도구를 제공합니다. 여기에서는 파라미터 없이 init 명령을 실행합니다.

CLI는 init 명령이 수행할 수 있는 모든 작업에 대한 정보로 응답합니다. 여러 유형의 앱을 초기화할 수 있으며, 여러 프로그래밍 언어도 사용할 수 있습니다. 물론, sample-apppython을 선택합니다.

$ cdk init --language python sample-app
Applying project template sample-app for python
Initializing a new git repository...
Executing python -m venv .env
Welcome to your CDK Python project!

You should explore the contents of this template. It demonstrates a CDK app with two instances of a stack (`HelloStack`) which also uses a user-defined construct (`HelloConstruct`). 

The `cdk.json` file tells the CDK Toolkit how to execute your app.

This project is set up like a standard Python project. The initialization process also creates a virtualenv within this project, stored under the .env directory.

After the init process completes, you can use the following steps to get your project set up.

'''
$ source .env/bin/activate
$ pip install -r requirements.txt
'''

At this point you can now synthesize the CloudFormation template for this code.

'''
$ cdk synth
'''

You can now begin exploring the source code, contained in the hello directory. There is also a very trivial test included that can be run like this:

'''
$ pytest
'''

To add additional dependencies, for example other CDK libraries, just add to your requirements.txt file and rerun the pip install -r requirements.txt command.

Useful commands:

cdk ls          list all stacks in the app
cdk synth       emits the synthesized CloudFormation template
cdk deploy      deploy this stack to your default AWS account/region
cdk diff        compare deployed stack with current state
cdk docs        open CDK documentation

Enjoy!

자, 어떤 작업이 수행되었나요? 실제로 꽤 많은 작업이 수행되었습니다. CDK CLI는 샘플 애플리케이션에 대한 몇 가지 Python 소스 코드를 생성했습니다. 그리고 Python에서 CDK를 쉽게 시작할 수 있도록 다른 지원 파일 및 인프라도 생성했습니다. 다음은 현재 디렉터리에 포함된 콘텐츠입니다.

(.env) $ tree
.
├── README.md
├── app.py
├── cdk.json
├── hello
│   ├── __init__.py
│   ├── hello_construct.py
│   └── hello_stack.py
├── requirements.txt
├── setup.py
└── tests
    ├── __init__.py
    └── unit
        ├── __init__.py
        └── test_hello_construct.py

디렉터리 콘텐츠를 더 자세히 살펴보겠습니다.

  • README.md – 이 프로젝트의 소개용 README입니다.
  • app.py – 이 샘플 애플리케이션의 “기본” 영역입니다.
  • cdk.json – 실행 가능한 CDK에서 CDK 구문 트리를 생성하기 위해 실행해야 하는 작업을 정의하는 CDK용 구성 파일입니다.
  • hello – Python 모듈 디렉터리입니다.
    • hello_construct.py – CDK 애플리케이션에서 사용하도록 정의된 사용자 지정 CDK 구문입니다.
    • hello_stack.py – CDK 애플리케이션에서 사용할 사용자 지정 CDK 스택 구문입니다.
  • requirements.txt – 이 파일은 애플리케이션의 모든 종속 항목을 설치하기 위해 pip에서 사용합니다. 이 경우 -e만 포함합니다. 이 표시는 setup.py에 지정된 필수 요소를 설치하도록 pip에 지시합니다. 또한 python setup.py develop을 실행하여 hello 모듈에 코드를 설치하도록 pip에 지시합니다. 그러면 해당 위치에서 바로 편집할 수 있습니다.
  • setup.py – 이 Python 패키지를 구성하는 방법과 포함되는 종속 항목을 정의합니다.
  • tests – 모든 테스트를 포함합니다.
  • unit – 단위 테스트를 포함합니다.
    • test_hello_construct.pyhello 패키지에서 생성된 사용자 지정 CDK 구문의 부수적인 테스트입니다. 여기에서는 주로 프로젝트에 테스트를 연결하는 방법을 보여줍니다.

또한 init 명령이 실행 중일 때 프로젝트에 대한 virtualenv도 생성했음을 표시합니다. 이 게시물에서는 virtualenvs를 자세히 설명하지는 않습니다. 기본적으로 이 기능은 시스템 Python 환경 및 다른 개발 환경과 사용자의 개발 환경을 분리하기 위한 Python 환경의 우수한 도구입니다.

모든 종속 항목은 이 가상 환경에 설치되어 있으며, 시스템의 다른 부분에는 영향을 주지 않습니다. 이 예제를 완료하면 전체 디렉터리를 삭제할 수 있으며, 그러면 모두 사라집니다.

여기에서 생성한 virtualenv를 사용하지 않아도 되지만, 사용하는 편이 좋습니다. 다음은 virtualenv를 초기화하고 모든 종속 항목을 설치하는 방법을 보여줍니다.

$ source .env/bin/activate
(.env) $ pip install -r requirements.txt
...
(.env) $ pytest
============================= test session starts ==============================
platform darwin -- Python 3.7.0, pytest-4.4.0, py-1.8.0, pluggy-0.9.0
rootdir: /Users/garnaat/projects/cdkdev/my_sample
collected 1 item                                                              
tests/unit/test_hello_construct.py .                                     [100%]
=========================== 1 passed in 0.67 seconds ===========================

보다시피, 현재 매우 간단하긴 해도 테스트를 포함하고 있습니다. 이를 통해 샘플 애플리케이션과 모든 종속 항목이 올바르게 설치되었는지 확인할 수 있습니다.

2. AWS CloudFormation 템플릿 생성

이제 무엇이 있는지 확인했으니, CDK 앱에서 정의하는 구문에 대한 AWS CloudFormation 템플릿을 생성해보겠습니다. CDK 툴킷(CLI)을 사용하여 템플릿을 생성합니다.

$ cdk synth 
Multiple stacks selected (hello-cdk-1, hello-cdk-2), but output is directed to stdout. Either select one stack, or use --output to send templates to a directory. 
$

음, 예상하지 못한 부분이군요. 어떤 의미일까요? 잠시 살펴보면 CDK 앱은 실제로 두 개의 스택, hello-cdk-1 및 hello-cdk-2를 정의합니다. synth 명령은 한 번에 하나의 스택만 통합할 수 있습니다. 여기에서는 두 개 스택을 찾았고, 그중 하나를 선택하라고 요청하고 있습니다.

$ cdk synth hello-cdk-1
Resources:
  MyFirstQueueFF09316A:
    Type: AWS::SQS::Queue
    Properties:
      VisibilityTimeout: 300
    Metadata:
      aws:cdk:path: hello-cdk-1/MyFirstQueue/Resource
  MyFirstQueueMyFirstTopicSubscription774591B6:
    Type: AWS::SNS::Subscription
    Properties:
      Protocol: sqs
      TopicArn:
        Ref: MyFirstTopic0ED1F8A4
      Endpoint:
        Fn::GetAtt:
          - MyFirstQueueFF09316A
          - Arn
    Metadata:
      aws:cdk:path: hello-cdk-1/MyFirstQueue/MyFirstTopicSubscription/Resource
  MyFirstQueuePolicy596EEC78:
    Type: AWS::SQS::QueuePolicy
    Properties:
      PolicyDocument:
        Statement:
          - Action: sqs:SendMessage
            Condition:
              ArnEquals:
                aws:SourceArn:
                  Ref: MyFirstTopic0ED1F8A4
            Effect: Allow
            Principal:
              Service: sns.amazonaws.com
            Resource:
              Fn::GetAtt:
               - MyFirstQueueFF09316A
                - Arn
        Version: "2012-10-17"
      Queues:
        - Ref: MyFirstQueueFF09316A
    Metadata:
      aws:cdk:path: hello-cdk-1/MyFirstQueue/Policy/Resource
  MyFirstTopic0ED1F8A4:
    Type: AWS::SNS::Topic
    Properties:
      DisplayName: My First Topic
    Metadata:
      aws:cdk:path: hello-cdk-1/MyFirstTopic/Resource
  MyHelloConstructBucket0DAEC57E1:
    Type: AWS::S3::Bucket
    DeletionPolicy: Retain
    Metadata:
      aws:cdk:path: hello-cdk-1/MyHelloConstruct/Bucket-0/Resource
  MyHelloConstructBucket18D9883BE:
    Type: AWS::S3::Bucket
    DeletionPolicy: Retain
    Metadata:
      aws:cdk:path: hello-cdk-1/MyHelloConstruct/Bucket-1/Resource
  MyHelloConstructBucket2C1DA3656:
    Type: AWS::S3::Bucket
    DeletionPolicy: Retain
    Metadata:
      aws:cdk:path: hello-cdk-1/MyHelloConstruct/Bucket-2/Resource
  MyHelloConstructBucket398A5DE67:
    Type: AWS::S3::Bucket
    DeletionPolicy: Retain
    Metadata:
      aws:cdk:path: hello-cdk-1/MyHelloConstruct/Bucket-3/Resource
  MyUserDC45028B:
    Type: AWS::IAM::User
    Metadata:
      aws:cdk:path: hello-cdk-1/MyUser/Resource
  MyUserDefaultPolicy7B897426:
    Type: AWS::IAM::Policy
    Properties:
      PolicyDocument:
        Statement:
         - Action:
              - s3:GetObject*
              - s3:GetBucket*
              - s3:List*
            Effect: Allow
            Resource:
              - Fn::GetAtt:
                  - MyHelloConstructBucket0DAEC57E1
                  - Arn
             - Fn::Join:
                  - ""
                  - - Fn::GetAtt:
                        - MyHelloConstructBucket0DAEC57E1
                        - Arn
                    - /*
          - Action:
              - s3:GetObject*
              - s3:GetBucket*
              - s3:List*
            Effect: Allow
            Resource:
              - Fn::GetAtt:
                 - MyHelloConstructBucket18D9883BE
                  - Arn
              - Fn::Join:
                  - ""
                 - - Fn::GetAtt:
                        - MyHelloConstructBucket18D9883BE
                        - Arn
                    - /*
          - Action:
              - s3:GetObject*
              - s3:GetBucket*
              - s3:List*
            Effect: Allow
            Resource:
              - Fn::GetAtt:
                  - MyHelloConstructBucket2C1DA3656
                  - Arn
             - Fn::Join:
                 - ""
                  - - Fn::GetAtt:
                        - MyHelloConstructBucket2C1DA3656
                        - Arn
                    - /*
          - Action:
              - s3:GetObject*
              - s3:GetBucket*
              - s3:List*
            Effect: Allow
            Resource:
              - Fn::GetAtt:
                  - MyHelloConstructBucket398A5DE67
                  - Arn
              - Fn::Join:
                  - ""
                  - - Fn::GetAtt:
                        - MyHelloConstructBucket398A5DE67
                       - Arn
                    - /*
        Version: "2012-10-17"
      PolicyName: MyUserDefaultPolicy7B897426
      Users:
       - Ref: MyUserDC45028B
    Metadata:
     aws:cdk:path: hello-cdk-1/MyUser/DefaultPolicy/Resource
  CDKMetadata:
    Type: AWS::CDK::Metadata
    Properties:
      Modules: aws-cdk=0.27.0,@aws-cdk/assets=0.27.0,@aws-cdk/aws-autoscaling-api=0.27.0,@aws-cdk/aws-cloudwatch=0.27.0,@aws-cdk/aws-codepipeline-api=0.27.0,@aws-cdk/aws-ec2=0.27.0,@aws-cdk/aws-events=0.27.0,@aws-cdk/aws-iam=0.27.0,@aws-cdk/aws-kms=0.27.0,@aws-cdk/aws-lambda=0.27.0,@aws-cdk/aws-logs=0.27.0,@aws-cdk/aws-s3=0.27.0,@aws-cdk/aws-s3-notifications=0.27.0,@aws-cdk/aws-sns=0.27.0,@aws-cdk/aws-sqs=0.27.0,@aws-cdk/aws-stepfunctions=0.27.0,@aws-cdk/cdk=0.27.0,@aws-cdk/cx-api=0.27.0,@aws-cdk/region-info=0.27.0,jsii-runtime=Python/3.7.0

많은 YAML이 있습니다. 정확히 147행입니다. 살펴보는 데 시간이 걸려도 생성 중인 AWS 리소스를 모두 이해할 수 있을 것입니다. 그리고 이러한 리소스를 왜 생성하는지도 알 수 있을 것입니다. 지금 당장 세부적인 부분을 살펴보는 대신, CDK 앱을 구성하는 Python 코드에 초점을 맞춥니다. 그래야 코드가 많이 짧아지고 이해하기도 훨씬 쉽습니다.

먼저, “기본” app.py를 보겠습니다.

#!/usr/bin/env python3

from aws_cdk import cdk
from hello.hello_stack import MyStack

app = cdk.App()

MyStack(app, "hello-cdk-1", env={'region': 'us-east-2'})
MyStack(app, "hello-cdk-2", env={'region': 'us-west-2'})

app.run()

이 코드는 짧고 깔끔하군요. App을 생성하고, MyStack이라고 하는 일부 클래스의 두 개 인스턴스를 앱에 추가하고, App 객체의 run 메서드를 호출합니다.

이제, MyStack 클래스에서 어떤 내용이 진행되는지 살펴봅니다.

from aws_cdk import (
    aws_iam as iam,
    aws_sqs as sqs,
    aws_sns as sns,
    cdk
)

from hello_construct import HelloConstruct

class MyStack(cdk.Stack):
    def __init__(self, app: cdk.App, id: str, **kwargs) -> None:
        super().__init__(app, id, **kwargs)

        queue = sqs.Queue(
            self, "MyFirstQueue",
            visibility_timeout_sec=300,
        )

        topic = sns.Topic(
            self, "MyFirstTopic",
            display_name="My First Topic"
        )

        topic.subscribe_queue(queue)

        hello = HelloConstruct(self, "MyHelloConstruct", num_buckets=4)
        user = iam.User(self, "MyUser")
        hello.grant_read(user)

이 코드는 조금 더 흥미롭군요. 이 코드는 CDK 패키지 몇 개를 가져와 이 패키지를 사용하여 몇 가지 AWS 리소스를 생성합니다.

먼저, MyFirstQueue라고 하는 SQS 큐를 생성하고 큐에 대한 visibility_timeout 값을 설정합니다. 그런 다음, MyFirstTopic이라고 하는 SNS 주제를 생성합니다.

다음 코드도 재미있군요. SQS 큐에 SNS 주제를 구독하는데, 하나의 간단하고 이해하기 쉬운 코드 행에서 이 모든 작업이 수행됩니다.

CLI나 SDK에서 이 작업을 수행해본 적이 있다면 이 프로세스를 수행하는 데 여러 단계가 있다는 점을 알 것입니다. 큐에 메시지를 전송할 권한을 주제에 부여하는 IAM 정책을 생성해야 하고, 주제 구독도 생성해야 합니다. 앞서 생성한 AWS CloudFormation 스택에서 세부 정보를 확인할 수 있습니다.

이 모든 작업이 읽기 쉬운 하나의 코드 행에서 단순화되었습니다. 다음은 인프라에서 복잡한 부분을 숨기기 위한 CDK 구문에 대한 예제입니다.

여기서 마지막 부분에서는 HelloConstruct 클래스의 인스턴스를 생성합니다. 그 이면의 코드를 살펴보겠습니다.


from aws_cdk import (
     aws_iam as iam,
     aws_s3 as s3,
     cdk,
)

class HelloConstruct(cdk.Construct):

    @property
    def buckets(self):
        return tuple(self._buckets)

    def __init__(self, scope: cdk.Construct, id: str, num_buckets: int) ->
 None:
        super().__init__(scope, id)
        self._buckets = []
        for i in range(0, num_buckets):
            self._buckets.append(s3.Bucket(self, f"Bucket-{i}"))

    def grant_read(self, principal: iam.IPrincipal):
        for b in self.buckets:
            b.grant_read(principal, "*")

이 코드는 단순한 API를 공개하는 동시에, 내부적으로는 임의의 AWS 리소스를 정의하는 CDK의 사용자 지정 구문을 생성하는 예제를 보여줍니다.

여기에서는, 구문이 생성자에서 정수 파라미터 num_buckets을 승인한 후, 전달되는 범위 내에서 해당 수만큼의 버킷을 생성합니다. 또한 구문과 연결된 모든 버킷에 IAM 프린시펄에서 전달하는 읽기 권한을 자동으로 부여하는 grant_read 메서드도 공개합니다.

3. AWS CloudFormation 템플릿 배포

CDK의 핵심은 AWS 인프라를 생성하는 것이며, 아직은 인프라를 생성하지 않았습니다. 이제 CDK 프로그램을 사용하여 AWS CloudFormation 템플릿을 생성합니다. 그런 다음, AWS 계정에 해당 템플릿을 배포하고 올바른 리소스가 생성되었는지 검증합니다.

$ cdk deploy
This deployment will make potentially sensitive changes according to your current security approval level (--require-approval broadening).
Please confirm you intend to make the following modifications:

IAM Statement Changes
┌───┬───────────────┬────────┬───────────────┬───────────────┬────────────────┐
│   │ Resource      │ Effect │ Action        │ Principal     │ Condition      │
├───┼───────────────┼────────┼───────────────┼───────────────┼────────────────┤
│ + │ ${MyFirstQueu │ Allow  │ sqs:SendMessa │ Service:sns.a │ "ArnEquals": { │
│   │ e.Arn}        │        │ ge            │ mazonaws.com  │   "aws:SourceA │
│   │               │        │               │               │ rn": "${MyFirs │
│   │               │        │               │               │ tTopic}"       │
│   │               │        │               │               │ }              │
├───┼───────────────┼────────┼───────────────┼───────────────┼────────────────┤
│ + │ ${MyHelloCons │ Allow  │ s3:GetBucket* │ AWS:${MyUser} │                │
│   │ truct/Bucket- │        │ s3:GetObject* │               │                │
│   │ 0.Arn}        │        │ s3:List*      │               │                │
│   │ ${MyHelloCons │        │               │               │                │
│   │ truct/Bucket- │        │               │               │                │
│   │ 0.Arn}/*      │        │               │               │                │
├───┼───────────────┼────────┼───────────────┼───────────────┼────────────────┤
│ + │ ${MyHelloCons │ Allow  │ s3:GetBucket* │ AWS:${MyUser} │                │
│   │ truct/Bucket- │        │ s3:GetObject* │               │                │
│   │ 1.Arn}        │        │ s3:List*      │               │                │
│   │ ${MyHelloCons │        │               │               │                │
│   │ truct/Bucket- │        │               │               │                │
│   │ 1.Arn}/*      │        │               │               │                │
├───┼───────────────┼────────┼───────────────┼───────────────┼────────────────┤
│ + │ ${MyHelloCons │ Allow  │ s3:GetBucket* │ AWS:${MyUser} │                │
│   │ truct/Bucket- │        │ s3:GetObject* │               │                │
│   │ 2.Arn}        │        │ s3:List*      │               │                │
│   │ ${MyHelloCons │        │               │               │                │
│   │ truct/Bucket- │        │               │               │                │
│   │ 2.Arn}/*      │        │               │               │                │
├───┼───────────────┼────────┼───────────────┼───────────────┼────────────────┤
│ + │ ${MyHelloCons │ Allow  │ s3:GetBucket* │ AWS:${MyUser} │                │
│   │ truct/Bucket- │        │ s3:GetObject* │               │                │
│   │ 3.Arn}        │        │ s3:List*      │               │                │
│   │ ${MyHelloCons │        │               │               │                │
│   │ truct/Bucket- │        │               │               │                │
│   │ 3.Arn}/*      │        │               │               │                │
└───┴───────────────┴────────┴───────────────┴───────────────┴────────────────┘
(NOTE: There may be security-related changes not in this list. See http://bit.ly/cdk-2EhF7Np)

Do you wish to deploy these changes (y/n)?

여기에서는, CDK가 이 배포에 포함된 보안 관련 변경 사항에 대해 알려줍니다. 그리고 관련된 ARN 패턴이나 리소스, 권한이 부여된 작업, 권한 부여가 적용되는 IAM 프린시펄을 보여줍니다. 다음을 검토하고 준비가 되면 y를 누릅니다. 그러면 생성되는 리소스에 대해 보고되는 상태를 볼 수 있습니다.

hello-cdk-1: deploying...
hello-cdk-1: creating CloudFormation changeset...
0/12 | 8:41:14 AM | CREATE_IN_PROGRESS | AWS::S3::Bucket | MyHelloConstruct/Bucket-0 (MyHelloConstructBucket0DAEC57E1)
0/12 | 8:41:14 AM | CREATE_IN_PROGRESS | AWS::IAM::User | MyUser (MyUserDC45028B)
0/12 | 8:41:14 AM | CREATE_IN_PROGRESS | AWS::IAM::User | MyUser (MyUserDC45028B) Resource creation Initiated
0/12 | 8:41:15 AM | CREATE_IN_PROGRESS | AWS::CDK::Metadata | CDKMetadata
0/12 | 8:41:15 AM | CREATE_IN_PROGRESS | AWS::S3::Bucket | MyHelloConstruct/Bucket-3 (MyHelloConstructBucket398A5DE67)
0/12 | 8:41:15 AM | CREATE_IN_PROGRESS | AWS::S3::Bucket | MyHelloConstruct/Bucket-1 (MyHelloConstructBucket18D9883BE)
0/12 | 8:41:15 AM | CREATE_IN_PROGRESS | AWS::S3::Bucket | MyHelloConstruct/Bucket-0 (MyHelloConstructBucket0DAEC57E1) Resource creation Initiated
0/12 | 8:41:15 AM | CREATE_IN_PROGRESS | AWS::SQS::Queue | MyFirstQueue (MyFirstQueueFF09316A)
0/12 | 8:41:15 AM | CREATE_IN_PROGRESS | AWS::S3::Bucket | MyHelloConstruct/Bucket-2 (MyHelloConstructBucket2C1DA3656)
0/12 | 8:41:15 AM | CREATE_IN_PROGRESS | AWS::SNS::Topic | MyFirstTopic (MyFirstTopic0ED1F8A4)
0/12 | 8:41:15 AM | CREATE_IN_PROGRESS | AWS::S3::Bucket | MyHelloConstruct/Bucket-3 (MyHelloConstructBucket398A5DE67) Resource creation Initiated
0/12 | 8:41:15 AM | CREATE_IN_PROGRESS | AWS::S3::Bucket | MyHelloConstruct/Bucket-1 (MyHelloConstructBucket18D9883BE) Resource creation Initiated
0/12 | 8:41:15 AM | CREATE_IN_PROGRESS | AWS::SQS::Queue | MyFirstQueue (MyFirstQueueFF09316A) Resource creation Initiated
0/12 | 8:41:16 AM | CREATE_IN_PROGRESS | AWS::SNS::Topic | MyFirstTopic (MyFirstTopic0ED1F8A4) Resource creation Initiated
0/12 | 8:41:16 AM | CREATE_IN_PROGRESS | AWS::S3::Bucket | MyHelloConstruct/Bucket-2 (MyHelloConstructBucket2C1DA3656) Resource creation Initiated
1/12 | 8:41:16 AM | CREATE_COMPLETE | AWS::SQS::Queue | MyFirstQueue (MyFirstQueueFF09316A)
1/12 | 8:41:17 AM | CREATE_IN_PROGRESS | AWS::CDK::Metadata | CDKMetadata Resource creation Initiated
2/12 | 8:41:17 AM | CREATE_COMPLETE | AWS::CDK::Metadata | CDKMetadata
3/12 | 8:41:26 AM | CREATE_COMPLETE | AWS::SNS::Topic | MyFirstTopic (MyFirstTopic0ED1F8A4)
3/12 | 8:41:28 AM | CREATE_IN_PROGRESS | AWS::SNS::Subscription | MyFirstQueue/MyFirstTopicSubscription (MyFirstQueueMyFirstTopicSubscription774591B6)
3/12 | 8:41:29 AM | CREATE_IN_PROGRESS | AWS::SQS::QueuePolicy | MyFirstQueue/Policy (MyFirstQueuePolicy596EEC78)
3/12 | 8:41:29 AM | CREATE_IN_PROGRESS | AWS::SNS::Subscription | MyFirstQueue/MyFirstTopicSubscription (MyFirstQueueMyFirstTopicSubscription774591B6) Resource creation Initiated
4/12 | 8:41:30 AM | CREATE_COMPLETE | AWS::SNS::Subscription | MyFirstQueue/MyFirstTopicSubscription (MyFirstQueueMyFirstTopicSubscription774591B6)
4/12 | 8:41:30 AM | CREATE_IN_PROGRESS | AWS::SQS::QueuePolicy | MyFirstQueue/Policy (MyFirstQueuePolicy596EEC78) Resource creation Initiated
5/12 | 8:41:30 AM | CREATE_COMPLETE | AWS::SQS::QueuePolicy | MyFirstQueue/Policy (MyFirstQueuePolicy596EEC78)
6/12 | 8:41:35 AM | CREATE_COMPLETE | AWS::S3::Bucket | MyHelloConstruct/Bucket-0 (MyHelloConstructBucket0DAEC57E1)
7/12 | 8:41:36 AM | CREATE_COMPLETE | AWS::S3::Bucket | MyHelloConstruct/Bucket-3 (MyHelloConstructBucket398A5DE67)
8/12 | 8:41:36 AM | CREATE_COMPLETE | AWS::S3::Bucket | MyHelloConstruct/Bucket-1 (MyHelloConstructBucket18D9883BE)
9/12 | 8:41:36 AM | CREATE_COMPLETE | AWS::S3::Bucket | MyHelloConstruct/Bucket-2 (MyHelloConstructBucket2C1DA3656)
10/12 | 8:41:50 AM | CREATE_COMPLETE | AWS::IAM::User | MyUser (MyUserDC45028B)
10/12 | 8:41:53 AM | CREATE_IN_PROGRESS | AWS::IAM::Policy | MyUser/DefaultPolicy (MyUserDefaultPolicy7B897426)
10/12 | 8:41:53 AM | CREATE_IN_PROGRESS | AWS::IAM::Policy | MyUser/DefaultPolicy (MyUserDefaultPolicy7B897426) Resource creation Initiated
11/12 | 8:42:02 AM | CREATE_COMPLETE | AWS::IAM::Policy | MyUser/DefaultPolicy (MyUserDefaultPolicy7B897426)
12/12 | 8:42:03 AM | CREATE_COMPLETE | AWS::CloudFormation::Stack | hello-cdk-1

✅ hello-cdk-1

Stack ARN:
arn:aws:cloudformation:us-east-2:433781611764:stack/hello-cdk-1/87482f50-6c27-11e9-87d0-026465bb0bfc

이제 CLI는 IAM 변경 사항에 대한 또 다른 요약 정보를 제시하고, 정보 확인을 요청합니다. CDK 샘플 애플리케이션이 다른 두 개의 AWS 리전에서 두 개 스택을 생성하기 때문입니다. 두 번째 스택에 대한 변경을 승인합니다. 그러면 비슷한 상태 출력을 확인할 수 있습니다.

4. 리소스 정리

이제 AWS Management Console을 사용하여 생성된 리소스를 살펴보고 모두 올바른지 검증할 수 있습니다. 완료했으면, 하나의 명령으로 이 모든 리소스를 간단하게 삭제할 수 있습니다.

$ cdk destroy
Are you sure you want to delete: hello-cdk-2, hello-cdk-1 (y/n)? y

hello-cdk-2: destroying...
   0 | 8:48:31 AM | DELETE_IN_PROGRESS   | AWS::CloudFormation::Stack | hello-cdk-2 User Initiated
   0 | 8:48:33 AM | DELETE_IN_PROGRESS   | AWS::CDK::Metadata     | CDKMetadata 
   0 | 8:48:33 AM | DELETE_IN_PROGRESS   | AWS::IAM::Policy       | MyUser/DefaultPolicy (MyUserDefaultPolicy7B897426) 
   0 | 8:48:33 AM | DELETE_IN_PROGRESS   | AWS::SNS::Subscription | MyFirstQueue/MyFirstTopicSubscription (MyFirstQueueMyFirstTopicSubscription774591B6) 
   0 | 8:48:33 AM | DELETE_IN_PROGRESS   | AWS::SQS::QueuePolicy  | MyFirstQueue/Policy (MyFirstQueuePolicy596EEC78) 
   1 | 8:48:34 AM | DELETE_COMPLETE      | AWS::SQS::QueuePolicy  | MyFirstQueue/Policy (MyFirstQueuePolicy596EEC78) <br />   2 | 8:48:34 AM | DELETE_COMPLETE      | AWS::SNS::Subscription | MyFirstQueue/MyFirstTopicSubscription (MyFirstQueueMyFirstTopicSubscription774591B6) 
   3 | 8:48:34 AM | DELETE_COMPLETE      | AWS::IAM::Policy       | MyUser/DefaultPolicy (MyUserDefaultPolicy7B897426) 
   4 | 8:48:35 AM | DELETE_COMPLETE      | AWS::CDK::Metadata     | CDKMetadata 
   4 | 8:48:35 AM | DELETE_IN_PROGRESS   | AWS::IAM::User         | MyUser (MyUserDC45028B) 
   4 | 8:48:36 AM | DELETE_IN_PROGRESS   | AWS::SNS::Topic        | MyFirstTopic (MyFirstTopic0ED1F8A4)
   4 | 8:48:36 AM | DELETE_SKIPPED       | AWS::S3::Bucket        | MyHelloConstruct/Bucket-0 (MyHelloConstructBucket0DAEC57E1) 
   4 | 8:48:36 AM | DELETE_SKIPPED       | AWS::S3::Bucket        | MyHelloConstruct/Bucket-2 (MyHelloConstructBucket2C1DA3656) 
   4 | 8:48:36 AM | DELETE_SKIPPED       | AWS::S3::Bucket        | MyHelloConstruct/Bucket-1 (MyHelloConstructBucket18D9883BE) 
   4 | 8:48:36 AM | DELETE_IN_PROGRESS   | AWS::SQS::Queue        | MyFirstQueue (MyFirstQueueFF09316A) 
   4 | 8:48:36 AM | DELETE_SKIPPED       | AWS::S3::Bucket        | MyHelloConstruct/Bucket-3 (MyHelloConstructBucket398A5DE67) 
   5 | 8:48:36 AM | DELETE_COMPLETE      | AWS::SNS::Topic        | MyFirstTopic (MyFirstTopic0ED1F8A4) 
   6 | 8:48:36 AM | DELETE_COMPLETE      | AWS::IAM::User         | MyUser (MyUserDC45028B) 
 6 Currently in progress: hello-cdk-2, MyFirstQueueFF09316A

 ✅  hello-cdk-2: destroyed
hello-cdk-1: destroying...
   0 | 8:49:38 AM | DELETE_IN_PROGRESS   | AWS::CloudFormation::Stack | hello-cdk-1 User Initiated
   0 | 8:49:40 AM | DELETE_IN_PROGRESS   | AWS::CDK::Metadata     | CDKMetadata 
   0 | 8:49:40 AM | DELETE_IN_PROGRESS   | AWS::IAM::Policy       | MyUser/DefaultPolicy (MyUserDefaultPolicy7B897426) 
   0 | 8:49:40 AM | DELETE_IN_PROGRESS   | AWS::SQS::QueuePolicy  | MyFirstQueue/Policy (MyFirstQueuePolicy596EEC78) 
   0 | 8:49:40 AM | DELETE_IN_PROGRESS   | AWS::SNS::Subscription | MyFirstQueue/MyFirstTopicSubscription (MyFirstQueueMyFirstTopicSubscription774591B6) 
   1 | 8:49:41 AM | DELETE_COMPLETE      | AWS::IAM::Policy       | MyUser/DefaultPolicy (MyUserDefaultPolicy7B897426) 
   2 | 8:49:41 AM | DELETE_COMPLETE      | AWS::SQS::QueuePolicy  | MyFirstQueue/Policy (MyFirstQueuePolicy596EEC78) 
   3 | 8:49:41 AM | DELETE_COMPLETE      | AWS::SNS::Subscription | MyFirstQueue/MyFirstTopicSubscription (MyFirstQueueMyFirstTopicSubscription774591B6) 
   4 | 8:49:42 AM | DELETE_COMPLETE      | AWS::CDK::Metadata     | CDKMetadata 
   4 | 8:49:42 AM | DELETE_IN_PROGRESS   | AWS::IAM::User         | MyUser (MyUserDC45028B) 
   4 | 8:49:42 AM | DELETE_SKIPPED       | AWS::S3::Bucket        | MyHelloConstruct/Bucket-2 (MyHelloConstructBucket2C1DA3656) 
   4 | 8:49:42 AM | DELETE_SKIPPED       | AWS::S3::Bucket        | MyHelloConstruct/Bucket-3 (MyHelloConstructBucket398A5DE67) 
   4 | 8:49:42 AM | DELETE_SKIPPED       | AWS::S3::Bucket        | MyHelloConstruct/Bucket-0 (MyHelloConstructBucket0DAEC57E1) 
   4 | 8:49:42 AM | DELETE_IN_PROGRESS   | AWS::SNS::Topic        | MyFirstTopic (MyFirstTopic0ED1F8A4) 
   4 | 8:49:42 AM | DELETE_SKIPPED       | AWS::S3::Bucket        | MyHelloConstruct/Bucket-1 (MyHelloConstructBucket18D9883BE) 
   5 | 8:49:42 AM | DELETE_COMPLETE      | AWS::IAM::User         | MyUser (MyUserDC45028B) 
   5 | 8:49:42 AM | DELETE_IN_PROGRESS   | AWS::SQS::Queue        | MyFirstQueue (MyFirstQueueFF09316A) 
   6 | 8:49:43 AM | DELETE_COMPLETE      | AWS::SNS::Topic        | MyFirstTopic (MyFirstTopic0ED1F8A4) 
 6 Currently in progress: hello-cdk-1, MyFirstQueueFF09316A
   7 | 8:50:43 AM | DELETE_COMPLETE      | AWS::SQS::Queue        | MyFirstQueue (MyFirstQueueFF09316A)

 ✅  hello-cdk-1: destroyed

마무리

이 게시물에서는 AWS Cloud Development Kit을 소개해드렸습니다. CDK를 통해 TypeScript, Java, C# 및 현재 Python과 같은 최신 프로그래밍 언어로 AWS 인프라를 정의하는 방법을 알아보았습니다. 그리고 CDK CLI를 사용하여 Python에서 새로운 샘플 애플리케이션을 초기화하는 방법을 제시하고, 프로젝트 구조를 살펴보았습니다. CDK를 사용하여 Python 코드를 AWS CloudFormation 템플릿에 통합하고 AWS CloudFormation에 배포하여 AWS 인프라를 프로비저닝하는 방법도 알려드렸습니다. 마지막으로 작업을 마치고 이러한 리소스를 정리하는 방법을 보여드렸습니다.

이제 여러분의 차례입니다. AWS CDK for Python에서 멋진 작품을 완성해보십시오! 처음 시작하는 경우 다음 리소스를 참조하십시오.

CDK와 Python 언어 바인딩은 현재 개발자 미리보기로 제공되므로, AWS에서 개선할 부분과 원하는 기능에 대한 피드백을 제공해주십시오. GitHub(https://github.com/awslabs/aws-cdk)에서 팀에 문의할 수 있으므로, CDK를 구축하는 엔지니어와 쉽게 연락할 수 있습니다. 버그를 찾았거나 요청할 기능이 있으면 이슈를 올릴 수 있습니다. aws-cdk Gitter 채널 대화에 참여하여 질문해 주셔도 됩니다.

– Mitch Garnaat

이 글은 AWS Developer Blog의 Getting started with the AWS Cloud Development Kit and Python의 한국어 번역입니다.