본문 바로가기

웹 운영/AWS

[CDA] 섹션 26 - 클라우드 개발 키트 (CDK)

728x90

<397 CDK 개요>

 

 

> CDK 란 사용하는 language 안에서 cloud infra 를 정의할 수 있는 Kit 를 말한다

> CF 를 대체할 수 있는 것

> 가히 혁명적인 기능이라고 생각한다고 하심

 

 

CDK 를 활용하여 TS로 인프라를 코드로 설계하는 예시

 

 

> ec2.Vpc 라는 construct 를 사용하는 모습을 볼 수 있다

>> "MyVpc" 라는 이름을 붙여주고, 3개의 AZ 를 부여.

>> 이 설정 그대로 VPC 를 만들어주게 된다 

 

> 또한 ECS Cluster 를 만들어주는데, vpc 는 위에서 정의한 vpc 가 parameter 로 들어가서, 두 객체를 연동한다

> 마지막으로 ALB 가 달린 Fargate Service 를 생성해준다

>> 방금 만든 ECS Cluster 를 넣어주고, 원하는 CPU 갯수, Task 갯수를 정의 

 

> 코드가 동작하는지 컴파일 오류를 한 번 검증해줄 수 있다

>> 컴파일이 된다면 이를 SAM 에서 했던 것처럼 CF Template 으로 변형시켜준다

> 애플리케이션과 infra 코드를 함께 배포할 수 있다는 장점!

>> 람다 함수에게 좋고, ECS/EKS 내부 Docker container 에게도 좋음

>> 개인적으로 CI/CD 할 때 매우 유용할 듯. 앱 패키지 안에 같이 있을 것 같은 느낌 (패키지 내부  Dockerfile 활용하는 것처럼)

 

 

CDK 를 활용하여 AWS 리소스들을 Constructs 로 정의하여 CF Template 으로 만든다

 

 

> 위 언어들 등등을 활용하여 Application Contructs 들을 정의

> CDK CLI 가 동작하여 CF Template 으로 만들어줌

 

 

<CDK vs SAM>

 

> SAM

>> SAM 은 Serverless 자원에 대해 포커싱을 두고 있고, template 을 명시적으로 JSON/YML 을 활용하여 작성한다

> CDK

>> CF 의 상위 집합(?), 모든 AWS Service 를 활용할 수 있고, 프로그래밍 언어로 작성된다

>> SAM / CDK 둘다 CF 를 최종적으로 활용한다는 공통점은 있다

 

 

SAM 과 CDK 를 연동하여 사용할 수 있다 (로컬 테스트 시)

 

 

> SAM + CDK

>> 둘을 함께 사용할 수도 있는데, SAM CLI 를 활용하여 작성한 CDK 앱을 로컬에서 테스트 할 때 사용

>> $cdk synth 명령어를 사용하면 CDK 앱을 통해 CF Template 을 일차적으로 생성해준다

>> 그리고 이전에 배웠듯이, 이 Template 을 제공하여 $sam local invvoke -t {file} 로 정의된 람다함수를 호출해 볼 수 있다

 

 

------------------------------------------

 

 

<398 CDK 실습>

 

 

실습에서 할 일 요약 / CDK 로 S3 만들고 람다 정의해서 DD 에 저장하는거까지 함 / CloudShell 에서 진행하긴 함

 

 

> $ sudo npm install -g aws-cdk-lib

>> 노드에 CDK 를 활용할 수 있도록 관련 패키지를 설치. 이후 cdk-app 디렉토리를 만들어서 이동한다

> $ cdk init --language {사용언어}

>> 다른 언어로 initializing 해줄 수도 있다

> $ cdk ls

>> 초기화가 잘 되었는지 확인할 수 있다 (CdkAppStack 를 반환해주는데 의미가 뭔지는 안나옴)

> 이후로 lib 경로 안에 있는 cdk-app-stack.js 를 삭제하고 다시 만들어서 새로 만든다 (lib 경로 안)

> 일단 뭔지 이해할 필욘 없는데 위에 내용대로 붙여넣음

 

# cdk-app-stack.js 를 새로 작성
# 강사님이 제공해준 파일에 있음

const cdk = require("aws-cdk-lib");

