이 연재글은 Service Mesh Architecture의 3번째 글입니다.

AWS App Mesh

AWS App Mesh는 애플리케이션 수준의 네트워킹을 통해 서비스가 여러 유형의 컴퓨팅 인프라에서 서로 원활하게 통신할 수 있게 지원하는 서비스입니다. App Mesh는 서비스의 통신 방법을 표준화하여 사용자에게 엔드 투 엔드 가시성을 제공하고 애플리케이션의 고가용성을 보장합니다.

AWS App Mesh를 사용하면 다양한 유형의 컴퓨팅 인프라 전반에 구축된 서비스에 대한 일관된 가시성 및 네트워크 트래픽 제어 기능을 제공하여 손쉽게 서비스를 실행할 수 있습니다. App Mesh를 사용하면 모니터링 데이터 수집 방식이나 서비스 간에 트래픽이 라우팅되는 방식을 변경하기 위해 애플리케이션 코드를 업데이트할 필요가 없습니다. App Mesh는 모니터링 데이터를 내보내도록 각 서비스를 구성하고, 애플리케이션 전반에 일관된 통신 제어 로직을 구현합니다. 이를 통해 오류의 정확한 위치를 신속하게 찾아내고 오류가 있거나 코드 변경 사항을 배포해야 하는 경우 네트워크 트래픽을 자동으로 다시 라우팅할 수 있습니다.

End-to-end visibility

App Mesh는 모든 마이크로 서비스에서 지표, 로그 및 추적을 일관되게 캡처합니다. 이 데이터를 결합하고 Amazon CloudWatch, AWS X-Ray 및 모니터링 및 추적을 위해 호환되는 AWS 파트너 및 커뮤니티 도구로 내보낼 수 있습니다. 이를 통해 모든 마이크로 서비스의 문제를 신속하게 식별하고 격리하여 전체 애플리케이션을 최적화할 수 있습니다.

Ensure high availability

App Mesh는 마이크로 서비스 간의 트래픽 흐름 방식을 구성하는 제어 기능을 제공합니다. 사용자 지정 트래픽 라우팅 규칙을 쉽게 구현하여 배포 중, 장애 발생 후, 애플리케이션 확장 시 모든 마이크로 서비스의 가용성을 높일 수 있습니다.

Streamline operations

App Mesh는 컨테이너와의 모든 통신 트래픽을 관리하는 proxy를 배포하고 구성합니다. 따라서 각 마이크로 서비스에 대한 통신 프로토콜을 구성하거나, 사용자 지정 코드를 작성하거나, 애플리케이션을 작동하기 위한 라이브러리를 구현할 필요가 없습니다.

Enhance any application

AWS Fargate, Amazon ECS, Amazon EKS 및 AWS의 자체 관리 형 Kubernetes에서 실행되는 기존 또는 새로운 마이크로 서비스와 함께 App Mesh를 사용할 수 있습니다. App Mesh는 클러스터, 오케스트레이션 시스템 또는 VPC에서 코드 변경 없이 단일 애플리케이션으로 실행되는 마이크로 서비스에 대한 통신을 모니터링하고 제어할 수 있습니다.

App Mesh 구성 요소

Mesh

메시는 내부에 상주하는 서비스 간의 네트워크 트래픽에 대한 논리적 경계입니다.

Virtual gateway, gateway route

가상 게이트웨이를 사용하면 메시 외부에 있는 리소스가 메시 내부에 있는 리소스와 통신 할 수 있습니다. 가상 게이트웨이는 Amazon ECS 서비스, Kubernetes 서비스 또는 Amazon EC2 인스턴스에서 실행되는 Envoy Proxy를 나타냅니다. 애플리케이션과 함께 실행되는 Envoy를 나타내는 가상 노드와 달리 가상 게이트웨이는 자체적으로 배포 된 Envoy를 나타냅니다.

가상 경로(Gateway Route)는 가상 게이트웨이에 연결되고 트래픽을 기존 가상 서비스로 라우팅 합니다. 경로가 요청과 일치하면 트래픽을 가상 서비스로 분산할 수 있습니다.

