

本文属于机器翻译版本。若本译文内容与英语原文存在差异，则一律以英文原文为准。

# 教程：部署具有验证测试的 Amazon ECS 服务
<a name="tutorial-ecs-deployment-with-hooks"></a>

 在本教程中，您将学习如何使用 Lambda 函数验证已更新的 Amazon ECS 应用程序的部分部署。本教程使用您在中使用的 CodeDeploy 应用程序、 CodeDeploy 部署组和 Amazon ECS 应用程序[教程：将应用程序部署到 Amazon ECS](tutorial-ecs-deployment.md)。请先完成上述教程，然后再开始本教程。

 要添加验证测试，首先应在 Lambda 函数中实施测试。接下来，在部署 AppSpec 文件中，为要测试的生命周期挂钩指定 Lambda 函数。如果验证测试失败，部署将停止，然后回滚，并标记为失败。如果测试成功，部署将继续下一个部署生命周期事件或挂钩。

 在部署带有验证测试的 Amazon ECS 期间， CodeDeploy 使用配置有两个目标组的负载均衡器：一个生产流量侦听器和一个测试流量侦听器。下图显示了部署开始之前，负载均衡器、生产和测试侦听器、目标组以及 Amazon ECS 应用程序之间的关联方式。本教程使用应用程序负载均衡器。您也可以使用网络负载均衡器。

