

# AWS CDK를 사용하여 Lambda 함수 배포
<a name="lambda-cdk-tutorial"></a>

AWS Cloud Development Kit (AWS CDK)는 사용자가 선택한 프로그래밍 언어를 사용하여 AWS 클라우드 인프라를 정의하는 데 사용할 수 있는 코드형 인프라(IaC) 프레임워크입니다. 자체 클라우드 인프라를 정의하려면 먼저 하나 이상의 스택을 포함하는 앱(CDK 지원 언어 중 하나로)을 작성해야 합니다. 그런 다음 합성하여 CloudFormation 템플릿을 만들고 리소스를 AWS 계정에 배포합니다. 이 주제의 단계에 따라 Amazon API Gateway 엔드포인트에서 이벤트를 반환하는 Lambda 함수를 배포하세요.

CDK에 포함된 AWS Construct Library는 AWS 서비스가 제공하는 리소스를 모델링하는 데 사용할 수 있는 모듈을 제공합니다. 많이 사용되는 서비스의 라이브러리는 스마트 기본값과 모범 사례를 통해 큐레이트된 구조를 제공합니다. [aws\$1lambda](https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_lambda-readme.html) 모듈을 사용하여 단 몇 줄의 코드로 함수와 지원하는 리소스를 정의할 수 있습니다.

## 사전 조건
<a name="lambda-cdk-prerequisites"></a>

이 자습서를 시작하기 전에 다음 명령을 실행하여 AWS CDK를 설치합니다.

```
npm install -g aws-cdk
```

## 1단계: AWS CDK 프로젝트 설정
<a name="lambda-cdk-step-1"></a>

새 AWS CDK 앱에 대한 디렉터리를 생성하고 프로젝트를 초기화합니다.

------
#### [ JavaScript ]

```
mkdir hello-lambda
cd hello-lambda
cdk init --language javascript
```

------
#### [ TypeScript ]

```
mkdir hello-lambda
cd hello-lambda
cdk init --language typescript
```

------
#### [ Python ]

```
mkdir hello-lambda
cd hello-lambda
cdk init --language python
```

프로젝트가 시작되면 프로젝트의 가상 환경을 활성화하고 AWS CDK의 기준선 종속성을 설치합니다.

```
source .venv/bin/activate
python -m pip install -r requirements.txt
```

------
#### [ Java ]

```
mkdir hello-lambda
cd hello-lambda
cdk init --language java
```

이 Maven 프로젝트를 Java 통합 개발 환경(IDE)으로 가져옵니다. 예를 들어 Eclipse에서 **파일**, **가져오기**, **Maven**, **기존 Maven 프로젝트**를 사용합니다.

------
#### [ C\$1 ]

```
mkdir hello-lambda
cd hello-lambda
cdk init --language csharp
```

------

**참고**  
AWS CDK 애플리케이션 템플릿은 프로젝트 디렉토리의 이름을 사용하여 소스 파일 및 클래스의 이름을 생성합니다. 이 예에서 디렉터리 이름은 `hello-lambda`입니다. 다른 프로젝트 디렉터리 이름을 사용하는 경우 앱이 이 지침과 일치하지 않습니다.

AWS CDK v2에는 `aws-cdk-lib`라는 단일 패키지에 모든 AWS 서비스에 대한 안정적인 구성이 포함되어 있습니다. 이 패키지는 프로젝트를 초기화하거나 종속 항목으로 설치됩니다. 특정 프로그래밍 언어로 작업하는 경우 프로젝트를 처음 빌드할 때 패키지가 설치됩니다.

## 2단계: AWS CDK 스택 삭제
<a name="lambda-cdk-step-2"></a>

CDK *스택*은 AWS 리소스를 정의하는 하나 이상의 구문의 모음입니다. 각 CDK 스택은 CDK 앱의 CloudFormation 스택을 나타냅니다.