Virtual service, virtual nodes

가상 서비스는 가상 노드가 가상 라우터를 통해 직접 또는 간접적으로 제공하는 실제 서비스의 추상화입니다. 종속 서비스는 해당 virtualServiceName으로 가상 서비스를 호출하고 이러한 요청은 가상 서비스의 제공자로 지정된 가상 노드 또는 가상 라우터로 라우팅 됩니다.

가상 노드는 Amazon ECS 서비스 또는 Kubernetes 배포와 같은 특정 작업 그룹에 대한 논리적 포인터 역할을 합니다. 가상 노드를 생성할 때 작업 그룹에 대한 서비스 검색 방법을 지정해야 합니다. 가상 노드가 예상하는 모든 인바운드 트래픽은 리스너로 지정됩니다. 가상 노드가 아웃 바운드 트래픽을 보내는 가상 서비스는 백엔드로 지정됩니다.

Virtual router, virtual Route

가상 라우터는 메시 내에서 하나 이상의 가상 서비스에 대한 트래픽을 처리합니다. 가상 라우터를 만든 후에는 들어오는 요청을 다른 가상 노드로 보내는 가상 라우터의 경로를 만들고 연결할 수 있습니다.

경로(route)는 가상 라우터와 연결됩니다. route는 가상 라우터에 대한 요청을 일치시키고 트래픽을 연결된 가상 노드로 분산하는 데 사용됩니다. 경로가 요청과 일치하면 트래픽을 하나 이상의 가상 노드로 분산할 수 있습니다. 또한 각 가상 노드에 대해 상대적 가중치를 지정할 수 있습니다.

사전 준비사항

1.13 버전 이상의 Kubernetes Cluster

EKS 클러스터 생성 펼치기
$ eksctl create cluster \
--name eks-cluster-demo-mesh \
--region=ap-southeast-1 \
--vpc-private-subnets=subnet-01887582564722d0b,subnet-0cf77158921f1e7a2,subnet-0cf77158921f1e7a2 \
--vpc-public-subnets=subnet-9ac904fc,subnet-5d53a115,subnet-a0f74ff9 \
--auto-kubeconfig \
--without-nodegroup

$ eksctl create nodegroup --cluster=eks-cluster-demo-mesh \
--region=ap-southeast-1 \
--name=eks-cluster-demo-mesh-ng \
--node-type=t3.medium \
--nodes-min=1 \
--nodes=2 \
--nodes-max=3 \
--managed \
--full-ecr-access \
--appmesh-access \
--node-private-networking

$ aws eks --region ap-southeast-1 update-kubeconfig --name eks-cluster-demo-mesh

최신 awscli

최신 kubectl

3.0 버전 이상의 helm

http://3.36.120.4/post/12073/setup-elastic-kubernetes-service/

App Mesh controller 설치

Kubernetes Pod에 envoy proxy 컨테이너를 주입하는 WebHook을 설치합니다.

Helm에 eks-chart 저장소 추가

$ helm repo add eks https://aws.github.io/eks-charts
"eks" has been added to your repositories

App Mesh controller를 설치할 네임 스페이스 생성

$ kubectl create ns appmesh-system
namespace/appmesh-system created

App Mesh controller 설치 및 확인

$ helm upgrade -i appmesh-controller eks/appmesh-controller \
    --namespace appmesh-system
$ kubectl get pods -n appmesh-system
NAME                                  READY   STATUS    RESTARTS   AGE
appmesh-controller-66b749c78b-67n68   1/1     Running   0          6s

Deploy Sample App

AWS App Mesh를 구성하기 위해 먼저 Demo app을 kubernetes cluster에 배포합니다. front(yelb-ui), app(yelb-appserver), db(postgres), cache(redis)로 구성되어 있으며 각각의 리소스들을 추상화하여 Aws Mesh Component로 등록해야 합니다.

Demo App Repository Clone

