본문으로 건너뛰기
김신건의 로그

[IaC] AWS CDK: TypeScript 로 CloudFormation 생성

· 수정 · 📖 약 2분 · 804자/단어 #aws #cdk #iac #devops #cloudformation #cloud
AWS CDK, Cloud Development Kit, CDK construct, CDK stack, L1 L2 L3 construct, CDK Toolkit, cdktf, CDK Aspects, CDK bootstrap

정의

AWS CDK = TS/Python/Java/Go 로 AWS 인프라 정의CloudFormation 으로 컴파일 → 배포. AWS 전용 IaC 도구.

CloudFormation YAML 을 직접 쓰는 대신 프로그래밍 언어로 인프라를 선언. 타입 안전성, 추상화, 재사용, 테스트 가능.

흐름

flowchart LR
    Code["TypeScript / Python\n(CDK App)"] --> Synth["cdk synth\n(CFN template 생성)"]
    Synth --> Diff["cdk diff\n(변경 미리보기)"]
    Diff --> Deploy["cdk deploy\n(CloudFormation 호출)"]
    Deploy --> CFN["CloudFormation Stack"]
    CFN --> AWS["AWS Resources"]

Construct Level (L1, L2, L3)

CDK 의 핵심 추상화 단위는 Construct. 3단계 레벨로 분류.

Level이름의미예시
L1CloudFormation ResourcesCFN 그대로, 자동 생성CfnBucket, CfnFunction
L2Curated Constructs추상화 + 기본값 제공Bucket, Function, Table
L3Patterns합성 (여러 L2 묶음)LoadBalancedFargateService
flowchart TB
    L3["L3 Pattern\nLoadBalancedFargateService"] --> L2a["L2 Construct\nApplicationLoadBalancer"]
    L3 --> L2b["L2 Construct\nFargateService"]
    L2a --> L1a["L1 CfnLoadBalancer"]
    L2b --> L1b["L1 CfnService"]
    L1a --> CFN["CloudFormation Resource"]
    L1b --> CFN

예시: S3 + Lambda

import { Stack, StackProps, RemovalPolicy } from 'aws-cdk-lib';
import { Bucket, BucketEncryption } from 'aws-cdk-lib/aws-s3';
import { Function, Runtime, Code } from 'aws-cdk-lib/aws-lambda';
import { Construct } from 'constructs';

export class MyStack extends Stack {
  constructor(scope: Construct, id: string, props?: StackProps) {
    super(scope, id, props);

    const bucket = new Bucket(this, 'Data', {
      versioned: true,
      encryption: BucketEncryption.KMS_MANAGED,
      removalPolicy: RemovalPolicy.RETAIN,
    });

    const fn = new Function(this, 'Processor', {
      runtime: Runtime.NODEJS_22_X,
      handler: 'index.handler',
      code: Code.fromAsset('lambda'),
      environment: {
        BUCKET_NAME: bucket.bucketName,
      },
    });

    // IAM 자동 생성: bucket policy + role + policy
    bucket.grantReadWrite(fn);
  }
}

bucket.grantReadWrite(fn) 한 줄 = bucket resource policy + Lambda IAM role + policy 연결 자동. 가장 강력한 추상화.

L3 패턴 예시: ALB + Fargate

import { ApplicationLoadBalancedFargateService } from 'aws-cdk-lib/aws-ecs-patterns';
import { ContainerImage } from 'aws-cdk-lib/aws-ecs';

new ApplicationLoadBalancedFargateService(this, 'Service', {
  cluster,
  taskImageOptions: {
    image: ContainerImage.fromRegistry('nginx:latest'),
    containerPort: 80,
  },
  desiredCount: 3,
  cpu: 256,
  memoryLimitMiB: 512,
  publicLoadBalancer: true,
});

ALB + Target Group + Fargate Task Definition + ECS Service + Security Group + IAM Role 을 한 번에 생성.

CDK 명령