const s3 = require("aws-cdk-lib/aws-s3");
const iam = require("aws-cdk-lib/aws-iam");
const lambda = require("aws-cdk-lib/aws-lambda");
const lambdaEventSource = require("aws-cdk-lib/aws-lambda-event-sources");
const dynamodb = require("aws-cdk-lib/aws-dynamodb");

const imageBucket = "cdk-rekn-imagebucket";

class CdkAppStack extends cdk.Stack {
    /**
     *
     * @param {cdk.Construct} scope
     * @param {string} id
     * @param {cdk.StackProps=} props
     */
    constructor(scope, id, props) {
        super(scope, id, props);

        // The code that defines your stack goes here

        // ========================================
        // Bucket for storing images
        // ========================================
        const bucket = new s3.Bucket(this, imageBucket, {
            removalPolicy: cdk.RemovalPolicy.DESTROY,
        });
        new cdk.CfnOutput(this, "Bucket", { value: bucket.bucketName });

        // ========================================
        // Role for AWS Lambda
        // ========================================
        const role = new iam.Role(this, "cdk-rekn-lambdarole", {
            assumedBy: new iam.ServicePrincipal("lambda.amazonaws.com"),
        });
        role.addToPolicy(
            new iam.PolicyStatement({
                effect: iam.Effect.ALLOW,
                actions: [
                    "rekognition:*",
                    "logs:CreateLogGroup",
                    "logs:CreateLogStream",
                    "logs:PutLogEvents",
                ],
                resources: ["*"],
            })
        );

        // ========================================
        // DynamoDB table for storing image labels
        // ========================================
        const table = new dynamodb.Table(this, "cdk-rekn-imagetable", {
            partitionKey: { name: "Image", type: dynamodb.AttributeType.STRING },
            removalPolicy: cdk.RemovalPolicy.DESTROY,
        });
        new cdk.CfnOutput(this, "Table", { value: table.tableName });

        // ========================================
        // AWS Lambda function
        // ========================================
        const lambdaFn = new lambda.Function(this, "cdk-rekn-function", {
            code: lambda.AssetCode.fromAsset("lambda"),
            runtime: lambda.Runtime.PYTHON_3_9,
            handler: "index.handler",
            role: role,
            environment: {
                TABLE: table.tableName,
                BUCKET: bucket.bucketName,
            },
        });
        lambdaFn.addEventSource(
            new lambdaEventSource.S3EventSource(bucket, {
                events: [s3.EventType.OBJECT_CREATED],
            })
        );

        bucket.grantReadWrite(lambdaFn);
        table.grantFullAccess(lambdaFn);
    }
}

module.exports = { CdkAppStack };

 

> 이 파일이 결국 CDK 파일이며, 좀 살펴볼 필요가 있다

> 각 리소스들 s3, iam 등등을 앱에서 활용하기 위해 처음에 CDK-LIB 으로 부터 불러온다

> S3 버킷을 정의했다 -> 이런게 CF Template 으로 적용한 설정들과 함께 튀어나오는 것

> 개발자들 입장에선 훨씬 편리, 훨씬 Agile 한 느낌이라고 함

 

> iam 을 활용해서 role 도 정의하고, role 에 실제로 넣을 Policy 도 정의하는 모습도 볼 수 있다

> 그 밖에 DD,  Lambda 함수, Lambda 의 Trigger Event 정의 등등을 각각 배울 때 배웠던 익숙한 설정들과 함께 정의되어 있다.

 

> 마지막 줄에 특이한 점은, 권한을 줄 때도 함수를 사용할 수 있다는 점이다

>> bucket.grantReadWrite, table.grantFullAccess 를 통해 람다함수에게 권한을 부여함

 

> lib 경로에서 나와서 이번엔 lambda 란 디렉토리 생성 후 이동, 그 안에서 index.py 를 정의한다

> 이건 람다 함수로, 굳이 여기 붙여놓진 않는다

>> 람다가 하는 일 요약 - S3 에서 오는 이미지를 Rekognition 이란 리소스로 실행시킴 (분석), 그 결과를 가지고 와서 DD 에 저장한다

 

> $ cdk bootstrap (local 영역이 아닌, AWS 계정 내에 init 같은거) 

>> 초기화과정을 수행하는데, 계정별, 리전별로 한번씩만 하면 된다고 함