$ git clone https://github.com/aws/aws-app-mesh-examples.git
$ cd aws-app-mesh-examples/walkthroughs/eks-getting-started/

리소스를 배포 할 Kubernetes 네임 스페이스 생성 및 Demo App 배포

namespace 생성, demo app 배포 펼치기

namespace.yaml

apiVersion: v1
kind: Namespace
metadata:
  name: yelb
$ kubectl apply -f namespace.yaml

Demo App 배포 / 확인

$ kubectl apply -f infrastructure/yelb_initial_deployment.yaml
$ kubectl get pods -n yelb
NAME                              READY     STATUS    RESTARTS   AGE
redis-server-55664c8d98-rfj8x     1/1       Running   0          28s
yelb-appserver-7cb8446b7b-lthd6   1/1       Running   0          28s
yelb-db-54b6cb9bc9-67fsk          1/1       Running   0          28s
yelb-ui-984856b8f-nx6p7           1/1       Running   0          28s
$ kubectl get svc -n yelb yelb-ui
NAME      TYPE           CLUSTER-IP       EXTERNAL-IP                                                                   PORT(S)        AGE
yelb-ui   LoadBalancer   10.100.233.222   a86106efac93e40908788513c3e373ab-801064534.ap-southeast-1.elb.amazonaws.com   80:31474/TCP   91s

App 배포후에 생성된 LoadBalancer 주소로 접속하면 아래와 같은 화면을 확인할 수 있습니다.

Namespace에 sidecar injection label 적용

app에 envoy sidecar를 적용하려면 해당 app이 설치된 namespace에 label을 적용해야 합니다. 다음과 같이 애플리케이션에 적용될 mesh 이름과 사이드카 Injector webhook을 활성화하는 레이블을 적용합니다.

app-mesh 설정, 웹훅 활성화 펼치기
$ kubectl label namespace yelb mesh=yelb 
$ kubectl label namespace yelb appmesh.k8s.aws/sidecarInjectorWebhook=enabled
$ kubectl get namespaces --show-labels
NAME              STATUS    AGE       LABELS
appmesh-system    Active    9m27s     <none>
default           Active    11h       <none>
kube-node-lease   Active    11h       <none>
kube-public       Active    11h       <none>
kube-system       Active    11h       <none>
yelb              Active    25m       appmesh.k8s.aws/sidecarInjectorWebhook=enabled,mesh=yelb

App Mesh 컴포넌트 등록

sample app에 mesh를 적용하려면 먼저 sample app 각각의 서비스들을 추상화하는 app mesh 컴포넌트들을 먼저 생성해야 합니다.

Mesh 생성

메시 생성 펼치기

create-mesh.yaml

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

적용

$ kubectl apply -f create-mesh.yaml

aws web console에서 확인하면 다음과 같이 생성된것을 확인할 수 있습니다.

App Mesh 구성요소 생성

실제 서비스들을 추상화 하는 mesh 구성요소(virtual node, virtual service, virtual router 등)를 생성합니다.

Redis 서비스 추상화

Redis 서버에 대한 논리적 포인터인 가상 노드(port 6370)및 가상 서비스(Virtual Service)를 생성하여 연결합니다.

Redis 서비스 추상화 펼치기

appmesh-yelb-redis.yaml

apiVersion: appmesh.k8s.aws/v1beta2
kind: VirtualNode
metadata:
  name: redis-server
  namespace: yelb
spec:
  awsName: redis-server-virtual-node
  podSelector:
    matchLabels:
      app: redis-server
  listeners:
    - portMapping:
        port: 6379
        protocol: tcp
  serviceDiscovery:
    dns:
      hostname: redis-server.yelb.svc.cluster.local
---
apiVersion: appmesh.k8s.aws/v1beta2
kind: VirtualService
metadata:
  name: redis-server
  namespace: yelb
spec:
  awsName: redis-server
  provider:
    virtualNode:
      virtualNodeRef:
        name: redis-server
$ kubectl apply -f infrastructure/appmesh_templates/appmesh-yelb-redis.yaml

