공부하기싫어
article thumbnail

#AWS Certified Developer Associate

 

 

 

369. CDK 개요

AWS Cloud Development Kit

 

JavaScript/TypeScript, Python, Java 및 .NET 등을 이용해 클라우드 인프라를 정의하도록 해주는 키

CDK 는 CloudFormation 을 대체하는 기능

각 언어로 리소스를 정의한 후 CloudFormation 템플릿으로 컴파일링 됨

인프라와 애플리케이션 런타임 코드를 함께 배포할 수 있음

람다 함수, ECS/EKS 컨테이너 사용시 효율이 좋음

 

 

CDK vs SAM

SAM :

서버리스에 초점

템플릿을 JSON 또는 YAML 형식으로 선언적으로 작성

빠르게 람다 작업에 착수하는데에 탁월함

백엔드에서 CloudFormation 을 활용 - 그보다는 람다 함수와 서버리스 애플리케이션에 중점을 두고 있음

 

CDK :

CloudFormation 을 확장해주는 기능

사용 가능한 모든 AWS 서비스를 지원함

프로그래밍 언어를 사용해 인프라를 작성할 수 있음

백엔드에서 CloudFormation 활용

 

 

 

370. CDK 실습

실습

 

아래 steps.sh 의 단계를 따라 cloudshell 에서 실습한다고 함

 

# 1. install the CDK
sudo npm install -g aws-cdk

# directory name must be cdk-app/ to go with the rest of the tutorial, changing it will cause an error
mkdir cdk-app
cd cdk-app/

# initialize the application
cdk init --language javascript

# verify it works correctly
cdk ls

# install the necessary packages
npm install @aws-cdk/aws-s3 @aws-cdk/aws-iam @aws-cdk/aws-lambda @aws-cdk/aws-lambda-event-sources @aws-cdk/aws-dynamodb


# 2. copy the content of cdk-app-stack.js into lib/cdk-app-stack.js


# 3. setup the Lambda function
mkdir lambda && touch index.py

# 4. bootstrap the CDK application
cdk bootstrap

# 5. (optional) synthesize as a CloudFormation template
cdk synth


# 6. deploy the CDK stack
cdk deploy

# 7. empty the s3 bucket
# 8. destroy the stack
cdk destroy

 

 

step1

먼저 cdk 를 설치해준다고함 cloudshell 에는 npm 이 설치되어있기때문에 npm 으로 설치한다고 함

작업 디렉토리를 만들고 이동

cdk 를 init 한다고 함

init 이 끝나면 애플리케이션 스택 확인을 위해 cdk ls 로 확인할 수 있다

 

이후 Constructs 설치를 한다고 함 npm 명령으로 aws 리소스 Constructs 를 설치해줌

 

step2

예제로 사용할 스택을 넣어준다고 함

lib 디렉토리 안의 cdk-app-stack.js 를 삭제하고 같은 이름으로 새로 만들어준 다음 아래 코드를 붙여넣어줬다

 

const cdk = require("@aws-cdk/core");
const s3 = require("@aws-cdk/aws-s3");
const iam = require("@aws-cdk/aws-iam");
const lambda = require("@aws-cdk/aws-lambda");
const lambdaEventSource = require("@aws-cdk/aws-lambda-event-sources");
const dynamodb = require("@aws-cdk/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_8,
            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 };

 

step3

람다 함수에 쓰일 디렉토리와 코드를 넣어준다고 함

작업디렉토리로 가서 람다 디렉토리를 새로 만들어주고 아래 코드를 index.py 로 넣어줬다

 

#
# Lambda function detect labels in image using Amazon Rekognition
#

from __future__ import print_function
import boto3
import json
import os
from boto3.dynamodb.conditions import Key, Attr

minCofidence = 60


def handler(event, context):
    for record in event['Records']:
        bucket = record['s3']['bucket']['name']
        key = record['s3']['object']['key']

    rekFunction(bucket, key)


