

# AWS CDK を使用した Lambda 関数のデプロイ
<a name="lambda-cdk-tutorial"></a>

AWS Cloud Development Kit (AWS CDK) は、選択したプログラミング言語を使用して、AWS クラウドインフラストラクチャの定義に使用できる、Infrastructure as Code (IaC) フレームワークです。独自のクラウドインフラストラクチャを定義するには、最初に、(CDK でサポートされている言語のいずれかで) 1 つ以上のスタックが含まれるアプリケーションを記述します。次に、それを CloudFormation テンプレートに合成して、AWS アカウント にリソースをデプロイします。このトピックの手順に従って、Amazon API Gateway エンドポイントからイベントを返す Lambda 関数をデプロイします。

CDK に含まれる AWS 構成ライブラリは、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 リソースを定義する 1 つ以上のコンストラクトのコレクションです。各 CDK スタックは、CDK アプリ内の CloudFormation スタックを表します。

CDK スタックを定義するには、希望するプログラミング言語の手順に従います。このスタックでは、以下を定義します。
+ 関数の論理名: `MyFunction`
+ `code` プロパティで指定された関数コードの場所。詳細については、「*AWS Cloud Development Kit (AWS CDK) API リファレンス*」の「[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. `/lib/lambda-handler` ディレクトリに、`index.js` という名前の新しいファイルを作成します。ファイルに次のコードを貼り付けます。関数は 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 デプロイ](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)

------