aws web console에서 확인하면 다음과 같이 가상 노드와 서비스가 생성된것을 확인할 수 있습니다.

DB 서버 추상화

Redis서버와 동일하게 가상 노드(port 5432)를 생성하고 가상 서비스를 생성하여 연결합니다.

DB서버 추상화 펼치기

appmesh-yelb-db.yaml

apiVersion: appmesh.k8s.aws/v1beta2
kind: VirtualNode
metadata:
  name: yelb-db
  namespace: yelb
spec:
  awsName: yelb-db-virtual-node
  podSelector:
    matchLabels:
      app: yelb-db
  listeners:
    - portMapping:
        port: 5432
        protocol: tcp
  serviceDiscovery:
    dns:
      hostname: yelb-db.yelb.svc.cluster.local
---
apiVersion: appmesh.k8s.aws/v1beta2
kind: VirtualService
metadata:
  name: yelb-db
  namespace: yelb
spec:
  awsName: yelb-db
  provider:
    virtualNode:
      virtualNodeRef:
        name: yelb-db

적용

$ kubectl apply -f infrastructure/appmesh_templates/appmesh-yelb-db.yaml

APP(API) 서버 추상화

가상 노드(port 4567)와 가상 서비스를 생성하고 추가로 가상 라우터도 생성합니다.

app서버 추상화 펼치기

appmesh-yelb-appserver.yaml

apiVersion: appmesh.k8s.aws/v1beta2
kind: VirtualNode
metadata:
  name: yelb-appserver
  namespace: yelb
spec:
  awsName: yelb-appserver-virtual-node
  podSelector:
    matchLabels:
      app: yelb-appserver
  listeners:
    - portMapping:
        port: 4567
        protocol: http
  serviceDiscovery:
    dns:
      hostname: yelb-appserver.yelb.svc.cluster.local
  backends:
    - virtualService:
       virtualServiceRef:
          name: yelb-db
    - virtualService:
       virtualServiceRef:
          name: redis-server
---
apiVersion: appmesh.k8s.aws/v1beta2
kind: VirtualRouter
metadata:
  namespace: yelb
  name: yelb-appserver
spec:
  awsName: yelb-appserver-virtual-router
  listeners:
    - portMapping:
        port: 4567
        protocol: http
  routes:
    - name: route-to-yelb-appserver
      httpRoute:
        match:
          prefix: /
        action:
          weightedTargets:
            - virtualNodeRef:
                name: yelb-appserver
              weight: 1
        retryPolicy:
            maxRetries: 2
            perRetryTimeout:
                unit: ms
                value: 2000
            httpRetryEvents:
                - server-error
                - client-error
                - gateway-error
---
apiVersion: appmesh.k8s.aws/v1beta2
kind: VirtualService
metadata:
  name: yelb-appserver
  namespace: yelb
spec:
  awsName: yelb-appserver
  provider:
    virtualRouter:
        virtualRouterRef:
            name: yelb-appserver
$ kubectl apply -f infrastructure/appmesh_templates/appmesh-yelb-appserver.yaml

가상노드 backend 설정

app서버는 Redis와 DB를 사용하므로 가상 노드의 BackEnd로 Redis와 DB가 설정된것을 확인할 수 있습니다.

위에서 생성한 가상 서비스 설정과는 다르게 가상노드를 provider로 사용하지 않고 가상라우터(virtual router)를 provider로 설정한 것을 볼수 있습니다. 가상 라우터를 통해 인입되는 트래픽을 정책에 맞게 분산시켜 처리할 수 있습니다.

가상 라우터(virtual router)

들어오는 요청을 다른 가상 노드로 보내는 가상 라우터의 경로를 만들고 연결합니다. 현재는 하나의 가상 노드만 있으므로 해당 노드로 100% 요청을 보내도록 설정합니다.

Front 서버 추상화

가상 노드(port 80)와 가상 서비스를 생성하여 연결합니다.

front 서버 추상화 펼치기