cdk init app --language=typescript    # 프로젝트 초기화
cdk bootstrap                         # CDK metadata bucket 생성 (account+region 당 1회)
cdk synth                             # CFN template 생성 (cdk.out/)
cdk diff                              # 현재 배포 vs 변경 예정 diff
cdk deploy MyStack                    # 배포
cdk deploy --all                      # 전체 stack 배포
cdk destroy MyStack                   # 삭제
cdk ls                                # stack 목록

Aspects: 전체 적용 정책

Aspect = CDK tree 를 순회하며 모든 construct 에 적용하는 visitor.

import { Aspects, IAspect, IConstruct } from 'aws-cdk-lib';
import { CfnBucket } from 'aws-cdk-lib/aws-s3';

class EnforceEncryption implements IAspect {
  visit(node: IConstruct): void {
    if (node instanceof CfnBucket) {
      node.bucketEncryption = {
        serverSideEncryptionConfiguration: [{
          serverSideEncryptionByDefault: { sseAlgorithm: 'AES256' },
        }],
      };
    }
  }
}

// 앱 전체에 적용
Aspects.of(app).add(new EnforceEncryption());

사용 사례: 전사 보안 정책 강제, 태그 자동 추가, cost center 라벨링.

Snapshot 테스트

import { Template } from 'aws-cdk-lib/assertions';
import { App } from 'aws-cdk-lib';
import { MyStack } from '../lib/my-stack';

test('snapshot', () => {
  const app = new App();
  const stack = new MyStack(app, 'TestStack');
  const template = Template.fromStack(stack);

  // 특정 리소스 확인
  template.hasResourceProperties('AWS::S3::Bucket', {
    VersioningConfiguration: { Status: 'Enabled' },
  });

  // 전체 스냅샷 (변경 추적)
  expect(template.toJSON()).toMatchSnapshot();
});

CI 에 스냅샷 테스트 필수. 의도치 않은 인프라 변경을 PR 단계에서 캐치.

CDK vs Terraform vs Pulumi

항목CDKTerraformPulumi
언어TS/Python/Java/GoHCLTS/Python/Go/C#
Multi-cloudAWS 위주
StateCFN managed별도 backendPulumi Cloud
추상화L1/L2/L3provider코드
타입 안전성완전 (TS)제한적완전
테스트jest / pytestterratest언어 내장
AWS 새 서비스 대응즉시provider 업데이트 필요provider 업데이트 필요
학습 곡선AWS 잘 알면 낮음HCL 별도 학습코드 자유도 높음

판단 기준:

  • AWS-only + 개발자 친화성 + 타입 안전성 → CDK
  • Multi-cloud + 인프라 팀 중심 → Terraform
  • Multi-cloud + 완전한 프로그래밍 언어 → Pulumi

Custom Construct 패턴

재사용 가능한 인프라 패턴을 Construct 로 추상화.

import { Construct } from 'constructs';
import { Function, Runtime, Code } from 'aws-cdk-lib/aws-lambda';
import { Queue } from 'aws-cdk-lib/aws-sqs';
import { SqsEventSource } from 'aws-cdk-lib/aws-lambda-event-sources';

// 재사용 가능한 Lambda + SQS Construct
export class WorkerConstruct extends Construct {
  public readonly queue: Queue;
  public readonly fn: Function;

  constructor(scope: Construct, id: string, props: { handler: string }) {
    super(scope, id);

    this.queue = new Queue(this, 'Queue', {
      visibilityTimeout: cdk.Duration.seconds(300),
    });

    this.fn = new Function(this, 'Worker', {
      runtime: Runtime.NODEJS_22_X,
      handler: props.handler,
      code: Code.fromAsset('lambda'),
    });

    this.fn.addEventSource(new SqsEventSource(this.queue, {
      batchSize: 10,
      reportBatchItemFailures: true,
    }));
  }
}

// 사용: 두 줄로 SQS + Lambda 구성 완료
const worker = new WorkerConstruct(this, 'ImageProcessor', {
  handler: 'image.handler',
});

Pipelines (CI/CD)

CDK Pipelines = 코드로 선언한 배포 파이프라인.

import { CodePipeline, ShellStep, CodePipelineSource } from 'aws-cdk-lib/pipelines';

