$ yh.log
AWS CDK (Cloud Development Kit) 정리 - Constructs, 명령어, 테스트

AWS CDK (Cloud Development Kit) 정리 - Constructs, 명령어, 테스트

AWSCDKIaCCloudFormationDVA-C02

작성자 : 오예환 | 작성일 : 2026-01-20 | 수정일 : 2026-01-20 | 조회수 :

1. AWS CDK 개요

🤔 CDK가 뭔가요?

비유로 이해하기: CDK는 프로그래밍 언어로 인프라를 만드는 도구입니다.

  • 기존: YAML/JSON으로 인프라 정의 (CloudFormation)
  • CDK: TypeScript, Python, Java 등으로 인프라 정의!
  • 익숙한 언어로 AWS 리소스를 코드처럼 작성

CDK = Cloud Development Kit

┌─────────────────────────────────────────────────────────────────┐
                      CDK의 역할

  기존 방식 (CloudFormation YAML):                               │
  ┌────────────────────────────────────────────────────┐
  AWSTemplateFormatVersion: '2010-09-09'
  Resources:
    MyBucket:
      Type: AWS::S3::Bucket
      Properties:
        BucketName: my-bucket
        ...50줄 더...
  └────────────────────────────────────────────────────┘

  CDK 방식 (TypeScript):                                         │
  ┌────────────────────────────────────────────────────┐
  const bucket = new s3.Bucket(this, 'MyBucket', {
    bucketName: 'my-bucket'
  });                                                
  └────────────────────────────────────────────────────┘

 cdk synth

  ┌────────────────────────────────────────────────────┐
     CloudFormation Template (자동 생성!)             │        │
  └────────────────────────────────────────────────────┘

└─────────────────────────────────────────────────────────────────┘

CDK 특징

특징설명초보자 설명
프로그래밍 언어TypeScript, Python, Java, .NET익숙한 언어 사용!
Constructs고수준 컴포넌트레고 블록처럼 조립
CloudFormation 변환코드 → CF 템플릿자동으로 YAML 생성
인프라 + 앱 코드함께 배포 가능Lambda, ECS 배포 편리

지원 언어

