

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

# 开始使用 AWS App Mesh 和 Amazon EC2
<a name="getting-started-ec2"></a>

**重要**  
终止支持通知：2026 年 9 月 30 日， AWS 将停止对的支持。 AWS App Mesh 2026 年 9 月 30 日之后，您将无法再访问 AWS App Mesh 控制台或 AWS App Mesh 资源。有关更多信息，请访问此博客文章[从迁移 AWS App Mesh 到 Amazon ECS Service Connect](https://aws.amazon.com/blogs/containers/migrating-from-aws-app-mesh-to-amazon-ecs-service-connect)。

本主题可帮助您 AWS App Mesh 使用在 Amazon EC2 上运行的实际服务。本教程介绍了多种 App Mesh 资源类型的基本功能。

## 场景
<a name="scenario"></a>

为了说明如何配合使用 App Mesh，假定您有一个具有以下功能的应用程序：
+ 由名为 `serviceA` 和 `serviceB` 的两项服务组成。
+ 这两项服务均注册到名为 `apps.local` 的命名空间。
+ `ServiceA` 通过 HTTP/2 和端口 80 与 `serviceB` 通信。
+  您已部署 `serviceB` 的版本 2，并采用名称 `serviceBv2` 在 `apps.local` 命名空间中注册了该服务。

您的要求如下：
+ 您想将 75% 的流量从发送`serviceA`到`serviceB`，将 25% 的流量发送到`serviceBv2`第一个。通过仅向发送25％的流量`serviceBv2`，您就可以在发送来自的100％的流量之前验证它是否没有错误`serviceA`。
+ 您希望能够轻松调整流量权重，以便一旦证明 `serviceBv2` 可靠便可将 100% 的流量发送到该服务。将所有流量发送到 `serviceBv2` 后，您希望弃用 `serviceB`。
+ 您不想为了满足之前的要求而更改实际服务的任何现有应用程序代码或服务发现注册。

为了满足您的要求，您决定创建包含虚拟服务、虚拟节点、虚拟路由器和路由的 App Mesh 服务网格。实施您的网格后，更新使用 Envoy 代理的服务。更新后，您的服务将通过 Envoy 代理相互通信，而不是直接相互通信。

## 先决条件
<a name="prerequisites"></a>

App Mesh 支持在 DNS 中注册的 Linux 服务 AWS Cloud Map，或者两者兼而有之。要使用此入门指南，我们建议您提供三项已注册到 DNS 的现有服务。即使服务不存在，您也可以创建服务网格及其资源，但在部署实际服务之前，您无法使用网格。

如果您尚未运行服务，则可以启动 Amazon EC2 实例并向其部署应用程序。有关更多信息，请参阅亚马逊 EC2 用户指南中的[教程：亚马逊 EC2 Linux 实例入门](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ec2-lamp-amazon-linux-2.html)。剩余步骤假定实际服务命名为 `serviceA`、`serviceB` 和 `serviceBv2`，并且可以在名为 `apps.local` 的命名空间中发现所有服务。

## 步骤 1：创建网格和虚拟服务
<a name="create-mesh-and-virtual-service"></a>

服务网格是一种用于驻留在其内的服务之间的网络流量的逻辑边界。有关更多信息，请参阅 [服务网格](meshes.md)。虚拟服务是实际服务的抽象。有关更多信息，请参阅 [虚拟服务](virtual_services.md)。

创建以下 资源：
+ 名为 `apps` 的网格，因为此场景中的所有服务均注册到 `apps.local` 命名空间。
+ 名为 `serviceb.apps.local` 的虚拟服务，因为虚拟服务表示可以使用该名称发现的服务，并且您不希望更改代码以引用其他名称。稍后的步骤中将添加名为 `servicea.apps.local` 的虚拟服务。

您可以使用或 1.18.116 AWS 管理控制台 或更高 AWS CLI 版本或 2.0.38 或更高版本来完成以下步骤。如果使用 AWS CLI，请使用`aws --version`命令检查已安装的 AWS CLI 版本。如果您没有安装版本 1.18.116 或更高版本或者没有安装版本 2.0.38 或更高版本，则必须[安装或更新 AWS CLI](https://docs.aws.amazon.com/cli/latest/reference/appmesh/cli-chap-install.html)。选择要使用的工具所对应的选项卡。

------
#### [ AWS 管理控制台 ]

1. 在开始时打开 App Mesh 控制台的首次运行向导[https://console.aws.amazon.com/appmesh/。](https://console.aws.amazon.com/appmesh/get-started)

1. 对于**网格名称**，输入 **apps**。

1. 对于**虚拟服务名称**，输入 **serviceb.apps.local**。

1. 要继续，请选择 **Next**。

------
#### [ AWS CLI ]

1. 使用 `[create-mesh](https://docs.aws.amazon.com/cli/latest/reference/appmesh/create-mesh.html)` 命令创建网格。

   ```
   aws appmesh create-mesh --mesh-name apps
   ```

1. 使用 `[create-virtual-service](https://docs.aws.amazon.com/cli/latest/reference/appmesh/create-virtual-service.html)` 命令创建虚拟服务。

   ```
   aws appmesh create-virtual-service --mesh-name apps --virtual-service-name serviceb.apps.local --spec {}
   ```

------

## 步骤 2：创建虚拟节点
<a name="create-virtual-node"></a>

虚拟节点充当实际服务的逻辑指针。有关更多信息，请参阅 [虚拟节点](virtual_nodes.md)。

创建名为 `serviceB` 的虚拟节点，因为某个虚拟节点表示名为 `serviceB` 的实际服务。可使用主机名 `serviceb.apps.local`，通过 `DNS` 发现虚拟节点所表示的实际服务。或者，也可以使用 AWS Cloud Map发现实际服务。虚拟节点在端口 80 上使用 HTTP/2 协议监听流量。此外，还支持其他协议和运行状况检查。您将在后面的步骤中为 `serviceA` 和 `serviceBv2` 创建虚拟节点。

------
#### [ AWS 管理控制台 ]

1. 对于**虚拟节点名称**，输入 **serviceB**。

1. 对于**服务发现方法**，选择 **DNS**，并为**DNS 主机名**输入 **serviceb.apps.local**。

1. 在**侦听器配置**下，为**协议**选择 **http2**，并在**端口**中，输入 **80**。

1. 要继续，请选择 **Next**。

------
#### [ AWS CLI ]

1. 使用以下内容创建名为 `create-virtual-node-serviceb.json` 的文件：

   ```
   {
       "meshName": "apps",
       "spec": {
           "listeners": [
               {
                   "portMapping": {
                       "port": 80,
                       "protocol": "http2"
                   }
               }
           ],
           "serviceDiscovery": {
               "dns": {
                   "hostname": "serviceB.apps.local"
               }
           }
       },
       "virtualNodeName": "serviceB"
   }
   ```

1. 使用 JSON 文件作为输入使用[create-virtual-node](https://docs.aws.amazon.com/cli/latest/reference/appmesh/create-virtual-node.html)命令创建虚拟节点。

   ```
   aws appmesh create-virtual-node --cli-input-json file://create-virtual-node-serviceb.json
   ```

------

## 步骤 3：创建虚拟路由器和路由
<a name="create-virtual-router-and-route"></a>

虚拟路由器路由网格中一个或多个虚拟服务的流量。有关更多信息，请参阅[虚拟路由器](virtual_routers.md)和[Routes](routes.md)。

创建以下 资源：
+ 名为 `serviceB` 的虚拟路由器，因为 `serviceB.apps.local` 虚拟服务不会启动与任何其他服务的出站通信。请记住，您之前创建的虚拟服务是实际 `serviceb.apps.local` 服务的抽象。虚拟服务将流量发送到虚拟路由器。虚拟路由器采用 HTTP/2 协议在端口 80 上侦听流量。此外，还支持其他协议。
+ 名为 `serviceB` 的路由。它将 100% 的流量路由到`serviceB`虚拟节点。添加 `serviceBv2` 虚拟节点后，在稍后的步骤中出现权重。虽然本指南中未作介绍，但您可以为路由添加额外的筛选条件，并添加重试策略，从而使 Envoy 代理在遇到通信问题时会多次尝试将流量发送到虚拟节点。

------
#### [ AWS 管理控制台 ]

1. 对于**虚拟路由器名称**，输入 **serviceB**。

1. 在**侦听器配置**下，为**协议**选择 **http2**，并为**端口**指定 **80**。

1. 对于**路由名称**，输入 **serviceB**。

1. 对于**路由类型**，选择 **http2**。

1. 在**目标配置**下的**虚拟节点名称**中，选择 `serviceB`，并为**权重**输入 **100**。

1. 在**匹配配置**下，选择一种**方法**。

1. 要继续，请选择 **Next**。

------
#### [ AWS CLI ]

1. 创建虚拟路由器。

   1. 使用以下内容创建名为 `create-virtual-router.json` 的文件：

      ```
      {
          "meshName": "apps",
          "spec": {
              "listeners": [
                  {
                      "portMapping": {
                          "port": 80,
                          "protocol": "http2"
                      }
                  }
              ]
          },
          "virtualRouterName": "serviceB"
      }
      ```

   1. 使用 JSON 文件作为输入使用[create-virtual-router](https://docs.aws.amazon.com/cli/latest/reference/appmesh/create-virtual-router.html)命令创建虚拟路由器。

      ```
      aws appmesh create-virtual-router --cli-input-json file://create-virtual-router.json
      ```

1. 创建路由。

   1. 使用以下内容创建名为 `create-route.json` 的文件：

      ```
      {
          "meshName" : "apps",
          "routeName" : "serviceB",
          "spec" : {
              "httpRoute" : {
                  "action" : {
                      "weightedTargets" : [
                          {
                              "virtualNode" : "serviceB",
                              "weight" : 100
                          }
                      ]
                  },
                  "match" : {
                      "prefix" : "/"
                  }
              }
          },
          "virtualRouterName" : "serviceB"
      }
      ```

   1. 采用 JSON 文件作为输入，使用 [create-route](https://docs.aws.amazon.com/cli/latest/reference/appmesh/create-route.html) 命令创建路由。

      ```
      aws appmesh create-route --cli-input-json file://create-route.json
      ```

------

## 步骤 4：审核并创建
<a name="review-create"></a>

根据之前的说明审核设置。

------
#### [ AWS 管理控制台 ]

如果需要对任何部分进行任何更改，请选择**编辑**。在您对设置感到满意后，选择**创建网格**。

**状态**屏幕将显示已创建的所有网格资源。您可以通过选择**查看网格**来在控制台中查看创建的资源。

------
#### [ AWS CLI ]

使用 [describe-mesh](https://docs.aws.amazon.com/cli/latest/reference/appmesh/describe-mesh.html) 命令查看所创建网格的设置。

```
aws appmesh describe-mesh --mesh-name apps
```

查看您使用[describe-virtual-service](https://docs.aws.amazon.com/cli/latest/reference/appmesh/describe-virtual-service.html)命令创建的虚拟服务的设置。

```
aws appmesh describe-virtual-service --mesh-name apps --virtual-service-name serviceb.apps.local
```

查看您使用[describe-virtual-node](https://docs.aws.amazon.com/cli/latest/reference/appmesh/describe-virtual-node.html)命令创建的虚拟节点的设置。

```
aws appmesh describe-virtual-node --mesh-name apps --virtual-node-name serviceB
```

查看您使用[describe-virtual-router](https://docs.aws.amazon.com/cli/latest/reference/appmesh/describe-virtual-router.html)命令创建的虚拟路由器的设置。

```
aws appmesh describe-virtual-router --mesh-name apps --virtual-router-name serviceB
```

使用 [describe-route](https://docs.aws.amazon.com/cli/latest/reference/appmesh/describe-route.html) 命令查看所创建路由的设置。

```
aws appmesh describe-route --mesh-name apps \
    --virtual-router-name serviceB  --route-name serviceB
```

------

## 步骤 5：创建其他资源
<a name="create-additional-resources"></a>

要完成此场景，您需要执行以下操作：
+ 创建名为 `serviceBv2` 的虚拟节点，以及名为 `serviceA` 的虚拟节点。这两个虚拟节点均通过 HTTP/2 和端口 80 侦听请求。对于 `serviceA` 虚拟节点，将后端配置为 `serviceb.apps.local`。来自 `serviceA` 虚拟节点的所有出站流量都将发送到名为 `serviceb.apps.local` 的虚拟服务。虽然本指南中未作介绍，但您还可以为虚拟节点指定用于写入访问日志的文件路径。
+ 另外创建一个名为的虚拟服务`servicea.apps.local`，该服务将所有流量直接发送到`serviceA`虚拟节点。
+ 更新在上一步中创建的 `serviceB` 路由，以将 75% 的流量发送到 `serviceB` 虚拟节点，将 25% 的流量发送到 `serviceBv2` 虚拟节点。随着时间的推移，您可以继续修改权重，直到 `serviceBv2` 收到 100% 的流量。将所有流量发送到 `serviceBv2` 后，您可以关闭并弃用 `serviceB` 虚拟节点和实际服务。在更改权重时，不需要对代码进行任何修改，因为 `serviceb.apps.local` 虚拟服务名称和实际服务名称没有改变。回想一下，`serviceb.apps.local` 虚拟服务将流量发送到虚拟路由器，该路由器将流量路由到虚拟节点。虚拟节点的服务发现名称可以随时更改。

------
#### [ AWS 管理控制台 ]

1. 在左侧导航窗格中，选择**网格**。

1. 选择在上一步中创建的 `apps` 网格。

1. 在左侧导航窗格中，选择**虚拟节点**。

1. 选择**创建虚拟节点**。

1. 为**虚拟节点名称**输入 **serviceBv2**，为**服务发现方法**选择 **DNS**，并为 **DNS 主机名**输入 **servicebv2.apps.local**。

1. 对于**侦听器配置**，为**协议**选择 **http2**，并在**端口**中，输入 **80**。

1. 选择**创建虚拟节点**。

1. 再次选择**创建虚拟节点**。对于**虚拟节点名称**，输入 **serviceA**。对于**服务发现方法**，选择 **DNS**，并为 **DNS 主机名**输入 **servicea.apps.local**。

1. 在**新后端**下的**输入虚拟服务名称**中，输入 **serviceb.apps.local**。

1. 在**侦听器配置**下，为**协议**选择 **http2**，并在**端口**中输入 **80**，然后选择**创建虚拟节点**。

1. 在左侧导航窗格中，选择**虚拟路由器**，然后从列表中选择 `serviceB` 虚拟路由器。

1. 在**路由**下，选择在上一步中创建的名为 `ServiceB` 的路由，然后选择**编辑**。

1. 在**目标**、**虚拟节点名称**下，将 `serviceB` 的**权重**值更改为 **75**。

1. 选择**添加目标**，从下拉列表中选择 `serviceBv2`，然后将**权重**值设置为 **25**。

1. 选择**保存**。

1. 在左侧导航窗格中，选择**虚拟服务**，然后选择**创建虚拟服务**。

1. 针对**虚拟服务名称**输入 **servicea.apps.local**，为**提供者**选择**虚拟节点**，为**虚拟节点**选择 `serviceA`，然后选择**创建虚拟服务。**

------
#### [ AWS CLI ]

1. 创建 `serviceBv2` 虚拟节点。

   1. 使用以下内容创建名为 `create-virtual-node-servicebv2.json` 的文件：

      ```
      {
          "meshName": "apps",
          "spec": {
              "listeners": [
                  {
                      "portMapping": {
                          "port": 80,
                          "protocol": "http2"
                      }
                  }
              ],
              "serviceDiscovery": {
                  "dns": {
                      "hostname": "serviceBv2.apps.local"
                  }
              }
          },
          "virtualNodeName": "serviceBv2"
      }
      ```

   1. 创建虚拟节点。

      ```
      aws appmesh create-virtual-node --cli-input-json file://create-virtual-node-servicebv2.json
      ```

1. 创建 `serviceA` 虚拟节点。

   1. 使用以下内容创建名为 `create-virtual-node-servicea.json` 的文件：

      ```
      {
         "meshName" : "apps",
         "spec" : {
            "backends" : [
               {
                  "virtualService" : {
                     "virtualServiceName" : "serviceb.apps.local"
                  }
               }
            ],
            "listeners" : [
               {
                  "portMapping" : {
                     "port" : 80,
                     "protocol" : "http2"
                  }
               }
            ],
            "serviceDiscovery" : {
               "dns" : {
                  "hostname" : "servicea.apps.local"
               }
            }
         },
         "virtualNodeName" : "serviceA"
      }
      ```

   1. 创建虚拟节点。

      ```
      aws appmesh create-virtual-node --cli-input-json file://create-virtual-node-servicea.json
      ```

1. 更新在上一步中创建的 `serviceb.apps.local` 虚拟服务，以将其流量发送到 `serviceB` 虚拟路由器。最初创建虚拟服务时，它不会向任何位置发送流量，因为尚未创建 `serviceB` 虚拟路由器。

   1. 使用以下内容创建名为 `update-virtual-service.json` 的文件：

      ```
      {
         "meshName" : "apps",
         "spec" : {
            "provider" : {
               "virtualRouter" : {
                  "virtualRouterName" : "serviceB"
               }
            }
         },
         "virtualServiceName" : "serviceb.apps.local"
      }
      ```

   1. 使用[update-virtual-service](https://docs.aws.amazon.com/cli/latest/reference/appmesh/update-virtual-service.html)命令更新虚拟服务。

      ```
      aws appmesh update-virtual-service --cli-input-json file://update-virtual-service.json
      ```

1. 更新在上一步中创建的 `serviceB` 路径。

   1. 使用以下内容创建名为 `update-route.json` 的文件：

      ```
      {
         "meshName" : "apps",
         "routeName" : "serviceB",
         "spec" : {
            "http2Route" : {
               "action" : {
                  "weightedTargets" : [
                     {
                        "virtualNode" : "serviceB",
                        "weight" : 75
                     },
                     {
                        "virtualNode" : "serviceBv2",
                        "weight" : 25
                     }
                  ]
               },
               "match" : {
                  "prefix" : "/"
               }
            }
         },
         "virtualRouterName" : "serviceB"
      }
      ```

   1. 使用 [update-route](https://docs.aws.amazon.com/cli/latest/reference/appmesh/update-route.html) 命令更新路由。

      ```
      aws appmesh update-route --cli-input-json file://update-route.json
      ```

1. 创建 `serviceA` 虚拟服务。

   1. 使用以下内容创建名为 `create-virtual-servicea.json` 的文件：

      ```
      {
         "meshName" : "apps",
         "spec" : {
            "provider" : {
               "virtualNode" : {
                  "virtualNodeName" : "serviceA"
               }
            }
         },
         "virtualServiceName" : "servicea.apps.local"
      }
      ```

   1. 创建虚拟服务。

      ```
      aws appmesh create-virtual-service --cli-input-json file://create-virtual-servicea.json
      ```

------

**网格摘要**  
在创建服务网格之前，您具有三个名为 `servicea.apps.local`、`serviceb.apps.local` 和 `servicebv2.apps.local` 的实际服务。除实际服务之外，现在您还具有一个服务网格，其中包含用以表示实际服务的以下资源：
+ 两个虚拟服务。代理通过虚拟路由器将所有流量从 `servicea.apps.local` 虚拟服务发送到 `serviceb.apps.local` 虚拟服务。
+ 三个名为 `serviceA`、`serviceB` 和 `serviceBv2` 的虚拟节点。Envoy 代理使用为虚拟节点配置的服务发现信息来查找实际服务的 IP 地址。
+ 一个虚拟路由器，其路由指示 Envoy 代理将 75% 的入站流量路由到 `serviceB` 虚拟节点，将 25% 的流量路由到 `serviceBv2` 虚拟节点。

## 步骤 6：更新服务
<a name="update-services"></a>

创建网格后，您需要完成以下任务：
+ 授予随每项服务部署的 Envoy 代理读取一个或多个虚拟节点配置的权限。有关如何向代理授权的更多信息，请参阅 [Envoy Proxy 授权](proxy-authorization.md)。
+ 要更新现有服务，请完成以下步骤。

**将 Amazon EC2 实例配置为虚拟节点成员**

1. 创建 IAM 角色。

   1. 使用以下内容创建名为 `ec2-trust-relationship.json` 的文件。

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

****  

      ```
      {
        "Version":"2012-10-17",		 	 	 
        "Statement": [
          {
            "Effect": "Allow",
            "Principal": {
              "Service": "ec2.amazonaws.com"
            },
            "Action": "sts:AssumeRole"
          }
        ]
      }
      ```

------

   1. 使用以下命令创建 IAM 角色。

      ```
      aws iam create-role --role-name mesh-virtual-node-service-b --assume-role-policy-document file://ec2-trust-relationship.json
      ```

1. 将 IAM 策略附加到该角色，这将允许它仅从 Amazon ECR 中读取特定 App Mesh 虚拟节点的配置。

   1. 使用以下内容创建名为 `virtual-node-policy.json` 的文件。`apps` 是您在 [步骤 1：创建网格和虚拟服务](#create-mesh-and-virtual-service) 中创建的网格的名称，`serviceB` 是您在 [步骤 2：创建虚拟节点](#create-virtual-node) 中创建的虚拟节点的名称。*111122223333*替换为你的账户 ID *us-west-2* 和你在其中创建网格的区域。

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

****  

      ```
      {
          "Version":"2012-10-17",		 	 	 
          "Statement": [
              {
                  "Effect": "Allow",
                  "Action": "appmesh:StreamAggregatedResources",
                  "Resource": [
                      "arn:aws:appmesh:us-west-2:111122223333:mesh/apps/virtualNode/serviceB"
                  ]
              }
          ]
      }
      ```

------

   1. 使用以下命令创建策略。

      ```
      aws iam create-policy --policy-name virtual-node-policy --policy-document file://virtual-node-policy.json
      ```

   1. 将您在上一步中创建的策略附加到角色，以便角色仅从 App Mesh 中读取 `serviceB`虚拟节点的配置。

      ```
      aws iam attach-role-policy --policy-arn arn:aws:iam::111122223333:policy/virtual-node-policy --role-name mesh-virtual-node-service-b
      ```

   1. 将 `AmazonEC2ContainerRegistryReadOnly` 托管策略附加到角色，以便它可以从 Amazon ECR 中提取 Envoy 容器映像。

      ```
      aws iam attach-role-policy --policy-arn arn:aws:iam::aws:policy/AmazonEC2ContainerRegistryReadOnly --role-name mesh-virtual-node-service-b
      ```

1. [启动带创建的 IAM 角色](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/iam-roles-for-amazon-ec2.html#launch-instance-with-role)的 Amazon EC2 实例。

1. 通过 SSH 连接到实例。

1. 根据您的操作系统文档， AWS CLI 在您的实例上安装 Docker 和。

1. 对您希望 Docker 客户端从中拉取镜像的区域中的 Envoy 存储库进行身份验证：
   + 除 `me-south-1`、`ap-east-1`、`ap-southeast-3`、`eu-south-1`、`il-central-1` 和 `af-south-1` 以外的所有区域。您可以*us-west-2*替换为除了`me-south-1`、、、`ap-east-1``ap-southeast-3``eu-south-1``il-central-1`、和之外的任何[受支持区域](https://docs.aws.amazon.com/general/latest/gr/appmesh.html)`af-south-1`。

     ```
     $aws ecr get-login-password \
         --region us-west-2 \
     | docker login \
         --username AWS \
         --password-stdin 840364872350.dkr.ecr.us-west-2.amazonaws.com
     ```
   + `me-south-1` 区域

     ```
     $aws ecr get-login-password \
         --region me-south-1 \
     | docker login \
         --username AWS \
         --password-stdin 772975370895.dkr.ecr.me-south-1.amazonaws.com
     ```
   + `ap-east-1` 区域

     ```
     $aws ecr get-login-password \
         --region ap-east-1 \
     | docker login \
         --username AWS \
         --password-stdin 856666278305.dkr.ecr.ap-east-1.amazonaws.com
     ```

1. 运行下列命令之一，在您的实例上启动 Envoy 容器，具体取决于要从中拉取映像的区域。*apps*和*serviceB*值是在场景中定义的网格和虚拟节点名称。此信息告知代理要从 App Mesh 中读取的虚拟节点配置。要完成该场景，您还需要针对托管 `serviceBv2` 和 `serviceA` 虚拟节点所表示服务的 Amazon EC2 实例，完成这些步骤。对于您自己的应用程序，请将这些值替换为您自己的值。
   + 除 `me-south-1`、`ap-east-1`、`ap-southeast-3`、`eu-south-1`、`il-central-1` 和 `af-south-1` 以外的所有区域。您可以*Region-code*替换为除了`me-south-1`、、、`ap-east-1``ap-southeast-3``eu-south-1``il-central-1`、和[区域之外的任何受支持](https://docs.aws.amazon.com/general/latest/gr/appmesh.html)`af-south-1`区域。您可以将 `1337` 替换为介于 `0` 和 `2147483647` 之间的任何值。

     ```
     sudo docker run --detach --env APPMESH_RESOURCE_ARN=mesh/apps/virtualNode/serviceB  \
     -u 1337 --network host 840364872350.dkr.ecr.region-code.amazonaws.com/aws-appmesh-envoy:v1.34.13.0-prod
     ```
   + `me-south-1` 区域。您可以将 `1337` 替换为介于 `0` 和 `2147483647` 之间的任何值。

     ```
     sudo docker run --detach --env APPMESH_RESOURCE_ARN=mesh/apps/virtualNode/serviceB  \
     -u 1337 --network host 772975370895.dkr.ecr.me-south-1.amazonaws.com/aws-appmesh-envoy:v1.34.13.0-prod
     ```
   + `ap-east-1` 区域。您可以将 `1337` 替换为介于 `0` 和 `2147483647` 之间的任何值。

     ```
     sudo docker run --detach --env APPMESH_RESOURCE_ARN=mesh/apps/virtualNode/serviceB  \
     -u 1337 --network host 856666278305.dkr.ecr.ap-east-1.amazonaws.com/aws-appmesh-envoy:v1.34.13.0-prod
     ```
**注意**  
该 `APPMESH_RESOURCE_ARN` 属性需要版本 `1.15.0` 或更高版本的 Envoy 映像。有关更多信息，请参阅 [Envoy 镜像](envoy.md)。
**重要**  
仅支持将版本 v1.9.0.0-prod 或更高版本与 App Mesh 一起使用。

1. 在下面选择 `Show more`。使用以下内容在实例上创建名为 `envoy-networking.sh` 的文件。*8000*替换为应用程序代码用于传入流量的端口。您可以更改 `APPMESH_IGNORE_UID` 的值，但该值必须与您在上一步中指定的值相同；例如 `1337`。如有必要，您可以向 `APPMESH_EGRESS_IGNORED_IP` 添加其他地址。请不要修改任何其他行。

   ```
   #!/bin/bash -e
   
   #
   # Start of configurable options
   #
   
   
   #APPMESH_START_ENABLED="0"
   APPMESH_IGNORE_UID="1337"
   APPMESH_APP_PORTS="8000"
   APPMESH_ENVOY_EGRESS_PORT="15001"
   APPMESH_ENVOY_INGRESS_PORT="15000"
   APPMESH_EGRESS_IGNORED_IP="169.254.169.254,169.254.170.2" 
   
   # Enable routing on the application start.
   [ -z "$APPMESH_START_ENABLED" ] && APPMESH_START_ENABLED="0"
   
   # Enable IPv6.
   [ -z "$APPMESH_ENABLE_IPV6" ] && APPMESH_ENABLE_IPV6="0"
   
   # Egress traffic from the processess owned by the following UID/GID will be ignored.
   if [ -z "$APPMESH_IGNORE_UID" ] && [ -z "$APPMESH_IGNORE_GID" ]; then
       echo "Variables APPMESH_IGNORE_UID and/or APPMESH_IGNORE_GID must be set."
       echo "Envoy must run under those IDs to be able to properly route it's egress traffic."
       exit 1
   fi
   
   # Port numbers Application and Envoy are listening on.
   if [ -z "$APPMESH_ENVOY_EGRESS_PORT" ]; then
       echo "APPMESH_ENVOY_EGRESS_PORT must be defined to forward traffic from the application to the proxy."
       exit 1
   fi
   
   # If an app port was specified, then we also need to enforce the proxies ingress port so we know where to forward traffic.
   if [ ! -z "$APPMESH_APP_PORTS" ] && [ -z "$APPMESH_ENVOY_INGRESS_PORT" ]; then
       echo "APPMESH_ENVOY_INGRESS_PORT must be defined to forward traffic from the APPMESH_APP_PORTS to the proxy."
       exit 1
   fi
   
   # Comma separated list of ports for which egress traffic will be ignored, we always refuse to route SSH traffic.
   if [ -z "$APPMESH_EGRESS_IGNORED_PORTS" ]; then
       APPMESH_EGRESS_IGNORED_PORTS="22"
   else
       APPMESH_EGRESS_IGNORED_PORTS="$APPMESH_EGRESS_IGNORED_PORTS,22"
   fi
   
   #
   # End of configurable options
   #
   
   function initialize() {
       echo "=== Initializing ==="
       if [ ! -z "$APPMESH_APP_PORTS" ]; then
           iptables -t nat -N APPMESH_INGRESS
           if [ "$APPMESH_ENABLE_IPV6" == "1" ]; then
               ip6tables -t nat -N APPMESH_INGRESS
           fi
       fi
       iptables -t nat -N APPMESH_EGRESS
       if [ "$APPMESH_ENABLE_IPV6" == "1" ]; then
           ip6tables -t nat -N APPMESH_EGRESS
       fi
   }
   
   function enable_egress_routing() {
       # Stuff to ignore
       [ ! -z "$APPMESH_IGNORE_UID" ] && \
           iptables -t nat -A APPMESH_EGRESS \
           -m owner --uid-owner $APPMESH_IGNORE_UID \
           -j RETURN
   
       [ ! -z "$APPMESH_IGNORE_GID" ] && \
           iptables -t nat -A APPMESH_EGRESS \
           -m owner --gid-owner $APPMESH_IGNORE_GID \
           -j RETURN
   
       [ ! -z "$APPMESH_EGRESS_IGNORED_PORTS" ] && \
           for IGNORED_PORT in $(echo "$APPMESH_EGRESS_IGNORED_PORTS" | tr "," "\n"); do
             iptables -t nat -A APPMESH_EGRESS \
             -p tcp \
             -m multiport --dports "$IGNORED_PORT" \
             -j RETURN
           done
   
       if [ "$APPMESH_ENABLE_IPV6" == "1" ]; then
         # Stuff to ignore ipv6
         [ ! -z "$APPMESH_IGNORE_UID" ] && \
             ip6tables -t nat -A APPMESH_EGRESS \
             -m owner --uid-owner $APPMESH_IGNORE_UID \
             -j RETURN
   
         [ ! -z "$APPMESH_IGNORE_GID" ] && \
             ip6tables -t nat -A APPMESH_EGRESS \
             -m owner --gid-owner $APPMESH_IGNORE_GID \
             -j RETURN
   
         [ ! -z "$APPMESH_EGRESS_IGNORED_PORTS" ] && \
           for IGNORED_PORT in $(echo "$APPMESH_EGRESS_IGNORED_PORTS" | tr "," "\n"); do
             ip6tables -t nat -A APPMESH_EGRESS \
             -p tcp \
             -m multiport --dports "$IGNORED_PORT" \
             -j RETURN
           done
       fi
   
       # The list can contain both IPv4 and IPv6 addresses. We will loop over this list
       # to add every IPv4 address into `iptables` and every IPv6 address into `ip6tables`.
       [ ! -z "$APPMESH_EGRESS_IGNORED_IP" ] && \
           for IP_ADDR in $(echo "$APPMESH_EGRESS_IGNORED_IP" | tr "," "\n"); do
               if [[ $IP_ADDR =~ .*:.* ]]
               then
                   [ "$APPMESH_ENABLE_IPV6" == "1" ] && \
                       ip6tables -t nat -A APPMESH_EGRESS \
                           -p tcp \
                           -d "$IP_ADDR" \
                           -j RETURN
               else
                   iptables -t nat -A APPMESH_EGRESS \
                       -p tcp \
                       -d "$IP_ADDR" \
                       -j RETURN
               fi
           done
   
       # Redirect everything that is not ignored
       iptables -t nat -A APPMESH_EGRESS \
           -p tcp \
           -j REDIRECT --to $APPMESH_ENVOY_EGRESS_PORT
   
       # Apply APPMESH_EGRESS chain to non local traffic
       iptables -t nat -A OUTPUT \
           -p tcp \
           -m addrtype ! --dst-type LOCAL \
           -j APPMESH_EGRESS
   
       if [ "$APPMESH_ENABLE_IPV6" == "1" ]; then
           # Redirect everything that is not ignored ipv6
           ip6tables -t nat -A APPMESH_EGRESS \
               -p tcp \
               -j REDIRECT --to $APPMESH_ENVOY_EGRESS_PORT
           # Apply APPMESH_EGRESS chain to non local traffic ipv6
           ip6tables -t nat -A OUTPUT \
               -p tcp \
               -m addrtype ! --dst-type LOCAL \
               -j APPMESH_EGRESS
       fi
   
   }
   
   function enable_ingress_redirect_routing() {
       # Route everything arriving at the application port to Envoy
       iptables -t nat -A APPMESH_INGRESS \
           -p tcp \
           -m multiport --dports "$APPMESH_APP_PORTS" \
           -j REDIRECT --to-port "$APPMESH_ENVOY_INGRESS_PORT"
   
       # Apply AppMesh ingress chain to everything non-local
       iptables -t nat -A PREROUTING \
           -p tcp \
           -m addrtype ! --src-type LOCAL \
           -j APPMESH_INGRESS
   
       if [ "$APPMESH_ENABLE_IPV6" == "1" ]; then
           # Route everything arriving at the application port to Envoy ipv6
           ip6tables -t nat -A APPMESH_INGRESS \
               -p tcp \
               -m multiport --dports "$APPMESH_APP_PORTS" \
               -j REDIRECT --to-port "$APPMESH_ENVOY_INGRESS_PORT"
   
           # Apply AppMesh ingress chain to everything non-local ipv6
           ip6tables -t nat -A PREROUTING \
               -p tcp \
               -m addrtype ! --src-type LOCAL \
               -j APPMESH_INGRESS
       fi
   }
   
   function enable_routing() {
       echo "=== Enabling routing ==="
       enable_egress_routing
       if [ ! -z "$APPMESH_APP_PORTS" ]; then
           enable_ingress_redirect_routing
       fi
   }
   
   function disable_routing() {
       echo "=== Disabling routing ==="
       iptables -t nat -F APPMESH_INGRESS
       iptables -t nat -F APPMESH_EGRESS
   
       if [ "$APPMESH_ENABLE_IPV6" == "1" ]; then
           ip6tables -t nat -F APPMESH_INGRESS
           ip6tables -t nat -F APPMESH_EGRESS
       fi
   }
   
   function dump_status() {
       echo "=== iptables FORWARD table ==="
       iptables -L -v -n
       echo "=== iptables NAT table ==="
       iptables -t nat -L -v -n
   
       if [ "$APPMESH_ENABLE_IPV6" == "1" ]; then
           echo "=== ip6tables FORWARD table ==="
           ip6tables -L -v -n
           echo "=== ip6tables NAT table ==="
           ip6tables -t nat -L -v -n
       fi
   }
   
   function clean_up() {
       disable_routing
       ruleNum=$(iptables -L PREROUTING -t nat --line-numbers | grep APPMESH_INGRESS | cut -d " " -f 1)
       iptables -t nat -D PREROUTING $ruleNum
   
       ruleNum=$(iptables -L OUTPUT -t nat --line-numbers | grep APPMESH_EGRESS | cut -d " " -f 1)
       iptables -t nat -D OUTPUT $ruleNum
   
       iptables -t nat -X APPMESH_INGRESS
       iptables -t nat -X APPMESH_EGRESS
   
       if [ "$APPMESH_ENABLE_IPV6" == "1" ]; then
           ruleNum=$(ip6tables -L PREROUTING -t nat --line-numbers | grep APPMESH_INGRESS | cut -d " " -f 1)
           ip6tables -t nat -D PREROUTING $ruleNum
   
           ruleNum=$(ip6tables -L OUTPUT -t nat --line-numbers | grep APPMESH_EGRESS | cut -d " " -f 1)
           ip6tables -t nat -D OUTPUT $ruleNum
   
           ip6tables -t nat -X APPMESH_INGRESS
           ip6tables -t nat -X APPMESH_EGRESS
       fi
   }
   
   function main_loop() {
       echo "=== Entering main loop ==="
       while read -p '> ' cmd; do
           case "$cmd" in
               "quit")
                   clean_up
                   break
                   ;;
               "status")
                   dump_status
                   ;;
               "enable")
                   enable_routing
                   ;;
               "disable")
                   disable_routing
                   ;;
               *)
                   echo "Available commands: quit, status, enable, disable"
                   ;;
           esac
       done
   }
   
   function print_config() {
       echo "=== Input configuration ==="
       env | grep APPMESH_ || true
   }
   
   print_config
   
   initialize
   
   if [ "$APPMESH_START_ENABLED" == "1" ]; then
       enable_routing
   fi
   
   main_loop
   ```

1. 要配置 `iptables` 规则以将应用程序流量路由到 Envoy 代理，请运行您在上一步中创建的脚本。

   ```
   sudo ./envoy-networking.sh
   ```

1. 启动虚拟节点应用程序代码。

**注意**  
有关 [App Mesh](https://github.com/aws/aws-app-mesh-examples) 的更多示例和演练，请参阅 App Mesh 示例存储库。