>> 계정 내에서 CDK 를 작동하기 위한 것들을 SU 해준다고 함

>> 실제 CF 로 이동해보면 CDKToolkit 이란 Stack 이 생성되어 이것 저것 하고 있는걸 볼 수 있다

>> IAM Role, S3 Bucket, SSM Params 등등을 준비한다 

 

> $ cdk synth 를 통해 CF Template 을 Overview 할 수 있다 (선택사항)

> $ cdk deploy 를 통해 실제로 CF Template 을 만들어주고, 이를 배포한다

>> 둘이 다른걸 이해는 해야함!!

 

> 역시 CF 가보면 뚝딱뚝딱 하고 있다

> 그리고 다 완성되면 S3 에 업로드를 해보고, 그로 인해 람다를 다 동작시키고 DD 에 item 이 들어가는걸 확인해보기도 함

> Recognition? 이 리소스가 사진 안에 있는 것들 분석해주나봄 ㅋㅋㅋㅋㅋ item 에 사진 안에 있는 정보들 저장됨 (펭귄, 신발, 눈 등등) 

> 이게 더 신기하다 ㅅㅂ

 

 

------------------------------------------

 

 

<399 CDK Constructs >

 

 

> 최종 CF 스택을 생성하는데 CDK 가 필요한 모든 것을 캡슐화 해놓은 것이다

> S3 Bucket 같은 single resource 일 수 있고, 하나로 동작하는 여러 컴포넌트로 구성된 리소스일 수도 있다 (SQS 연동된 리소스 등) 

 

> AWS Construct Library

>> 모든 AWS Resource 들을 위한 Construct 를 가지고 있는 집합, 3계층으로 제공

>> Construct Hub 란 공간도 있는데, AWS 리소스 뿐만 아니라 제 3자 시스템의 개입 혹은 오픈 소스의 Construct 를 제공하여 너가 원하는 CDK 를 더 잘 형성할 수 있게 도와준다

 

 

<Layer 1>

 

const bucket = new s3.CfnBucket(this, "MyBucket", {
    bucketName : "MyBucket"
});

 

 

> CFN Resource 라고 하며, CF에서 사용 가능한 모든 리소스들을 가지고 있다 (cfn 으로 시작)

> CF Resource Specification 과 동일한 방식(?) 으로 resource 를 define 한다 (위에 모습이라고 함) 

> 정의하려는 리소스는 정의하는데 필요한 모든 리소스 property 를 가지고 있어야 함

> 뭔소린지 잘 모르겠음

 

 

<Layer 2>

 

const s3 = require('aws-sdk-lib/aws-s3');

const bckt = new s3.Bucket(this, 'MyBucket', {
    versioned: true,
    encryption: s3.BucketEncryption.KMS
});

// Returns the HTTPS URL of S3 Object
const objUrl = bckt.urlForObject('MyBucket/myObj');

 

 

> Intent Based API 를 제공하며, 더 높은 수준의 AWS 리소스를 지원. 

> 위에 모습을 보면, cfn 으로 시작하지 않고, s3.Bucket 으로 선언된다. 선언할 때 추가 속성 지원, 특정 객체에 대한 objUrl 반환 가능 (L1 과 유사하지만 extra methods 들이 지원된다고 보면 되는 듯) 

>> resource property 에 대해 모든걸 다 알 필요가 없음 (편리한 기본값이 있음)

 

 

<Layer 3>

 