CDK 스택을 정의하려면 선호하는 프로그래밍 언어에 대한 지침을 따르세요. 이 스택은 다음을 정의합니다.
+ 함수의 논리명: `MyFunction`
+ `code` 속성에 지정된 함수 코드의 위치. 자세한 내용은 *AWS Cloud Development Kit (AWS CDK) API Reference*의 [Handler Code](https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_lambda-readme.html#handler-code)를 참조하세요.
+ REST API의 논리명: `HelloApi`
+ API Gateway 엔드포인트의 논리명: `ApiGwEndpoint`

이 자습서의 모든 CDK 스택은 Lambda 함수에 Node.js [런타임](lambda-runtimes.md)을 사용한다는 점에 유의하세요. CDK 스택과 Lambda 함수에 다양한 프로그래밍 언어를 사용하여 각 언어의 장점을 활용할 수 있습니다. 예를 들어 CDK 스택에 TypeScript를 사용하여 인프라 코드에 정적 입력의 이점을 활용할 수 있습니다. Lambda 함수에 JavaScript를 사용하여 동적으로 입력되는 언어의 유연성과 빠른 개발의 이점을 활용할 수 있습니다.

------
#### [ JavaScript ]

`lib/hello-lambda-stack.js` 파일을 열고 내용을 다음으로 바꿉니다.

```
const { Stack } = require('aws-cdk-lib');
const lambda = require('aws-cdk-lib/aws-lambda');
const apigw = require('aws-cdk-lib/aws-apigateway');

class HelloLambdaStack extends Stack {
  /**
   *
   * @param {Construct} scope
   * @param {string} id
   * @param {StackProps=} props
   */
  constructor(scope, id, props) {
    super(scope, id, props);
    const fn = new lambda.Function(this, 'MyFunction', {
      code: lambda.Code.fromAsset('lib/lambda-handler'),
      runtime: lambda.Runtime.NODEJS_LATEST,
      handler: 'index.handler'
    });

    const endpoint = new apigw.LambdaRestApi(this, 'MyEndpoint', {
      handler: fn,
      restApiName: "HelloApi"
    });

  }
}

module.exports = { HelloLambdaStack }
```

------
#### [ TypeScript ]

`lib/hello-lambda-stack.ts` 파일을 열고 내용을 다음으로 바꿉니다.

```
import * as cdk from 'aws-cdk-lib';
import { Construct } from 'constructs';
import * as apigw from "aws-cdk-lib/aws-apigateway";
import * as lambda from "aws-cdk-lib/aws-lambda";
import * as path from 'node:path';

export class HelloLambdaStack extends cdk.Stack {
  constructor(scope: Construct, id: string, props?: cdk.StackProps){
    super(scope, id, props)
    const fn = new lambda.Function(this, 'MyFunction', {
      runtime: lambda.Runtime.NODEJS_LATEST,
      handler: 'index.handler',
      code: lambda.Code.fromAsset(path.join(__dirname, 'lambda-handler')),
    });

    const endpoint = new apigw.LambdaRestApi(this, `ApiGwEndpoint`, {
      handler: fn,
      restApiName: `HelloApi`,
    });

  }
}
```

------
#### [ Python ]

`/hello-lambda/hello_lambda/hello_lambda_stack.py` 파일을 열고 내용을 다음으로 바꿉니다.

```
from aws_cdk import (
    Stack,
    aws_apigateway as apigw,
    aws_lambda as _lambda
)
from constructs import Construct

class HelloLambdaStack(Stack):

    def __init__(self, scope: Construct, construct_id: str, **kwargs) -> None:
        super().__init__(scope, construct_id, **kwargs)

        fn = _lambda.Function(
            self,
            "MyFunction",
            runtime=_lambda.Runtime.NODEJS_LATEST,
            handler="index.handler",
            code=_lambda.Code.from_asset("lib/lambda-handler")
        )

        endpoint = apigw.LambdaRestApi(
            self,
            "ApiGwEndpoint",
            handler=fn,
            rest_api_name="HelloApi"
        )
```

------
#### [ Java ]

`/hello-lambda/src/main/java/com/myorg/HelloLambdaStack.java` 파일을 열고 내용을 다음으로 바꿉니다.

```
package com.myorg;

import software.constructs.Construct;
import software.amazon.awscdk.Stack;
import software.amazon.awscdk.StackProps;
import software.amazon.awscdk.services.apigateway.LambdaRestApi;
import software.amazon.awscdk.services.lambda.Function;

public class HelloLambdaStack extends Stack {
    public HelloLambdaStack(final Construct scope, final String id) {
        this(scope, id, null);
    }

    public HelloLambdaStack(final Construct scope, final String id, final StackProps props) {
        super(scope, id, props);

        Function hello = Function.Builder.create(this, "MyFunction")
                            .runtime(software.amazon.awscdk.services.lambda.Runtime.NODEJS_LATEST)
                            .code(software.amazon.awscdk.services.lambda.Code.fromAsset("lib/lambda-handler"))
                            .handler("index.handler")
                            .build();

        LambdaRestApi api = LambdaRestApi.Builder.create(this, "ApiGwEndpoint")
                                .restApiName("HelloApi")
                                .handler(hello)
                                .build();

    }
}
```

------
#### [ C\$1 ]

`src/HelloLambda/HelloLambdaStack.cs` 파일을 열고 내용을 다음으로 바꿉니다.

```
using Amazon.CDK;
using Amazon.CDK.AWS.APIGateway;
using Amazon.CDK.AWS.Lambda;
using Constructs;

namespace HelloLambda
{
    public class HelloLambdaStack : Stack
    {
        internal HelloLambdaStack(Construct scope, string id, IStackProps props = null) : base(scope, id, props)
        {
            var fn = new Function(this, "MyFunction", new FunctionProps
            {
                Runtime = Runtime.NODEJS_LATEST,
                Code = Code.FromAsset("lib/lambda-handler"),
                Handler = "index.handler"
            });

            var api = new LambdaRestApi(this, "ApiGwEndpoint", new LambdaRestApiProps
            {
                Handler = fn
            });
        }
    }
}
```

------

## 3단계: Lambda 함수 코드 생성
<a name="lambda-cdk-step-3"></a>

1. 프로젝트 루트(`hello-lambda`)에서 Lambda 함수 코드에 대한 `/lib/lambda-handler` 디렉터리를 생성합니다. 이 디렉터리는 AWS CDK 스택의 `code` 속성에 지정됩니다.

1. `index.js` 디렉터리에서 `/lib/lambda-handler`라는 파일을 새로 생성합니다. 다음 코드를 파일에 붙여 넣습니다. 함수는 API 요청에서 특정 속성을 추출하여 JSON 응답으로 반환합니다.

   ```
   exports.handler = async (event) => {
     // Extract specific properties from the event object
     const { resource, path, httpMethod, headers, queryStringParameters, body } = event;
     const response = {
       resource,
       path,
       httpMethod,
       headers,
       queryStringParameters,
       body,
     };
     return {
       body: JSON.stringify(response, null, 2),
       statusCode: 200,
     };
   };
   ```

## 4단계: AWS CDK 스택 배포
<a name="lambda-cdk-step-4"></a>

1. 프로젝트의 루트에서 [cdk synth](https://docs.aws.amazon.com/cdk/v2/guide/ref-cli-cmd-synth.html) 명령을 실행합니다.

   ```
   cdk synth
   ```

   이 명령은 CDK 스택에서 AWS CloudFormation 템플릿을 합성합니다. 템플릿은 다음과 유사한 약 400줄의 YAML 파일입니다.
**참고**  
다음 오류가 발생하면 현재 위치가 프로젝트 디렉터리의 루트인지 확인합니다.  

   ```
   --app is required either in command-line, in cdk.json or in ~/.cdk.json
   ```  
**Example CloudFormation 템플릿**  

   ```
   Resources:
     MyFunctionServiceRole3C357FF2:
       Type: AWS::IAM::Role
       Properties:
         AssumeRolePolicyDocument:
           Statement:
             - Action: sts:AssumeRole
               Effect: Allow
               Principal:
                 Service: lambda.amazonaws.com
           Version: "2012-10-17"		 	 	 
         ManagedPolicyArns:
           - Fn::Join:
               - ""
               - - "arn:"
                 - Ref: AWS::Partition
                 - :iam::aws:policy/service-role/AWSLambdaBasicExecutionRole
       Metadata:
         aws:cdk:path: HelloLambdaStack/MyFunction/ServiceRole/Resource
     MyFunction1BAA52E7:
       Type: AWS::Lambda::Function
       Properties:
         Code:
           S3Bucket:
             Fn::Sub: cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}
           S3Key: ab1111111cd32708dc4b83e81a21c296d607ff2cdef00f1d7f48338782f92l3901.zip
         Handler: index.handler
         Role:
           Fn::GetAtt:
             - MyFunctionServiceRole3C357FF2
             - Arn
         Runtime: nodejs24.x
         ...
   ```

1. [cdk deploy](https://docs.aws.amazon.com/cdk/v2/guide/ref-cli-cmd-deploy.html) 명령을 실행합니다.

   ```
   cdk deploy
   ```

   리소스가 생성되는 동안 기다립니다. 최종 출력에는 API Gateway 엔드포인트의 URL이 포함됩니다. 예제:

   ```
   Outputs:
   HelloLambdaStack.ApiGwEndpoint77F417B1 = https://abcd1234.execute-api.us-east-1.amazonaws.com/prod/
   ```

## 5단계: 함수 테스트
<a name="lambda-cdk-step-5"></a>

Lambda 함수를 간접적으로 간접 호출하려면 API Gateway 엔드포인트를 복사하여 웹 브라우저에 붙여넣거나 `curl` 명령을 실행합니다.

```
curl -s https://abcd1234.execute-api.us-east-1.amazonaws.com/prod/
```

응답은 원래 이벤트 객체에서 선택한 속성을 JSON으로 표현한 것으로, API Gateway 엔드포인트에 대한 요청 정보를 담고 있습니다. 예제:

```
{
  "resource": "/",
  "path": "/",
  "httpMethod": "GET",
  "headers": {
    "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7",
    "Accept-Encoding": "gzip, deflate, br, zstd",
    "Accept-Language": "en-US,en;q=0.9",
    "CloudFront-Forwarded-Proto": "https",
    "CloudFront-Is-Desktop-Viewer": "true",
    "CloudFront-Is-Mobile-Viewer": "false",
    "CloudFront-Is-SmartTV-Viewer": "false",
    "CloudFront-Is-Tablet-Viewer": "false",
    "CloudFront-Viewer-ASN": "16509",
    "CloudFront-Viewer-Country": "US",
    "Host": "abcd1234.execute-api.us-east-1.amazonaws.com",
     ...
```

## 6단계: 리소스 정리
<a name="lambda-cdk-step-6"></a>

API Gateway 엔드포인트는 공개적으로 액세스할 수 있습니다. 예상치 못한 요금이 부과되지 않도록 하려면 [cdk destroy](https://docs.aws.amazon.com/cdk/v2/guide/ref-cli-cmd-destroy.html) 명령을 실행하여 스택과 모든 관련 리소스를 삭제하세요.

```
cdk destroy
```

## 다음 단계
<a name="lambda-cdk-next-steps"></a>

선택한 언어로 AWS CDK 앱을 작성하는 방법에 대한 내용은 다음을 참조하세요.

------
#### [ TypeScript ]

[TypeScript에서 AWS CDK 작업](https://docs.aws.amazon.com/cdk/v2/guide/work-with-cdk-typescript.html)

------
#### [ JavaScript ]

[JavaScript에서 AWS CDK 작업](https://docs.aws.amazon.com/cdk/v2/guide/work-with-cdk-javascript.html)

------
#### [ Python ]

[Python에서 AWS CDK 작업](https://docs.aws.amazon.com/cdk/v2/guide/work-with-cdk-python.html)

------
#### [ Java ]

[Java에서 AWS CDK 작업](https://docs.aws.amazon.com/cdk/v2/guide/work-with-cdk-java.html)

------
#### [ C\$1 ]

[C\$1에서 AWS CDK 작업](https://docs.aws.amazon.com/cdk/v2/guide/work-with-cdk-csharp.html)

------
#### [ Go ]

[Go에서 AWS CDK 작업](https://docs.aws.amazon.com/cdk/v2/guide/work-with-cdk-go.html)

------