

# Getting started with App Mesh
Getting started

**Important**  
End of support notice: On September 30, 2026, AWS will discontinue support for AWS App Mesh. After September 30, 2026, you will no longer be able to access the AWS App Mesh console or AWS App Mesh resources. For more information, visit this blog post [Migrating from AWS App Mesh to Amazon ECS Service Connect](https://aws.amazon.com/blogs/containers/migrating-from-aws-app-mesh-to-amazon-ecs-service-connect). 

You can use App Mesh with applications that you deploy to Amazon ECS, Kubernetes (that you deploy to your own Amazon EC2 instances or running on Amazon EKS), and Amazon EC2. To get started with App Mesh, select one of the services that you have applications deployed to that you want to use with App Mesh. You can always enable applications in the other services to also work with App Mesh after you complete one of the Getting started guides.

**Topics**
+ [

# Getting started with AWS App Mesh and Amazon ECS
](getting-started-ecs.md)
+ [

# Getting started with AWS App Mesh and Kubernetes
](getting-started-kubernetes.md)
+ [

# Getting started with AWS App Mesh and Amazon EC2
](getting-started-ec2.md)
+ [

# App Mesh Examples
](examples.md)

# Getting started with AWS App Mesh and Amazon ECS
App Mesh and Amazon ECS

**Important**  
End of support notice: On September 30, 2026, AWS will discontinue support for AWS App Mesh. After September 30, 2026, you will no longer be able to access the AWS App Mesh console or AWS App Mesh resources. For more information, visit this blog post [Migrating from AWS App Mesh to Amazon ECS Service Connect](https://aws.amazon.com/blogs/containers/migrating-from-aws-app-mesh-to-amazon-ecs-service-connect). 

This topic helps you use AWS App Mesh with an actual service that is running on Amazon ECS. This tutorial covers basic features of several App Mesh resource types.

## Scenario


To illustrate how to use App Mesh, assume that you have an application with the following characteristics:
+ Consists of two services named `serviceA` and `serviceB`. 
+ Both services are registered to a namespace named `apps.local`.
+ `ServiceA` communicates with `serviceB` over HTTP/2, port 80.
+  You have already deployed version 2 of `serviceB` and registered it with the name `serviceBv2` in the `apps.local` namespace.

You have the following requirements:
+ You want to send 75 percent of the traffic from `serviceA` to `serviceB` and 25 percent of the traffic to `serviceBv2` first. By only sending 25 percent to `serviceBv2`, you can validate that it's bug free before you send 100 percent of the traffic from `serviceA`.
+ You want to be able to easily adjust the traffic weighting so that 100 percent of the traffic goes to `serviceBv2` once it is proven to be reliable. Once all traffic is being sent to `serviceBv2`, you want to discontinue `serviceB`.
+ You do not want to have to change any existing application code or service discovery registration for your actual services to meet the previous requirements. 

To meet your requirements, you decide to create an App Mesh service mesh with virtual services, virtual nodes, a virtual router, and a route. After implementing your mesh, you update your services to use the Envoy proxy. Once updated, your services communicate with each other through the Envoy proxy rather than directly with each other.

## Prerequisites


**Important**  
End of support notice: On September 30, 2026, AWS will discontinue support for AWS App Mesh. After September 30, 2026, you will no longer be able to access the AWS App Mesh console or AWS App Mesh resources. For more information, visit this blog post [Migrating from AWS App Mesh to Amazon ECS Service Connect](https://aws.amazon.com/blogs/containers/migrating-from-aws-app-mesh-to-amazon-ecs-service-connect). 
+ An existing understanding of App Mesh concepts. For more information, see [What Is AWS App Mesh?](what-is-app-mesh.md).
+ An existing understanding of Amazon ECSs concepts. For more information, see [What is Amazon ECS](https://docs.aws.amazon.com/AmazonECS/latest/developerguide/Welcome.html) in the Amazon Elastic Container Service Developer Guide.
+ App Mesh supports Linux services that are registered with DNS, AWS Cloud Map, or both. To use this getting started guide, we recommend that you have three existing services that are registered with DNS. The procedures in this topic assume that the existing services are named `serviceA`, `serviceB`, and `serviceBv2` and that all services are discoverable through a namespace named `apps.local`. 

  You can create a service mesh and its resources even if the services don't exist, but you cannot use the mesh until you have deployed actual services. For more information about service discovery on Amazon ECS, see [Service Discovery](https://docs.aws.amazon.com/AmazonECS/latest/developerguide/service-discovery.html). To create an Amazon ECS service with service discovery, see [Tutorial: Creating a Service Using Service Discovery](https://docs.aws.amazon.com/AmazonECS/latest/developerguide/create-service-discovery.html). If you don't already have services running, you can [Create an Amazon ECS service with service discovery](https://docs.aws.amazon.com/AmazonECS/latest/developerguide/create-service-discovery.html).

## Step 1: Create a mesh and virtual service


A service mesh is a logical boundary for network traffic between the services that reside within it. For more information, see [Service Meshes](meshes.md). A virtual service is an abstraction of an actual service. For more information, see [Virtual services](virtual_services.md). 

Create the following resources:
+ A mesh named `apps`, since all of the services in the scenario are registered to the `apps.local` namespace.
+ A virtual service named `serviceb.apps.local`, since the virtual service represents a service that is discoverable with that name, and you don't want to change your code to reference another name. A virtual service named `servicea.apps.local` is added in a later step.

You can use the AWS Management Console or the AWS CLI version 1.18.116 or higher or 2.0.38 or higher to complete the following steps. If using the AWS CLI, use the `aws --version` command to check your installed AWS CLI version. If you don't have version 1.18.116 or higher or 2.0.38 or higher installed, then you must [install or update the AWS CLI](https://docs.aws.amazon.com/cli/latest/reference/appmesh/cli-chap-install.html). Select the tab for the tool that you want to use.

------
#### [ AWS Management Console ]

1. Open the App Mesh console first-run wizard at [https://console.aws.amazon.com/appmesh/get-started](https://console.aws.amazon.com/appmesh/get-started).

1. For **Mesh name**, enter **apps**.

1. For **Virtual service name**, enter **serviceb.apps.local**.

1. To continue, choose **Next**.

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

1. Create a mesh with the `[create-mesh](https://docs.aws.amazon.com/cli/latest/reference/appmesh/create-mesh.html)` command.

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

1. Create a virtual service with the `[create-virtual-service](https://docs.aws.amazon.com/cli/latest/reference/appmesh/create-virtual-service.html)` command.

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

------

## Step 2: Create a virtual node


A virtual node acts as a logical pointer to an actual service. For more information, see [Virtual nodes](virtual_nodes.md). 

Create a virtual node named `serviceB`, since one of the virtual nodes represents the actual service named `serviceB`. The actual service that the virtual node represents is discoverable through `DNS` with a hostname of `serviceb.apps.local`. Alternately, you can discover actual services using AWS Cloud Map. The virtual node will listen for traffic using the HTTP/2 protocol on port 80. Other protocols are also supported, as are health checks. You will create virtual nodes for `serviceA` and `serviceBv2` in a later step.

------
#### [ AWS Management Console ]

1. For **Virtual node name**, enter **serviceB**. 

1. For **Service discovery method**, choose **DNS** and enter **serviceb.apps.local** for **DNS hostname**.

1. Under **Listener configuration**, choose **http2** for **Protocol** and enter **80** for **Port**.

1. To continue, choose **Next**.

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

1. Create a file named `create-virtual-node-serviceb.json` with the following contents:

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

1. Create the virtual node with the [create-virtual-node](https://docs.aws.amazon.com/cli/latest/reference/appmesh/create-virtual-node.html) command using the JSON file as input.

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

------

## Step 3: Create a virtual router and route


Virtual routers route traffic for one or more virtual services within your mesh. For more information, see [Virtual routers](virtual_routers.md) and [Routes](routes.md).

Create the following resources:
+ A virtual router named `serviceB`, since the `serviceB.apps.local` virtual service does not initiate outbound communication with any other service. Remember that the virtual service that you created previously is an abstraction of your actual `serviceb.apps.local` service. The virtual service sends traffic to the virtual router. The virtual router listens for traffic using the HTTP/2 protocol on port 80. Other protocols are also supported. 
+ A route named `serviceB`. It routes 100 percent of its traffic to the `serviceB` virtual node. The weight is in a later step once you add the `serviceBv2` virtual node. Though not covered in this guide, you can add additional filter criteria for the route and add a retry policy to cause the Envoy proxy to make multiple attempts to send traffic to a virtual node when it experiences a communication problem.

------
#### [ AWS Management Console ]

1. For **Virtual router name,** enter **serviceB**.

1. Under **Listener configuration**, choose **http2** for **Protocol** and specify **80** for **Port**.

1. For **Route name**, enter **serviceB**. 

1. For **Route type**, choose **http2**.

1. For **Virtual node name** under **Target configuration**, select `serviceB` and enter **100** for **Weight**.

1. Under **Match configuration**, choose a **Method**.

1. To continue, choose **Next**.

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

1. Create a virtual router.

   1. Create a file named `create-virtual-router.json` with the following contents:

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

   1. Create the virtual router with the [create-virtual-router](https://docs.aws.amazon.com/cli/latest/reference/appmesh/create-virtual-router.html) command using the JSON file as input.

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

1. Create a route.

   1. Create a file named `create-route.json` with the following contents:

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

   1. Create the route with the [create-route](https://docs.aws.amazon.com/cli/latest/reference/appmesh/create-route.html) command using the JSON file as input.

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

------

## Step 4: Review and create


Review the settings against the previous instructions.

------
#### [ AWS Management Console ]

Choose **Edit** if you need to make changes in any section. Once you are satisfied with the settings, choose **Create mesh**.

The **Status** screen shows you all of the mesh resources that were created. You can see the created resources in the console by selecting **View mesh**.

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

Review the settings of the mesh you created with the [describe-mesh](https://docs.aws.amazon.com/cli/latest/reference/appmesh/describe-mesh.html) command.

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

Review the settings of the virtual service that you created with the [describe-virtual-service](https://docs.aws.amazon.com/cli/latest/reference/appmesh/describe-virtual-service.html) command.

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

Review the settings of the virtual node that you created with the [describe-virtual-node](https://docs.aws.amazon.com/cli/latest/reference/appmesh/describe-virtual-node.html) command.

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

Review the settings of the virtual router that you created with the [describe-virtual-router](https://docs.aws.amazon.com/cli/latest/reference/appmesh/describe-virtual-router.html) command.

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

Review the settings of the route that you created with the [describe-route](https://docs.aws.amazon.com/cli/latest/reference/appmesh/describe-route.html) command.

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

------

## Step 5: Create additional resources


To complete the scenario, you need to:
+ Create one virtual node named `serviceBv2` and another named `serviceA`. Both virtual nodes listen for requests over HTTP/2 port 80. For the `serviceA` virtual node, configure a backend of `serviceb.apps.local`. All outbound traffic from the `serviceA` virtual node is sent to the virtual service named `serviceb.apps.local`. Though not covered in this guide, you can also specify a file path to write access logs to for a virtual node.
+ Create one additional virtual service named `servicea.apps.local`, which sends all traffic directly to the `serviceA` virtual node.
+ Update the `serviceB` route that you created in a previous step to send 75 percent of its traffic to the `serviceB` virtual node and 25 percent of its traffic to the `serviceBv2` virtual node. Over time, you can continue to modify the weights until `serviceBv2` receives 100 percent of the traffic. Once all traffic is sent to `serviceBv2`, you can shut down and discontinue the `serviceB` virtual node and actual service. As you change weights, your code does not require any modification, because the `serviceb.apps.local` virtual and actual service names don't change. Recall that the `serviceb.apps.local` virtual service sends traffic to the virtual router, which routes the traffic to the virtual nodes. The service discovery names for the virtual nodes can be changed at any time.

------
#### [ AWS Management Console ]

1. In the left navigation pane, select **Meshes**.

1. Select the `apps` mesh that you created in a previous step.

1. In the left navigation pane, select **Virtual nodes**.

1. Choose **Create virtual node**.

1. For **Virtual node name**, enter **serviceBv2**, for **Service discovery method**, choose **DNS**, and for **DNS hostname**, enter **servicebv2.apps.local**.

1. For **Listener configuration**, select **http2** for **Protocol** and enter **80** for **Port**.

1. Choose **Create virtual node**.

1. Choose **Create virtual node** again. Enter **serviceA** for the **Virtual node name**. For **Service discovery method**, choose **DNS**, and for **DNS hostname**, enter **servicea.apps.local**.

1. For **Enter a virtual service name** under **New backend**, enter **serviceb.apps.local**.

1. Under **Listener configuration**, choose **http2** for **Protocol**, enter **80** for **Port**, and then choose **Create virtual node**.

1. In the left navigation pane, select** Virtual routers** and then select the `serviceB` virtual router from the list.

1. Under **Routes**, select the route named `ServiceB` that you created in a previous step, and choose **Edit**.

1. Under **Targets**, **Virtual node name**, change the value of **Weight** for `serviceB` to **75**.

1. Choose **Add target**, choose `serviceBv2` from the dropdown list, and set the value of **Weight** to **25**.

1. Choose **Save**.

1. In the left navigation pane, select** Virtual services** and then choose **Create virtual service**.

1. Enter **servicea.apps.local** for **Virtual service name**, select **Virtual node** for **Provider**, select `serviceA` for **Virtual node**, and then choose **Create virtual service.**

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

1. Create the `serviceBv2` virtual node.

   1. Create a file named `create-virtual-node-servicebv2.json` with the following contents:

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

   1. Create the virtual node.

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

1. Create the `serviceA` virtual node.

   1. Create a file named `create-virtual-node-servicea.json` with the following contents:

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

   1. Create the virtual node.

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

1. Update the `serviceb.apps.local` virtual service that you created in a previous step to send its traffic to the `serviceB` virtual router. When the virtual service was originally created, it did not send traffic anywhere, since the `serviceB` virtual router had not been created yet.

   1. Create a file named `update-virtual-service.json` with the following contents:

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

   1. Update the virtual service with the [update-virtual-service](https://docs.aws.amazon.com/cli/latest/reference/appmesh/update-virtual-service.html) command.

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

1. Update the `serviceB` route that you created in a previous step.

   1. Create a file named `update-route.json` with the following contents:

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

   1. Update the route with the [update-route](https://docs.aws.amazon.com/cli/latest/reference/appmesh/update-route.html) command.

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

1. Create the `serviceA` virtual service.

   1. Create a file named `create-virtual-servicea.json` with the following contents:

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

   1. Create the virtual service.

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

------

**Mesh summary**  
Before you created the service mesh, you had three actual services named `servicea.apps.local`, `serviceb.apps.local`, and `servicebv2.apps.local`. In addition to the actual services, you now have a service mesh that contains the following resources that represent the actual services:
+ Two virtual services. The proxy sends all traffic from the `servicea.apps.local` virtual service to the `serviceb.apps.local` virtual service through a virtual router. 
+ Three virtual nodes named `serviceA`, `serviceB`, and `serviceBv2`. The Envoy proxy uses the service discovery information configured for the virtual nodes to look up the IP addresses of the actual services. 
+ One virtual router with one route that instructs the Envoy proxy to route 75 percent of inbound traffic to the `serviceB` virtual node and 25 percent of the traffic to the `serviceBv2` virtual node. 

## Step 6: Update services


After creating your mesh, you need to complete the following tasks:
+ Authorize the Envoy proxy that you deploy with each Amazon ECS task to read the configuration of one or more virtual nodes. For more information about how to authorize the proxy, see [Proxy authorization](https://docs.aws.amazon.com/app-mesh/latest/userguide/proxy-authorization.html).
+ Update each of your existing Amazon ECS task definitions to use the Envoy proxy.

**Credentials**  
The Envoy container requires AWS Identity and Access Management credentials for signing requests that are sent to the App Mesh service. For Amazon ECS tasks deployed with the Amazon EC2 launch type, the credentials can come from the [instance role](https://docs.aws.amazon.com/AmazonECS/latest/developerguide/instance_IAM_role.html) or from a [task IAM role](https://docs.aws.amazon.com/AmazonECS/latest/developerguide/task-iam-roles.html). Amazon ECS tasks deployed with Fargate on Linux containers don't have access to the Amazon EC2 metadata server that supplies instance IAM profile credentials. To supply the credentials, you must attach an IAM task role to any tasks deployed with the Fargate on Linux containers type. 

If a task is deployed with the Amazon EC2 launch type and access is blocked to the Amazon EC2 metadata server, as described in the *Important* annotation in [IAM Role for Tasks](https://docs.aws.amazon.com/AmazonECS/latest/developerguide/task-iam-roles.html), then a task IAM role must also be attached to the task. The role that you assign to the instance or task must have an IAM policy attached to it as described in [Proxy authorization](https://docs.aws.amazon.com/app-mesh/latest/userguide/proxy-authorization.html).



**To update your task definition using the AWS CLI**  
You use Amazon ECS AWS CLI command [https://docs.aws.amazon.com/cli/latest/reference/ecs/register-task-definition.html](https://docs.aws.amazon.com/cli/latest/reference/ecs/register-task-definition.html). The example task definition below shows how to configure App Mesh for your service.

**Note**  
Configuring App Mesh for Amazon ECS through the console is unavailable.

### Task definition json


**Proxy configuration**  
To configure your Amazon ECS service to use App Mesh, your service's task definition must have the following proxy configuration section. Set the proxy configuration `type` to `APPMESH` and the `containerName` to `envoy`. Set the following property values accordingly.

`IgnoredUID`  
The Envoy proxy doesn't route traffic from processes that use this user ID. You can choose any user ID that you want for this property value, but this ID must be the same as the `user` ID for the Envoy container in your task definition. This matching allows Envoy to ignore its own traffic without using the proxy. Our examples use `1337` for historical purposes.

`ProxyIngressPort`  
This is the inbound port for the Envoy proxy container. Set this value to `15000`.

`ProxyEgressPort`  
This is the outbound port for the Envoy proxy container. Set this value to `15001`.

`AppPorts`  
Specify any inbound ports that your application containers listen on. In this example, the application container listens on port `9080`. The port that you specify must match the port configured on the virtual node listener.

`EgressIgnoredIPs`  
Envoy doesn't proxy traffic to these IP addresses. Set this value to `169.254.170.2,169.254.169.254`, which ignores the Amazon EC2 metadata server and the Amazon ECS task metadata endpoint. The metadata endpoint provides IAM roles for tasks credentials. You can add additional addresses.

`EgressIgnoredPorts`  
You can add a comma separated list of ports. Envoy doesn't proxy traffic to these ports. Even if you list no ports, port 22 is ignored.  
The maximum number of outbound ports that can be ignored is 15.

```
"proxyConfiguration": {
	"type": "APPMESH",
	"containerName": "envoy",
	"properties": [{
			"name": "IgnoredUID",
			"value": "1337"
		},
		{
			"name": "ProxyIngressPort",
			"value": "15000"
		},
		{
			"name": "ProxyEgressPort",
			"value": "15001"
		},
		{
			"name": "AppPorts",
			"value": "9080"
		},
		{
			"name": "EgressIgnoredIPs",
			"value": "169.254.170.2,169.254.169.254"
		},
		{
			"name": "EgressIgnoredPorts",
			"value": "22"
		}
	]
}
```

**Application container Envoy dependency**  
The application containers in your task definitions must wait for the Envoy proxy to bootstrap and start before they can start. To make sure this happens, you set a `dependsOn` section in each application container definition to wait for the Envoy container to report as `HEALTHY`. The following code shows an application container definition example with this dependency. All of the properties in the following example are required. Some of the property values are also required, but some are *replaceable*.

```
{
	"name": "appName",
	"image": "appImage",
	"portMappings": [{
		"containerPort": 9080,
		"hostPort": 9080,
		"protocol": "tcp"
	}],
	"essential": true,
	"dependsOn": [{
		"containerName": "envoy",
		"condition": "HEALTHY"
	}]
}
```

**Envoy container definition**

Your Amazon ECS task definitions must contain an App Mesh Envoy container image.

All [supported](https://docs.aws.amazon.com/general/latest/gr/appmesh.html) Regions can replace *Region-code* with any Region other than `me-south-1`, `ap-east-1`, `ap-southeast-3`, `eu-south-1`, `il-central-1`, and `af-south-1`.  
Standard  

```
840364872350.dkr.ecr.region-code.amazonaws.com/aws-appmesh-envoy:v1.34.13.0-prod
```
FIPS-compliant  

```
840364872350.dkr.ecr.region-code.amazonaws.com/aws-appmesh-envoy:v1.34.13.0-prod-fips
```

`me-south-1`  
Standard  

```
772975370895.dkr.ecr.me-south-1.amazonaws.com/aws-appmesh-envoy:v1.34.13.0-prod
```

`ap-east-1`  
Standard  

```
856666278305.dkr.ecr.ap-east-1.amazonaws.com/aws-appmesh-envoy:v1.34.13.0-prod
```

`ap-southeast-3`  
Standard  

```
909464085924.dkr.ecr.ap-southeast-3.amazonaws.com/aws-appmesh-envoy:v1.34.13.0-prod
```

`eu-south-1`  
Standard  

```
422531588944.dkr.ecr.eu-south-1.amazonaws.com/aws-appmesh-envoy:v1.34.13.0-prod
```

`il-central-1`  
Standard  

```
564877687649.dkr.ecr.il-central-1.amazonaws.com/aws-appmesh-envoy:v1.34.13.0-prod
```

`af-south-1`  
Standard  

```
924023996002.dkr.ecr.af-south-1.amazonaws.com/aws-appmesh-envoy:v1.34.13.0-prod
```

`Public repository`  
Standard  

```
public.ecr.aws/appmesh/aws-appmesh-envoy:v1.34.13.0-prod
```
FIPS-compliant  

```
public.ecr.aws/appmesh/aws-appmesh-envoy:v1.34.13.0-prod-fips
```

**Important**  
Only version v1.9.0.0-prod or later is supported for use with App Mesh.

You must use the App Mesh Envoy container image until the Envoy project team merges changes that support App Mesh. For additional details, see the [GitHub roadmap issue](https://github.com/aws/aws-app-mesh-roadmap/issues/10).

All of the properties in the following example are required. Some of the property values are also required, but some are *replaceable*.

**Note**  
The Envoy container definition must be marked as `essential`.
We recommend allocating `512` CPU units and at least `64` MiB of memory to the Envoy container. On Fargate the lowest you will be able to set is `1024` MiB of memory.
The virtual node name for the Amazon ECS service must be set to the value of the `APPMESH_RESOURCE_ARN` property. This property requires version `1.15.0` or later of the Envoy image. For more information, see [Envoy image](envoy.md).
The value for the `user` setting must match the `IgnoredUID` value from the task definition proxy configuration. In this example, we use `1337`. 
The health check shown here waits for the Envoy container to bootstrap properly before reporting to Amazon ECS that the Envoy container is healthy and ready for the application containers to start. 
By default, App Mesh uses the name of the resource you specified in `APPMESH_RESOURCE_ARN` when Envoy is referring to itself in metrics and traces. You can override this behavior by setting the `APPMESH_RESOURCE_CLUSTER` environment variable with your own name. This property requires version `1.15.0` or later of the Envoy image. For more information, see [Envoy image](envoy.md).

The following code shows an Envoy container definition example.

```
{
	"name": "envoy",
	"image": "840364872350.dkr.ecr.us-west-2.amazonaws.com/aws-appmesh-envoy:v1.34.13.0-prod",
	"essential": true,
	"environment": [{
		"name": "APPMESH_RESOURCE_ARN",
		"value": "arn:aws:appmesh:us-west-2:111122223333:mesh/apps/virtualNode/serviceB"
	}],
	"healthCheck": {
		"command": [
			"CMD-SHELL",
			"curl -s http://localhost:9901/server_info | grep state | grep -q LIVE"
		],
		"startPeriod": 10,
		"interval": 5,
		"timeout": 2,
		"retries": 3
	},
	"user": "1337"
}
```

**Example task definitions**  
The following example Amazon ECS task definitions show how to merge the examples from above into a task definition for `taskB`. Examples are provided for creating tasks for both Amazon ECS launch types with or without using AWS X-Ray. Change the *replaceable* values, as appropriate, to create task definitions for the tasks named `taskBv2` and `taskA` from the scenario. Substitute your mesh name and virtual node name for the `APPMESH_RESOURCE_ARN` value and a list of ports that your application listens on for the proxy configuration `AppPorts` value. By default, App Mesh uses the name of the resource you specified in `APPMESH_RESOURCE_ARN` when Envoy is referring to itself in metrics and traces. You can override this behavior by setting the `APPMESH_RESOURCE_CLUSTER` environment variable with your own name. All of the properties in the following examples are required. Some of the property values are also required, but some are *replaceable*.

If you're running an Amazon ECS task as described in the Credentials section, then you need to add an existing [task IAM role](https://docs.aws.amazon.com/AmazonECS/latest/developerguide/task-iam-roles.html), to the examples.

**Important**  
Fargate must use a port value greater than 1024.

**Example JSON for Amazon ECS task definition - Fargate on Linux containers**  

```
{
   
   "family" : "taskB",
   "memory" : "1024",
   "cpu" : "0.5 vCPU",
   "proxyConfiguration" : {
      "containerName" : "envoy",
      "properties" : [
         {
            "name" : "ProxyIngressPort",
            "value" : "15000"
         },
         {
            "name" : "AppPorts",
            "value" : "9080"
         },
         {
            "name" : "EgressIgnoredIPs",
            "value" : "169.254.170.2,169.254.169.254"
         },
         {
            "name": "EgressIgnoredPorts",
            "value": "22"
         },
         {
            "name" : "IgnoredUID",
            "value" : "1337"
         },
         {
            "name" : "ProxyEgressPort",
            "value" : "15001"
         }
      ],
      "type" : "APPMESH"
   },
   "containerDefinitions" : [
      {
         "name" : "appName",
         "image" : "appImage",
         "portMappings" : [
            {
               "containerPort" : 9080,
               "protocol" : "tcp"
            }
         ],
         "essential" : true,
         "dependsOn" : [
            {
               "containerName" : "envoy",
               "condition" : "HEALTHY"
            }
         ]
      },
      {         
         "name" : "envoy",
         "image" : "840364872350.dkr.ecr.us-west-2.amazonaws.com/aws-appmesh-envoy:v1.34.13.0-prod",
         "essential" : true,
         "environment" : [
            {
               "name" : "APPMESH_VIRTUAL_NODE_NAME",
               "value" : "mesh/apps/virtualNode/serviceB"
            }
         ],
         "healthCheck" : {
            "command" : [
               "CMD-SHELL",
               "curl -s http://localhost:9901/server_info | grep state | grep -q LIVE"
            ],
            "interval" : 5,
            "retries" : 3,
            "startPeriod" : 10,
            "timeout" : 2
         },
         "memory" : 500,
         "user" : "1337"
      }
   ],
   "requiresCompatibilities" : [ "FARGATE" ],
   "taskRoleArn" : "arn:aws:iam::123456789012:role/ecsTaskRole",
   "executionRoleArn" : "arn:aws:iam::123456789012:role/ecsTaskExecutionRole",
   "networkMode" : "awsvpc"
}
```

**Example JSON for Amazon ECS task definition with AWS X-Ray - Fargate on Linux containers**  
X-Ray allows you to collect data about requests that an application serves and provides tools that you can use to visualize traffic flow. Using the X-Ray driver for Envoy enables Envoy to report tracing information to X-Ray. You can enable X-Ray tracing using the [Envoy configuration](https://docs.aws.amazon.com/app-mesh/latest/userguide/envoy.html). Based on the configuration, Envoy sends tracing data to the X-Ray daemon running as a [sidecar](https://docs.aws.amazon.com/xray/latest/devguide/xray-daemon-ecs.html) container and the daemon forwards the traces to the X-Ray service. Once the traces are published to X-Ray, you can use the X-Ray console to visualize the service call graph and request trace details. The following JSON represents a task definition to enable X-Ray integration.  

```
{
   
   
   "family" : "taskB",
   "memory" : "1024",
   "cpu" : "512",
   "proxyConfiguration" : {
      "containerName" : "envoy",
      "properties" : [
         {
            "name" : "ProxyIngressPort",
            "value" : "15000"
         },
         {
            "name" : "AppPorts",
            "value" : "9080"
         },
         {
            "name" : "EgressIgnoredIPs",
            "value" : "169.254.170.2,169.254.169.254"
         },
         {
            "name": "EgressIgnoredPorts",
            "value": "22"
         },
         {
            "name" : "IgnoredUID",
            "value" : "1337"
         },
         {
            "name" : "ProxyEgressPort",
            "value" : "15001"
         }
      ],
      "type" : "APPMESH"
   },
   "containerDefinitions" : [
      {
         "name" : "appName",
         "image" : "appImage",
         "portMappings" : [
            {
               "containerPort" : 9080,
               "protocol" : "tcp"
            }
         ],
         "essential" : true,
         "dependsOn" : [
            {
               "containerName" : "envoy",
               "condition" : "HEALTHY"
            }
         ]
      },
      {
         
         "name" : "envoy",
         "image" : "840364872350.dkr.ecr.us-west-2.amazonaws.com/aws-appmesh-envoy:v1.34.13.0-prod",
         "essential" : true,
         "environment" : [
            {
               "name" : "APPMESH_VIRTUAL_NODE_NAME",
               "value" : "mesh/apps/virtualNode/serviceB"
            },
            {
               "name": "ENABLE_ENVOY_XRAY_TRACING",
               "value": "1"
            }
         ],
         "healthCheck" : {
            "command" : [
               "CMD-SHELL",
               "curl -s http://localhost:9901/server_info | grep state | grep -q LIVE"
            ],
            "interval" : 5,
            "retries" : 3,
            "startPeriod" : 10,
            "timeout" : 2
         },
         "memory" : 500,
         "user" : "1337"
      },
      {
         "name" : "xray-daemon",
         "image" : "amazon/aws-xray-daemon",
         "user" : "1337",
         "essential" : true,
         "cpu" : "32",
         "memoryReservation" : "256",
         "portMappings" : [
            {
               "containerPort" : 2000,
               "protocol" : "udp"
            }
         ]
      }
   ],
   "requiresCompatibilities" : [ "FARGATE" ],
   "taskRoleArn" : "arn:aws:iam::123456789012:role/ecsTaskRole",
   "executionRoleArn" : "arn:aws:iam::123456789012:role/ecsTaskExecutionRole",
   "networkMode" : "awsvpc"
}
```

**Example JSON for Amazon ECS task definition - EC2 launch type**  

```
{
  "family": "taskB",
  "memory": "256",
  "proxyConfiguration": {
    "type": "APPMESH",
    "containerName": "envoy",
    "properties": [
      {
        "name": "IgnoredUID",
        "value": "1337"
      },
      {
        "name": "ProxyIngressPort",
        "value": "15000"
      },
      {
        "name": "ProxyEgressPort",
        "value": "15001"
      },
      {
        "name": "AppPorts",
        "value": "9080"
      },
      {
        "name": "EgressIgnoredIPs",
        "value": "169.254.170.2,169.254.169.254"
      },
      {
        "name": "EgressIgnoredPorts",
        "value": "22"
      }
    ]
  },
  "containerDefinitions": [
    {
      "name": "appName",
      "image": "appImage",
      "portMappings": [
        {
          "containerPort": 9080,
          "hostPort": 9080,
          "protocol": "tcp"
        }
      ],
      "essential": true,
      "dependsOn": [
        {
          "containerName": "envoy",
          "condition": "HEALTHY"
        }
      ]
    },
    {
      "name": "envoy",
      "image": "840364872350.dkr.ecr.us-west-2.amazonaws.com/aws-appmesh-envoy:v1.34.13.0-prod",
      "essential": true,
      "environment": [
        {
          "name": "APPMESH_VIRTUAL_NODE_NAME",
          "value": "mesh/apps/virtualNode/serviceB"
        }
      ],
      "healthCheck": {
        "command": [
          "CMD-SHELL",
          "curl -s http://localhost:9901/server_info | grep state | grep -q LIVE"
        ],
        "startPeriod": 10,
        "interval": 5,
        "timeout": 2,
        "retries": 3
      },
      "user": "1337"
    }
  ],
  "requiresCompatibilities" : [ "EC2" ],
  "taskRoleArn" : "arn:aws:iam::123456789012:role/ecsTaskRole",
  "executionRoleArn" : "arn:aws:iam::123456789012:role/ecsTaskExecutionRole",
  "networkMode": "awsvpc"
}
```

**Example JSON for Amazon ECS task definition with AWS X-Ray - EC2 launch type**  

```
{
  "family": "taskB",
  "memory": "256",
   "cpu" : "1024",
  "proxyConfiguration": {
    "type": "APPMESH",
    "containerName": "envoy",
    "properties": [
      {
        "name": "IgnoredUID",
        "value": "1337"
      },
      {
        "name": "ProxyIngressPort",
        "value": "15000"
      },
      {
        "name": "ProxyEgressPort",
        "value": "15001"
      },
      {
        "name": "AppPorts",
        "value": "9080"
      },
      {
        "name": "EgressIgnoredIPs",
        "value": "169.254.170.2,169.254.169.254"
      },
      {
        "name": "EgressIgnoredPorts",
        "value": "22"
      }
    ]
  },
  "containerDefinitions": [
    {
      "name": "appName",
      "image": "appImage",
      "portMappings": [
        {
          "containerPort": 9080,
          "hostPort": 9080,
          "protocol": "tcp"
        }
      ],
      "essential": true,
      "dependsOn": [
        {
          "containerName": "envoy",
          "condition": "HEALTHY"
        }
      ]
    },
    {
      "name": "envoy",
      "image": "840364872350.dkr.ecr.us-west-2.amazonaws.com/aws-appmesh-envoy:v1.34.13.0-prod",
      "essential": true,
      "environment": [
        {
          "name": "APPMESH_VIRTUAL_NODE_NAME",
          "value": "mesh/apps/virtualNode/serviceB"
        },
        {
         "name": "ENABLE_ENVOY_XRAY_TRACING",
         "value": "1"
        }
      ],
      "healthCheck": {
        "command": [
          "CMD-SHELL",
          "curl -s http://localhost:9901/server_info | grep state | grep -q LIVE"
        ],
        "startPeriod": 10,
        "interval": 5,
        "timeout": 2,
        "retries": 3
      },
      "user": "1337"
    },
    {
      "name": "xray-daemon",
      "image": "amazon/aws-xray-daemon",
      "user": "1337",
      "essential": true,
      "cpu": 32,
      "memoryReservation": 256,
      "portMappings": [
        {
          "containerPort": 2000,
          "protocol": "udp"
        }
      ]
    }
  ],
  "requiresCompatibilities" : [ "EC2" ],
  "taskRoleArn" : "arn:aws:iam::123456789012:role/ecsTaskRole",
  "executionRoleArn" : "arn:aws:iam::123456789012:role/ecsTaskExecutionRole",
  "networkMode": "awsvpc"
}
```

## Advanced topics


### Canary deployments using App Mesh


Canary deployments and releases help you switch traffic between an old version of an application and a newly deployed version. It also monitors the health of the newly deployed version. If there are any problems with the new version, the canary deployment can automatically switch traffic back to the old version. Canary deployments give you the ability to switch traffic between application versions with more control.

For more information about how to implement canary deployments for Amazon ECS using App Mesh, see [Create a pipeline with canary deployments for Amazon ECS using App Mesh](https://aws.amazon.com/blogs/containers/create-a-pipeline-with-canary-deployments-for-amazon-ecs-using-aws-app-mesh/)

**Note**  
For more examples and walkthroughs for App Mesh, see the [App Mesh examples repository](https://github.com/aws/aws-app-mesh-examples).

# Getting started with AWS App Mesh and Kubernetes
App Mesh and Kubernetes

**Important**  
End of support notice: On September 30, 2026, AWS will discontinue support for AWS App Mesh. After September 30, 2026, you will no longer be able to access the AWS App Mesh console or AWS App Mesh resources. For more information, visit this blog post [Migrating from AWS App Mesh to Amazon ECS Service Connect](https://aws.amazon.com/blogs/containers/migrating-from-aws-app-mesh-to-amazon-ecs-service-connect). 

When you integrate AWS App Mesh with Kubernetes using the App Mesh controller for Kubernetes, you manage App Mesh resources, such as meshes, virtual services, virtual nodes, virtual routers, and routes through Kubernetes. You also automatically add the App Mesh sidecar container images to Kubernetes pod specifications. This tutorial guides you through the installation of the App Mesh controller for Kubernetes to enable this integration.

The controller is accompanied by the deployment of the following Kubernetes custom resource definitions: `meshes`, `virtual services`, `virtual nodes`, and `virtual routers`. The controller watches for creation, modification, and deletion of the custom resources and makes changes to the corresponding App Mesh [Service Meshes](meshes.md), [Virtual services](virtual_services.md), [Virtual nodes](virtual_nodes.md), [Virtual gateways](virtual_gateways.md), [Gateway routes](gateway-routes.md), [Virtual routers](virtual_routers.md) (including [Routes](routes.md)) resources through the App Mesh API. To learn more or contribute to the controller, see the [GitHub project](https://github.com/aws/aws-app-mesh-controller-for-k8s).

The controller also installs a webhook that injects the following containers into Kubernetes pods that are labeled with a name that you specify.
+ **App Mesh Envoy proxy** – Envoy uses the configuration defined in the App Mesh control plane to determine where to send your application traffic. 
+ **App Mesh proxy route manager **– Updates `iptables` rules in a pod's network namespace that route inbound and outbound traffic through Envoy. This container runs as a Kubernetes init container inside of the pod.

## Prerequisites

+ An existing understanding of App Mesh concepts. For more information, see [What Is AWS App Mesh?](what-is-app-mesh.md).
+ An existing understanding of Kubernetes concepts. For more information, see [What is Kubernetes](https://kubernetes.io/docs/concepts/overview/what-is-kubernetes/) in the Kubernetes documentation.
+ An existing Kubernetes cluster. If you don't have an existing cluster, see [Getting Started with Amazon EKS](https://docs.aws.amazon.com/eks/latest/userguide/getting-started.html) in the *Amazon EKS User Guide*. If you're running your own Kubernetes cluster on Amazon EC2, then ensure that Docker is authenticated to the Amazon ECR repository that the Envoy image is in. For more information, see [Envoy image](https://docs.aws.amazon.com/app-mesh/latest/userguide/envoy.html), [Registry authentication](https://docs.aws.amazon.com/AmazonECR/latest/userguide/Registries.html#registry_auth) in the Amazon Elastic Container Registry User Guide, and [Pull an Image from a Private Registry](https://kubernetes.io/docs/tasks/configure-pod-container/pull-image-private-registry/) in the Kubernetes documentation.
+ App Mesh supports Linux services that are registered with DNS, AWS Cloud Map, or both. To use this getting started guide, we recommend that you have three existing services that are registered with DNS. The procedures in this topic assume that the existing services are named `serviceA`, `serviceB`, and `serviceBv2` and that all services are discoverable through a namespace named `apps.local`.

  You can create a service mesh and its resources even if the services don't exist, but you cannot use the mesh until you have deployed actual services.
+ The AWS CLI version 1.18.116 or later or 2.0.38 or later installed. To install or upgrade the AWS CLI, see [Installing the AWS CLI](https://docs.aws.amazon.com/cli/latest/userguide/cli-chap-install.html). 
+ A `kubectl` client that is configured to communicate with your Kubernetes cluster. If you're using Amazon Elastic Kubernetes Service, you can use the instructions for installing `[kubectl](https://docs.aws.amazon.com/eks/latest/userguide/install-kubectl.html)` and configuring a `[kubeconfig](https://docs.aws.amazon.com/eks/latest/userguide/create-kubeconfig.html)` file.
+ Helm version 3.0 or later installed. If you don't have Helm installed, see [Using Helm with Amazon EKS](https://docs.aws.amazon.com/eks/latest/userguide/helm.html) in the *Amazon EKS User Guide*.
+ Amazon EKS currently only supports `IPv4_ONLY` and `IPv6_ONLY` only IP preferences, because Amazon EKS currently only supports pods that are capable of serving either only `IPv4` traffic or only `IPv6` traffic. 

The remaining steps assume that the actual services are named `serviceA`, `serviceB`, and `serviceBv2` and that all services are discoverable through a namespace named `apps.local`.

## Step 1: Install the integration components


Install the integration components one time to each cluster that hosts pods that you want to use with App Mesh.

**To install the integration components**

1. The remaining steps of this procedure require a cluster without a pre-release version of the controller installed. If you have installed a pre-release version, or are not sure whether you have, you can download and run a script that checks to see whether a pre-release version is installed on your cluster.

   ```
   curl -o pre_upgrade_check.sh https://raw.githubusercontent.com/aws/eks-charts/master/stable/appmesh-controller/upgrade/pre_upgrade_check.sh
   sh ./pre_upgrade_check.sh
   ```

   If the script returns `Your cluster is ready for upgrade. Please proceed to the installation instructions` then you can proceed to the next step. If a different message is returned, then you'll need to complete the upgrade steps before continuing. For more information about upgrading a pre-release version, see [Upgrade](https://github.com/aws/eks-charts/blob/master/stable/appmesh-controller/README.md#upgrade) on GitHub.

1. Add the `eks-charts` repository to Helm.

   ```
   helm repo add eks https://aws.github.io/eks-charts
   ```

1. Install the App Mesh Kubernetes custom resource definitions (CRD).

   ```
   kubectl apply -k "https://github.com/aws/eks-charts/stable/appmesh-controller/crds?ref=master"
   ```

1. Create a Kubernetes namespace for the controller.

   ```
   kubectl create ns appmesh-system
   ```

1. Set the following variables for use in later steps. Replace `cluster-name` and `Region-code` with the values for your existing cluster.

   ```
   export CLUSTER_NAME=cluster-name
   export AWS_REGION=Region-code
   ```

1. (Optional) If you want to run the controller on Fargate, then you need to create a Fargate profile. If you don't have `eksctl` installed, see [Installing or Upgrading `eksctl`](https://docs.aws.amazon.com/eks/latest/userguide/eksctl.html#installing-eksctl) in the *Amazon EKS User Guide*. If you'd prefer to create the profile using the console, see [Creating a Fargate profile](https://docs.aws.amazon.com/eks/latest/userguide/fargate-profile.html#create-fargate-profile) in the *Amazon EKS User Guide*.

   ```
   eksctl create fargateprofile --cluster $CLUSTER_NAME --name appmesh-system --namespace appmesh-system
   ```

1. Create an OpenID Connect (OIDC) identity provider for your cluster. If you don't have `eksctl` installed, you can install it with the instructions in [Installing or upgrading `eksctl`](https://docs.aws.amazon.com/eks/latest/userguide/eksctl.html#installing-eksctl) in the *Amazon EKS User Guide*. If you'd prefer to create the provider using the console, see [Enabling IAM roles for service accounts on your cluster](https://docs.aws.amazon.com/eks/latest/userguide/enable-iam-roles-for-service-accounts.html) in the *Amazon EKS User Guide*.

   ```
   eksctl utils associate-iam-oidc-provider \
       --region=$AWS_REGION \
       --cluster $CLUSTER_NAME \
       --approve
   ```

1. Create an IAM role, attach the [https://console.aws.amazon.com/iam/home?#policies/arn:aws:iam::aws:policy/AWSAppMeshFullAccess$jsonEditor](https://console.aws.amazon.com/iam/home?#policies/arn:aws:iam::aws:policy/AWSAppMeshFullAccess$jsonEditor) and [https://console.aws.amazon.com/iam/home?#policies/arn:aws:iam::aws:policy/AWSCloudMapFullAccess$jsonEditor](https://console.aws.amazon.com/iam/home?#policies/arn:aws:iam::aws:policy/AWSCloudMapFullAccess$jsonEditor) AWS managed policies to it, and bind it to the `appmesh-controller` Kubernetes service account. The role enables the controller to add, remove, and change App Mesh resources.
**Note**  
The command creates an AWS IAM role with an auto-generated name. You are not able to specify the IAM role name that is created.

   ```
   eksctl create iamserviceaccount \
       --cluster $CLUSTER_NAME \
       --namespace appmesh-system \
       --name appmesh-controller \
       --attach-policy-arn  arn:aws:iam::aws:policy/AWSCloudMapFullAccess,arn:aws:iam::aws:policy/AWSAppMeshFullAccess \
       --override-existing-serviceaccounts \
       --approve
   ```

   If you prefer to create the service account using the AWS Management Console or AWS CLI, see [Creating an IAM role and policy for your service account](https://docs.aws.amazon.com/eks/latest/userguide/create-service-account-iam-policy-and-role.html#create-service-account-iam-role) in the *Amazon EKS User Guide*. If you use the AWS Management Console or AWS CLI to create the account, you also need to map the role to a Kubernetes service account. For more information, see [Specifying an IAM role for your service account](https://docs.aws.amazon.com/eks/latest/userguide/specify-service-account-role.html) in the *Amazon EKS User Guide*. 

1. 

**Deploy the App Mesh controller. For a list of all configuration options, see [Configuration](https://github.com/aws/eks-charts/blob/master/stable/appmesh-controller/README.md#configuration) on GitHub.**

   1. To deploy the App Mesh controller for a private cluster, you have to enable App Mesh and service discovery Amazon VPC endpoints to the linked private subnet first. You're also required to set the `accountId`.

      ```
      --set accountId=$AWS_ACCOUNT_ID
      ```

      To enable X-Ray tracing in a private cluster, enable the X-Ray and Amazon ECR Amazon VPC endpoints. The controller uses `public.ecr.aws/xray/aws-xray-daemon:latest` by default, so pull this image to local and [push it into your personal ECR repository](https://docs.aws.amazon.com/AmazonECR/latest/userguide/docker-push-ecr-image.html).
**Note**  
[Amazon VPC endpoints](https://docs.aws.amazon.com/AmazonECR/latest/userguide/vpc-endpoints.html) currently don't support Amazon ECR public repositories.

      The following example shows deploying the controller with configurations for X-Ray.

      ```
      helm upgrade -i appmesh-controller eks/appmesh-controller \
          --namespace appmesh-system \
          --set region=$AWS_REGION \
          --set serviceAccount.create=false \
          --set serviceAccount.name=appmesh-controller \
          --set accountId=$AWS_ACCOUNT_ID \
          --set log.level=debug \
          --set tracing.enabled=true \
          --set tracing.provider=x-ray \
          --set xray.image.repository=your-account-id.dkr.ecr.your-region.amazonaws.com/your-repository \
          --set xray.image.tag=your-xray-daemon-image-tag
      ```

      Verify if the X-Ray daemon is injected successfully when binding the application deployment with your virtual node or gateway.

      For more information, see [Private Clusters](https://docs.aws.amazon.com/eks/latest/userguide/private-clusters.html) in the *Amazon EKS User Guide*.

   1. Deploy the App Mesh controller for other clusters. For a list of all configuration options, see [Configuration](https://github.com/aws/eks-charts/blob/master/stable/appmesh-controller/README.md#configuration) on GitHub.

      ```
      helm upgrade -i appmesh-controller eks/appmesh-controller \
          --namespace appmesh-system \
          --set region=$AWS_REGION \
          --set serviceAccount.create=false \
          --set serviceAccount.name=appmesh-controller
      ```
**Note**  
If your Amazon EKS cluster family is `IPv6`, please set the cluster name when deploying the App Mesh controller by adding the following option to the previous command `--set clusterName=$CLUSTER_NAME`.
**Important**  
If your cluster is in the `me-south-1`, `ap-east-1`, `ap-southeast-3`, `eu-south-1`, `il-central-1`, or `af-south-1` Regions, then you need to add the following option to the previous command:  
Replace *account-id* and *Region-code* with one of the appropriate sets of values.  

       ```
        --set image.repository=account-id.dkr.ecr.Region-code.amazonaws.com/amazon/appmesh-controller
       ```
772975370895.dkr.ecr.me-south-1.amazonaws.com/aws-appmesh-envoy:v1.34.13.0-prod
856666278305.dkr.ecr.ap-east-1.amazonaws.com/aws-appmesh-envoy:v1.34.13.0-prod
909464085924.dkr.ecr.ap-southeast-3.amazonaws.com/aws-appmesh-envoy:v1.34.13.0-prod
422531588944.dkr.ecr.eu-south-1.amazonaws.com/aws-appmesh-envoy:v1.34.13.0-prod
564877687649.dkr.ecr.il-central-1.amazonaws.com/aws-appmesh-envoy:v1.34.13.0-prod
924023996002.dkr.ecr.af-south-1.amazonaws.com/aws-appmesh-envoy:v1.34.13.0-prod
The older image URIs can be found in the [change log](https://github.com/aws/aws-app-mesh-controller-for-k8s/releases) on GitHub. The AWS accounts on which the images are present have changed in version `v1.5.0`. Older version of the images are hosted on AWS accounts found on the Amazon Elastic Kubernetes Service [Amazon container image registries](https://docs.aws.amazon.com/eks/latest/userguide/add-ons-images.html).

       ```
       --set sidecar.image.repository=account-id.dkr.ecr.Region-code.amazonaws.com/aws-appmesh-envoy
       ```
772975370895.dkr.ecr.me-south-1.amazonaws.com/amazon/appmesh-controller:v1.13.1
856666278305.dkr.ecr.ap-east-1.amazonaws.com/amazon/appmesh-controller:v1.13.1
909464085924.dkr.ecr.ap-southeast-3.amazonaws.com/amazon/appmesh-controller:v1.13.1
422531588944.dkr.ecr.eu-south-1.amazonaws.com/amazon/appmesh-controller:v1.13.1
564877687649.dkr.ecr.il-central-1.amazonaws.com/amazon/appmesh-controller:v1.13.1
924023996002.dkr.ecr.af-south-1.amazonaws.com/amazon/appmesh-controller:v1.13.1

       ```
       --set sidecar.image.repository=account-id.dkr.ecr.Region-code.amazonaws.com/aws-appmesh-envoy
       ```
772975370895.dkr.ecr.me-south-1.amazonaws.com/aws-appmesh-proxy-route-manager:v7-prod
856666278305.dkr.ecr.ap-east-1.amazonaws.com/aws-appmesh-proxy-route-manager:v7-prod
909464085924.dkr.ecr.ap-southeast-3.amazonaws.com/aws-appmesh-proxy-route-manager:v7-prod
422531588944.dkr.ecr.eu-south-1.amazonaws.com/aws-appmesh-proxy-route-manager:v7-prod
564877687649.dkr.ecr.il-central-1.amazonaws.com/aws-appmesh-proxy-route-manager:v7-prod
924023996002.dkr.ecr.af-south-1.amazonaws.com/aws-appmesh-proxy-route-manager:v7-prod
**Important**  
Only version v1.9.0.0-prod or later is supported for use with App Mesh.

1. Confirm that the controller version is `v1.4.0` or later. You can review the [change log](https://github.com/aws/aws-app-mesh-controller-for-k8s/releases) on GitHub.

   ```
   kubectl get deployment appmesh-controller \
       -n appmesh-system \
       -o json  | jq -r ".spec.template.spec.containers[].image" | cut -f2 -d ':'
   ```
**Note**  
If you view the log for the running container, you may see a line that includes the following text, which can be safely ignored.  

   ```
   Neither -kubeconfig nor -master was specified. Using the inClusterConfig. This might not work.
   ```

## Step 2: Deploy App Mesh resources


When you deploy an application in Kubernetes, you also create the Kubernetes custom resources so that the controller can create the corresponding App Mesh resources. The following procedure helps you deploy App Mesh resources with some of their features. You can find example manifests for deploying other App Mesh resource features in the `v1beta2` sub-folders of many of the feature folders listed at [App Mesh walkthroughs](https://github.com/aws/aws-app-mesh-examples/tree/main/walkthroughs) on GitHub.

**Important**  
Once the controller has created an App Mesh resource, we recommend that you only make changes to or delete the App Mesh resource using the controller. If you make changes to or delete the resource using App Mesh, the controller won't change or recreate the changed or deleted App Mesh resource for ten hours, by default. You can configure this duration to be less. For more information, see [Configuration](https://github.com/aws/eks-charts/blob/master/stable/appmesh-controller/README.md#configuration) on GitHub.

**To deploy App Mesh resources**

1. Create a Kubernetes namespace to deploy App Mesh resources to. 

   1. Save the following contents to a file named `namespace.yaml` on your computer.

      ```
      apiVersion: v1
      kind: Namespace
      metadata:
        name: my-apps
        labels:
          mesh: my-mesh
          appmesh.k8s.aws/sidecarInjectorWebhook: enabled
      ```

   1. Create the namespace.

      ```
      kubectl apply -f namespace.yaml
      ```

1. Create an App Mesh service mesh.

   1. Save the following contents to a file named `mesh.yaml` on your computer. The file is used to create a mesh resource named `my-mesh`. A service mesh is a logical boundary for network traffic between the services that reside within it.

      ```
      apiVersion: appmesh.k8s.aws/v1beta2
      kind: Mesh
      metadata:
        name: my-mesh
      spec:
        namespaceSelector:
          matchLabels:
            mesh: my-mesh
      ```

   1. Create the mesh.

      ```
      kubectl apply -f mesh.yaml
      ```

   1. View the details of the Kubernetes mesh resource that was created.

      ```
      kubectl describe mesh my-mesh
      ```

      Output

      ```
      Name:         my-mesh
      Namespace:
      Labels:       <none>
      Annotations:  kubectl.kubernetes.io/last-applied-configuration:
                      {"apiVersion":"appmesh.k8s.aws/v1beta2","kind":"Mesh","metadata":{"annotations":{},"name":"my-mesh"},"spec":{"namespaceSelector":{"matchLa...
      API Version:  appmesh.k8s.aws/v1beta2
      Kind:         Mesh
      Metadata:
        Creation Timestamp:  2020-06-17T14:51:37Z
        Finalizers:
          finalizers.appmesh.k8s.aws/mesh-members
          finalizers.appmesh.k8s.aws/aws-appmesh-resources
        Generation:        1
        Resource Version:  6295
        Self Link:         /apis/appmesh.k8s.aws/v1beta2/meshes/my-mesh
        UID:               111a11b1-c11d-1e1f-gh1i-j11k1l111m711
      Spec:
        Aws Name:  my-mesh
        Namespace Selector:
          Match Labels:
            Mesh:  my-mesh
      Status:
        Conditions:
          Last Transition Time:  2020-06-17T14:51:37Z
          Status:                True
          Type:                  MeshActive
        Mesh ARN:                arn:aws:appmesh:us-west-2:111122223333:mesh/my-mesh
        Observed Generation:     1
      Events:                    <none>
      ```

   1. View the details about the App Mesh service mesh that the controller created.

      ```
      aws appmesh describe-mesh --mesh-name my-mesh
      ```

      Output

      ```
      {
          "mesh": {
              "meshName": "my-mesh",
              "metadata": {
                  "arn": "arn:aws:appmesh:us-west-2:111122223333:mesh/my-mesh",
                  "createdAt": "2020-06-17T09:51:37.920000-05:00",
                  "lastUpdatedAt": "2020-06-17T09:51:37.920000-05:00",
                  "meshOwner": "111122223333",
                  "resourceOwner": "111122223333",
                  "uid": "111a11b1-c11d-1e1f-gh1i-j11k1l111m711",
                  "version": 1
              },
              "spec": {},
              "status": {
                  "status": "ACTIVE"
              }
          }
      }
      ```

1. Create an App Mesh virtual node. A virtual node acts as a logical pointer to a Kubernetes deployment.

   1. Save the following contents to a file named `virtual-node.yaml` on your computer. The file is used to create an App Mesh virtual node named `my-service-a` in the *`my-apps`* namespace. The virtual node represents a Kubernetes service that is created in a later step. The value for `hostname` is the fully qualified DNS hostname of the actual service that this virtual node represents.

      ```
      apiVersion: appmesh.k8s.aws/v1beta2
      kind: VirtualNode
      metadata:
        name: my-service-a
        namespace: my-apps
      spec:
        podSelector:
          matchLabels:
            app: my-app-1
        listeners:
          - portMapping:
              port: 80
              protocol: http
        serviceDiscovery:
          dns:
            hostname: my-service-a.my-apps.svc.cluster.local
      ```

      Virtual nodes have capabilities, such as end-to-end encryption and health checks, that aren't covered in this tutorial. For more information, see [Virtual nodes](virtual_nodes.md). To see all available settings for a virtual node that you can set in the preceding spec, run the following command.

      ```
      aws appmesh create-virtual-node --generate-cli-skeleton yaml-input
      ```

   1. Deploy the virtual node.

      ```
      kubectl apply -f virtual-node.yaml
      ```

   1. View the details of the Kubernetes virtual node resource that was created.

      ```
      kubectl describe virtualnode my-service-a -n my-apps
      ```

      Output

      ```
      Name:         my-service-a
      Namespace:    my-apps
      Labels:       <none>
      Annotations:  kubectl.kubernetes.io/last-applied-configuration:
                      {"apiVersion":"appmesh.k8s.aws/v1beta2","kind":"VirtualNode","metadata":{"annotations":{},"name":"my-service-a","namespace":"my-apps"},"s...
      API Version:  appmesh.k8s.aws/v1beta2
      Kind:         VirtualNode
      Metadata:
        Creation Timestamp:  2020-06-17T14:57:29Z
        Finalizers:
          finalizers.appmesh.k8s.aws/aws-appmesh-resources
        Generation:        2
        Resource Version:  22545
        Self Link:         /apis/appmesh.k8s.aws/v1beta2/namespaces/my-apps/virtualnodes/my-service-a
        UID:               111a11b1-c11d-1e1f-gh1i-j11k1l111m711
      Spec:
        Aws Name:  my-service-a_my-apps
        Listeners:
          Port Mapping:
            Port:      80
            Protocol:  http
        Mesh Ref:
          Name:  my-mesh
          UID:   111a11b1-c11d-1e1f-gh1i-j11k1l111m711
        Pod Selector:
          Match Labels:
            App:  nginx
        Service Discovery:
          Dns:
            Hostname:  my-service-a.my-apps.svc.cluster.local
      Status:
        Conditions:
          Last Transition Time:  2020-06-17T14:57:29Z
          Status:                True
          Type:                  VirtualNodeActive
        Observed Generation:     2
        Virtual Node ARN:        arn:aws:appmesh:us-west-2:111122223333:mesh/my-mesh/virtualNode/my-service-a_my-apps
      Events:                    <none>
      ```

   1. View the details of the virtual node that the controller created in App Mesh.
**Note**  
Even though the name of the virtual node created in Kubernetes is `my-service-a`, the name of the virtual node created in App Mesh is `my-service-a_my-apps`. The controller appends the Kubernetes namespace name to the App Mesh virtual node name when it creates the App Mesh resource. The namespace name is added because in Kubernetes you can create virtual nodes with the same name in different namespaces, but in App Mesh a virtual node name must be unique within a mesh.

      ```
      aws appmesh describe-virtual-node --mesh-name my-mesh --virtual-node-name my-service-a_my-apps
      ```

      Output

      ```
      {
          "virtualNode": {
              "meshName": "my-mesh",
              "metadata": {
                  "arn": "arn:aws:appmesh:us-west-2:111122223333:mesh/my-mesh/virtualNode/my-service-a_my-apps",
                  "createdAt": "2020-06-17T09:57:29.840000-05:00",
                  "lastUpdatedAt": "2020-06-17T09:57:29.840000-05:00",
                  "meshOwner": "111122223333",
                  "resourceOwner": "111122223333",
                  "uid": "111a11b1-c11d-1e1f-gh1i-j11k1l111m711",
                  "version": 1
              },
              "spec": {
                  "backends": [],
                  "listeners": [
                      {
                          "portMapping": {
                              "port": 80,
                              "protocol": "http"
                          }
                      }
                  ],
                  "serviceDiscovery": {
                      "dns": {
                          "hostname": "my-service-a.my-apps.svc.cluster.local"
                      }
                  }
              },
              "status": {
                  "status": "ACTIVE"
              },
              "virtualNodeName": "my-service-a_my-apps"
          }
      }
      ```

1. Create an App Mesh virtual router. Virtual routers handle traffic for one or more virtual services within your mesh.

   1. Save the following contents to a file named `virtual-router.yaml` on your computer. The file is used to create a virtual router to route traffic to the virtual node named `my-service-a` that was created in the previous step. The controller creates the App Mesh virtual router and route resources. You can specify many more capabilities for your routes and use protocols other than `http`. For more information, see [Virtual routers](virtual_routers.md) and [Routes](routes.md). Notice that the virtual node name referenced is the Kubernetes virtual node name, not the App Mesh virtual node name that was created in App Mesh by the controller.

      ```
      apiVersion: appmesh.k8s.aws/v1beta2
      kind: VirtualRouter
      metadata:
        namespace: my-apps
        name: my-service-a-virtual-router
      spec:
        listeners:
          - portMapping:
              port: 80
              protocol: http
        routes:
          - name: my-service-a-route
            httpRoute:
              match:
                prefix: /
              action:
                weightedTargets:
                  - virtualNodeRef:
                      name: my-service-a
                    weight: 1
      ```

      (Optional) To see all available settings for a virtual router that you can set in the preceding spec, run the following command.

      ```
      aws appmesh create-virtual-router --generate-cli-skeleton yaml-input
      ```

      To see all available settings for a route that you can set in the preceding spec, run the following command.

      ```
      aws appmesh create-route --generate-cli-skeleton yaml-input
      ```

   1. Deploy the virtual router.

      ```
      kubectl apply -f virtual-router.yaml
      ```

   1. View the Kubernetes virtual router resource that was created.

      ```
      kubectl describe virtualrouter my-service-a-virtual-router -n my-apps
      ```

      Abbreviated output

      ```
      Name:         my-service-a-virtual-router
      Namespace:    my-apps
      Labels:       <none>
      Annotations:  kubectl.kubernetes.io/last-applied-configuration:
                      {"apiVersion":"appmesh.k8s.aws/v1beta2","kind":"VirtualRouter","metadata":{"annotations":{},"name":"my-service-a-virtual-router","namespac...
      API Version:  appmesh.k8s.aws/v1beta2
      Kind:         VirtualRouter
      ...
      Spec:
        Aws Name:  my-service-a-virtual-router_my-apps
        Listeners:
          Port Mapping:
            Port:      80
            Protocol:  http
        Mesh Ref:
          Name:  my-mesh
          UID:   111a11b1-c11d-1e1f-gh1i-j11k1l111m711
        Routes:
          Http Route:
            Action:
              Weighted Targets:
                Virtual Node Ref:
                  Name:  my-service-a
                Weight:  1
            Match:
              Prefix:  /
          Name:        my-service-a-route
      Status:
        Conditions:
          Last Transition Time:  2020-06-17T15:14:01Z
          Status:                True
          Type:                  VirtualRouterActive
        Observed Generation:     1
        Route AR Ns:
          My - Service - A - Route:  arn:aws:appmesh:us-west-2:111122223333:mesh/my-mesh/virtualRouter/my-service-a-virtual-router_my-apps/route/my-service-a-route
        Virtual Router ARN:          arn:aws:appmesh:us-west-2:111122223333:mesh/my-mesh/virtualRouter/my-service-a-virtual-router_my-apps
      Events:                        <none>
      ```

   1. View the virtual router resource that the controller created in App Mesh. You specify `my-service-a-virtual-router_my-apps` for `name`, because when the controller created the virtual router in App Mesh, it appended the Kubernetes namespace name to the name of the virtual router.

      ```
      aws appmesh describe-virtual-router --virtual-router-name my-service-a-virtual-router_my-apps --mesh-name my-mesh
      ```

      Output

      ```
      {
          "virtualRouter": {
              "meshName": "my-mesh",
              "metadata": {
                  "arn": "arn:aws:appmesh:us-west-2:111122223333:mesh/my-mesh/virtualRouter/my-service-a-virtual-router_my-apps",
                  "createdAt": "2020-06-17T10:14:01.547000-05:00",
                  "lastUpdatedAt": "2020-06-17T10:14:01.547000-05:00",
                  "meshOwner": "111122223333",
                  "resourceOwner": "111122223333",
                  "uid": "111a11b1-c11d-1e1f-gh1i-j11k1l111m711",
                  "version": 1
              },
              "spec": {
                  "listeners": [
                      {
                          "portMapping": {
                              "port": 80,
                              "protocol": "http"
                          }
                      }
                  ]
              },
              "status": {
                  "status": "ACTIVE"
              },
              "virtualRouterName": "my-service-a-virtual-router_my-apps"
          }
      }
      ```

   1. View the route resource that the controller created in App Mesh. A route resource was not created in Kubernetes because the route is part of the virtual router configuration in Kubernetes. The route information was shown in the Kubernetes resource detail in sub-step `c`. The controller did not append the Kubernetes namespace name to the App Mesh route name when it created the route in App Mesh because route names are unique to a virtual router.

      ```
      aws appmesh describe-route \
          --route-name my-service-a-route \
          --virtual-router-name my-service-a-virtual-router_my-apps \
          --mesh-name my-mesh
      ```

      Output

      ```
      {
          "route": {
              "meshName": "my-mesh",
              "metadata": {
                  "arn": "arn:aws:appmesh:us-west-2:111122223333:mesh/my-mesh/virtualRouter/my-service-a-virtual-router_my-apps/route/my-service-a-route",
                  "createdAt": "2020-06-17T10:14:01.577000-05:00",
                  "lastUpdatedAt": "2020-06-17T10:14:01.577000-05:00",
                  "meshOwner": "111122223333",
                  "resourceOwner": "111122223333",
                  "uid": "111a11b1-c11d-1e1f-gh1i-j11k1l111m711",
                  "version": 1
              },
              "routeName": "my-service-a-route",
              "spec": {
                  "httpRoute": {
                      "action": {
                          "weightedTargets": [
                              {
                                  "virtualNode": "my-service-a_my-apps",
                                  "weight": 1
                              }
                          ]
                      },
                      "match": {
                          "prefix": "/"
                      }
                  }
              },
              "status": {
                  "status": "ACTIVE"
              },
              "virtualRouterName": "my-service-a-virtual-router_my-apps"
          }
      }
      ```

1. Create an App Mesh virtual service. A virtual service is an abstraction of a real service that is provided by a virtual node directly or indirectly by means of a virtual router. Dependent services call your virtual service by its name. Though the name doesn't matter to App Mesh, we recommend naming the virtual service the fully qualified domain name of the actual service that the virtual service represents. By naming your virtual services this way, you don't need to change your application code to reference a different name. The requests are routed to the virtual node or virtual router that is specified as the provider for the virtual service.

   1. Save the following contents to a file named `virtual-service.yaml` on your computer. The file is used to create a virtual service that uses a virtual router provider to route traffic to the virtual node named `my-service-a` that was created in a previous step. The value for `awsName` in the `spec` is the fully qualified domain name (FQDN) of the actual Kubernetes service that this virtual service abstracts. The Kubernetes service is created in [Step 3: Create or update services](#create-update-services). For more information, see [Virtual services](virtual_services.md).

      ```
      apiVersion: appmesh.k8s.aws/v1beta2
      kind: VirtualService
      metadata:
        name: my-service-a
        namespace: my-apps
      spec:
        awsName: my-service-a.my-apps.svc.cluster.local
        provider:
          virtualRouter:
            virtualRouterRef:
              name: my-service-a-virtual-router
      ```

      To see all available settings for a virtual service that you can set in the preceding spec, run the following command.

      ```
      aws appmesh create-virtual-service --generate-cli-skeleton yaml-input
      ```

   1. Create the virtual service.

      ```
      kubectl apply -f virtual-service.yaml
      ```

   1. View the details of the Kubernetes virtual service resource that was created.

      ```
      kubectl describe virtualservice my-service-a -n my-apps
      ```

      Output

      ```
      Name:         my-service-a
      Namespace:    my-apps
      Labels:       <none>
      Annotations:  kubectl.kubernetes.io/last-applied-configuration:
                      {"apiVersion":"appmesh.k8s.aws/v1beta2","kind":"VirtualService","metadata":{"annotations":{},"name":"my-service-a","namespace":"my-apps"}...
      API Version:  appmesh.k8s.aws/v1beta2
      Kind:         VirtualService
      Metadata:
        Creation Timestamp:  2020-06-17T15:48:40Z
        Finalizers:
          finalizers.appmesh.k8s.aws/aws-appmesh-resources
        Generation:        1
        Resource Version:  13598
        Self Link:         /apis/appmesh.k8s.aws/v1beta2/namespaces/my-apps/virtualservices/my-service-a
        UID:               111a11b1-c11d-1e1f-gh1i-j11k1l111m711
      Spec:
        Aws Name:  my-service-a.my-apps.svc.cluster.local
        Mesh Ref:
          Name:  my-mesh
          UID:   111a11b1-c11d-1e1f-gh1i-j11k1l111m711
        Provider:
          Virtual Router:
            Virtual Router Ref:
              Name:  my-service-a-virtual-router
      Status:
        Conditions:
          Last Transition Time:  2020-06-17T15:48:40Z
          Status:                True
          Type:                  VirtualServiceActive
        Observed Generation:     1
        Virtual Service ARN:     arn:aws:appmesh:us-west-2:111122223333:mesh/my-mesh/virtualService/my-service-a.my-apps.svc.cluster.local
      Events:                    <none>
      ```

   1. View the details of the virtual service resource that the controller created in App Mesh. The Kubernetes controller did not append the Kubernetes namespace name to the App Mesh virtual service name when it created the virtual service in App Mesh because the virtual service's name is a unique FQDN.

      ```
      aws appmesh describe-virtual-service --virtual-service-name my-service-a.my-apps.svc.cluster.local --mesh-name my-mesh
      ```

      Output

      ```
      {
          "virtualService": {
              "meshName": "my-mesh",
              "metadata": {
                  "arn": "arn:aws:appmesh:us-west-2:111122223333:mesh/my-mesh/virtualService/my-service-a.my-apps.svc.cluster.local",
                  "createdAt": "2020-06-17T10:48:40.182000-05:00",
                  "lastUpdatedAt": "2020-06-17T10:48:40.182000-05:00",
                  "meshOwner": "111122223333",
                  "resourceOwner": "111122223333",
                  "uid": "111a11b1-c11d-1e1f-gh1i-j11k1l111m711",
                  "version": 1
              },
              "spec": {
                  "provider": {
                      "virtualRouter": {
                          "virtualRouterName": "my-service-a-virtual-router_my-apps"
                      }
                  }
              },
              "status": {
                  "status": "ACTIVE"
              },
              "virtualServiceName": "my-service-a.my-apps.svc.cluster.local"
          }
      }
      ```

Though not covered in this tutorial, the controller can also deploy App Mesh [Virtual gateways](virtual_gateways.md) and [Gateway routes](gateway-routes.md). For a walkthrough of deploying these resources with the controller, see [Configuring Inbound Gateway](https://github.com/aws/aws-app-mesh-examples/tree/main/walkthroughs/howto-k8s-ingress-gateway), or a [sample manifest](https://github.com/aws/aws-app-mesh-examples/blob/main/walkthroughs/howto-k8s-ingress-gateway/v1beta2/manifest.yaml.template) that includes the resources on GitHub.

## Step 3: Create or update services


Any pods that you want to use with App Mesh must have the App Mesh sidecar containers added to them. The injector automatically adds the sidecar containers to any pod deployed with a label that you specify.

1. Enable proxy authorization. We recommend that you enable each Kubernetes deployment to stream only the configuration for its own App Mesh virtual node.

   1. Save the following contents to a file named `proxy-auth.json` on your computer. Make sure to replace the *alternate-colored values* with your own.

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

****  

      ```
      {
          "Version":"2012-10-17",		 	 	 
          "Statement": [
              {
                  "Effect": "Allow",
                  "Action": "appmesh:StreamAggregatedResources",
                  "Resource": [
                      "arn:aws:appmesh:us-east-1:111122223333:mesh/my-mesh/virtualNode/my-service-a_my-apps"
                  ]
              }
          ]
      }
      ```

------

   1. Create the policy.

      ```
      aws iam create-policy --policy-name my-policy --policy-document file://proxy-auth.json
      ```

   1. Create an IAM role, attach the policy you created in the previous step to it, create a Kubernetes service account, and bind the policy to the Kubernetes service account. The role enables the controller to add, remove, and change App Mesh resources.

      ```
      eksctl create iamserviceaccount \
          --cluster $CLUSTER_NAME \
          --namespace my-apps \
          --name my-service-a \
          --attach-policy-arn  arn:aws:iam::111122223333:policy/my-policy \
          --override-existing-serviceaccounts \
          --approve
      ```

      If you prefer to create the service account using the AWS Management Console or AWS CLI, see [Creating an IAM Role and policy for your service account](https://docs.aws.amazon.com/eks/latest/userguide/create-service-account-iam-policy-and-role.html#create-service-account-iam-role) in the *Amazon EKS User Guide*. If you use the AWS Management Console or AWS CLI to create the account, you also need to map the role to a Kubernetes service account. For more information, see [Specifying an IAM role for your service account](https://docs.aws.amazon.com/eks/latest/userguide/specify-service-account-role.html) in the *Amazon EKS User Guide*.

1. (Optional) If you want to deploy your deployment to Fargate pods, then you need to create a Fargate profile. If you don't have `eksctl` installed, you can install it with the instructions in [Installing or Upgrading `eksctl`](https://docs.aws.amazon.com/eks/latest/userguide/eksctl.html#installing-eksctl) in the *Amazon EKS User Guide*. If you'd prefer to create the profile using the console, see [Creating a Fargate profile](https://docs.aws.amazon.com/eks/latest/userguide/fargate-profile.html#create-fargate-profile) in the *Amazon EKS User Guide*.

   ```
   eksctl create fargateprofile --cluster my-cluster --region Region-code --name my-service-a --namespace my-apps
   ```

1. Create a Kubernetes service and deployment. If you have an existing deployment that you want to use with App Mesh, then you need to deploy a virtual node, as you did in sub-step `3` of [Step 2: Deploy App Mesh resources](#configure-app-mesh). Update your deployment to make sure that its label matches the label that you set on the virtual node, so that the sidecar containers are automatically added to the pods and the pods are redeployed.

   1. Save the following contents to a file named `example-service.yaml` on your computer. If you change the namespace name and are using Fargate pods, make sure that the namespace name matches the namespace name that you defined in your Fargate profile.

      ```
      apiVersion: v1
      kind: Service
      metadata:
        name: my-service-a
        namespace: my-apps
        labels:
          app: my-app-1
      spec:
        selector:
          app: my-app-1
        ports:
          - protocol: TCP
            port: 80
            targetPort: 80
      ---
      apiVersion: apps/v1
      kind: Deployment
      metadata:
        name: my-service-a
        namespace: my-apps
        labels:
          app: my-app-1
      spec:
        replicas: 3
        selector:
          matchLabels:
            app: my-app-1
        template:
          metadata:
            labels:
              app: my-app-1
          spec:
            serviceAccountName: my-service-a
            containers:
            - name: nginx
              image: nginx:1.19.0
              ports:
              - containerPort: 80
      ```
**Important**  
The value for the `app` `matchLabels` `selector` in the spec must match the value that you specified when you created the virtual node in sub-step `3` of [Step 2: Deploy App Mesh resources](#configure-app-mesh), or the sidecar containers won't be injected into the pod. In the previous example, the value for the label is `my-app-1`. If you deploy a virtual gateway, rather than a virtual node, then the `Deployment` manifest should include only the Envoy container. For more information about the image to use, see [Envoy image](envoy.md). For a sample manfest, see the [deployment example](https://github.com/aws/aws-app-mesh-examples/blob/main/walkthroughs/howto-k8s-ingress-gateway/v1beta2/manifest.yaml.template#L585) on GitHub.

   1. Deploy the service.

      ```
      kubectl apply -f example-service.yaml
      ```

   1. View the service and deployment.

      ```
      kubectl -n my-apps get pods
      ```

      Output

      ```
      NAME                            READY   STATUS    RESTARTS   AGE
      my-service-a-54776556f6-2cxd9   2/2     Running   0          10s
      my-service-a-54776556f6-w26kf   2/2     Running   0          18s
      my-service-a-54776556f6-zw5kt   2/2     Running   0          26s
      ```

   1. View the details for one of the pods that was deployed.

      ```
      kubectl -n my-apps describe pod my-service-a-54776556f6-2cxd9
      ```

      Abbreviated output

      ```
      Name:         my-service-a-54776556f6-2cxd9
      Namespace:    my-app-1
      Priority:     0
      Node:         ip-192-168-44-157.us-west-2.compute.internal/192.168.44.157
      Start Time:   Wed, 17 Jun 2020 11:08:59 -0500
      Labels:       app=nginx
                    pod-template-hash=54776556f6
      Annotations:  kubernetes.io/psp: eks.privileged
      Status:       Running
      IP:           192.168.57.134
      IPs:
        IP:           192.168.57.134
      Controlled By:  ReplicaSet/my-service-a-54776556f6
      Init Containers:
        proxyinit:
          Container ID:   docker://e0c4810d584c21ae0cb6e40f6119d2508f029094d0e01c9411c6cf2a32d77a59
          Image:          111345817488.dkr.ecr.us-west-2.amazonaws.com/aws-appmesh-proxy-route-manager:v2
          Image ID:       docker-pullable://111345817488.dkr.ecr.us-west-2.amazonaws.com/aws-appmesh-proxy-route-manager
          Port:           <none>
          Host Port:      <none>
          State:          Terminated
            Reason:       Completed
            Exit Code:    0
            Started:      Fri, 26 Jun 2020 08:36:22 -0500
            Finished:     Fri, 26 Jun 2020 08:36:22 -0500
          Ready:          True
          Restart Count:  0
          Requests:
            cpu:     10m
            memory:  32Mi
          Environment:
            APPMESH_START_ENABLED:         1
            APPMESH_IGNORE_UID:            1337
            APPMESH_ENVOY_INGRESS_PORT:    15000
            APPMESH_ENVOY_EGRESS_PORT:     15001
            APPMESH_APP_PORTS:             80
            APPMESH_EGRESS_IGNORED_IP:     169.254.169.254
            APPMESH_EGRESS_IGNORED_PORTS:  22
            AWS_ROLE_ARN:                  arn:aws:iam::111122223333:role/eksctl-app-mesh-addon-iamserviceaccount-my-a-Role1-NMNCVWB6PL0N
            AWS_WEB_IDENTITY_TOKEN_FILE:   /var/run/secrets/eks.amazonaws.com/serviceaccount/token
          ...
      Containers:
        nginx:
          Container ID:   docker://be6359dc6ecd3f18a1c87df7b57c2093e1f9db17d5b3a77f22585ce3bcab137a
          Image:          nginx:1.19.0
          Image ID:       docker-pullable://nginx
          Port:           80/TCP
          Host Port:      0/TCP
          State:          Running
            Started:      Fri, 26 Jun 2020 08:36:28 -0500
          Ready:          True
          Restart Count:  0
          Environment:
            AWS_ROLE_ARN:                 arn:aws:iam::111122223333:role/eksctl-app-mesh-addon-iamserviceaccount-my-a-Role1-NMNCVWB6PL0N
            AWS_WEB_IDENTITY_TOKEN_FILE:  /var/run/secrets/eks.amazonaws.com/serviceaccount/token
          ...
        envoy:
          Container ID:   docker://905b55cbf33ef3b3debc51cb448401d24e2e7c2dbfc6a9754a2c49dd55a216b6
          Image:          840364872350.dkr.ecr.us-west-2.amazonaws.com/aws-appmesh-envoy:v1.12.4.0-prod
          Image ID:       docker-pullable://840364872350.dkr.ecr.us-west-2.amazonaws.com/aws-appmesh-envoy
          Port:           9901/TCP
          Host Port:      0/TCP
          State:          Running
            Started:      Fri, 26 Jun 2020 08:36:36 -0500
          Ready:          True
          Restart Count:  0
          Requests:
            cpu:     10m
            memory:  32Mi
          Environment:
            APPMESH_RESOURCE_ARN:         arn:aws:iam::111122223333:mesh/my-mesh/virtualNode/my-service-a_my-apps
            APPMESH_PREVIEW:              0
            ENVOY_LOG_LEVEL:              info
            AWS_REGION:                   us-west-2
            AWS_ROLE_ARN:                 arn:aws:iam::111122223333:role/eksctl-app-mesh-addon-iamserviceaccount-my-a-Role1-NMNCVWB6PL0N
            AWS_WEB_IDENTITY_TOKEN_FILE:  /var/run/secrets/eks.amazonaws.com/serviceaccount/token
      ...
      Events:
        Type    Reason     Age   From                                                   Message
        ----    ------     ----  ----                                                   -------
        Normal  Pulling    30s   kubelet, ip-192-168-44-157.us-west-2.compute.internal  Pulling image "111345817488.dkr.ecr.us-west-2.amazonaws.com/aws-appmesh-proxy-route-manager:v2"
        Normal  Pulled     23s   kubelet, ip-192-168-44-157.us-west-2.compute.internal  Successfully pulled image "111345817488.dkr.ecr.us-west-2.amazonaws.com/aws-appmesh-proxy-route-manager:v2"
        Normal  Created    21s   kubelet, ip-192-168-44-157.us-west-2.compute.internal  Created container proxyinit
        Normal  Started    21s   kubelet, ip-192-168-44-157.us-west-2.compute.internal  Started container proxyinit
        Normal  Pulling    20s   kubelet, ip-192-168-44-157.us-west-2.compute.internal  Pulling image "nginx:1.19.0"
        Normal  Pulled     16s   kubelet, ip-192-168-44-157.us-west-2.compute.internal  Successfully pulled image "nginx:1.19.0"
        Normal  Created    15s   kubelet, ip-192-168-44-157.us-west-2.compute.internal  Created container nginx
        Normal  Started    15s   kubelet, ip-192-168-44-157.us-west-2.compute.internal  Started container nginx
        Normal  Pulling    15s   kubelet, ip-192-168-44-157.us-west-2.compute.internal  Pulling image "840364872350.dkr.ecr.us-west-2.amazonaws.com/aws-appmesh-envoy:v1.12.4.0-prod"
        Normal  Pulled     8s    kubelet, ip-192-168-44-157.us-west-2.compute.internal  Successfully pulled image "840364872350.dkr.ecr.us-west-2.amazonaws.com/aws-appmesh-envoy:v1.12.4.0-prod"
        Normal  Created    7s    kubelet, ip-192-168-44-157.us-west-2.compute.internal  Created container envoy
        Normal  Started    7s    kubelet, ip-192-168-44-157.us-west-2.compute.internal  Started container envoy
      ```

      In the preceding output, you can see that the `proxyinit` and `envoy` containers were added to the pod by the controller. If you deployed the example service to Fargate, then the `envoy` container was added to the pod by the controller, but the `proxyinit` container was not.

1. (Optional) Install add-ons such as Prometheus, Grafana, AWS X-Ray, Jaeger, and Datadog. For more information, see [App Mesh add-ons](https://github.com/aws/eks-charts#app-mesh-add-ons) on GitHub and the [Observability](https://docs.aws.amazon.com/app-mesh/latest/userguide/observability.html) section of the App Mesh User Guide. 

**Note**  
For more examples and walkthroughs for App Mesh, see the [App Mesh examples repository](https://github.com/aws/aws-app-mesh-examples).

## Step 4: Clean up


Remove all of the example resources created in this tutorial. The controller also removes the resources that were created in the `my-mesh` App Mesh service mesh.

```
kubectl delete namespace my-apps
```

If you created a Fargate profile for the example service, then remove it.

```
eksctl delete fargateprofile --name my-service-a --cluster my-cluster --region Region-code
```

Delete the mesh.

```
kubectl delete mesh my-mesh
```

(Optional) You can remove the Kubernetes integration components.

```
helm delete appmesh-controller -n appmesh-system
```

(Optional) If you deployed the Kubernetes integration components to Fargate, then delete the Fargate profile.

```
eksctl delete fargateprofile --name appmesh-system --cluster my-cluster --region Region-code
```

# Getting started with AWS App Mesh and Amazon EC2
App Mesh and Amazon EC2

**Important**  
End of support notice: On September 30, 2026, AWS will discontinue support for AWS App Mesh. After September 30, 2026, you will no longer be able to access the AWS App Mesh console or AWS App Mesh resources. For more information, visit this blog post [Migrating from AWS App Mesh to Amazon ECS Service Connect](https://aws.amazon.com/blogs/containers/migrating-from-aws-app-mesh-to-amazon-ecs-service-connect). 

This topic helps you use AWS App Mesh with an actual service that is running on Amazon EC2. This tutorial covers basic features of several App Mesh resource types.

## Scenario


To illustrate how to use App Mesh, assume that you have an application with the following characteristics:
+ Consists of two services named `serviceA` and `serviceB`. 
+ Both services are registered to a namespace named `apps.local`.
+ `ServiceA` communicates with `serviceB` over HTTP/2, port 80.
+  You have already deployed version 2 of `serviceB` and registered it with the name `serviceBv2` in the `apps.local` namespace.

You have the following requirements:
+ You want to send 75 percent of the traffic from `serviceA` to `serviceB` and 25 percent of the traffic to `serviceBv2` first. By only sending 25 percent to `serviceBv2`, you can validate that it's bug free before you send 100 percent of the traffic from `serviceA`.
+ You want to be able to easily adjust the traffic weighting so that 100 percent of the traffic goes to `serviceBv2` once it is proven to be reliable. Once all traffic is being sent to `serviceBv2`, you want to discontinue `serviceB`.
+ You do not want to have to change any existing application code or service discovery registration for your actual services to meet the previous requirements. 

To meet your requirements, you decide to create an App Mesh service mesh with virtual services, virtual nodes, a virtual router, and a route. After implementing your mesh, you update your services to use the Envoy proxy. Once updated, your services communicate with each other through the Envoy proxy rather than directly with each other.

## Prerequisites


App Mesh supports Linux services that are registered with DNS, AWS Cloud Map, or both. To use this getting started guide, we recommend that you have three existing services that are registered with DNS. You can create a service mesh and its resources even if the services don't exist, but you cannot use the mesh until you have deployed actual services.

If you don't already have services running, you can launch Amazon EC2 instances and deploy applications to them. For more information, see [Tutorial: Getting started with Amazon EC2 Linux instances](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ec2-lamp-amazon-linux-2.html) in the Amazon EC2 User Guide. The remaining steps assume that the actual services are named `serviceA`, `serviceB`, and `serviceBv2` and that all services are discoverable through a namespace named `apps.local`. 

## Step 1: Create a mesh and virtual service


A service mesh is a logical boundary for network traffic between the services that reside within it. For more information, see [Service Meshes](meshes.md). A virtual service is an abstraction of an actual service. For more information, see [Virtual services](virtual_services.md). 

Create the following resources:
+ A mesh named `apps`, since all of the services in the scenario are registered to the `apps.local` namespace.
+ A virtual service named `serviceb.apps.local`, since the virtual service represents a service that is discoverable with that name, and you don't want to change your code to reference another name. A virtual service named `servicea.apps.local` is added in a later step.

You can use the AWS Management Console or the AWS CLI version 1.18.116 or higher or 2.0.38 or higher to complete the following steps. If using the AWS CLI, use the `aws --version` command to check your installed AWS CLI version. If you don't have version 1.18.116 or higher or 2.0.38 or higher installed, then you must [install or update the AWS CLI](https://docs.aws.amazon.com/cli/latest/reference/appmesh/cli-chap-install.html). Select the tab for the tool that you want to use.

------
#### [ AWS Management Console ]

1. Open the App Mesh console first-run wizard at [https://console.aws.amazon.com/appmesh/get-started](https://console.aws.amazon.com/appmesh/get-started).

1. For **Mesh name**, enter **apps**.

1. For **Virtual service name**, enter **serviceb.apps.local**.

1. To continue, choose **Next**.

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

1. Create a mesh with the `[create-mesh](https://docs.aws.amazon.com/cli/latest/reference/appmesh/create-mesh.html)` command.

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

1. Create a virtual service with the `[create-virtual-service](https://docs.aws.amazon.com/cli/latest/reference/appmesh/create-virtual-service.html)` command.

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

------

## Step 2: Create a virtual node


A virtual node acts as a logical pointer to an actual service. For more information, see [Virtual nodes](virtual_nodes.md). 

Create a virtual node named `serviceB`, since one of the virtual nodes represents the actual service named `serviceB`. The actual service that the virtual node represents is discoverable through `DNS` with a hostname of `serviceb.apps.local`. Alternately, you can discover actual services using AWS Cloud Map. The virtual node listens for traffic using the HTTP/2 protocol on port 80. Other protocols are also supported, as are health checks. You create virtual nodes for `serviceA` and `serviceBv2` in a later step.

------
#### [ AWS Management Console ]

1. For **Virtual node name**, enter **serviceB**. 

1. For **Service discovery method**, choose **DNS** and enter **serviceb.apps.local** for **DNS hostname**.

1. Under **Listener configuration**, choose **http2** for **Protocol** and enter **80** for **Port**.

1. To continue, choose **Next**.

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

1. Create a file named `create-virtual-node-serviceb.json` with the following contents:

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

1. Create the virtual node with the [create-virtual-node](https://docs.aws.amazon.com/cli/latest/reference/appmesh/create-virtual-node.html) command using the JSON file as input.

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

------

## Step 3: Create a virtual router and route


Virtual routers route traffic for one or more virtual services within your mesh. For more information, see [Virtual routers](virtual_routers.md) and [Routes](routes.md).

Create the following resources:
+ A virtual router named `serviceB`, since the `serviceB.apps.local` virtual service does not initiate outbound communication with any other service. Remember that the virtual service that you created previously is an abstraction of your actual `serviceb.apps.local` service. The virtual service sends traffic to the virtual router. The virtual router listens for traffic using the HTTP/2 protocol on port 80. Other protocols are also supported. 
+ A route named `serviceB`. It routes 100 percent of its traffic to the `serviceB` virtual node. The weight is in a later step once you add the `serviceBv2` virtual node. Though not covered in this guide, you can add additional filter criteria for the route and add a retry policy to cause the Envoy proxy to make multiple attempts to send traffic to a virtual node when it experiences a communication problem.

------
#### [ AWS Management Console ]

1. For **Virtual router name,** enter **serviceB**.

1. Under **Listener configuration**, choose **http2** for **Protocol** and specify **80** for **Port**.

1. For **Route name**, enter **serviceB**. 

1. For **Route type**, choose **http2**.

1. For **Virtual node name** under **Target configuration**, select `serviceB` and enter **100** for **Weight**.

1. Under **Match configuration**, choose a **Method**.

1. To continue, choose **Next**.

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

1. Create a virtual router.

   1. Create a file named `create-virtual-router.json` with the following contents:

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

   1. Create the virtual router with the [create-virtual-router](https://docs.aws.amazon.com/cli/latest/reference/appmesh/create-virtual-router.html) command using the JSON file as input.

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

1. Create a route.

   1. Create a file named `create-route.json` with the following contents:

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

   1. Create the route with the [create-route](https://docs.aws.amazon.com/cli/latest/reference/appmesh/create-route.html) command using the JSON file as input.

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

------

## Step 4: Review and create


Review the settings against the previous instructions.

------
#### [ AWS Management Console ]

Choose **Edit** if you need to make changes in any section. Once you are satisfied with the settings, choose **Create mesh**.

The **Status** screen shows you all of the mesh resources that were created. You can see the created resources in the console by selecting **View mesh**.

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

Review the settings of the mesh you created with the [describe-mesh](https://docs.aws.amazon.com/cli/latest/reference/appmesh/describe-mesh.html) command.

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

Review the settings of the virtual service that you created with the [describe-virtual-service](https://docs.aws.amazon.com/cli/latest/reference/appmesh/describe-virtual-service.html) command.

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

Review the settings of the virtual node that you created with the [describe-virtual-node](https://docs.aws.amazon.com/cli/latest/reference/appmesh/describe-virtual-node.html) command.

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

Review the settings of the virtual router that you created with the [describe-virtual-router](https://docs.aws.amazon.com/cli/latest/reference/appmesh/describe-virtual-router.html) command.

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

Review the settings of the route that you created with the [describe-route](https://docs.aws.amazon.com/cli/latest/reference/appmesh/describe-route.html) command.

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

------

## Step 5: Create additional resources


To complete the scenario, you need to:
+ Create one virtual node named `serviceBv2` and another named `serviceA`. Both virtual nodes listen for requests over HTTP/2 port 80. For the `serviceA` virtual node, configure a backend of `serviceb.apps.local`. All outbound traffic from the `serviceA` virtual node is sent to the virtual service named `serviceb.apps.local`. Though not covered in this guide, you can also specify a file path to write access logs to for a virtual node.
+ Create one additional virtual service named `servicea.apps.local`, which sends all traffic directly to the `serviceA` virtual node.
+ Update the `serviceB` route that you created in a previous step to send 75 percent of its traffic to the `serviceB` virtual node and 25 percent of its traffic to the `serviceBv2` virtual node. Over time, you can continue to modify the weights until `serviceBv2` receives 100 percent of the traffic. Once all traffic is sent to `serviceBv2`, you can shut down and discontinue the `serviceB` virtual node and actual service. As you change weights, your code does not require any modification, because the `serviceb.apps.local` virtual and actual service names don't change. Recall that the `serviceb.apps.local` virtual service sends traffic to the virtual router, which routes the traffic to the virtual nodes. The service discovery names for the virtual nodes can be changed at any time.

------
#### [ AWS Management Console ]

1. In the left navigation pane, select **Meshes**.

1. Select the `apps` mesh that you created in a previous step.

1. In the left navigation pane, select **Virtual nodes**.

1. Choose **Create virtual node**.

1. For **Virtual node name**, enter **serviceBv2**, for **Service discovery method**, choose **DNS**, and for **DNS hostname**, enter **servicebv2.apps.local**.

1. For **Listener configuration**, select **http2** for **Protocol** and enter **80** for **Port**.

1. Choose **Create virtual node**.

1. Choose **Create virtual node** again. Enter **serviceA** for the **Virtual node name**. For **Service discovery method**, choose **DNS**, and for **DNS hostname**, enter **servicea.apps.local**.

1. For **Enter a virtual service name** under **New backend**, enter **serviceb.apps.local**.

1. Under **Listener configuration**, choose **http2** for **Protocol**, enter **80** for **Port**, and then choose **Create virtual node**.

1. In the left navigation pane, select** Virtual routers** and then select the `serviceB` virtual router from the list.

1. Under **Routes**, select the route named `ServiceB` that you created in a previous step, and choose **Edit**.

1. Under **Targets**, **Virtual node name**, change the value of **Weight** for `serviceB` to **75**.

1. Choose **Add target**, choose `serviceBv2` from the dropdown list, and set the value of **Weight** to **25**.

1. Choose **Save**.

1. In the left navigation pane, select** Virtual services** and then choose **Create virtual service**.

1. Enter **servicea.apps.local** for **Virtual service name**, select **Virtual node** for **Provider**, select `serviceA` for **Virtual node**, and then choose **Create virtual service.**

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

1. Create the `serviceBv2` virtual node.

   1. Create a file named `create-virtual-node-servicebv2.json` with the following contents:

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

   1. Create the virtual node.

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

1. Create the `serviceA` virtual node.

   1. Create a file named `create-virtual-node-servicea.json` with the following contents:

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

   1. Create the virtual node.

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

1. Update the `serviceb.apps.local` virtual service that you created in a previous step to send its traffic to the `serviceB` virtual router. When the virtual service was originally created, it did not send traffic anywhere, since the `serviceB` virtual router had not been created yet.

   1. Create a file named `update-virtual-service.json` with the following contents:

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

   1. Update the virtual service with the [update-virtual-service](https://docs.aws.amazon.com/cli/latest/reference/appmesh/update-virtual-service.html) command.

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

1. Update the `serviceB` route that you created in a previous step.

   1. Create a file named `update-route.json` with the following contents:

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

   1. Update the route with the [update-route](https://docs.aws.amazon.com/cli/latest/reference/appmesh/update-route.html) command.

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

1. Create the `serviceA` virtual service.

   1. Create a file named `create-virtual-servicea.json` with the following contents:

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

   1. Create the virtual service.

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

------

**Mesh summary**  
Before you created the service mesh, you had three actual services named `servicea.apps.local`, `serviceb.apps.local`, and `servicebv2.apps.local`. In addition to the actual services, you now have a service mesh that contains the following resources that represent the actual services:
+ Two virtual services. The proxy sends all traffic from the `servicea.apps.local` virtual service to the `serviceb.apps.local` virtual service through a virtual router. 
+ Three virtual nodes named `serviceA`, `serviceB`, and `serviceBv2`. The Envoy proxy uses the service discovery information configured for the virtual nodes to look up the IP addresses of the actual services. 
+ One virtual router with one route that instructs the Envoy proxy to route 75 percent of inbound traffic to the `serviceB` virtual node and 25 percent of the traffic to the `serviceBv2` virtual node. 

## Step 6: Update services


After creating your mesh, you need to complete the following tasks:
+ Authorize the Envoy proxy that you deploy with each service to read the configuration of one or more virtual nodes. For more information about how to authorize the proxy, see [Envoy Proxy authorization](proxy-authorization.md).
+ To update your existing service, complete the steps that follow.

**To configure an Amazon EC2 instance as a virtual node member**

1. Create an IAM role.

   1. Create a file named `ec2-trust-relationship.json` with the following contents.

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

****  

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

------

   1. Create an IAM role with the following command.

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

1. Attach IAM policies to the role that allow it to read from Amazon ECR and only the configuration of a specific App Mesh virtual node.

   1. Create a file named `virtual-node-policy.json` with the following contents. `apps` is the name of the mesh you created in [Step 1: Create a mesh and virtual service](#create-mesh-and-virtual-service) and `serviceB` is the name of the virtual node that you created in [Step 2: Create a virtual node](#create-virtual-node). Replace *111122223333* with your account ID and *us-west-2* with the Region that you created your mesh in.

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

****  

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

------

   1. Create the policy with the following command.

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

   1. Attach the policy that you created in the previous step to the role so the role can read the configuration for only the `serviceB` virtual node from App Mesh.

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

   1. Attach the `AmazonEC2ContainerRegistryReadOnly` managed policy to the role so that it can pull the Envoy container image from Amazon ECR.

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

1. [Launch an Amazon EC2 instance with the IAM role](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/iam-roles-for-amazon-ec2.html#launch-instance-with-role) that you created. 

1. Connect to your instance via SSH.

1. Install Docker and the AWS CLI on your instance according to your operating system documentation.

1. Authenticate to the Envoy Amazon ECR repository in the Region that you want your Docker client to pull the image from.
   + All Regions except `me-south-1`, `ap-east-1`, `ap-southeast-3`, `eu-south-1`, `il-central-1`, and `af-south-1`. You can replace *us-west-2* with any [supported Region](https://docs.aws.amazon.com/general/latest/gr/appmesh.html) except `me-south-1`, `ap-east-1`, `ap-southeast-3`, `eu-south-1`, `il-central-1`, and `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` Region

     ```
     $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` Region

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

1. Run one of the following commands to start the App Mesh Envoy container on your instance, depending on which Region you want to pull the image from. The *apps* and *serviceB* values are the mesh and virtual node names defined in the scenario. This information tells the proxy which virtual node configuration to read from App Mesh. To complete the scenario, you also need to complete these steps for the Amazon EC2 instances that host the services represented by the `serviceBv2` and `serviceA` virtual nodes. For your own application, replace these values with your own.
   + All Regions except `me-south-1`, `ap-east-1`, `ap-southeast-3`, `eu-south-1`, `il-central-1`, and `af-south-1`. You can replace *Region-code* with any [supported Region](https://docs.aws.amazon.com/general/latest/gr/appmesh.html) except the `me-south-1`, `ap-east-1`, `ap-southeast-3`, `eu-south-1`, `il-central-1`, and `af-south-1` Regions. You can replace `1337` with any value between `0` and `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` Region. You can replace `1337` with any value between `0` and `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` Region. You can replace `1337` with any value between `0` and `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
     ```
**Note**  
The `APPMESH_RESOURCE_ARN` property requires version `1.15.0` or later of the Envoy image. For more information, see [Envoy image](envoy.md).
**Important**  
Only version v1.9.0.0-prod or later is supported for use with App Mesh.

1. Select `Show more` below. Create a file named `envoy-networking.sh` on your instance with the following contents. Replace *8000* with the port that your application code uses for incoming traffic. You can change the value for `APPMESH_IGNORE_UID`, but the value must be the same as the value that you specified in the previous step; for example `1337`. You can add additional addresses to `APPMESH_EGRESS_IGNORED_IP` if necessary. Do not modify any other lines.

   ```
   #!/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. To configure `iptables` rules to route application traffic to the Envoy proxy, run the script that you created in the previous step.

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

1. Start your virtual node application code.

**Note**  
For more examples and walkthroughs for App Mesh, see the [App Mesh examples repository](https://github.com/aws/aws-app-mesh-examples).

# App Mesh Examples


**Important**  
End of support notice: On September 30, 2026, AWS will discontinue support for AWS App Mesh. After September 30, 2026, you will no longer be able to access the AWS App Mesh console or AWS App Mesh resources. For more information, visit this blog post [Migrating from AWS App Mesh to Amazon ECS Service Connect](https://aws.amazon.com/blogs/containers/migrating-from-aws-app-mesh-to-amazon-ecs-service-connect). 

You can find end-to-end walkthroughs showing AWS App Mesh in action and code examples for integrating with various AWS services in the following repository:

[App Mesh Examples](https://github.com/aws/aws-app-mesh-examples)