def rekFunction(bucket, key):
    print("Detected the following image in S3")
    print("Bucket: " + bucket + " key name: " + key)

    client = boto3.client("rekognition")

    response = client.detect_labels(Image={"S3Object": {"Bucket": bucket, "Name": key}},
                                    MaxLabels=10, MinConfidence=minCofidence)

    # Get the service resource
    dynamodb = boto3.resource("dynamodb")

    # Instantiate a table resource object
    imageLabelsTable = os.environ["TABLE"]
    table = dynamodb.Table(imageLabelsTable)

    # Put item into table
    table.put_item(
        Item={"Image": key}
    )

    objectsDetected = []

    for label in response["Labels"]:
        newItem = label["Name"]
        objectsDetected.append(newItem)
        objectNum = len(objectsDetected)
        itemAtt = f"object{objectNum}"
        response = table.update_item(
            Key={"Image": key},
            UpdateExpression=f"set {itemAtt} = :r",
            ExpressionAttributeValues={":r": f"{newItem}"},
            ReturnValues="UPDATED_NEW"
        )

 

 

step4

cdk 애플리케이션을 부트스트랩한다고 한다

환경을 부트스트랩하고 CloudFormation changeset 을 생성하는 작업이다

cdk 가 애플리케이션의 배포를 위해 사용할 필수 S3 버킷과 IAM 역할을 받게 된다

- cloudformation 으로 가서 확인해보면 CDKToolkit 스택이 생성되어있다

- 리소스탭으로 가서 확인해보면 StagingBucket (s3 bucket) 과 StagingBucketPolicy 가 생성되어있

 

그런데 아래와 같은 에러 발생

 

[cloudshell-user@ip-10-6-11-248 cdk-app]$ cdk bootstrap
/home/cloudshell-user/cdk-app/node_modules/@aws-cdk/core/node_modules/constructs/lib/construct.js:49
            throw new Error('construct does not have an associated node. All constructs must extend the "Construct" base class');
            ^

Error: construct does not have an associated node. All constructs must extend the "Construct" base class
    at Function.of (/home/cloudshell-user/cdk-app/node_modules/@aws-cdk/core/node_modules/constructs/lib/construct.js:49:19)
    at new Node (/home/cloudshell-user/cdk-app/node_modules/@aws-cdk/core/node_modules/constructs/lib/construct.js:35:18)
    at new ConstructNode (/home/cloudshell-user/cdk-app/node_modules/@aws-cdk/core/lib/construct-compat.js:174:28)
    at Object.createNode (/home/cloudshell-user/cdk-app/node_modules/@aws-cdk/core/lib/construct-compat.js:35:42)
    at new Construct (/home/cloudshell-user/cdk-app/node_modules/@aws-cdk/core/node_modules/constructs/lib/construct.js:503:32)
    at new Construct (/home/cloudshell-user/cdk-app/node_modules/@aws-cdk/core/lib/construct-compat.js:33:9)
    at new Stack (/home/cloudshell-user/cdk-app/node_modules/@aws-cdk/core/lib/stack.js:65:9)
    at new CdkAppStack (/home/cloudshell-user/cdk-app/lib/cdk-app-stack.js:18:9)
    at Object.<anonymous> (/home/cloudshell-user/cdk-app/bin/cdk-app.js:7:1)
    at Module._compile (node:internal/modules/cjs/loader:1165:14)

Subprocess exited with error 1
[cloudshell-user@ip-10-6-11-248 cdk-app]$

 

찾아보니 영상은 cdk 버전 1인것 같고 나는 2인것 같다

그냥 강의만 쭉 봐야겠다

 

 

step5

cdk 스택이 생성될때 사용했던 cloudformation template 을 확인하려면 cdk synth 를 사용할 수 있다고 한다

 

step6

cdk deploy 를 입력해 스택을 배포한다고 한다

명령을 입력하면 changeset 을 확인할 수 있다

 

step7,8

실습 했던 자원 삭제