언어지원
TypeScript✅ (가장 인기)
JavaScript
Python
Java
.NET (C#)
Go

2. CDK 동작 방식

CDK 워크플로우

┌─────────────────────────────────────────────────────────────────┐
                    CDK 워크플로우

  1. CDK 코드 작성
  ┌─────────────────────────────────────────┐
  // lib/my-stack.ts
  export class MyStack extends Stack {
    constructor(...) {
      const bucket = new s3.Bucket(...); 
      const lambda = new lambda.Function
    }
  }
  └─────────────────────────────────────────┘

 cdk synth

  2. CloudFormation 템플릿 생성
  ┌─────────────────────────────────────────┐
  cdk.out/MyStack.template.json
  (자동 생성된 CloudFormation 템플릿)     │                   │
  └─────────────────────────────────────────┘

 cdk deploy

  3. CloudFormation 배포
  ┌─────────────────────────────────────────┐
  AWS CloudFormation
 S3 Bucket 생성
 Lambda Function 생성
 IAM Role 생성
  └─────────────────────────────────────────┘

└─────────────────────────────────────────────────────────────────┘

CDK vs CloudFormation vs SAM

항목CloudFormationSAMCDK
언어YAML/JSONYAML/JSON프로그래밍 언어
범위모든 AWS서버리스 중심모든 AWS
추상화낮음중간높음
재사용중첩 스택-Constructs
IDE 지원제한적제한적자동완성, 타입체크

3. CDK vs SAM

🤔 언제 뭘 써야 하나요?

비교표

항목SAMCDK
주요 용도서버리스 (Lambda)모든 AWS 서비스
작성 방식선언형 (YAML)명령형 (코드)
학습 곡선낮음중간
유연성제한적매우 높음
타입 안전성✅ (TypeScript)
IDE 지원제한적강력함

선택 가이드

┌─────────────────────────────────────────────────────────────────┐
                    SAM vs CDK 선택

  Q1. 서버리스 앱만 만드나요? (Lambda + API Gateway)             │
      ├─ Yes SAM (빠르게 시작)                                │
      └─ No CDK

  Q2. 복잡한 인프라가 필요한가요? (VPC, RDS, ECS...)            │
      ├─ Yes CDK
      └─ No SAM

  Q3. 프로그래밍 언어로 인프라를 관리하고 싶나요?
      ├─ Yes CDK
      └─ No SAM 또는 CloudFormation

  Q4. 타입 안전성과 IDE 자동완성이 중요한가요?
      ├─ Yes CDK (TypeScript)                                 │
      └─ No OK

└─────────────────────────────────────────────────────────────────┘

CDK + SAM 함께 사용

CDK로 만든 앱을 SAM CLI로 로컬 테스트 가능!
 
┌─────────────────────────────────────────────────────────────────┐
                    CDK + SAM 조합

  1. CDK 작성
  ┌─────────────────────────────────────────┐
  const fn = new lambda.Function(...)    
  └─────────────────────────────────────────┘

 cdk synth

  2. CloudFormation 템플릿 생성
  ┌─────────────────────────────────────────┐
  cdk.out/MyCDKStack.template.json
  └─────────────────────────────────────────┘

 SAM CLI

  3. 로컬 테스트
  ┌─────────────────────────────────────────┐
  sam local invoke \ 
    -t cdk.out/MyCDKStack.template.json \│
    myFunction
  └─────────────────────────────────────────┘

└─────────────────────────────────────────────────────────────────┘

4. CDK Constructs

🤔 Construct가 뭔가요?

비유로 이해하기: 레고 블록과 같습니다.

  • L1 블록: 가장 기본 블록 (1x1 브릭)
  • L2 블록: 미리 조립된 블록 (자동차 바퀴)
  • L3 블록: 완성된 세트 (자동차 전체)

Construct 레벨

┌─────────────────────────────────────────────────────────────────┐
                    Construct Levels

  ┌─────────────────────────────────────────────────────────┐
  L3 Constructs (Patterns)                                │   │
  ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
 여러 리소스의 패턴
 예: LambdaRestApi, ApplicationLoadBalancedFargateService│
 가장 높은 추상화 수준
  └─────────────────────────────────────────────────────────┘

  ┌─────────────────────────────────────────────────────────┐
  L2 Constructs (High-level)                              │   │
  ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
 AWS 리소스의 고수준 표현
 편리한 기본값 제공
 예: s3.Bucket, lambda.Function
 메서드 제공: bucket.addLifeCycleRule()               
  └─────────────────────────────────────────────────────────┘

  ┌─────────────────────────────────────────────────────────┐
  L1 Constructs (CFN Resources)                           │   │
  ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
 CloudFormation 리소스와 1:1 매핑
 모든 속성 직접 설정 필요
 이름이 Cfn으로 시작: CfnBucket, CfnFunction
 가장 낮은 추상화 수준
  └─────────────────────────────────────────────────────────┘

└─────────────────────────────────────────────────────────────────┘

L1, L2, L3 코드 비교

L1 Construct (CFN Resources)

// L1: CfnBucket (CloudFormation 리소스 직접 사용)
// 모든 속성을 직접 설정해야 함
 
import { CfnBucket } from "aws-cdk-lib/aws-s3";
 
const bucket = new CfnBucket(this, "MyBucket", {
  bucketName: "my-bucket",
  versioningConfiguration: {
    status: "Enabled",
  },
  publicAccessBlockConfiguration: {
    blockPublicAcls: true,
    blockPublicPolicy: true,
    ignorePublicAcls: true,
    restrictPublicBuckets: true,
  },
});

L2 Construct (High-level)

// L2: Bucket (편리한 기본값 + 메서드)
// 훨씬 간단하고, 보안 설정이 기본으로 적용됨!
 
import * as s3 from "aws-cdk-lib/aws-s3";
 
const bucket = new s3.Bucket(this, "MyBucket", {
  bucketName: "my-bucket",
  versioned: true, // 간단한 플래그
  blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL, // 편의 상수
});
 
// 편리한 메서드 제공!
bucket.addLifecycleRule({
  expiration: Duration.days(90),
});

L3 Construct (Patterns)

// L3: LambdaRestApi (API Gateway + Lambda 한 번에!)
// 복잡한 아키텍처를 한 줄로!
 
import * as apigateway from "aws-cdk-lib/aws-apigateway";
 
const api = new apigateway.LambdaRestApi(this, "MyApi", {
  handler: myLambdaFunction,
  // API Gateway, Lambda 권한, 통합 등이 모두 자동 설정!
});
 
// 또는 Fargate 패턴
import * as ecsPatterns from "aws-cdk-lib/aws-ecs-patterns";
 
const fargate = new ecsPatterns.ApplicationLoadBalancedFargateService(this, "MyService", {
  taskImageOptions: {
    image: ecs.ContainerImage.fromRegistry("amazon/amazon-ecs-sample"),
  },
  // ALB + Fargate + ECS Cluster + IAM Role 등 모두 자동!
});

Construct 레벨 비교

레벨이름 형식추상화설정사용 시기
L1CfnXxx낮음모든 속성 직접CF에 없는 속성 필요 시
L2Xxx중간편리한 기본값일반적인 경우
L3XxxPattern높음최소 설정표준 아키텍처

Construct Hub

AWS가 제공하는 Construct 외에도
3rd party, 오픈소스 Construct 사용 가능!
 
https://constructs.dev
 
예시:
- cdk-dynamo-table-viewer: DynamoDB 테이블 뷰어 UI
- cdk-watchful: 자동 CloudWatch 대시보드
- cdk-nag: 보안/컴플라이언스 검사

5. CDK 주요 명령어

CDK CLI 명령어

명령어설명
npm install -g aws-cdkCDK CLI 전역 설치
cdk init app새 CDK 프로젝트 생성
cdk synthCloudFormation 템플릿 생성
cdk bootstrapCDK 배포 환경 준비
cdk deploy스택 배포
cdk diff로컬 vs 배포된 스택 비교
cdk destroy스택 삭제
cdk ls스택 목록

명령어 상세

1️⃣ 프로젝트 초기화

# 새 CDK 프로젝트 생성 (TypeScript)
mkdir my-cdk-app
cd my-cdk-app
cdk init app --language typescript
 
# 생성되는 구조
my-cdk-app/
├── bin/
   └── my-cdk-app.ts      # 엔트리 포인트
├── lib/
   └── my-cdk-app-stack.ts # 스택 정의
├── test/
   └── my-cdk-app.test.ts  # 테스트
├── cdk.json                # CDK 설정
├── package.json
└── tsconfig.json

2️⃣ CloudFormation 템플릿 생성

# 템플릿 생성 (cdk.out/ 디렉토리에 저장)
cdk synth
 
# 출력 예시
Resources:
  MyBucketF68F3FF0:
    Type: AWS::S3::Bucket
    Properties:
      BucketName: my-bucket
...

3️⃣ Bootstrap (환경 준비)

# 각 AWS 계정/리전에 처음 1회 필요!
cdk bootstrap aws://123456789012/ap-northeast-2
 
# CDKToolkit 스택이 생성됨:
# - S3 버킷 (아티팩트 저장)
# - IAM 역할 (배포 권한)

4️⃣ 배포

# 스택 배포
cdk deploy
 
# 모든 스택 배포
cdk deploy --all
 
# 특정 스택 배포
cdk deploy MyStack
 
# 승인 없이 배포 (CI/CD용)
cdk deploy --require-approval never

5️⃣ 차이점 확인

# 로컬 코드 vs 배포된 스택 비교
cdk diff
 
# 출력 예시
Stack MyStack
Resources
[~] AWS::S3::Bucket MyBucket MyBucketF68F3FF0
 └─ [+] VersioningConfiguration
     └─ {"Status":"Enabled"}

6. CDK Bootstrapping

🤔 Bootstrapping이 뭔가요?

비유로 이해하기: CDK를 사용하기 전 기초 공사입니다.

  • 건물 짓기 전에 기초를 다져야 하듯이
  • CDK 배포 전에 S3 버킷, IAM Role 등을 미리 생성

Bootstrap 프로세스

┌─────────────────────────────────────────────────────────────────┐
                    CDK Bootstrap

  ┌───────────────────────────────────────────────────┐
  cdk bootstrap aws://123456789012/ap-northeast-2
  └─────────────────────────┬─────────────────────────┘


  ┌───────────────────────────────────────────────────┐
            CloudFormation Stack
               "CDKToolkit"

  ┌────────────────────────────────────────────┐
  S3 Bucket
  - 아티팩트 저장 (Lambda 코드, Assets)   │   │         │
  └────────────────────────────────────────────┘

  ┌────────────────────────────────────────────┐
  IAM Roles
  - CloudFormation 실행 역할
  - 배포 역할
  - 파일 업로드 역할
  └────────────────────────────────────────────┘

  └───────────────────────────────────────────────────┘

  ⚠️ AWS 계정 + 리전 조합마다 1회 필요!

└─────────────────────────────────────────────────────────────────┘

Bootstrap이 안 되어 있으면?

Error: Policy contains a statement with one or more invalid principal
 
 cdk bootstrap을 먼저 실행하세요!

여러 환경 Bootstrap

# 개발 환경
cdk bootstrap aws://123456789012/ap-northeast-2
 
# 스테이징 환경
cdk bootstrap aws://123456789012/us-east-1
 
# 프로덕션 환경 (다른 계정)
cdk bootstrap aws://987654321098/ap-northeast-2

7. CDK Testing

🤔 CDK 앱도 테스트할 수 있나요?

비유로 이해하기: 일반 코드처럼 단위 테스트 가능!

  • CDK 코드 → CloudFormation 템플릿 생성
  • 템플릿의 내용을 검증

테스트 종류

테스트설명용도
Fine-grained Assertions특정 리소스/속성 검증세부 검증
Snapshot Tests전체 템플릿 비교변경 감지

Fine-grained Assertions (세부 검증)

// test/my-stack.test.ts
import * as cdk from "aws-cdk-lib";
import { Template, Match } from "aws-cdk-lib/assertions";
import { MyStack } from "../lib/my-stack";
 
describe("MyStack", () => {
  test("S3 Bucket Created", () => {
    // 1. 스택 생성
    const app = new cdk.App();
    const stack = new MyStack(app, "TestStack");
 
    // 2. 템플릿 추출
    const template = Template.fromStack(stack);
 
    // 3. 검증: S3 버킷이 존재하는지
    template.hasResourceProperties("AWS::S3::Bucket", {
      BucketName: "my-bucket",
      VersioningConfiguration: {
        Status: "Enabled",
      },
    });
  });
 
  test("Lambda Function with Correct Memory", () => {
    const app = new cdk.App();
    const stack = new MyStack(app, "TestStack");
    const template = Template.fromStack(stack);
 
    // Lambda 함수의 메모리가 512MB인지 확인
    template.hasResourceProperties("AWS::Lambda::Function", {
      MemorySize: 512,
      Runtime: "nodejs18.x",
    });
  });
 
  test("Correct Number of Resources", () => {
    const app = new cdk.App();
    const stack = new MyStack(app, "TestStack");
    const template = Template.fromStack(stack);
 
    // S3 버킷이 정확히 2개인지 확인
    template.resourceCountIs("AWS::S3::Bucket", 2);
  });
});

Snapshot Tests (스냅샷 테스트)

// test/my-stack.test.ts
import * as cdk from "aws-cdk-lib";
import { Template } from "aws-cdk-lib/assertions";
import { MyStack } from "../lib/my-stack";
 
test("Snapshot Test", () => {
  const app = new cdk.App();
  const stack = new MyStack(app, "TestStack");
  const template = Template.fromStack(stack);
 
  // 스냅샷과 비교
  expect(template.toJSON()).toMatchSnapshot();
});
┌─────────────────────────────────────────────────────────────────┐
                    Snapshot Test 동작

 실행:
  ┌─────────────────────────────────────────┐
  현재 템플릿 스냅샷으로 저장
  __snapshots__/my-stack.test.ts.snap
  └─────────────────────────────────────────┘

  이후 실행:
  ┌─────────────────────────────────────────┐
  현재 템플릿 vs 저장된 스냅샷
 다르면 테스트 실패!
 의도된 변경이면 스냅샷 업데이트
  └─────────────────────────────────────────┘

  npm test -- -u  (스냅샷 업데이트)                              │

└─────────────────────────────────────────────────────────────────┘

Template 가져오는 방법

메서드용도
Template.fromStack(stack)CDK로 만든 스택
Template.fromString(json)외부 템플릿 문자열

8. CDK 실전 예시

S3 + Lambda + DynamoDB 예시

// lib/my-stack.ts
import * as cdk from "aws-cdk-lib";
import * as s3 from "aws-cdk-lib/aws-s3";
import * as lambda from "aws-cdk-lib/aws-lambda";
import * as dynamodb from "aws-cdk-lib/aws-dynamodb";
import * as s3n from "aws-cdk-lib/aws-s3-notifications";
import { Construct } from "constructs";
 
export class MyStack extends cdk.Stack {
  constructor(scope: Construct, id: string, props?: cdk.StackProps) {
    super(scope, id, props);
 
    // 1. DynamoDB 테이블
    const table = new dynamodb.Table(this, "ResultsTable", {
      partitionKey: { name: "id", type: dynamodb.AttributeType.STRING },
      billingMode: dynamodb.BillingMode.PAY_PER_REQUEST,
      removalPolicy: cdk.RemovalPolicy.DESTROY, // 개발용
    });
 
    // 2. Lambda 함수
    const fn = new lambda.Function(this, "ProcessImageFunction", {
      runtime: lambda.Runtime.NODEJS_18_X,
      handler: "index.handler",
      code: lambda.Code.fromAsset("lambda"), // lambda/ 폴더의 코드
      environment: {
        TABLE_NAME: table.tableName,
      },
      timeout: cdk.Duration.seconds(30),
      memorySize: 512,
    });
 
    // 3. Lambda에 DynamoDB 권한 부여
    table.grantWriteData(fn);
 
    // 4. S3 버킷
    const bucket = new s3.Bucket(this, "ImageBucket", {
      removalPolicy: cdk.RemovalPolicy.DESTROY,
      autoDeleteObjects: true, // 개발용
    });
 
    // 5. S3 → Lambda 트리거
    bucket.addEventNotification(s3.EventType.OBJECT_CREATED, new s3n.LambdaDestination(fn));
 
    // 6. 출력
    new cdk.CfnOutput(this, "BucketName", {
      value: bucket.bucketName,
    });
  }
}

프로젝트 구조

my-cdk-app/
├── bin/
   └── my-cdk-app.ts
├── lib/
   └── my-stack.ts
├── lambda/                    # Lambda 코드
   ├── index.ts
   └── package.json
├── test/
   └── my-stack.test.ts
├── cdk.json
├── package.json
└── tsconfig.json

L3 Construct 사용 예시 (API Gateway + Lambda)

// API Gateway + Lambda 한 번에!
import * as apigateway from "aws-cdk-lib/aws-apigateway";
 
export class ApiStack extends cdk.Stack {
  constructor(scope: Construct, id: string) {
    super(scope, id);
 
    const fn = new lambda.Function(this, "HelloFunction", {
      runtime: lambda.Runtime.NODEJS_18_X,
      handler: "index.handler",
      code: lambda.Code.fromInline(`
        exports.handler = async () => ({
          statusCode: 200,
          body: JSON.stringify({ message: 'Hello!' })
        });
      `),
    });
 
    // L3 Pattern: API Gateway + Lambda 통합
    const api = new apigateway.LambdaRestApi(this, "HelloApi", {
      handler: fn,
      // API Gateway, Lambda 권한, 통합 모두 자동!
    });
 
    new cdk.CfnOutput(this, "ApiUrl", {
      value: api.url,
    });
  }
}

Fargate 서비스 예시 (L3 Pattern)

import * as ecs from "aws-cdk-lib/aws-ecs";
import * as ecsPatterns from "aws-cdk-lib/aws-ecs-patterns";
 
export class FargateStack extends cdk.Stack {
  constructor(scope: Construct, id: string) {
    super(scope, id);
 
    // L3 Pattern: ALB + Fargate 한 번에!
    const service = new ecsPatterns.ApplicationLoadBalancedFargateService(this, "MyService", {
      taskImageOptions: {
        image: ecs.ContainerImage.fromRegistry("nginx"),
      },
      publicLoadBalancer: true,
      // VPC, ECS Cluster, ALB, Target Group, Security Group 모두 자동!
    });
 
    // Auto Scaling 추가도 간단!
    service.service
      .autoScaleTaskCount({
        minCapacity: 1,
        maxCapacity: 10,
      })
      .scaleOnCpuUtilization("CpuScaling", {
        targetUtilizationPercent: 50,
      });
  }
}

핵심 요약

CDK vs SAM vs CloudFormation

항목CloudFormationSAMCDK
언어YAML/JSONYAML프로그래밍 언어
범위모든 AWS서버리스모든 AWS
추상화낮음중간높음
타입 안전성

Construct 레벨

레벨예시특징
L1CfnBucketCF 리소스 1:1
L2Bucket편리한 기본값
L3LambdaRestApi완성된 패턴

주요 명령어

명령어용도
cdk init프로젝트 생성
cdk synthCF 템플릿 생성
cdk bootstrap환경 준비 (1회)
cdk deploy배포
cdk diff차이 확인
cdk destroy삭제