appmesh-yelb-ui.yaml

apiVersion: appmesh.k8s.aws/v1beta2
kind: VirtualNode
metadata:
  name: yelb-ui
  namespace: yelb
spec:
  awsName: yelb-ui-virtual-node
  podSelector:
    matchLabels:
      app: yelb-ui
  listeners:
    - portMapping:
        port: 80
        protocol: http
  serviceDiscovery:
    dns:
      hostname: yelb-ui.yelb.svc.cluster.local
  backends:
    - virtualService:
       virtualServiceRef:
          name: yelb-appserver
---
apiVersion: appmesh.k8s.aws/v1beta2
kind: VirtualService
metadata:
  name: yelb-ui
  namespace: yelb
spec:
  awsName: yelb-ui
  provider:
    virtualNode:
      virtualNodeRef:
        name: yelb-ui
$ kubectl apply -f infrastructure/appmesh_templates/appmesh-yelb-ui.yaml

virtual node backend 설정

app서버로부터 데이터를 요청하므로 가상노드의 BackEnd로 app서버를 설정합니다.

virtual service 설정

Envoy SideCar 주입

Mesh의 모든 구성요소가 준비되었으면 sidecar를 주입합니다. 위에서 app mesh controller를 namespace에 설정하였으므로 pod를 새로 띄우면 자동으로 주입됩니다. 다시 띄워주면 READY가 1/1에서 2/2로 변경되는것을 확인할 수 있습니다.

envoy 주입 펼치기
$ kubectl -n yelb get pods
NAME                              READY     STATUS    RESTARTS   AGE
redis-server-55664c8d98-rfj8x     1/1       Running   0          63m
yelb-appserver-7cb8446b7b-lthd6   1/1       Running   0          63m
yelb-db-54b6cb9bc9-67fsk          1/1       Running   0          63m
yelb-ui-984856b8f-nx6p7           1/1       Running   0          63m
$ kubectl rollout restart deployment -n yelb
$ kubectl -n yelb get pods
NAME                              READY     STATUS    RESTARTS   AGE
redis-server-55664c8d98-fg6cg     2/2       Running   0          3m2s
yelb-appserver-7cb8446b7b-5q25z   2/2       Running   0          3m2s
yelb-db-54b6cb9bc9-vdhvc          2/2       Running   0          3m2s
yelb-ui-984856b8f-6hpzh           2/2       Running   0          3m2s

새로운 App Version으로의 트래픽 분할

App Mesh가 완성되었으므로 App Mesh의 가상 라우터를 사용하여 새로운 앱 버전의 애플리케이션으로 트래픽을 보낼수 있습니다.

app mesh에 app서버 v2를 위한 가상노드(Virtual Node)생성

가상노드 생성 펼치기

appmesh-yelb-appserver-v2.yaml

apiVersion: appmesh.k8s.aws/v1beta2
kind: VirtualNode
metadata:
  name: yelb-appserver-v2
  namespace: yelb
spec:
  awsName: yelb-appserver-virtual-node-v2
  podSelector:
    matchLabels:
      app: yelb-appserver-v2
  listeners:
    - portMapping:
        port: 4567
        protocol: http
  serviceDiscovery:
    dns:
      hostname: yelb-appserver-v2.yelb.svc.cluster.local
  backends:
    - virtualService:
       virtualServiceRef:
          name: yelb-db
    - virtualService:
       virtualServiceRef:
          name: redis-server
$ kubectl apply -f infrastructure/appmesh_templates/appmesh-yelb-appserver-v2.yaml

새로운 버전의 서비스 배포

생성된 가상노드에 대응하는 v2 서비스를 배포합니다.

새로운 v2 버전 앱 배포 펼치기

yelb_appserver_v2_deployment.yaml

apiVersion: v1
kind: Service
metadata:
  namespace: yelb
  name: yelb-appserver-v2
  labels:
    app: yelb-appserver-v2
    tier: middletier