const pipeline = new CodePipeline(this, 'Pipeline', {
  pipelineName: 'MyPipeline',
  synth: new ShellStep('Synth', {
    input: CodePipelineSource.gitHub('org/repo', 'main'),
    commands: ['npm ci', 'npx cdk synth'],
  }),
});

// 스테이지 추가
pipeline.addStage(new MyAppStage(this, 'Prod', {
  env: { account: '123', region: 'ap-northeast-2' },
}));

self-mutating: pipeline 자체도 코드에서 관리. 파이프라인 정의 변경 시 자동 업데이트.

CDK for Terraform (cdktf)

import { S3Bucket } from '@cdktf/provider-aws/lib/s3-bucket';
import { App, TerraformStack } from 'cdktf';

class MyStack extends TerraformStack {
  constructor(scope: App, id: string) {
    super(scope, id);
    new S3Bucket(this, 'data', { bucket: 'myapp-data' });
  }
}

CDK 의 언어 (TS/Python) + Terraform 의 multi-cloud backend. HashiCorp 와 협력.

비용

CDK 자체는 무료. 생성되는 AWS 리소스 요금 + bootstrap bucket (S3) 비용.

비용 최적화:

  • cdk deploy --hotswap: Lambda / ECS 변경을 CFN 대신 직접 배포 (개발 속도 향상)
  • bootstrap bucket 의 오래된 asset 주기적 정리
  • cdk diff 로 불필요한 replacement 사전 차단

흔한 함정

WARNING

  1. cdk bootstrap 누락: account+region 당 1회 필요. CI/CD 파이프라인에서 첫 실행 시 실패.
  2. CFN limit 500 resource: 대형 stack 은 Nested stack 으로 분리.
  3. CDK Asset S3 누적: bootstrap bucket 에 Lambda zip 등 asset 누적. 정기 정리 또는 lifecycle 설정.
  4. L2 기본값 함정: Bucket 은 public access block 기본 활성. 의도한 설정인지 확인.
  5. snapshot 테스트 미적용: stack 변경 시 의도치 않은 resource 재생성 (replacement) 놓침.

CAUTION

RemovalPolicy.DESTROY 는 stack 삭제 시 S3 버킷, RDS 등 데이터 포함 삭제. 프로덕션 리소스는 반드시 RETAIN.

관련 위키

이 글의 용어 (7개)
[AWS] CloudFormationcloud
정의 AWS CloudFormation 은 JSON 또는 YAML 템플릿으로 AWS 인프라를 선언적으로 프로비저닝하는 IaC (Infrastructure as Code) 서비스입…
[AWS] EKS: managed Kubernetescloud
정의 EKS (Elastic Kubernetes Service) = AWS 의 managed K8s control plane. worker node 는 사용자 (또는 Fargat…
[AWS] IAM: User, Role, Policy, STScloud
정의 IAM (Identity and Access Management) = AWS 의 권한 관리 전부. User, Group, Role, Policy 로 구성. "누가 어떤 리소…
[AWS] Lambda: 서버리스 함수, 트리거, 동시성cloud
정의 AWS Lambda = 서버리스 함수 실행. 이벤트 트리거 → 함수 실행 → 결과 / 비동기 처리. 서버 관리 0. 사용 상황 | 상황 | Lambda 적합성 | |---|…
[AWS] S3: object storage, storage classes, lifecyclecloud
정의 S3 = AWS 의 object storage. bucket + key + object. 11 9's durability (99.999999999%), 무한 확장. 2026…
[IaC] Pulumi: 코드로 인프라 (TS/Python/Go)cloud
정의 Pulumi = 일반 프로그래밍 언어로 IaC. TypeScript, Python, Go, .NET, Java. Terraform 의 HCL DSL 대신 코드 자유도. 사용…
[IaC] Terraform: HCL, provider, statecloud
정의 Terraform = 선언적 인프라 코드. HCL (HashiCorp Configuration Language) 로 리소스 정의 → AWS/GCP/Azure 등 provid…

💬 댓글

사이트 검색 / 명령어

검색

스크롤 = 확대/축소 · 드래그 = 이동 · 0 = 원래 크기 · ESC = 닫기