

本文為英文版的機器翻譯版本，如內容有任何歧義或不一致之處，概以英文版為準。

# 穿越-第 1 部分
<a name="walkthrough-part-1"></a>

**注意**  
AWS CDK 版本和 1.46.0 支援 AWS 解決方案建構。

 本教學將逐步引導您如何建立和部署使用 AWS 解決方案建構模式的簡單「Hello Protets」AWS CDK 應用程式，從初始化專案到部署產生的 AWS CloudFormation 範本。Hello 構造應用程序將創建以下簡單的解決方案：

![架構圖](http://docs.aws.amazon.com/zh_tw/solutions/latest/constructs/images/tutorial-part1.png)


## Hello 建構
<a name="hello-konstruk"></a>

 讓我們開始使用以模式為基礎的開發來建置我們的第一個 AWS CDK 應用程式。

**注意**  
 這是一個範例修改`Hello CDK!`來自[CDK 工作坊](https://cdkworkshop.com/)。如果這是您第一次使用 AWS CDK，我們建議您從本研討會開始實際操作逐步解說，以及如何利用 CDK 建置真實世界的專案。

## 建立應用程式目錄並初始化 AWS CDK
<a name="creating-the-app-directory-and-initializing-the-aws-cdk"></a>

 為您的 CDK 應用程式建立目錄，然後在該目錄中建立 AWS CDK 應用程式。

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

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

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

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

------

**提示**  
現在是在您最喜愛的 IDE 中開啟專案並探索的好時機。若要進一步了解專案結構，請選取適當的連結：  
[TypeScript](https://cdkworkshop.com/20-typescript/20-create-project/300-structure.html)
[Python](https://cdkworkshop.com/30-python/20-create-project/300-structure.html)

## 更新專案基礎相依性
<a name="update-project-base-dependencies-to-use-aws-cdk"></a>

**警告**  
為了確保功能正確，AWS 解決方案建構和 AWS CDK 套件必須在專案中使用相同的版本號碼。例如，如果您使用的是 AWS 解決方案建構 1.52.0 版，則也必須使用 AWS CDK 版 1.52.0 版。

**提示**  
 請注意 AWS 解決方案建構的最新版本，並將該版本號碼套用至`VERSION_NUMBER`預留位置 (適用於 AWS 解決方案建構和 AWS CDK 套件)。要檢查構造函數庫的所有公開版本，[Click here](https://github.com/awslabs/aws-solutions-constructs/releases)。

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

編輯`package.json`檔案，並包含下列資訊：

```
  "devDependencies": {
    "@aws-cdk/assert": "VERSION_NUMBER",
    "@types/jest": "^24.0.22",
    "@types/node": "10.17.5",
    "jest": "^24.9.0",
    "ts-jest": "^24.1.0",
    "aws-cdk": "VERSION_NUMBER",
    "ts-node": "^8.1.0",
    "typescript": "~3.7.2"
  },
  "dependencies": {
    "@aws-cdk/core": "VERSION_NUMBER",
    "source-map-support": "^0.5.16"
  }
```

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

編輯`setup.py`檔案，並包含下列資訊：

```
install_requires=[
    "aws-cdk.core==VERSION_NUMBER",
],
```

------

 安裝項目基礎依賴關係。

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

```
npm install      
```

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

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

------

 建置並執行應用程式，並確認它會建立空的堆疊。

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

```
 npm run build 
 cdk synth
```

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

```
 cdk synth           
```

------

 你應該看到一個像下面這樣的堆棧，其中`CDK-VERSION`是 CDK 的版本。(您的輸出可能與此處顯示的內容略有不同。) 

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

```
Resources:
  CDKMetadata:
    Type: AWS::CDK::Metadata
    Properties:
          Modules: aws-cdk=CDK-VERSION,@aws-cdk/core=VERSION_NUMBER,@aws-cdk/cx-api=VERSION_NUMBER,jsii-runtime=node.js/10.17.0
```

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

```
Resources:
  CDKMetadata:
    Type: AWS::CDK::Metadata
    Properties:
          Modules: aws-cdk=CDK-VERSION,@aws-cdk/core=VERSION_NUMBER,@aws-cdk/cx-api=VERSION_NUMBER,jsii-runtime=Python/3.7.7
```

------

## Lambda 處理常式代碼
<a name="lambda-handler-code"></a>

 我們將從 AWS Lambda 處理常式程式碼開始。

 建立目錄`lambda`在您的專案樹的根目錄中。

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

新增稱為的檔案`lambda/hello.js`，並包含：

```
exports.handler = async function(event) {
  console.log("request:", JSON.stringify(event, null, 2));
  return {
    statusCode: 200,
    headers: { "Content-Type": "text/plain" },
    body: `Hello, AWS Solutions Constructs! You've hit ${event.path}\n`
  };
};
```

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

新增稱為的檔案`lambda/hello.py`，並包含：

```
import json

def handler(event, context):
    print('request: {}'.format(json.dumps(event)))
    return {
        'statusCode': 200,
        'headers': {
            'Content-Type': 'text/plain'
        },
        'body': 'Hello, CDK! You have hit {}\n'.format(event['path'])
    }
```

------

 這是一個簡單的 Lambda 函數，它返回文本「你好，構造！你已經點擊 [網址路徑]」。該函數的輸出還包括 HTTP 狀態碼和 HTTP 標頭。這些通過 API Gateway 用於制定 HTTP 響應給用戶。

 這個 Lambda 寓式酒店在 JavaScript 中提供。如需使用您選擇的語言編寫 Lambda 函數的詳細資訊，請參閱[AWS Lambda 文件](https://docs.aws.amazon.com/lambda/latest/dg/welcome.html)。

## 安裝 AWS CDK 和 AWS 解決方案建構相依性
<a name="install-the-aws-cdk-and-aws-solutions-constructs-library-dependencies"></a>

 AWS 解決方案建構隨附廣泛的建構程式庫。該庫被分為模塊，每個架構良好的模式一個。例如，如果您想要將 Amazon API Gateway 休息 API 定義給 AWS Lambda 函數，我們需要使用`aws-apigateway-lambda`模式資源庫。

 我們還需要從 AWS CDK 新增 AWS Lambda 和 Amazon API Gateway 建構程式庫。

 將 AWS Lambda 模組及其所有相依性安裝到我們的專案中：

**注意**  
請記得將用於 AWS 解決方案構造和 AWS CDK 的正確相符版本替換為`VERSION_NUMBER`預留位置欄位。套件之間的版本不相符可能會導致錯誤。

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

```
 npm install -s @aws-cdk/aws-lambda@VERSION_NUMBER       
```

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

```
 pip install aws_cdk.aws_lambda==VERSION_NUMBER 
```

------

 接下來，將 Amazon API Gateway 模組及其所有依賴項安裝到我們的專案中：

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

```
 npm install -s @aws-cdk/aws-apigateway@VERSION_NUMBER         
```

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

```
 pip install aws_cdk.aws_apigateway==VERSION_NUMBER          
```

------

 最後，安裝 AWS 解決方案建構`aws-apigateway-lambda`模塊及其所有依賴關係到我們的項目中：

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

```
 npm install -s @aws-solutions-constructs/aws-apigateway-lambda@VERSION_NUMBER        
```

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

```
 pip install aws_solutions_constructs.aws_apigateway_lambda==VERSION_NUMBER          
```

------

## 將亞馬遜 API 网關 /AWS Lambda 模式添加到您的堆棧
<a name="add-an-aws-api-gatewayaws-lambda-pattern-to-your-stack"></a>

 現在，讓我們定義 AWS 解決方案建構模式，用於使用 AWS Lambda 代理實作 Amazon API Gateway。

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

編輯檔案`lib/hello-constructs.ts`，並包含：

```
import * as cdk from '@aws-cdk/core';
import * as lambda from '@aws-cdk/aws-lambda';
import * as api from '@aws-cdk/aws-apigateway';
import { ApiGatewayToLambda, ApiGatewayToLambdaProps } from '@aws-solutions-constructs/aws-apigateway-lambda';

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

    // The code that defines your stack goes here
    const api_lambda_props: ApiGatewayToLambdaProps = {
      lambdaFunctionProps: {
        code: lambda.Code.fromAsset('lambda'),
        runtime: lambda.Runtime.NODEJS_12_X,
        handler: 'hello.handler'
      },
      apiGatewayProps: {
        defaultMethodOptions: {
          authorizationType: api.AuthorizationType.NONE
        }
      }
    };

    new ApiGatewayToLambda(this, 'ApiGatewayToLambda', api_lambda_props);
  }
}
```

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

編輯檔案`hello_constructs/hello_constructs_stack.py`，並包含：

```
from aws_cdk import (
    aws_lambda as _lambda,
    aws_apigateway as apigw,
    core,
)

from aws_solutions_constructs import (
    aws_apigateway_lambda as apigw_lambda
)

class HelloConstructsStack(core.Stack):

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

        # The code that defines your stack goes here

        apigw_lambda.ApiGatewayToLambda(
            self, 'ApiGatewayToLambda',
            lambda_function_props=_lambda.FunctionProps(
                runtime=_lambda.Runtime.PYTHON_3_7,
                code=_lambda.Code.asset('lambda'),
                handler='hello.handler',
            ),
            api_gateway_props=apigw.RestApiProps(
                default_method_options=apigw.MethodOptions(
                    authorization_type=apigw.AuthorizationType.NONE
                )
            )
        )
```

------

 就是這樣 為了定義將所有請求代理到 AWS Lambda 函數的 API Gateway，您需要執行這項操作。讓我們將我們的新堆棧與原始堆棧進行比較：

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

```
npm run build    
cdk diff
```

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

```
cdk diff       
```

------

 輸出應如下所示：

```
Stack HelloConstructsStack
IAM Statement Changes
┌───┬─────────────────────────────┬────────┬─────────────────────────────┬─────────────────────────────┬──────────────────────────────┐
│   │ Resource                    │ Effect │ Action                      │ Principal                   │ Condition                    │
├───┼─────────────────────────────┼────────┼─────────────────────────────┼─────────────────────────────┼──────────────────────────────┤
│ + │ ${LambdaFunction.Arn}       │ Allow  │ lambda:InvokeFunction       │ Service:apigateway.amazonaw │ "ArnLike": {                 │
│   │                             │        │                             │ s.com                       │   "AWS:SourceArn": "arn:${AW │
│   │                             │        │                             │                             │ S::Partition}:execute-api:${ │
│   │                             │        │                             │                             │ AWS::Region}:${AWS::AccountI │
│   │                             │        │                             │                             │ d}:${RestApi0C43BF4B}/${Rest │
│   │                             │        │                             │                             │ Api/DeploymentStage.prod}/*/ │
│   │                             │        │                             │                             │ {proxy+}"                    │
│   │                             │        │                             │                             │ }                            │
│ + │ ${LambdaFunction.Arn}       │ Allow  │ lambda:InvokeFunction       │ Service:apigateway.amazonaw │ "ArnLike": {                 │
│   │                             │        │                             │ s.com                       │   "AWS:SourceArn": "arn:${AW │
│   │                             │        │                             │                             │ S::Partition}:execute-api:${ │
│   │                             │        │                             │                             │ AWS::Region}:${AWS::AccountI │
│   │                             │        │                             │                             │ d}:${RestApi0C43BF4B}/test-i │
│   │                             │        │                             │                             │ nvoke-stage/*/{proxy+}"      │
│   │                             │        │                             │                             │ }                            │
│ + │ ${LambdaFunction.Arn}       │ Allow  │ lambda:InvokeFunction       │ Service:apigateway.amazonaw │ "ArnLike": {                 │
│   │                             │        │                             │ s.com                       │   "AWS:SourceArn": "arn:${AW │
│   │                             │        │                             │                             │ S::Partition}:execute-api:${ │
│   │                             │        │                             │                             │ AWS::Region}:${AWS::AccountI │
│   │                             │        │                             │                             │ d}:${RestApi0C43BF4B}/${Rest │
│   │                             │        │                             │                             │ Api/DeploymentStage.prod}/*/ │
│   │                             │        │                             │                             │ "                            │
│   │                             │        │                             │                             │ }                            │
│ + │ ${LambdaFunction.Arn}       │ Allow  │ lambda:InvokeFunction       │ Service:apigateway.amazonaw │ "ArnLike": {                 │
│   │                             │        │                             │ s.com                       │   "AWS:SourceArn": "arn:${AW │
│   │                             │        │                             │                             │ S::Partition}:execute-api:${ │
│   │                             │        │                             │                             │ AWS::Region}:${AWS::AccountI │
│   │                             │        │                             │                             │ d}:${RestApi0C43BF4B}/test-i │
│   │                             │        │                             │                             │ nvoke-stage/*/"              │
│   │                             │        │                             │                             │ }                            │
├───┼─────────────────────────────┼────────┼─────────────────────────────┼─────────────────────────────┼──────────────────────────────┤
│ + │ ${LambdaFunctionServiceRole │ Allow  │ sts:AssumeRole              │ Service:lambda.amazonaws.co │                              │
│   │ .Arn}                       │        │                             │ m                           │                              │
├───┼─────────────────────────────┼────────┼─────────────────────────────┼─────────────────────────────┼──────────────────────────────┤
│ + │ ${LambdaRestApiCloudWatchRo │ Allow  │ sts:AssumeRole              │ Service:apigateway.amazonaw │                              │
│   │ le.Arn}                     │        │                             │ s.com                       │                              │
├───┼─────────────────────────────┼────────┼─────────────────────────────┼─────────────────────────────┼──────────────────────────────┤
│ + │ arn:aws:logs:${AWS::Region} │ Allow  │ logs:CreateLogGroup         │ AWS:${LambdaRestApiCloudWat │                              │
│   │ :${AWS::AccountId}:*        │        │ logs:CreateLogStream        │ chRole}                     │                              │
│   │                             │        │ logs:DescribeLogGroups      │                             │                              │
│   │                             │        │ logs:DescribeLogStreams     │                             │                              │
│   │                             │        │ logs:FilterLogEvents        │                             │                              │
│   │                             │        │ logs:GetLogEvents           │                             │                              │
│   │                             │        │ logs:PutLogEvents           │                             │                              │
├───┼─────────────────────────────┼────────┼─────────────────────────────┼─────────────────────────────┼──────────────────────────────┤
│ + │ arn:aws:logs:${AWS::Region} │ Allow  │ logs:CreateLogGroup         │ AWS:${LambdaFunctionService │                              │
│   │ :${AWS::AccountId}:log-grou │        │ logs:CreateLogStream        │ Role}                       │                              │
│   │ p:/aws/lambda/*             │        │ logs:PutLogEvents           │                             │                              │
└───┴─────────────────────────────┴────────┴─────────────────────────────┴─────────────────────────────┴──────────────────────────────┘
(NOTE: There may be security-related changes not in this list. See https://github.com/aws/aws-cdk/issues/1299)

Parameters
[+] Parameter AssetParameters/ba91444ebd644d9419e8cfee417f3aaa728507dd428788a2fc40574646c4340a/S3Bucket AssetParametersba91444ebd644d9419e8cfee417f3aaa728507dd428788a2fc40574646c4340aS3Bucket9780A3BC: {"Type":"String","Description":"S3 bucket for asset \"ba91444ebd644d9419e8cfee417f3aaa728507dd428788a2fc40574646c4340a\""}
[+] Parameter AssetParameters/ba91444ebd644d9419e8cfee417f3aaa728507dd428788a2fc40574646c4340a/S3VersionKey AssetParametersba91444ebd644d9419e8cfee417f3aaa728507dd428788a2fc40574646c4340aS3VersionKey37F36FFB: {"Type":"String","Description":"S3 key for asset version \"ba91444ebd644d9419e8cfee417f3aaa728507dd428788a2fc40574646c4340a\""}
[+] Parameter AssetParameters/ba91444ebd644d9419e8cfee417f3aaa728507dd428788a2fc40574646c4340a/ArtifactHash AssetParametersba91444ebd644d9419e8cfee417f3aaa728507dd428788a2fc40574646c4340aArtifactHash80199FBC: {"Type":"String","Description":"Artifact hash for asset \"ba91444ebd644d9419e8cfee417f3aaa728507dd428788a2fc40574646c4340a\""}

Conditions
[+] Condition CDKMetadataAvailable: {"Fn::Or":[{"Fn::Or":[{"Fn::Equals":[{"Ref":"AWS::Region"},"ap-east-1"]},{"Fn::Equals":[{"Ref":"AWS::Region"},"ap-northeast-1"]},{"Fn::Equals":[{"Ref":"AWS::Region"},"ap-northeast-2"]},{"Fn::Equals":[{"Ref":"AWS::Region"},"ap-south-1"]},{"Fn::Equals":[{"Ref":"AWS::Region"},"ap-southeast-1"]},{"Fn::Equals":[{"Ref":"AWS::Region"},"ap-southeast-2"]},{"Fn::Equals":[{"Ref":"AWS::Region"},"ca-central-1"]},{"Fn::Equals":[{"Ref":"AWS::Region"},"cn-north-1"]},{"Fn::Equals":[{"Ref":"AWS::Region"},"cn-northwest-1"]},{"Fn::Equals":[{"Ref":"AWS::Region"},"eu-central-1"]}]},{"Fn::Or":[{"Fn::Equals":[{"Ref":"AWS::Region"},"eu-north-1"]},{"Fn::Equals":[{"Ref":"AWS::Region"},"eu-west-1"]},{"Fn::Equals":[{"Ref":"AWS::Region"},"eu-west-2"]},{"Fn::Equals":[{"Ref":"AWS::Region"},"eu-west-3"]},{"Fn::Equals":[{"Ref":"AWS::Region"},"me-south-1"]},{"Fn::Equals":[{"Ref":"AWS::Region"},"sa-east-1"]},{"Fn::Equals":[{"Ref":"AWS::Region"},"us-east-1"]},{"Fn::Equals":[{"Ref":"AWS::Region"},"us-east-2"]},{"Fn::Equals":[{"Ref":"AWS::Region"},"us-west-1"]},{"Fn::Equals":[{"Ref":"AWS::Region"},"us-west-2"]}]}]}

Resources
[+] AWS::Logs::LogGroup ApiGatewayToLambda/ApiAccessLogGroup ApiGatewayToLambdaApiAccessLogGroupE2B41502 
[+] AWS::IAM::Role LambdaFunctionServiceRole LambdaFunctionServiceRole0C4CDE0B 
[+] AWS::Lambda::Function LambdaFunction LambdaFunctionBF21E41F 
[+] AWS::ApiGateway::RestApi RestApi RestApi0C43BF4B 
[+] AWS::ApiGateway::Deployment RestApi/Deployment RestApiDeployment180EC503d2c6df3c8dc8b7193b98c1a0bff4e677 
[+] AWS::ApiGateway::Stage RestApi/DeploymentStage.prod RestApiDeploymentStageprod3855DE66 
[+] AWS::ApiGateway::Resource RestApi/Default/{proxy+} RestApiproxyC95856DD 
[+] AWS::Lambda::Permission RestApi/Default/{proxy+}/ANY/ApiPermission.HelloConstructsStackRestApiFDB18C2E.ANY..{proxy+} RestApiproxyANYApiPermissionHelloConstructsStackRestApiFDB18C2EANYproxyE43D39B3 
[+] AWS::Lambda::Permission RestApi/Default/{proxy+}/ANY/ApiPermission.Test.HelloConstructsStackRestApiFDB18C2E.ANY..{proxy+} RestApiproxyANYApiPermissionTestHelloConstructsStackRestApiFDB18C2EANYproxy0B23CDC7 
[+] AWS::ApiGateway::Method RestApi/Default/{proxy+}/ANY RestApiproxyANY1786B242 
[+] AWS::Lambda::Permission RestApi/Default/ANY/ApiPermission.HelloConstructsStackRestApiFDB18C2E.ANY.. RestApiANYApiPermissionHelloConstructsStackRestApiFDB18C2EANY5684C1E6 
[+] AWS::Lambda::Permission RestApi/Default/ANY/ApiPermission.Test.HelloConstructsStackRestApiFDB18C2E.ANY.. RestApiANYApiPermissionTestHelloConstructsStackRestApiFDB18C2EANY81DBDF56 
[+] AWS::ApiGateway::Method RestApi/Default/ANY RestApiANYA7C1DC94 
[+] AWS::ApiGateway::UsagePlan RestApi/UsagePlan RestApiUsagePlan6E1C537A 
[+] AWS::Logs::LogGroup ApiAccessLogGroup ApiAccessLogGroupCEA70788 
[+] AWS::IAM::Role LambdaRestApiCloudWatchRole LambdaRestApiCloudWatchRoleF339D4E6 
[+] AWS::ApiGateway::Account LambdaRestApiAccount LambdaRestApiAccount 

Outputs
[+] Output RestApi/Endpoint RestApiEndpoint0551178A: {"Value":{"Fn::Join":["",["https://",{"Ref":"RestApi0C43BF4B"},".execute-api.",{"Ref":"AWS::Region"},".",{"Ref":"AWS::URLSuffix"},"/",{"Ref":"RestApiDeploymentStageprod3855DE66"},"/"]]}}
```

 那很好 這個簡單的範例包含 AWS 解決方案建構中的一個架構良好的模式，為您的堆疊增加了 21 個新資源。

## cdk 部署
<a name="cdk-deploy"></a>

**提示**  
在部署包含 Lambda 函數的第一個 AWS CDK 應用程式之前，您必須先啟動 AWS 環境。這會建立一個臨時儲存貯體，AWS CDK 用來部署包含資產的堆疊。如果這是您第一次使用 AWS CDK 部署資產，則需要執行`cdk bootstrap`，將 CDK 工具組堆疊部署到您的 AWS 環境中。

 好，準備好部署嗎？ 

```
cdk deploy
```

## 堆疊輸出
<a name="stack-outputs"></a>

 部署完成後，您會注意到這一行：

```
Outputs:
HelloConstructsStack.RestApiEndpoint0551178A = https://{{xxxxxxxxxx}}.execute-api.us-east-1.amazonaws.com/prod/
```

 這是由 AWS 解決方案建構模式自動新增的堆疊輸出，並包含 API Gateway 端點的 URL。

## 測試您的應用程式
<a name="testing-your-app"></a>

 讓我們嘗試用`curl`。複製 URL 並執行（您的前綴和地區可能不同）。

```
curl https://{{xxxxxxxxxx}}.execute-api.us-east-1.amazonaws.com/prod/
```

 輸出應如下所示：

```
Hello, AWS Solutions Constructs! You've hit /
```

 如果這是你收到的輸出，你的應用程序工作！