

# 使用 AWS CLI 配置 Amazon ECS Service Connect
<a name="create-service-connect"></a>

您可以创建 Fargate 任务的 Amazon ECS 服务，该任务将 Service Connect 和 AWS CLI 结合使用。

**注意**  
您可以使用双堆栈服务端点通过 IPv4 和 IPv6 从 AWS CLI、SDK 和 Amazon ECS API 与 Amazon ECS 进行交互。有关更多信息，请参阅 [使用 Amazon ECS 双堆栈端点](dual-stack-endpoint.md)。

## 先决条件
<a name="create-service-connect-prereqs"></a>

以下是 Service Connect 的先决条件：
+ 验证安装并配置了最新版本的 AWS CLI。有关更多信息，请参阅[安装或更新到最新版本的 AWS CLI](https://docs.aws.amazon.com/cli/latest/userguide/getting-started-install.html)。
+ 您的 IAM 用户具有 [AmazonECS\$1FullAccess](security-iam-awsmanpol.md#security-iam-awsmanpol-AmazonECS_FullAccess) IAM 策略示例中指定的必需权限。
+ 您已创建要使用的 VPC、子网、路由表和安全组。有关更多信息，请参阅 [创建虚拟私有云](get-set-up-for-amazon-ecs.md#create-a-vpc)。
+ 您有一个名为 `ecsTaskExecutionRole` 的任务执行角色，并且 `AmazonECSTaskExecutionRolePolicy` 托管策略已附加到该角色。此角色允许 Fargate 将 NGINX 应用程序日志和 Service Connect 代理日志写入 Amazon CloudWatch Logs。有关更多信息，请参阅 [创建任务执行 角色](task_execution_IAM_role.md#create-task-execution-role)。

## 第 1 步：创建集群
<a name="create-service-connect-cluster"></a>

请按照以下步骤创建 Amazon ECS 集群和命名空间。

**要创建 Amazon ECS 集群和 AWS Cloud Map 命名空间。**

1. 创建要使用的名为 `tutorial` 的 Amazon ECS 集群。参数 `--service-connect-defaults` 设置集群的默认命名空间。在示例输出中，此账户和 AWS 区域 中不存在名称 `service-connect` 的 AWS Cloud Map 命名空间，因此命名空间由 Amazon ECS 创建。命名空间是在账户中的 AWS Cloud Map 中创建的，所有其他命名空间都可见，因此请使用表明目的的名称。

   ```
   aws ecs create-cluster --cluster-name tutorial --service-connect-defaults namespace=service-connect
   ```

   输出：

   ```
   {
       "cluster": {
           "clusterArn": "arn:aws:ecs:us-west-2:123456789012:cluster/tutorial",
           "clusterName": "tutorial",
           "serviceConnectDefaults": {
               "namespace": "arn:aws:servicediscovery:us-west-2:123456789012:namespace/ns-EXAMPLE"
           },
           "status": "PROVISIONING",
           "registeredContainerInstancesCount": 0,
           "runningTasksCount": 0,
           "pendingTasksCount": 0,
           "activeServicesCount": 0,
           "statistics": [],
           "tags": [],
           "settings": [
               {
                   "name": "containerInsights",
                   "value": "disabled"
               }
           ],
           "capacityProviders": [],
           "defaultCapacityProviderStrategy": [],
           "attachments": [
               {
                   "id": "a1b2c3d4-5678-90ab-cdef-EXAMPLE11111",
                   "type": "sc",
                   "status": "ATTACHING",
                   "details": []
               }
           ],
           "attachmentsStatus": "UPDATE_IN_PROGRESS"
       }
   }
   }
   ```

1. 验证集群是否已创建：

   ```
   aws ecs describe-clusters --clusters tutorial
   ```

   输出：

   ```
   {
       "clusters": [
           {
               "clusterArn": "arn:aws:ecs:us-west-2:123456789012:cluster/tutorial",
               "clusterName": "tutorial",
               "serviceConnectDefaults": {
                   "namespace": "arn:aws:servicediscovery:us-west-2:123456789012:namespace/ns-EXAMPLE"
               },
               "status": "ACTIVE",
               "registeredContainerInstancesCount": 0,
               "runningTasksCount": 0,
               "pendingTasksCount": 0,
               "activeServicesCount": 0,
               "statistics": [],
               "tags": [],
               "settings": [],
               "capacityProviders": [],
               "defaultCapacityProviderStrategy": []
           }
       ],
       "failures": []
   }
   ```

1. （可选）验证命名空间是否是在 AWS Cloud Map 中创建的。您可以使用在 AWS Cloud Map 中创建的 AWS 管理控制台 或普通 AWS CLI 配置。

   例如，使用 AWS CLI：

   ```
   aws servicediscovery get-namespace --id ns-EXAMPLE
   ```

   输出：

   ```
   {
       "Namespace": {
           "Id": "ns-EXAMPLE",
           "Arn": "arn:aws:servicediscovery:us-west-2:123456789012:namespace/ns-EXAMPLE",
           "Name": "service-connect",
           "Type": "HTTP",
           "Properties": {
               "DnsProperties": {
                   "SOA": {}
               },
               "HttpProperties": {
                   "HttpName": "service-connect"
               }
           },
           "CreateDate": 1661749852.422,
           "CreatorRequestId": "service-connect"
       }
   }
   ```

## 步骤 2：为服务器创建服务
<a name="create-service-connect-nginx-server"></a>

Service Connect 功能旨在互连 Amazon ECS 上的多个应用程序。这些应用程序中至少有一个需要提供 Web 服务才能连接。在此步骤中，您将创建：
+ 使用未经修改的官方 NGINX 容器映像并包括 Service Connect 配置的任务定义。
+ Amazon ECS 服务定义，用于配置 Service Connect，从而为该服务的流量提供服务发现和服务网格代理。该配置重复使用集群配置中的默认命名空间，以减少您为每项服务所做的服务配置量。
+ Amazon ECS 服务。它使用任务定义运行一项任务，并为 Service Connect 代理插入一个额外的容器。代理侦听任务定义的容器端口映射中的端口。在 Amazon ECS 中运行的客户端应用程序中，客户端任务中的代理侦听与任务定义端口名、服务发现名称或服务客户端别名以及来自客户端别名的端口号的出站连接。

**使用 Service Connect 创建 Web 服务**

1. 注册与 Fargate 兼容的任务定义并使用 `awsvpc` 网络模式。按照以下步骤进行操作：

   1. 使用以下任务定义的内容创建名为 `service-connect-nginx.json` 的文件。

      此任务定义通过向端口映射添加 `name` 和 `appProtocol` 参数来配置 Service Connect。使用多个端口时，端口名称使该端口在服务配置中更易于识别。默认情况下，端口名也用作命名空间中其他应用程序使用的可发现名称。

      任务定义包含任务 IAM 角色，因为该服务已启用 ECS Exec。
**重要**  
此任务定义使用 `logConfiguration` 从 `stdout` 和 `stderr` 向 Amazon CloudWatch Logs 发送 nginx 输出。此任务执行角色不具有创建 CloudWatch Logs 日志组所需的额外权限。使用 AWS 管理控制台 或 AWS CLI 在 CloudWatch Logs 中创建日志组。如果您不想将 nginx 日志发送到 CloudWatch Logs，可以删除 `logConfiguration`。  
用您的 AWS 账户 ID 替换任务执行角色中的 AWS 账户 ID。

      ```
      {
          "family": "service-connect-nginx",
          "executionRoleArn": "arn:aws:iam::123456789012:role/ecsTaskExecutionRole",
          "taskRoleArn": "arn:aws:iam::123456789012:role/ecsTaskRole",
          "networkMode": "awsvpc",
          "containerDefinitions": [
              {
              "name": "webserver",
              "image": "public.ecr.aws/docker/library/nginx:latest",
              "cpu": 100,
              "portMappings": [
                  {
                      "name": "nginx",
                      "containerPort": 80,
                      "protocol": "tcp", 
                      "appProtocol": "http"
                  }
              ],
              "essential": true,
              "logConfiguration": {
                  "logDriver": "awslogs",
                  "options": {
                      "awslogs-group": "/ecs/service-connect-nginx",
                      "awslogs-region": "region", 
                      "awslogs-stream-prefix": "nginx"
                  }
              }
              }
          ],
          "cpu": "256",
          "memory": "512"
      }
      ```

   1. 使用 `service-connect-nginx.json` 文件注册任务定义：

      ```
      aws ecs register-task-definition --cli-input-json file://service-connect-nginx.json
      ```

1. 创建服务：

   1. 使用您将要创建的 Amazon ECS 服务的内容，创建名为 `service-connect-nginx-service.json` 的文件。此示例会使用在上一步中创建的任务定义。由于示例任务定义使用 `awsvpc` 网络模式，`awsvpcConfiguration` 是必需的。

      创建 ECS 服务时，请指定 Fargate 和支持 Service Connect 的 `LATEST` 平台版本。`securityGroups` 和 `subnets` 必须属于符合使用 Amazon ECS 要求的 VPC。您可以从 Amazon VPC 控制台获取安全组和子网 ID。

      此服务通过添加 `serviceConnectConfiguration` 参数来配置 Service Connect。不需要命名空间，因为集群配置了默认命名空间。在命名空间中的 ECS 中运行的客户端应用程序通过使用 `portName` 和 `clientAliases` 中的端口连接到此服务。例如，可使用 `http://nginx:80/` 访问此服务，因为 nginx 在根位置 `/` 提供了欢迎页面。不在 Amazon ECS 中运行或不在同一命名空间中的外部应用程序可以使用任务的 IP 地址和任务定义中的端口号，通过 Service Connect 代理访问此应用程序。对于您的 `tls` 配置，请为您的 IAM 角色的 `awsPcaAuthorityArn`、`kmsKey` 和 `roleArn` 添加证书 `arn`。

      此服务使用 `logConfiguration` 将 Service Connect 代理输出从 `stdout` 和 `stderr` 发送到 Amazon CloudWatch Logs。此任务执行角色不具有创建 CloudWatch Logs 日志组所需的额外权限。使用 AWS 管理控制台 或 AWS CLI 在 CloudWatch Logs 中创建日志组。我们建议您创建此日志组并将代理日志存储在 CloudWatch Logs 中。如果您不想将代理日志发送到 CloudWatch Logs，可以删除 `logConfiguration`。

      ```
      {
          "cluster": "tutorial",
          "deploymentConfiguration": {
              "maximumPercent": 200,
              "minimumHealthyPercent": 0
          },
          "deploymentController": {
              "type": "ECS"
          },
          "desiredCount": 1,
          "enableECSManagedTags": true,
          "enableExecuteCommand": true,
          "launchType": "FARGATE",
          "networkConfiguration": {
              "awsvpcConfiguration": {
                  "assignPublicIp": "ENABLED",
                  "securityGroups": [
                      "sg-EXAMPLE"
                  ],
                  "subnets": [
                      "subnet-EXAMPLE",
                      "subnet-EXAMPLE",
                      "subnet-EXAMPLE"
                  ]
                 }
          },
          "platformVersion": "LATEST",
          "propagateTags": "SERVICE",
          "serviceName": "service-connect-nginx-service",
          "serviceConnectConfiguration": {
              "enabled": true,
              "services": [
                  {
                      "portName": "nginx",
                      "clientAliases": [
                          {
                              "port": 80
                          }
                      ],
                      "tls": {
                         "issuerCertificateAuthority": {
                            "awsPcaAuthorityArn": "certificateArn"
                         }, 
                         "kmsKey": "kmsKey", 
                         "roleArn": "iamRoleArn"
                      }
                  }
              ],
              "logConfiguration": {
                  "logDriver": "awslogs",
                  "options": {
                      "awslogs-group": "/ecs/service-connect-proxy",
                      "awslogs-region": "region",
                      "awslogs-stream-prefix": "service-connect-proxy"
                  }
              }
          },
          "taskDefinition": "service-connect-nginx"
      }
      ```

   1. 使用 `service-connect-nginx-service.json` 文件创建服务：

      ```
      aws ecs create-service --cluster tutorial --cli-input-json file://service-connect-nginx-service.json
      ```

      输出：

      ```
      {
          "service": {
              "serviceArn": "arn:aws:ecs:us-west-2:123456789012:service/tutorial/service-connect-nginx-service",
              "serviceName": "service-connect-nginx-service",
              "clusterArn": "arn:aws:ecs:us-west-2:123456789012:cluster/tutorial",
              "loadBalancers": [],
              "serviceRegistries": [],
              "status": "ACTIVE",
              "desiredCount": 1,
              "runningCount": 0,
              "pendingCount": 0,
              "launchType": "FARGATE",
              "platformVersion": "LATEST",
              "platformFamily": "Linux",
              "taskDefinition": "arn:aws:ecs:us-west-2:123456789012:task-definition/service-connect-nginx:1",
              "deploymentConfiguration": {
                  "deploymentCircuitBreaker": {
                      "enable": false,
                      "rollback": false
                  },
                  "maximumPercent": 200,
                  "minimumHealthyPercent": 0
              },
              "deployments": [
                  {
                      "id": "ecs-svc/3763308422771520962",
                      "status": "PRIMARY",
                      "taskDefinition": "arn:aws:ecs:us-west-2:123456789012:task-definition/service-connect-nginx:1",
                      "desiredCount": 1,
                      "pendingCount": 0,
                      "runningCount": 0,
                      "failedTasks": 0,
                      "createdAt": 1661210032.602,
                      "updatedAt": 1661210032.602,
                      "launchType": "FARGATE",
                      "platformVersion": "1.4.0",
                      "platformFamily": "Linux",
                      "networkConfiguration": {
                          "awsvpcConfiguration": {
                              "assignPublicIp": "ENABLED",
                              "securityGroups": [
                                  "sg-EXAMPLE"
                              ],
                              "subnets": [
                                  "subnet-EXAMPLEf",
                                  "subnet-EXAMPLE",
                                  "subnet-EXAMPLE"
                              ]
                          }
                      },
                      "rolloutState": "IN_PROGRESS",
                      "rolloutStateReason": "ECS deployment ecs-svc/3763308422771520962 in progress.",
                      "failedLaunchTaskCount": 0,
                      "replacedTaskCount": 0,
                      "serviceConnectConfiguration": {
                          "enabled": true,
                          "namespace": "service-connect",
                          "services": [
                              {
                                  "portName": "nginx",
                                  "clientAliases": [
                                      {
                                          "port": 80
                                      }
                                  ]
                              }
                          ],
                          "logConfiguration": {
                              "logDriver": "awslogs",
                              "options": {
                                  "awslogs-group": "/ecs/service-connect-proxy",
                                  "awslogs-region": "us-west-2",
                                  "awslogs-stream-prefix": "service-connect-proxy"
                              },
                              "secretOptions": []
                          }
                      },
                      "serviceConnectResources": [
                          {
                              "discoveryName": "nginx",
                              "discoveryArn": "arn:aws:servicediscovery:us-west-2:123456789012:service/srv-EXAMPLE"
                          }
                      ]
                  }
              ],
              "roleArn": "arn:aws:iam::123456789012:role/aws-service-role/ecs.amazonaws.com/AWSServiceRoleForECS",
              "version": 0,
              "events": [],
              "createdAt": 1661210032.602,
              "placementConstraints": [],
              "placementStrategy": [],
              "networkConfiguration": {
                  "awsvpcConfiguration": {
                      "assignPublicIp": "ENABLED",
                      "securityGroups": [
                          "sg-EXAMPLE"
                      ],
                      "subnets": [
                          "subnet-EXAMPLE",
                          "subnet-EXAMPLE",
                          "subnet-EXAMPLE"
                      ]
                  }
              },
              "schedulingStrategy": "REPLICA",
              "enableECSManagedTags": true,
              "propagateTags": "SERVICE",
              "enableExecuteCommand": true
          }
      }
      ```

      您提供的 `serviceConnectConfiguration` 出现在输出的第一个*部署*中。当您以需要更改任务的方式更改 ECS 服务时，Amazon ECS 会创建新的部署。

## 步骤 3：验证是否可以连接
<a name="create-service-connect-verify"></a>

要验证 Service Connect 是否已配置并正常运行，请按照以下步骤从外部应用程序连接到 Web 服务。然后，查看 CloudWatch 中 Service Connect 代理创建的其他指标。

**从外部应用程序连接到 Web 服务**
+ 使用任务 IP 地址连接到任务 IP 地址和容器端口

  使用 AWS CLI 并利用 `aws ecs list-tasks --cluster tutorial` 获取任务 ID。

  如果您的子网和安全组允许来自任务定义的端口上的公共互联网流量，则可以从计算机连接到公有 IP。但是“describe-tasks”无法获得公有 IP，因此这些步骤包括前往 Amazon EC2 AWS 管理控制台 或 AWS CLI 获取弹性网络接口的详细信息。

  在此示例中，同一 VPC 中的 Amazon EC2 实例使用任务的私有 IP。应用程序是 nginx，但 `server: envoy` 标头显示使用了 Service Connect 代理。Service Connect 代理正在从任务定义侦听容器端口。

  ```
  $ curl -v 10.0.19.50:80/
  *   Trying 10.0.19.50:80...
  * Connected to 10.0.19.50 (10.0.19.50) port 80 (#0)
  > GET / HTTP/1.1
  > Host: 10.0.19.50
  > User-Agent: curl/7.79.1
  > Accept: */*
  >
  * Mark bundle as not supporting multiuse
  < HTTP/1.1 200 OK
  < server: envoy
  < date: Tue, 23 Aug 2022 03:53:06 GMT
  < content-type: text/html
  < content-length: 612
  < last-modified: Tue, 16 Apr 2019 13:08:19 GMT
  < etag: "5cb5d3c3-264"
  < accept-ranges: bytes
  < x-envoy-upstream-service-time: 0
  <
  <!DOCTYPE html>
  <html>
  <head>
  <title>Welcome to nginx!</title>
  <style>
      body {
          width: 35em;
          margin: 0 auto;
          font-family: Tahoma, Verdana, Arial, sans-serif;
      }
  </style>
  </head>
  <body>
  <h1>Welcome to nginx!</h1>
  <p>If you see this page, the nginx web server is successfully installed and
  working. Further configuration is required.</p>
  
  <p>For online documentation and support please refer to
  <a href="http://nginx.org/">nginx.org</a>.<br/>
  Commercial support is available at
  <a href="http://nginx.com/">nginx.com</a>.</p>
  
  <p><em>Thank you for using nginx.</em></p>
  </body>
  </html>
  ```

**查看 Service Connect 指标**  
Service Connect 代理在 CloudWatch 指标中创建应用程序（HTTP、HTTP2、gRPC 或 TCP 连接）指标。使用 CloudWatch 控制台时，请查看 Amazon ECS 命名空间下的 **DiscoveryName**、（**DiscoveryName、ServiceName、ClusterName**）、**TargetDiscoveryName** 和（**TargetDiscoveryName、ServiceName、ClusterName**）等其他指标维度。有关这些指标和维度的更多信息，请参阅《Amazon CloudWatch Logs 用户指南》中的[查看可用指标](https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/viewing_metrics_with_cloudwatch.html)。