const api = new apigateway.LambdaRestApi(this, 'myapi', {
  handler: backend,
  proxy: false
}

const items = api.root.addResource('items'); // root 로 시작, 경로 시작
items.addMethod('GET');  // GET /items
items.addMethod('POST');  // GET /items

const item = items.addResource('{item}'); // 경로 추가
item.addMethod('GET');  // GET /items/{item}

item.addMethod('DELETE', new apigateway.HttpIntegration('http://amazon.com'));

 

> 위는 L3 CDK Cosntruct 로 API Gateway 와 상호작용 하는 모습을 보여줌

> Patterns 라고 부르는데, multiple related resource 를 보여주기 때문

> AWS 에서 수행하는 기본적인 동작 (정의 뿐만 아니라) 까지 지원해준다. (위에서 처럼 API Gateway 로 REST API 만들기) 

> 가령, ECS Pattern : Fargate 서비스에 ALB 를 연동한 그런 패턴인데, 이게 CF 로 작성하면 꽤나 복잡할 수 있음. 이럴 때 CDK 를 이용하여 Parameter 만 주고 연관관계만 맺어주고 하면 구성할 수 있다

 

 

------------------------------------------

 

 

<400 CDK 알아둬야할 주요 명령어 >

 

 

CDK 를 활용함에 있어서 알아두어야 할 명령어들

 

 

> 1: CDK, CLI, Library 를 설치, CDK 스택을 작성을 시작할 수 있다

> 2: 특정 템플렛에 맞춰서 앱을 초기화함. (Python, Java 등) 

> 3: 코드로된 CDK 스택을 CF Template 으로 변환시켜준다

> 4: 다음장에 나옴

> 5: CF Template 완성되면 스택을 배포하기 위함

> 6: 배포된 스택과, 현재 로컬에 작성되어 변경된 내용을 비교해준다

> 7: Stack 파괴

 

 

<CDK Boostrap>

 

 

Boostrap 이 동작하는 원리

 

 

> Boostrap 이란 AWS 환경에 CDK 배포를 하기 전에 필요한 자원들을 provisioning 하는 과정을 말한다

> 여기서 환경이란 한 계정내 특정 Region 을 말한다

>> 그 환경에 배포하기 전에 CDKToolkit 이라는 CF Stack 을 생성해야 한다

>> S3 Bucket & IAM Role 을 가지고 있음

 

> 새로운 환경에 배포할 때는 (Account + Region 단위) cdk bootstrap 을 실행해야 함.  

>> $ cdk bootstrap aws://<<account>>/<<region>>

> 만약 "Policy contains a statement with one or more invalid principal" 이라는 에러가 발생한다면, 이는 필요한 IAM Role 이 빠져 있을 때 발생하므로, bootstrap 을 진행했는지 확인하는 것을 권장

 

 

------------------------------------------

 

 

<400 CDK Unit Test >

 

 

test 를 수행하는 모습

 

 

>  CDK 앱을 테스트하려면, 유명한 Test Module 인 Jest(JS) 나 PyTest(Python) 결합된 CDK Assertion Module 을 사용하면 된다

> CDK 에서는 두가지 종류의 test 가 있음. 그냥 이런게 있다 정도만 알며 될 듯!

>> Fine-Grained Assertion

>> 특정 리소스가 특정 Property 를 가지고 있는지 test 한다

>> 위 예시에선 람다 함수가 handler 함수를 가지고 있는지, 적합한 runtime 을 가지고 있는지 테스트 함

>> SNS 토픽 Subscription 하는게 1건인지도 test 가능

>> Snapshot Test

>> synthesized CF Template (형성된 CF Template?) 과 previously stored baseline template 을 비교? 태스트 한다

>> DD Table 이 아직 CF Template 안에 있는지, 뭐 이런거 테스트 한다고 하는데, 잘 모르겠음 ㅋㅋ 

 

> Template 을 Test 하기 위해선 import 가 필요 :: 시험에서 매우 중요!!

>> Template.fromStack(MyStack) : CDK 에서 정의한 Stack 을 로딩함 (위 예시에도 있음)

>> Template.fromString(string) : CDK 에 Template 이 아직 없을 경우, String 은 파일이고 CDK Template 이 외부에 있을때 유용

> 끄으읏

 

 

------------------------------------------

 

 

<퀴즈>

 

> 질문 1개임

코드를 사용하여 AWS에서 인프라를 생성하고 싶지만 CloudFormation 템플릿을 작성하기 위해 JSON 또는 YAML을 배울 시간이 없습니다. 여러분은 이미 파이썬을 알고 있습니다. 어떤 AWS 서비스가 도움이 됩니까?

 

> 답: CDK ㅋㅋ

 

 

 

====================================================================================

 

 

교육 출처

 

- AWS Certified Developer Associate 시험 대비 강의 - Udemy

 

https://www.udemy.com/share/105Hxw3@z0Wqme5D9voly52i8MuQYl_c8462GP25Oul4H38G3nVfgD4fMrYPJE5LOB88iDuZ/

728x90