spec:
  type: ClusterIP
  ports:
    - port: 4567
  selector:
    app: yelb-appserver-v2
    tier: middletier
---
apiVersion: apps/v1
kind: Deployment
metadata:
  namespace: yelb
  name: yelb-appserver-v2
spec:
  replicas: 1
  selector:
    matchLabels:
      app: yelb-appserver-v2
      tier: middletier
  template:
    metadata:
      labels:
        app: yelb-appserver-v2
        tier: middletier
    spec:
      containers:
        - name: yelb-appserver-v2
          image: codej99/mesh:latest
          ports:
            - containerPort: 4567

v2 버전 배포 및 확인

$ kubectl apply -f infrastructure/yelb_appserver_v2_deployment.yaml
$ kubectl get pods -n yelb
NAME                                 READY     STATUS    RESTARTS   AGE
redis-server-55664c8d98-fg6cg        2/2       Running   0          127m
yelb-appserver-7cb8446b7b-5q25z      2/2       Running   0          127m
yelb-appserver-v2-649d7dc57f-lhthw   2/2       Running   0          7m42s
yelb-db-54b6cb9bc9-vdhvc             2/2       Running   0          127m
yelb-ui-984856b8f-6hpzh              2/2       Running   0          127m

버전별 트래픽 라우팅

v2 서비스가 배포되면 가상 라우터 정보를 수정 하여 새로운 버전으로 트래픽을 보낼 수 있습니다. 아래 내용을 적용하면 가상 라우터에 의해 50% 확률로 v1과 v2의 내용이 번갈아 가며 노출됩니다.

버전별 트래픽 라우팅 펼치기

appmesh-virtual-router-appserver-v1-v2.yaml

apiVersion: appmesh.k8s.aws/v1beta2
kind: VirtualRouter
metadata:
  namespace: yelb
  name: yelb-appserver
spec:
  awsName: yelb-appserver-virtual-router
  listeners:
    - portMapping:
        port: 4567
        protocol: http
  routes:
    - name: route-to-yelb-appserver
      httpRoute:
        match:
          prefix: /
        action:
          weightedTargets:
            - virtualNodeRef:
                name: yelb-appserver
              weight: 1
            - virtualNodeRef:
                name: yelb-appserver-v2
              weight: 1
        retryPolicy:
            maxRetries: 2
            perRetryTimeout:
                unit: ms
                value: 2000
            httpRetryEvents:
                - server-error
                - client-error
                - gateway-error
$ kubectl apply -f ./infrastructure/appmesh_templates/appmesh-virtual-router-appserver-v1-v2.yaml

v1

v2

모든 트래픽을 v2로 보내도록 설정

가상 라우터 설정에서 v1 내용을 삭제합니다. 이제 다시 페이지를 호출하면 v2 내용만 보여지는것을 확인할 수 있습니다.

모든 트래픽을 v2로 라우팅 펼치기

appmesh-virtual-router-appserver-v2.yaml

apiVersion: appmesh.k8s.aws/v1beta2
kind: VirtualRouter
metadata:
  namespace: yelb
  name: yelb-appserver
spec:
  awsName: yelb-appserver-virtual-router
  listeners:
    - portMapping:
        port: 4567
        protocol: http
  routes:
    - name: route-to-yelb-appserver
      httpRoute:
        match:
          prefix: /
        action:
          weightedTargets:
            - virtualNodeRef:
                name: yelb-appserver-v2
              weight: 1
        retryPolicy:
            maxRetries: 2
            perRetryTimeout:
                unit: ms
                value: 2000
            httpRetryEvents:
                - server-error
                - client-error
                - gateway-error
$ kubectl apply -f infrastructure/appmesh_templates/appmesh-virtual-router-appserver-v2.yaml

Virtual Gateway, gateway route

가상 게이트웨이(virtual gateway)는 메시 외부 요청에 대해 메시 내부 리소스에 대한 액세스를 제공합니다. 게이트웨이 경로(gateway route) 설정을 통해 메시 내의 가상 서비스에 대한 인바운드 트래픽에 대한 라우팅 규칙을 설정할 수 있습니다.

