

기계 번역으로 제공되는 번역입니다. 제공된 번역과 원본 영어의 내용이 상충하는 경우에는 영어 버전이 우선합니다.

# AWS App Mesh 및 Amazon EC2 시작하기
<a name="getting-started-ec2"></a>

**중요**  
지원 종료 공지: 2026년 9월 30일에 AWS 는에 대한 지원을 중단합니다 AWS App Mesh. 2026년 9월 30일 이후에는 AWS App Mesh 콘솔 또는 AWS App Mesh 리소스에 더 이상 액세스할 수 없습니다. 자세한 내용은이 블로그 게시물 [Migrating from to Amazon ECS Service Connect를 참조 AWS App Mesh 하세요](https://aws.amazon.com/blogs/containers/migrating-from-aws-app-mesh-to-amazon-ecs-service-connect).

이 주제는 Amazon EC2에서 실행 중인 실제 서비스와 AWS App Mesh 함께를 사용하는 데 도움이 됩니다. 이 자습서에서는 몇 가지 App Mesh 리소스 유형의 기본 기능을 다룹니다.

## 시나리오
<a name="scenario"></a>

App Mesh를 사용하는 방법을 설명하기 위해 다음과 같은 특징을 가진 애플리케이션이 있다고 가정합니다.
+ `serviceA`및 `serviceB`라는 두 개의 서비스로 구성됩니다.
+ 두 서비스 모두 `apps.local`이라는 네임스페이스에 등록됩니다.
+ `ServiceA`는 HTTP/2, 포트 80을 통해 `serviceB`와 통신합니다.
+  `serviceB`의 버전 2를 이미 배포했고 `apps.local` 네임스페이스에 `serviceBv2` 이름으로 등록했습니다.

다음과 같은 요구 사항이 있습니다.
+ 에서 로 트래픽의 75%`serviceA`를 전송`serviceB`하고 트래픽의 25%를 `serviceBv2` 먼저 전송하려고 합니다. 에 25%만 전송하면에서 트래픽의 100%를 전송하기 전에 버그가 없는지 확인할 `serviceBv2`수 있습니다`serviceA`.
+ 트래픽이 신뢰할 수 있는 것으로 입증되면 해당 트래픽의 100%가 `serviceBv2`로 이동하도록 트래픽 가중치를 쉽게 조정할 수 있기를 원합니다. 모든 트래픽이 `serviceBv2`로 전송되면 `serviceB`를 중단하려고 할 수 있습니다.
+ 이전 요구 사항을 충족하기 위해 실제 서비스에 대한 기존 애플리케이션 코드 또는 서비스 검색 등록을 변경할 필요가 없도록 하고 싶습니다.

요구 사항을 충족하기 위해 가상 서비스, 가상 노드, 가상 라우터 및 루트가 포함된 App Mesh 서비스 메시를 생성하기로 결정했습니다. 메시를 구현한 후 서비스가 Envoy 프록시를 사용하도록 서비스를 업데이트합니다. 업데이트된 서비스는 서로 직접 통신하지 않고 Envoy 프록시를 통해 서로 통신합니다.

## 사전 조건
<a name="prerequisites"></a>

App Mesh는 DNS AWS Cloud Map또는 둘 다에 등록된 Linux 서비스를 지원합니다. 이 시작 안내서를 사용하려면 DNS에 등록된 기존 서비스 3개가 있으면 좋습니다. 서비스가 존재하지 않더라도 서비스 메시 및 해당 리소스를 생성할 수 있지만 실제 서비스를 배포할 때까지 메시를 사용할 수 없습니다.

서비스를 아직 실행 중이지 않은 경우 Amazon EC2 인스턴스를 시작하고 애플리케이션을 배포할 수 있습니다. 자세한 내용은 [ Amazon EC2 사용 설명서의 자습서: Amazon EC2 Linux 인스턴스 시작하기](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ec2-lamp-amazon-linux-2.html)를 참조하세요. Amazon EC2 나머지 단계에서는 실제 서비스의 이름이 `serviceA`, `serviceB` 및 `serviceBv2`이고 `apps.local`이라는 네임스페이스를 통해 모든 서비스를 검색할 수 있다고 가정합니다.

## 1단계: 메시 및 가상 서비스 생성
<a name="create-mesh-and-virtual-service"></a>

서비스 메시는 내부에 있는 서비스 간의 네트워크 트래픽에 대한 논리적 경계입니다. 자세한 내용은 [서비스 메시](meshes.md) 단원을 참조하십시오. 가상 서비스는 실제 서비스를 추상화한 것입니다. 자세한 내용은 [가상 서비스](virtual_services.md) 단원을 참조하십시오.

다음의 리소스를 생성합니다.
+ 시나리오의 모든 서비스가 `apps.local` 네임스페이스에 등록되기 때문에 `apps`이라는 메시를 생성합니다.
+ 가상 서비스는 해당 이름으로 검색할 수 있는 서비스를 나타내며 다른 이름을 참조하도록 코드를 변경하고 싶지 않기 때문에 `serviceb.apps.local`이라는 이름의 가상 서비스를 생성합니다. `servicea.apps.local`이라는 이름의 가상 서비스는 이후 단계에서 추가됩니다.

 AWS Management Console 또는 AWS CLI 버전 1.18.116 이상 또는 2.0.38 이상을 사용하여 다음 단계를 완료할 수 있습니다. 를 사용하는 경우 `aws --version` 명령을 AWS CLI사용하여 설치된 AWS CLI 버전을 확인합니다. 버전 1.18.116 이상 또는 2.0.38 이상이 설치되어 있지 않으면 [AWS CLI를 설치하거나 업데이트](https://docs.aws.amazon.com/cli/latest/reference/appmesh/cli-chap-install.html)해야 합니다. 사용할 도구의 탭을 선택합니다.

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

1. [https://console.aws.amazon.com/appmesh/get-started](https://console.aws.amazon.com/appmesh/get-started)에서 App Mesh 콘솔 처음 실행 마법사를 엽니다.

1. **Mesh name(메시 이름)**에 **apps**를 입력합니다.

1. **Virtual service name(가상 서비스 이름)**에 **serviceb.apps.local**를 입력합니다.

1. 계속하려면 **다음**을 선택합니다.

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

1. `[create-mesh](https://docs.aws.amazon.com/cli/latest/reference/appmesh/create-mesh.html)` 명령을 사용하여 메시를 생성합니다.

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

1. `[create-virtual-service](https://docs.aws.amazon.com/cli/latest/reference/appmesh/create-virtual-service.html)` 명령을 사용하여 가상 서비스를 생성합니다.

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

------

## 2단계: 가상 노드 생성
<a name="create-virtual-node"></a>

가상 노드는 실제 서비스에 대한 논리적 포인터 역할을 합니다. 자세한 내용은 [가상 노드](virtual_nodes.md) 단원을 참조하십시오.

가상 노드 중 하나가 `serviceB`라는 실제 서비스를 나타내므로 `serviceB`이라는 가상 노드를 생성합니다. 가상 노드가 나타내는 실제 서비스는 호스트 이름 `serviceb.apps.local`을 사용하여 `DNS`를 통해 검색할 수 있습니다. 또는 AWS Cloud Map을 사용하여 실제 서비스를 검색할 수 있습니다. 가상 노드는 포트 80에서 HTTP/2 프로토콜을 사용하여 트래픽을 수신합니다. 상태 확인과 마찬가지로 다른 프로토콜도 지원됩니다. 이후 단계에서 `serviceA` 및 `serviceBv2`에 대한 가상 노드를 생성합니다.

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

1. **Virtual node name(가상 노드 이름)**에 **serviceB**를 입력합니다.

1. **서비스 검색 방법**에 대해 **DNS**를 선택하고 **DNS 호스트 이름**에 대해 **serviceb.apps.local**을 입력합니다.

1. **리스너 구성**에서 **프로토콜**로 **http2**를 선택하고 **포트**로 **80**을 입력합니다.

1. 계속하려면 **다음**을 선택합니다.

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

1. 다음 콘텐츠를 가진 `create-virtual-node-serviceb.json`이라는 파일을 생성합니다:

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

1. JSON 파일을 입력으로 사용하여 [create-virtual-node](https://docs.aws.amazon.com/cli/latest/reference/appmesh/create-virtual-node.html) 명령으로 가상 노드를 생성합니다.

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

------

## 3단계: 가상 라우터 생성 및 라우팅
<a name="create-virtual-router-and-route"></a>

가상 라우터는 메시 내에 있는 하나 이상의 가상 서비스에 대한 트래픽을 라우팅합니다. 자세한 내용은 [가상 라우터](virtual_routers.md) 및 [Routes](routes.md) 섹션을 참조하세요.

다음의 리소스를 생성합니다.
+ `serviceB`라는 이름의 가상 라우터. `serviceB.apps.local`이라는 가상 서비스는 다른 서비스와의 아웃바운드 통신을 시작하지 않기 때문입니다. 이전에 만든 가상 서비스는 실제 `serviceb.apps.local` 서비스를 추상화한 것입니다. 가상 서비스는 가상 라우터로 트래픽을 보냅니다. 가상 라우터는 포트 80에서 HTTP/2 프로토콜을 사용하여 트래픽을 수신합니다. 다른 프로토콜도 지원됩니다.
+ `serviceB`라는 이름의 라우팅. 트래픽을 100% `serviceB` 가상 노드로 라우팅합니다. `serviceBv2` 가상 노드를 추가한 후 이후 단계에서 가중치가 변경됩니다. 이 안내서에서는 다루지 않지만 해당 라우팅에 대한 필터 조건을 추가하고 재시도 정책을 추가하여 통신 문제가 발생할 경우 Envoy 프록시가 가상 노드에 트래픽을 여러 번 보내도록 할 수 있습니다.

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

1. **Virtual router name(가상 라우터 이름)**에 **serviceB**를 입력합니다.

1. **리스너 구성**에서 **프로토콜**로 **http2**를 선택하고 **포트**로 **80**을 지정합니다.

1. **Route Name(라우팅 이름)**에 **serviceB**를 입력합니다.

1. **루트 유형**에 대해 **http2**를 선택합니다.

1. **대상 구성**의 **가상 노드 이름**에 대해 `serviceB`를 선택하고 **가중치**로 **100**을 입력합니다.

1. **일치 구성**에서 **방법**을 선택합니다.

1. 계속하려면 **다음**을 선택합니다.

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

1. 가상 라우터를 생성합니다.

   1. 다음 콘텐츠를 가진 `create-virtual-router.json`이라는 파일을 생성합니다:

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

   1. JSON 파일을 입력으로 사용하여 [create-virtual-router](https://docs.aws.amazon.com/cli/latest/reference/appmesh/create-virtual-router.html) 명령으로 가상 라우터를 생성합니다.

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

1. 라우팅을 생성합니다.

   1. 다음 콘텐츠를 가진 `create-route.json`이라는 파일을 생성합니다:

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

   1. JSON 파일을 입력으로 사용하여 [create-route](https://docs.aws.amazon.com/cli/latest/reference/appmesh/create-route.html) 명령으로 라우팅을 생성합니다.

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

------

## 4단계: 검토 및 생성
<a name="review-create"></a>

이전 지침에 대한 설정을 검토합니다.

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

섹션에서 변경해야 할 경우 **편집**을 선택합니다. 설정에 만족하면 **메시 생성**을 선택합니다.

**상태** 화면에는 생성된 모든 메시 리소스가 표시됩니다. **메시 보기**를 선택하여 콘솔에서 생성된 리소스를 볼 수 있습니다.

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

[describe-mesh](https://docs.aws.amazon.com/cli/latest/reference/appmesh/describe-mesh.html) 명령을 사용하여 생성한 메시의 설정을 검토합니다.

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

[describe-virtual-service](https://docs.aws.amazon.com/cli/latest/reference/appmesh/describe-virtual-service.html) 명령으로 생성한 가상 서비스의 설정을 검토합니다.

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

[describe-virtual-node](https://docs.aws.amazon.com/cli/latest/reference/appmesh/describe-virtual-node.html) 명령으로 생성한 가상 노드의 설정을 검토합니다.

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

[describe-virtual-router](https://docs.aws.amazon.com/cli/latest/reference/appmesh/describe-virtual-router.html) 명령으로 생성한 가상 라우터의 설정을 검토합니다.

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

[describe-route](https://docs.aws.amazon.com/cli/latest/reference/appmesh/describe-route.html) 명령으로 생성한 라우팅의 설정을 검토합니다.

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

------

## 5단계: 추가 리소스 생성
<a name="create-additional-resources"></a>

시나리오를 완료하려면 다음을 수행해야 합니다.
+ `serviceBv2`라는 가상 노드 하나와 `serviceA`라는 가상 노드 하나를 생성합니다. 두 가상 노드 모두 HTTP/2 포트 80을 통해 요청을 수신합니다. `serviceA` 가상 노드의 경우 `serviceb.apps.local`의 백엔드를 구성합니다. `serviceA` 가상 노드의 모든 아웃바운드 트래픽은 이름이 `serviceb.apps.local`인 가상 서비스로 전송됩니다. 이 안내서에서는 다루지 않지만 가상 노드에 대한 액세스 로그를 쓸 파일 경로를 지정할 수도 있습니다.
+ `servicea.apps.local`이라는 가상 서비스를 추가로 생성하면 모든 트래픽이 `serviceA` 가상 노드로 직접 전송됩니다.
+ 트래픽의 75%를 `serviceB` 가상 노드로 보내고 트래픽의 25%를 `serviceBv2` 가상 노드로 보내도록 이전 단계에서 생성한 `serviceB` 라우팅을 업데이트합니다. 시간이 지남에 따라 `serviceBv2`가 트래픽의 100%를 수신할 때까지 가중치를 계속 수정할 수 있습니다. 모든 트래픽이 `serviceBv2`로 전송되면 `serviceB` 가상 노드와 실제 서비스를 종료하고 중단할 수 있습니다. `serviceb.apps.local` 가상 및 실제 서비스 이름이 변경되지 않으므로 가중치를 변경할 때 코드를 수정할 필요가 없습니다. `serviceb.apps.local` 가상 서비스는 트래픽을 가상 라우터로 전송하여 트래픽을 가상 노드로 라우팅한다는 점을 기억하십시오. 가상 노드의 서비스 검색 이름은 언제든지 변경할 수 있습니다.

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

1. 왼쪽 탐색 창에서 **Meshes(메시)**를 선택합니다.

1. 이전 단계에서 생성한 `apps` 메시를 선택합니다.

1. 왼쪽 탐색 창에서 **Virtual node(가상 노드)**를 선택합니다.

1. **Create virtual node(가상 노드 생성)**를 선택합니다.

1. **가상 노드 이름**에 대해 **serviceBv2**를 입력하고, **서비스 검색 방법**에 대해 **DNS**를 선택하고 **DNS 호스트 이름**에 대해 **servicebv2.apps.local**을 입력합니다.

1. **리스너 구성**에서 **프로토콜**로 **http2**를 선택하고 **포트**로 **80**을 입력합니다.

1. **Create virtual node(가상 노드 생성)**를 선택합니다.

1. **가상 노드 생성**을 다시 선택합니다. **가상 노드 이름**에 **serviceA**를 입력합니다. **서비스 검색 방법**에 대해 **DNS**를 선택하고 **DNS 호스트 이름**에 대해 **servicea.apps.local**을 입력합니다.

1. **새 백엔드**에서 **가상 서비스 이름 입력**에 **serviceb.apps.local**을 입력합니다.

1. **리스너 구성**에서 **프로토콜**로 **http2**를 선택하고 **포트**에 **80**을 입력한 다음, **가상 노드 생성**을 선택합니다.

1. 왼쪽 탐색 창에서 **Virtual routers(가상 라우터)**를 선택한 다음 목록에서 `serviceB` 가상 라우터를 선택합니다.

1. **루트**에서 이전 단계에서 생성한 `ServiceB`라는 루트를 선택하고 **편집**을 선택합니다.

1. **대상**, **가상 노드 이름**에서 `serviceB`의 **가중치** 값을 **75**로 변경합니다.

1. **대상 추가**를 선택하고 드롭다운 목록에서 `serviceBv2`를 선택하고 **가중치**의 값을 **25**로 설정합니다.

1. **저장**을 선택합니다.

1. 왼쪽 탐색 창에서 **가상 서비스**를 선택한 다음 **가상 서비스 생성**을 선택합니다.

1. **가상 서비스 이름**으로 **servicea.apps.local**을 입력하고 **공급자**로 **가상 노드**를 선택하고 **가상 노드**로 `serviceA`를 선택한 다음, **가상 서비스 생성**을 선택합니다.

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

1. `serviceBv2` 가상 노드를 생성합니다.

   1. 다음 콘텐츠를 가진 `create-virtual-node-servicebv2.json`이라는 파일을 생성합니다:

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

   1. 가상 노드를 생성합니다.

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

1. `serviceA` 가상 노드를 생성합니다.

   1. 다음 콘텐츠를 가진 `create-virtual-node-servicea.json`이라는 파일을 생성합니다:

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

   1. 가상 노드를 생성합니다.

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

1. 이전 단계에서 생성한 `serviceb.apps.local` 가상 서비스를 업데이트하여 트래픽을 `serviceB` 가상 라우터로 보냅니다. 가상 서비스가 원래 생성되었을 때는 `serviceB` 가상 라우터가 아직 생성되지 않았기 때문에 트래픽을 어디에도 보내지 않았습니다.

   1. 다음 콘텐츠를 가진 `update-virtual-service.json`이라는 파일을 생성합니다:

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

   1. [update-virtual-service](https://docs.aws.amazon.com/cli/latest/reference/appmesh/update-virtual-service.html) 명령을 사용하여 가상 서비스를 업데이트합니다.

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

1. 이전 단계에서 생성한 `serviceB` 라우팅을 업데이트합니다.

   1. 다음 콘텐츠를 가진 `update-route.json`이라는 파일을 생성합니다:

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

   1. [update-route](https://docs.aws.amazon.com/cli/latest/reference/appmesh/update-route.html) 명령을 사용하여 라우팅을 업데이트합니다.

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

1. `serviceA` 가상 서비스를 생성합니다.

   1. 다음 콘텐츠를 가진 `create-virtual-servicea.json`이라는 파일을 생성합니다:

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

   1. 가상 서비스를 생성합니다.

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

------

**메시 요약**  
서비스 메시를 생성하기 전에는 `servicea.apps.local`, `serviceb.apps.local` 및 `servicebv2.apps.local`이라는 세 가지 실제 서비스가 있었습니다. 실제 서비스 외에도 이제 실제 서비스를 나타내는 다음 리소스가 포함된 서비스 메시가 있습니다.
+ 두 개의 가상 서비스. 프록시는 가상 라우터를 통해 `servicea.apps.local` 가상 서비스의 모든 트래픽을 `serviceb.apps.local` 가상 서비스로 보냅니다.
+ `serviceA`, `serviceB` 및 `serviceBv2`라는 세 개의 가상 노드. Envoy 프록시는 가상 노드에 대해 구성된 서비스 검색 정보를 사용하여 실제 서비스의 IP 주소를 조회합니다.
+ Envoy 프록시가 인바운드 트래픽의 75%를 `serviceB` 가상 노드로 라우팅하고 트래픽의 25%를 `serviceBv2` 가상 노드로 라우팅하도록 지시하는 하나의 라우팅이 있는 가상 라우터 하나.

## 6단계: 서비스 업데이트
<a name="update-services"></a>

메시를 생성한 후에는 다음 작업을 완료해야 합니다.
+ 각 서비스와 함께 배포하는 Envoy 프록시에 하나 이상의 가상 노드의 구성을 읽을 수 있는 권한을 부여합니다. 프록시에 권한을 부여하는 방법에 대한 자세한 내용은 [Envoy 프록시 권한 부여](proxy-authorization.md) 섹션을 참조하세요.
+ 기존 서비스를 업데이트하려면 다음 단계를 완료하세요.

**Amazon EC2 인스턴스를 가상 노드 멤버로 구성하려면**

1. IAM 역할을 생성합니다.

   1. 다음 콘텐츠를 가진 `ec2-trust-relationship.json`이라는 파일을 생성합니다:

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

****  

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

------

   1. 다음 명령을 사용하여 IAM 역할을 생성합니다.

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

1. 역할이 Amazon ECR에서 특정 App Mesh 가상 노드의 구성만 읽을 수 있도록 하는 IAM 정책을 역할에 연결합니다.

   1. 다음 콘텐츠를 통해 `virtual-node-policy.json`이라는 파일을 생성합니다. `apps`는 [1단계: 메시 및 가상 서비스 생성](#create-mesh-and-virtual-service)에서 생성한 메시의 이름이고, `serviceB`는 [2단계: 가상 노드 생성](#create-virtual-node)에서 생성한 가상 노드의 이름입니다. *111122223333*을 사용자의 계정 ID로 바꾸고 *us-west-2*를 메시를 생성한 리전으로 바꿉니다.

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

****  

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

------

   1. 다음 명령을 사용하여 정책을 생성합니다.

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

   1. 이전 단계에서 생성한 정책을 역할에 연결하여 역할이 App Mesh에서 `serviceB` 가상 노드에 대한 구성만 읽을 수 있도록 합니다.

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

   1. `AmazonEC2ContainerRegistryReadOnly` 관리형 정책을 역할에 연결하여 해당 역할이 Amazon ECR에서 Envoy 컨테이너 이미지를 끌어올 수 있도록 합니다.

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

1. 생성한 [IAM 역할로 Amazon EC2 인스턴스를 시작](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/iam-roles-for-amazon-ec2.html#launch-instance-with-role)합니다.

1. SSH를 통해 인스턴스에 연결합니다.

1. 운영 체제 설명서에 따라 인스턴스 AWS CLI 에 Docker와를 설치합니다.

1. Dockerㅅ서 클라이언트가 이미지를 끌어올 리전에서 Envoy Amazon ECR 리포지토리에서 인증을 받습니다.
   + `me-south-1`, `ap-east-1`, `ap-southeast-3`, `eu-south-1`, `il-central-1` 및 `af-south-1`을 제외한 모든 리전입니다. *us-west-2*를 `me-south-1`, `ap-east-1`, `ap-southeast-3`, `eu-south-1`, `il-central-1` 및 `af-south-1`을 제외한 [지원되는 리전](https://docs.aws.amazon.com/general/latest/gr/appmesh.html)으로 바꿀 수 있습니다.

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

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

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

1. 이미지를 가져올 리전에 따라 다음 명령 중 하나를 실행하여 인스턴스에서 App Mesh Envoy 컨테이너를 시작합니다. *apps* 및 *serviceB* 값은 시나리오에 정의된 메시 및 가상 노드 이름입니다. 이 정보는 프록시에 App Mesh에서 읽을 가상 노드 구성을 알려줍니다. 시나리오를 완료하려면 `serviceBv2` 및 `serviceA` 가상 노드가 나타내는 서비스를 호스팅하는 Amazon EC2 인스턴스에 대해서도 이러한 단계를 완료해야 합니다. 자체 애플리케이션의 경우 이 값을 자체 값으로 바꿉니다.
   + `me-south-1`, `ap-east-1`, `ap-southeast-3`, `eu-south-1`, `il-central-1` 및 `af-south-1`을 제외한 모든 리전입니다. *Region-code*를 `me-south-1`, `ap-east-1`, `ap-southeast-3`, `eu-south-1`, `il-central-1` 및 `af-south-1` 리전을 제외한 [지원되는 리전](https://docs.aws.amazon.com/general/latest/gr/appmesh.html)으로 바꿀 수 있습니다. `1337`을 `0`과 `2147483647` 사이의 값으로 바꿀 수 있습니다.

     ```
     sudo docker run --detach --env APPMESH_RESOURCE_ARN=mesh/apps/virtualNode/serviceB  \
     -u 1337 --network host 840364872350.dkr.ecr.region-code.amazonaws.com/aws-appmesh-envoy:v1.34.13.0-prod
     ```
   + `me-south-1` 리전. `1337`을 `0`과 `2147483647` 사이의 값으로 바꿀 수 있습니다.

     ```
     sudo docker run --detach --env APPMESH_RESOURCE_ARN=mesh/apps/virtualNode/serviceB  \
     -u 1337 --network host 772975370895.dkr.ecr.me-south-1.amazonaws.com/aws-appmesh-envoy:v1.34.13.0-prod
     ```
   + `ap-east-1` 리전. `1337`을 `0`과 `2147483647` 사이의 값으로 바꿀 수 있습니다.

     ```
     sudo docker run --detach --env APPMESH_RESOURCE_ARN=mesh/apps/virtualNode/serviceB  \
     -u 1337 --network host 856666278305.dkr.ecr.ap-east-1.amazonaws.com/aws-appmesh-envoy:v1.34.13.0-prod
     ```
**참고**  
`APPMESH_RESOURCE_ARN` 속성에는 `1.15.0` 이상의 Envoy 이미지 버전이 필요합니다. 자세한 내용은 [Envoy 이미지](envoy.md) 단원을 참조하십시오.
**중요**  
v1.9.0.0-prod 이상 버전만 App Mesh에서 사용할 수 있습니다.

1. 아래의 `Show more`를 선택합니다. 다음 콘텐츠를 통해 인스턴스에 `envoy-networking.sh`라는 파일을 생성합니다. *8000*을 애플리케이션 코드에서 수신 트래픽에 사용하는 포트로 바꿉니다. `APPMESH_IGNORE_UID`의 값을 변경할 수 있지만 이 값은 이전 단계에서 지정한 값과 같아야 합니다(예: `1337`). 필요한 경우 `APPMESH_EGRESS_IGNORED_IP`에 주소를 추가할 수 있습니다. 어떠한 행도 수정하지 마십시오.

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

1. 애플리케이션 트래픽을 Envoy 프록시로 라우팅하는 `iptables` 규칙을 구성하려면 이전 단계에서 생성한 스크립트를 실행합니다.

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

1. 가상 노드 애플리케이션 코드를 시작합니다.

**참고**  
App Mesh에 대한 더 많은 예제와 연습 내용을 보려면 [App Mesh 예제 리포지토리](https://github.com/aws/aws-app-mesh-examples)를 참조하세요.