![\[应用程序负载均衡器或网络负载均衡器、侦听器、目标组、任务集和 Amazon ECS 服务之间的连接。\]](http://docs.aws.amazon.com/zh_cn/codedeploy/latest/userguide/images/codedeploy-ecs-deployment-step-1.png)


 在 Amazon ECS 部署过程中，有五个用于测试的生命周期挂钩。本教程在第三个生命周期部署挂钩（`AfterAllowTestTraffic`）期间实施了一次测试。有关更多信息，请参阅 [用于 Amazon ECS 部署的生命周期事件挂钩的列表](reference-appspec-file-structure-hooks.md#reference-appspec-file-structure-hooks-list-ecs)。成功部署之后，生产流量侦听器将流量提供给新的替换任务集，原始任务集终止。下图显示了成功部署后资源之间的关联方式。有关更多信息，请参阅 [在 Amazon ECS 部署过程中发生的事件](deployment-steps-ecs.md#deployment-steps-what-happens)。

![\[部署后应用程序负载均衡器或网络负载均衡器、侦听器、目标组和替换任务集之间的连接。\]](http://docs.aws.amazon.com/zh_cn/codedeploy/latest/userguide/images/codedeploy-ecs-deployment-step-6.png)


**注意**  
完成本教程可能会导致您的 AWS 账户被扣款。这些费用包括 CodeDeploy AWS Lambda、和可能收取的费用 CloudWatch。[有关更多信息，请参阅[AWS CodeDeploy 定价、AWS Lambda 定价](https://aws.amazon.com/codedeploy/pricing/)和 [Amazon CloudWatch 定价](https://aws.amazon.com/cloudwatch/pricing/)。](https://aws.amazon.com/lambda/pricing/)

**Topics**
+ [先决条件](tutorial-ecs-with-hooks-prereqs.md)
+ [步骤 1：创建测试侦听器](tutorial-ecs-with-hooks-create-second-listener.md)
+ [步骤 2：更新 Amazon ECS 应用程序](tutorial-ecs-with-hooks-update-the-ecs-application.md)
+ [步骤 3：创建生命周期挂钩 Lambda 函数](tutorial-ecs-with-hooks-create-hooks.md)
+ [第 4 步：更新您的 AppSpec 文件](tutorial-ecs-with-hooks-create-appspec-file.md)
+ [步骤 5：使用 CodeDeploy 控制台部署您的 Amazon ECS 服务](tutorial-ecs-with-hooks-deployment.md)
+ [步骤 6：在日志中查看您的 Lambda 挂钩函数输出 CloudWatch](tutorial-ecs-with-hooks-view-cw-logs.md)
+ [步骤 7：清除](tutoria-ecs-with-hooks-clean-up.md)

# 先决条件
<a name="tutorial-ecs-with-hooks-prereqs"></a>

要成功完成本教程，您首先必须：
+  满足[先决条件](tutorial-ecs-prereqs.md)中针对[教程：将应用程序部署到 Amazon ECS](tutorial-ecs-deployment.md) 的先决条件。
+  完成 [教程：将应用程序部署到 Amazon ECS](tutorial-ecs-deployment.md) 中的步骤。记录以下内容：
  +  负载均衡器的名称。
  +  目标组的名称。
  +  负载均衡器侦听器所用的端口。
  +  负载均衡器的 ARN。您可以使用此项创建新的侦听器。
  +  其中一个目标组的 ARN。您可以使用此项创建新的侦听器。
  +  您创建的 CodeDeploy 应用程序和部署组。
  +  您创建的、供 CodeDeploy 部署使用的 AppSpec 文件。您可以在本教程中编辑此文件。

# 步骤 1：创建测试侦听器
<a name="tutorial-ecs-with-hooks-create-second-listener"></a>

 具有验证测试的 Amazon ECS 部署需要第二个侦听器。此侦听器用于为替换任务集中更新的 Amazon ECS 应用程序提供测试流量。验证测试针对测试流量运行。

 测试流量侦听器可以使用任一目标组。使用 [create-listener](https://docs.aws.amazon.com/cli/latest/reference/elbv2/create-listener.html) AWS CLI 命令创建第二个监听器，其默认规则将测试流量转发到端口 8080。使用负载均衡器的 ARN 和其中一个目标组的 ARN。

```
aws elbv2 create-listener --load-balancer-arn your-load-balancer-arn \
--protocol HTTP --port 8080 \
--default-actions Type=forward,TargetGroupArn=your-target-group-arn --region your-aws-region
```

# 步骤 2：更新 Amazon ECS 应用程序
<a name="tutorial-ecs-with-hooks-update-the-ecs-application"></a>

 在本部分中，您将更新 Amazon ECS 应用程序以使用其任务定义的新修订。您可以创建新的修订，并通过添加标签向其添加次要更新。

**更新任务定义**

1. 打开 Amazon ECS 经典控制台，网址为[https://console.aws.amazon.com/ecs/](https://console.aws.amazon.com/ecs/)。

1.  在导航窗格中，选择 **Task Definitions**。

1.  选中 Amazon ECS 服务所使用的任务定义对应的复选框。

1.  选择 **Create new revision（创建新修订）**。

1.  通过添加标签对任务定义进行细微更新。在页面底部的 **Tags（标签）**中，输入新的键值对以创建新的标签。

1.  选择**创建**。您应当看到任务定义的修订号增加了 1。

1.  选择 **JSON** 选项卡。记下 `taskDefinitionArn` 的值。其格式为 `arn:aws:ecs:aws-region: account-id:task-definition/task-definition-family: task-definition-revision`。这是已更新的任务定义的 ARN。

# 步骤 3：创建生命周期挂钩 Lambda 函数
<a name="tutorial-ecs-with-hooks-create-hooks"></a>

在本部分中，您将为 Amazon ECS 部署的 `AfterAllowTestTraffic` 挂钩实施一个 Lambda 函数。在安装更新的 Amazon ECS 应用程序之前，Lambda 函数将运行验证测试。对于本教程，Lambda 函数返回 `Succeeded`。在实际部署过程中，验证测试可能返回 `Succeeded` 或 `Failed`，具体取决于验证测试的结果。此外，您可能会对其他 Amazon ECS 部署生命周期事件挂钩（`BeforeInstall`、`AfterInstall`、`BeforeAllowTraffic` 和 `AfterAllowTraffic`）中的一个或多个实施 Lambda 测试函数。有关更多信息，请参阅 [用于 Amazon ECS 部署的生命周期事件挂钩的列表](reference-appspec-file-structure-hooks.md#reference-appspec-file-structure-hooks-list-ecs)。

 必须具有 IAM 角色才能创建 Lambda 函数。该角色向 Lambda 函数授予写入 CloudWatch 日志和设置 CodeDeploy 生命周期挂钩状态的权限。

**创建 IAM 角色**

1. 使用 [https://console.aws.amazon.com/iam/](https://console.aws.amazon.com/iam/) 打开 IAM 控制台。

1. 从导航窗格中选择**角色**，然后选择**创建角色**。

1.  创建具有以下属性的角色：
   +  **Trusted entity（可信任的实体）**：**AWS Lambda**。
   +  **权限**：**AWSLambdaBasicExecutionRole**。这会授予您的 Lambda 函数写入日志的权限。 CloudWatch 
   +  **Role name（角色名称）**：**`lambda-cli-hook-role`**。

   有关更多信息，请参阅[创建 AWS Lambda 执行角色](https://docs.aws.amazon.com/lambda/latest/dg/with-userapp.html#with-userapp-walkthrough-custom-events-create-iam-role)。

1.  将权限 `codedeploy:PutLifecycleEventHookExecutionStatus` 附加到您创建的角色。这会授予您的 Lambda 函数在部署期间设置 CodeDeploy 生命周期挂钩状态的权限。有关更多信息，请参阅*AWS Identity and Access Management 用户指南*和 [PutLifecycleEventHookExecutionStatusCodeDeploy ](https://docs.aws.amazon.com/codedeploy/latest/APIReference/API_PutLifecycleEventHookExecutionStatus.html)*API 参考*中的[添加 IAM 身份权限](https://docs.aws.amazon.com/IAM/latest/UserGuide/access_policies_manage-attach-detach.html#add-policies-console)。

**创建 `AfterAllowTestTraffic` 挂钩 Lambda 函数**

1.  使用以下内容创建名为 `AfterAllowTestTraffic.js` 的文件。

   ```
   'use strict';
    
    const AWS = require('aws-sdk');
    const codedeploy = new AWS.CodeDeploy({apiVersion: '2014-10-06'});
    
    exports.handler = (event, context, callback) => {
    
    	console.log("Entering AfterAllowTestTraffic hook.");
    	
    	// Read the DeploymentId and LifecycleEventHookExecutionId from the event payload
     var deploymentId = event.DeploymentId;
    	var lifecycleEventHookExecutionId = event.LifecycleEventHookExecutionId;
    	var validationTestResult = "Failed";
    	
    	// Perform AfterAllowTestTraffic validation tests here. Set the test result 
    	// to "Succeeded" for this tutorial.
    	console.log("This is where AfterAllowTestTraffic validation tests happen.")
    	validationTestResult = "Succeeded";
    	
    	// Complete the AfterAllowTestTraffic hook by sending CodeDeploy the validation status
    	var params = {
    		deploymentId: deploymentId,
    		lifecycleEventHookExecutionId: lifecycleEventHookExecutionId,
    		status: validationTestResult // status can be 'Succeeded' or 'Failed'
    	};
    	
    	// Pass CodeDeploy the prepared validation test results.
    	codedeploy.putLifecycleEventHookExecutionStatus(params, function(err, data) {
    		if (err) {
    			// Validation failed.
    			console.log('AfterAllowTestTraffic validation tests failed');
    			console.log(err, err.stack);
    			callback("CodeDeploy Status update failed");
    		} else {
    			// Validation succeeded.
    			console.log("AfterAllowTestTraffic validation tests succeeded");
    			callback(null, "AfterAllowTestTraffic validation tests succeeded");
    		}
    	});
    }
   ```

1.  创建 Lambda 部署包。

   ```
   zip AfterAllowTestTraffic.zip AfterAllowTestTraffic.js 
   ```

1.  使用 `create-function` 命令为 `AfterAllowTestTraffic` 挂钩创建 Lambda 函数。

   ```
   aws lambda create-function --function-name AfterAllowTestTraffic \
          --zip-file fileb://AfterAllowTestTraffic.zip \
          --handler AfterAllowTestTraffic.handler \
          --runtime nodejs10.x \
          --role arn:aws:iam::aws-account-id:role/lambda-cli-hook-role
   ```

1.  记下 `create-function` 响应中的 Lambda 函数 ARN。在下一步中更新 CodeDeploy 部署 AppSpec 文件时，您将使用此 ARN。

# 第 4 步：更新您的 AppSpec 文件
<a name="tutorial-ecs-with-hooks-create-appspec-file"></a>

 在本节中，您将使用一个`Hooks`部分来更新您的 AppSpec 文件。在 `Hooks` 部分中，您将为 `AfterAllowTestTraffic` 生命周期挂钩指定 Lambda 函数。

**更新您的 AppSpec 文件**

1.  打开您在中[步骤 2：创建 AppSpec 文件](tutorial-ecs-create-appspec-file.md)创建 AppSpec 的文件文件[教程：将应用程序部署到 Amazon ECS](tutorial-ecs-deployment.md)。

1.  采用您在 [步骤 2：更新 Amazon ECS 应用程序](tutorial-ecs-with-hooks-update-the-ecs-application.md) 中记下的任务定义 ARN 更新 `TaskDefinition` 属性。

1. 将该`Hooks`部分复制并粘贴到您的 AppSpec 文件文件中。采用您在[步骤 3：创建生命周期挂钩 Lambda 函数](tutorial-ecs-with-hooks-create-hooks.md)中记下的 Lambda 函数的 ARN，在 `AfterAllowTestTraffic` 之后更新 ARN。

------
#### [ JSON AppSpec ]

   ```
   {
     "version": 0.0,
     "Resources": [
       {
         "TargetService": {
           "Type": "AWS::ECS::Service",
           "Properties": {
             "TaskDefinition": "arn:aws:ecs:aws-region-id:aws-account-id::task-definition/ecs-demo-task-definition:revision-number",
             "LoadBalancerInfo": {
               "ContainerName": "sample-website",
               "ContainerPort": 80
             }
           }
         }
       }
     ],
     "Hooks": [
       {
         "AfterAllowTestTraffic": "arn:aws:lambda:aws-region-id:aws-account-id:function:AfterAllowTestTraffic"
       }
     ]
   }
   ```

------
#### [ YAML AppSpec ]

   ```
   version: 0.0
   Resources:
     - TargetService:
         Type: AWS::ECS::Service
         Properties:
           TaskDefinition: "arn:aws:ecs:aws-region-id:aws-account-id::task-definition/ecs-demo-task-definition:revision-number"
           LoadBalancerInfo:
             ContainerName: "sample-website"
             ContainerPort: 80
   Hooks:
     - AfterAllowTestTraffic: "arn:aws:lambda:aws-region-id:aws-account-id:function:AfterAllowTestTraffic"
   ```

------

1.  保存您的 AppSpec 文件并上传到其 S3 存储桶。

# 步骤 5：使用 CodeDeploy 控制台部署您的 Amazon ECS 服务
<a name="tutorial-ecs-with-hooks-deployment"></a>

 在本部分中，您将通过为测试侦听器指定端口更新部署组。这是您在 [步骤 1：创建测试侦听器](tutorial-ecs-with-hooks-create-second-listener.md) 中创建的侦听器。在部署过程中， CodeDeploy 在 `AfterAllowTestTraffic` 部署生命周期挂钩期间，使用通过测试侦听器提供给替换任务集的测试流量运行验证测试。您的验证测试返回 `Succeeded` 结果，因此，部署将继续下一个部署生命周期事件。在实际场景中，测试函数可能返回 `Succeeded` 或 `Failed`。

**向部署组添加测试侦听器**

1. 登录 AWS 管理控制台 并打开 CodeDeploy 控制台，网址为[https://console.aws.amazon.com/codedeploy/](https://console.aws.amazon.com/codedeploy/)。

1. 从导航窗格中，选择 **Applications（应用程序）**。

1. 选择您在 [教程：将应用程序部署到 Amazon ECS](tutorial-ecs-deployment.md) 中创建的应用程序。如果您使用建议的名称，则该名称是 **ecs-demo-codedeploy-app**。

1. 在 **Deployment group（部署组）**中，选择您在 [教程：将应用程序部署到 Amazon ECS](tutorial-ecs-deployment.md) 中创建的部署组。如果您使用建议的名称，则该名称是 **ecs-demo-dg**。

1.  选择**编辑**。

1. 从 **Test listener port（测试侦听器端口）**中，为您之前在本教程中创建的测试侦听器选择端口和协议。应当为 **HTTP: 8080**。

1.  选择**保存更改**。

**部署您的 Amazon ECS 应用程序**

1. 从部署组控制台页面中，选择 **Create deployment（创建部署）**。

1.  对于**部署组**，选择**ecs-demo-dg**。

1.  对于 **Revision type（修订类型）**，选择 **My application is stored in Amazon S3（我的应用程序存储在 Amazon S3 中）**。在**修订位置**中，输入您的 S3 存储桶和 AppSpec 文件的名称（例如，**s3://my-s3-bucket/appspec.json**）。

1.  对于 **Revision file type（修订文件类型）**，根据情况选择 **.json** 或 **.yaml**。

1.  （可选）在 **Deployment description（部署描述）**框中，为部署输入描述。

1. 选择 **Create deployment（创建部署）**。

 您可以在 **Deployment status（部署状态）**中监控部署。在生产流量已全部路由至替换任务集之后，您可以选择**终止原始任务集**，以立即终止原始任务集。如果未选择 **Terminate original task set（终止原始任务集）**，则原始任务集将在您创建部署组时指定的持续时间之后终止。

![\[CodeDeploy 控制台的部署状态部分。\]](http://docs.aws.amazon.com/zh_cn/codedeploy/latest/userguide/images/ecs-tutorial-deployment-status-with-test-listener.png)


# 步骤 6：在日志中查看您的 Lambda 挂钩函数输出 CloudWatch
<a name="tutorial-ecs-with-hooks-view-cw-logs"></a>

 如果您的 CodeDeploy 部署成功，那么您的 Lambda 挂钩函数中的验证测试也会成功。您可以通过在 Log CloudWatch s 中查看挂钩函数的日志来确认这一点。

1. 打开 CloudWatch 控制台，网址为[https://console.aws.amazon.com/cloudwatch/](https://console.aws.amazon.com/cloudwatch/)。

1.  从导航窗格中，选择 **Logs（日志）**。您应该看到一个与您在文件中指定的 Lambda 挂钩函数对应的新日志组。 AppSpec   
![\[CloudWatch 控制台中的新日志组。\]](http://docs.aws.amazon.com/zh_cn/codedeploy/latest/userguide/images/ecs-demo-cw-logs.png)

1.  选择新的日志组。这应该是**/aws/lambda/AfterAllowTestTrafficHook**。

1.  选择日志流。如果您看到多个日志流，请在 **Last Event Time（上次事件时间）**下选择日期和时间最近的一个日志流。

1.  展开日志流事件，确认 Lambda 挂钩函数已成功将消息写入日志。下面显示了 `AfterAllowTraffic` Lambda 挂钩函数成功。  
![\[显示 AfterAllowTraffic 钩子的日志流事件。\]](http://docs.aws.amazon.com/zh_cn/codedeploy/latest/userguide/images/ecs-demo-cw-log-events.png)

# 步骤 7：清除
<a name="tutoria-ecs-with-hooks-clean-up"></a>

 完成本教程后，请清除与本教程关联的资源，以避免对您未使用的资源产生费用。此步骤中的资源名称是本教程中建议的名称（**ecs-demo-codedeploy-app**例如， CodeDeploy 应用程序的名称）。如果您使用的是不同的名称，请确保在清除过程中使用这些名称。

**清除教程资源**

1. 使用[delete-deployment-group](https://docs.aws.amazon.com/cli/latest/reference/deploy/delete-deployment-group.html)命令删除 CodeDeploy 部署组。

   ```
   aws deploy delete-deployment-group --application-name ecs-demo-deployment-group --deployment-group-name ecs-demo-dg --region aws-region-id
   ```

1. 使用 [delete-application 命令删除应用程序](https://docs.aws.amazon.com/cli/latest/reference/deploy/delete-application.html)。 CodeDeploy 

   ```
   aws deploy delete-application --application-name ecs-demo-deployment-group --region aws-region-id
   ```

1. 使用 [delete-function](https://docs.aws.amazon.com/cli/latest/reference/lambda/delete-function.html) 命令删除 Lambda 挂钩函数。

   ```
   aws lambda delete-function --function-name AfterAllowTestTraffic
   ```

1. 使用[delete-log-group](https://docs.aws.amazon.com/cli/latest/reference/logs/delete-log-group.html)命令删除您的 CloudWatch 日志组。

   ```
   aws logs delete-log-group --log-group-name /aws/lambda/AfterAllowTestTraffic
   ```