사용할 virtual gateway Labeling

가상 게이트웨이를 적용하려면 namespace label에 가상 게이트웨이 이름을 명시해 줘야 합니다.

$ kubectl label namespace yelb gateway=yelb-gateway
$ kubectl get namespace --show-labels
NAME              STATUS    AGE       LABELS
appmesh-system    Active    4d3h      <none>
default           Active    4d15h     <none>
kube-node-lease   Active    4d15h     <none>
kube-public       Active    4d15h     <none>
kube-system       Active    4d15h     <none>
yelb              Active    4d1h      appmesh.k8s.aws/sidecarInjectorWebhook=enabled,gateway=yelb-gateway,mesh=yelb

app Mesh에 virtual gateway 및 virtual router 생성

가상 게이트웨이와 라우터를 mesh에 생성합니다.(게이트웨이 추상화). 이때 외부 요청의 path에 따라 front ui 서비스나 app 서비스로 라우팅 되도록 설정합니다.

가상 게이트웨이 생성 펼치기

create-virtual-gateway.yaml

apiVersion: appmesh.k8s.aws/v1beta2
kind: VirtualGateway
metadata:
  name: yelb-gateway
  namespace: yelb
spec:
  namespaceSelector:
    matchLabels:
      gateway: yelb-gateway
  podSelector:
    matchLabels:
      app: yelb-gateway
  listeners:
    - portMapping:
        port: 8088
        protocol: http
---
apiVersion: appmesh.k8s.aws/v1beta2
kind: GatewayRoute
metadata:
  name: yelbui-gatewayroute
  namespace: yelb
spec:
  httpRoute:
    match:
      prefix: "/"
    action:
      target:
        virtualService:
          virtualServiceRef:
            name: yelb-ui
---
apiVersion: appmesh.k8s.aws/v1beta2
kind: GatewayRoute
metadata:
  name: yelbapp-gatewayroute
  namespace: yelb
spec:
  httpRoute:
    match:
      prefix: "/api"
    action:
      target:
        virtualService:
          virtualServiceRef:
            name: yelb-appserver

gateway 적용

$ kubectl apply -f create-virtual-gateway.yaml
virtualgateway.appmesh.k8s.aws/yelb-gateway created
gatewayroute.appmesh.k8s.aws/yelbui-gatewayroute created
gatewayroute.appmesh.k8s.aws/yelbapp-gatewayroute created

Envoy로 gateway 생성하여 외부에 서비스 노출

추상화한 게이트웨이에 대응되는 실제 게이트웨이 서비스를 kubernetes cluster에 배포합니다. 게이트웨이는 envoy 이미지로 생성하며 NLB로 외부에 오픈합니다.

envoy gateway 배포 펼치기

create-gateway.yaml

apiVersion: v1
kind: Service
metadata:
  name: yelb-gateway
  namespace: yelb
  annotations:
    service.beta.kubernetes.io/aws-load-balancer-type: "nlb"
spec:
  type: LoadBalancer
  ports:
    - port: 80
      targetPort: 8088
      name: http
  selector:
    app: yelb-gateway
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: yelb-gateway
  namespace: yelb
spec:
  replicas: 1
  selector:
    matchLabels:
      app: yelb-gateway
  template:
    metadata:
      labels:
        app: yelb-gateway
    spec:
      containers:
        - name: envoy
          image: 840364872350.dkr.ecr.ap-southeast-1.amazonaws.com/aws-appmesh-envoy:v1.15.0.0-prod
          ports:
            - containerPort: 8088

게이트 웨이 생성 확인

$ kubectl apply -f create-gateway.yaml
$ kubectl get svc yelb-gateway -n yelb
NAME           TYPE           CLUSTER-IP       EXTERNAL-IP                                                                          PORT(S)        AGE
yelb-gateway   LoadBalancer   10.100.154.239   a3d427d37705348608470e0b6d5d6ace-57470a035ac39ec1.elb.ap-southeast-1.amazonaws.com   80:32560/TCP   112s

이제 생성된 Gateway 하나의 엔드포인트로 path에 따라서 front ui 서비스나 app 서비스를 요청할 수 있습니다.

http://게이트웨이 주소

http://게이트웨이주소/api/api/getvotes

[
  {
    "name": "outback",
    "value": 2
  },
  {
    "name": "bucadibeppo",
    "value": 2
  },
  {
    "name": "ihop",
    "value": 1
  },
  {
    "name": "chipotle",
    "value": 2
  }
]

Mesh Monitoring / Visualizing

메시 내부 서비스들은 envoy sidecar에 의해 통신이 이루어지므로 서비스간 통신 정보는 수집되어 모니터링 툴로 확인할 수 있습니다. aws에서 자체 제공하는 cloud watch나 x-ray 서비스들 뿐만 아니라 envoy와 호환되는 3rd party 모니터링 툴도 설치하여 사용할 수 있습니다.

Logging

HTTP Access logging
Amazone CloudWatch Logs
Available as container logs on ECS, EKS, Fargate

Metrics

CloudWatch Metrics

Tracing

AWS X-Ray

AWS X-Ray 적용 펼치기

IAM 정책 적용

arn:aws:iam::aws:policy/AWSXRayDaemonWriteAccess정책을 EKS 클러스터의 EC2 auto-scaling group에 연결합니다.

$ AUTOSCALING_GROUP =$(aws eks describe-nodegroup --cluster-name eks-cluster-demo-mesh --nodegroup-name eks-cluster-demo-mesh-ng | jq -r '.nodegroup.resources.autoScalingGroups[0].name')
$ ROLE_NAME=$(aws iam get-instance-profile --instance-profile-name $AUTOSCALING_GROUP | jq -r '.InstanceProfile.Roles[] | .RoleName')
$ aws iam attach-role-policy \
      --role-name $ROLE_NAME \
      --policy arn:aws:iam::aws:policy/AWSXRayDaemonWriteAccess

App Mesh data plane의 X-Ray tracing 활성화

$ helm upgrade -i appmesh-controller eks/appmesh-controller \
    --namespace appmesh-system \
    --set tracing.enabled=true \
    --set tracing.provider=x-ray

pod 재시작하여 x-ray daemon 주입

$ kubectl rollout restart deployment -n yelb
$ kubectl -n yelb get pods
NAME                              READY   STATUS    RESTARTS   AGE
redis-server-684cdc6f5-8229f      3/3     Running   0          11m
yelb-appserver-5d756c4545-dpjwb   3/3     Running   0          11m
yelb-db-56dcbd6b6b-zkvcn          3/3     Running   0          11m
yelb-gateway-94c667669-2c6xp      2/2     Running   0          3m54s
yelb-ui-55f8ff9b7b-h7l8f          3/3     Running   0          11m

3rd Party

Splunk, Prometheus, Grafana, Zipkin, LightStep …

[참고]

https://aws.amazon.com/ko/blogs/containers/getting-started-with-app-mesh-and-eks/

https://docs.aws.amazon.com/app-mesh/latest/userguide/app-mesh-ug.pdf

https://aws.amazon.com/ko/blogs/containers/introducing-ingress-support-in-aws-app-mesh/

https://docs.aws.amazon.com/app-mesh/latest/userguide/virtual_gateways.html

https://docs.aws.amazon.com/app-mesh/latest/userguide/gateway-routes.html

https://docs.aws.amazon.com/app-mesh/latest/userguide/virtual_services.html

https://docs.aws.amazon.com/app-mesh/latest/userguide/virtual_nodes.html

https://awskrug.github.io/eks-workshop/servicemesh_with_appmesh

https://github.com/aws/aws-app-mesh-examples/blob/master/walkthroughs/eks/o11y-xray.md

https://aws.amazon.com/ko/app-mesh/features/

https://github.com/aws/aws-app-mesh-examples

연재글 이동[이전글] Istio Service Mesh