亚马逊AWS官方博客

使用 AWS Cloud Map 建立跨 Amazon EKS 集群 App Mesh

Original URL:https://aws.amazon.com/cn/blogs/containers/cross-amazon-eks-cluster-app-mesh-using-aws-cloud-map/

 

内容概述

在本文中,我们将探讨如何在Amazon EKS(EKS)集群当中使用AWS App Mesh。App Mesh是一种服务网格,可帮助用户对部署在同一VPC上两套集群之间的各项服务进行控制与监视。在本文的演示中,我们将在VPC内部署两个EKS集群,并使用AWS Cloud Map实现App Mesh服务发现。

在位于同一VPC内的这两个EKS集群上,我们可以通过AWS Cloud Map理解跨集群网格的基本概念。下图为演示环境的总体架构。为了明确起见,这里选择了较为简单的示例,在现实场景中,App Mesh往往会跨越ECS、Fargate以及Kubernetes on EC2等多种不同容器集群。

在本示例中,VPC内部署有两个EKS集群,并由此建立跨集群网格。从上图可以看到,front容器将部署在集群1内,color容器则部署在集群2中。我们的目标是以AWS Cloud Map服务发现为基础,跨越这2个集群建立起网格。

集群

为了简单起见,我们在同一VPC内启动两个EKS集群,并配置Mesh以部署各集群组件。

部署

可以看到colorapp有两种部署,蓝色和红色。这两种部署的Pod都注册在虚拟服务colorapp.appmesh-demo.pvt.aws.local之后。其中蓝色Pod在网格中注册为colorapp-blue虚拟节点,红色Pod则注册为colorapp-red虚拟节点。通过配置,AWS Cloud Map可以通过服务发现识别出这两个虚拟节点,这是因为各Pod的IP地址已经连同相关属性在AWS Cloud Map服务中完成了注册。另外,我们还定义了一项colorapp虚拟服务,用于将流量路由至蓝色与红色虚拟节点。

Front应用则充当网关,其能够远程调用colorapp。Front应用为单一部署,其中各Pod都作为front虚拟节点在网格中完成了注册。该虚拟节点使用colorapp虚拟服务作为后端。在这套架构中,我们将Envoy注入至front Pod以使用App Mesh的端点发现服务(EDS)发现colorapp的各个端点。

网格

App Mesh各组件将被部署在两套集群之一当中。具体部署位置并不重要,最重要的是各组件能够切实部署到位。每项服务对应一个虚拟节点,并由虚拟服务中的路由机制将将来自提供方的流量在红色与蓝色节点间平均分配。在这里,我们使用自定义CRD、网格控制器以及网格注入组件——这些组件将使用标准kubectl处理网格的创建工作。也就是自动在Pod创建过程中注入代理边车。

注意:如果需要,大家也可以通过调用App Mesh API的方式部署App Mesh组件。

AWS Cloud Map

在网格创建完成之后,我们将使用服务发现属性,由其在我们预先创建的命名空间内自动生成DNS记录。第一个集群内的front应用程序将在AWS Cloud Map中使用此DNS条目,从而与第二个集群内的colorapp进行通信。

下面马上开始……

先决条件

要成功完成部署,我们需要做好以下准备工作:

  • 保证安装有最新的AWS CLI,版本应为1.16.268或者更高。
  • 保证安装有kubectl,且版本为1.11或更高。
  • 保证安装有jq
  • 保证安装有aws-iam-authenticator,否则将无法使用eksctl。
  • 安装有eksctl,在macOS上的安装方式为brew tap weaveworks/tap 与brew install weaveworks/tap/eksctl,请保证其版本至少为0.1.26

请注意,本演练的整个流程选择在us-east-1区域进行。

集群配置

使用以下命令,通过eksctl创建一个EKS集群:

eksctl create cluster --name=eksc2 --nodes=3 --alb-ingress-access 
--region=us-east-1 --ssh-access --asg-access  --full-ecr-access  
--external-dns-access --appmesh-access --vpc-cidr 172.16.0.0/16
--auto-kubeconfig
#[✔]  EKS cluster "eksc2-useast1" in "us-east-1" region is ready

在集群创建完毕之后,打开新的选项卡并使用以下命令,通过eksctl创建另一个EKS集群:

注意:请使用此命令中的公共与私有子网来创建集群2。关于更多详细信息,请点击此处

eksctl create cluster --name=eksc1 --nodes=2 --alb-ingress-access 
--region=us-east-1 --ssh-access --asg-access  --full-ecr-access  
--external-dns-access --appmesh-access  --auto-kubeconfig 
--vpc-private-subnets=<comma seperated private subnets>
--vpc-public-subnets=<comma seperated public subnets>
#[✔]  EKS cluster "eksc1" in "us-east-1" region is ready

在完成之后,分别根据eksctl的输出结果更新各选项卡中的KUBECONFIG环境变量:

在各选项卡中运行以下命令。

export KUBECONFIG=~/.kube/eksctl/clusters/eksc1 

export KUBECONFIG=~/.kube/eksctl/clusters/eksc2

现在,我们已经设置了两个集群,并将kubectl指向相应的集群。恭喜大家!

部署App Mesh自定义组件

为了在创建Pod时自动注入App Mesh组件与代理,我们还需要在集群上创建一些自定义资源。在这里,我们使用helm。首先需要在两个集群上安装tiller,而后使用helm在两个集群上运行以下命令。

代码库

>> git clone https://github.com/aws/aws-app-mesh-examples (https://github.com/aws/aws-app-mesh-examples).git
>> cd aws-app-mesh-examples/walkthroughs/howto-k8s-cross-cluster

安装Helm

>>brew install kubernetes-helm

安装tiller

要使用helm,我们需要在集群之上安装名为tiller的服务器端组件。请根据说明文档的指示在两个集群上分别安装tiller。

验证tiller安装

>>kubectl get po -n kube-system | grep -i tiller
tiller-deploy-6d65d78679-whwzn 1/1 Running 0 5h35m

安装App Mesh组件

运行以下命令,安装App Mesh控制器与Injector组件。

helm repo add eks https://aws.github.io/eks-charts
kubectl create ns appmesh-system
kubectl apply -f https://raw.githubusercontent.com/aws/eks-charts/master/stable/appmesh-controller/crds/crds.yaml
helm upgrade -i appmesh-controller eks/appmesh-controller --namespace appmesh-system
helm upgrade -i appmesh-inject eks/appmesh-inject --namespace appmesh-system --set mesh.create=true --set mesh.name=global

Opitionally add x-ray tracing
helm upgrade -i appmesh-inject eks/appmesh-inject --namespace appmesh-system --set tracing.enabled=true --set tracing.provider=x-ray

现在,我们已经做好了前期准备,可以将front与colorapp应用程序以及App Mesh部署到各集群当中了。

部署服务与网格结构

1.大家应该位于walkthrough/howto-k8s-cross-cluster文件夹内,所有的命令都由此位置运行。

2.您的账户id为:

export AWS_ACCOUNT_ID=<your_account_id>

3. 区域,本示例中为us-east-1:

export AWS_DEFAULT_REGION=us-east-1

4. 将ENVOY_IMAGE环境变量设置为App Mesh Envoy,详见Envoy

export ENVOY_IMAGE=...

5. 将VPC_ID环境变量设置为Kubernetes Pod启动时所处的VPC。我们将使用此VPC,通过create-private-dns-namespace API在AWS当中设置私有DNS命名空间。要查找EKS集群的VPC,大家可以使用aws eks describe-cluster。在后文中,我们将解释为何需要使用AWS Cloud Map PrivateDnsNamespace。

export VPC_ID=...

6. CLUSTER环境变量用于导出kube配置

export CLUSTER1=eksc1
export CLUSTER2=eksc2

部署

./deploy.sh

验证部署

集群1

>>kubectl get all -n appmesh-demo
NAME READY STATUS RESTARTS AGE
pod/front-7d7bc9458f-g2hnx 3/3 Running 0 5h23m

NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/front LoadBalancer 10.100.145.29 af3c595c8fb3b11e987a30ab4de89fc8-1707174071.us-east-1.elb.amazonaws.com 80:31646/TCP 5h23m

NAME READY UP-TO-DATE AVAILABLE AGE
deployment.apps/front 1/1 1 1 5h23m

NAME DESIRED CURRENT READY AGE
replicaset.apps/front-7d7bc9458f 1 1 1 5h23m

NAME AGE
mesh.appmesh.k8s.aws/global 5h
>>kubectl get all -n appmesh-system
NAME                                      READY   STATUS    RESTARTS   AGE
pod/appmesh-controller-84d46946b9-5lj7f   1/1     Running   0          5h27m
pod/appmesh-inject-5d8b86846-67fc6        1/1     Running   0          5h26m

NAME                     TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)   AGE
service/appmesh-inject   ClusterIP   10.100.75.167   <none>        443/TCP   5h27m

NAME                                 READY   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/appmesh-controller   1/1     1            1           5h27m
deployment.apps/appmesh-inject       1/1     1            1           5h27m

NAME                                            DESIRED   CURRENT   READY   AGE
replicaset.apps/appmesh-controller-84d46946b9   1         1         1       5h27m
replicaset.apps/appmesh-inject-5d8b86846        1         1         1       5h26m
replicaset.apps/appmesh-inject-7bb9f6d7b8       0         0         0       5h27m

NAME                          AGE
mesh.appmesh.k8s.aws/global   5h

集群2

>>kubectl get all -n appmesh-demo
NAME                                 READY   STATUS    RESTARTS   AGE
pod/colorapp-blue-7b6dbc5c97-wrsp9   3/3     Running   0          13h
pod/colorapp-red-59b577f5bc-mnh9q    3/3     Running   0          13h
pod/curler-5bd7c8d767-kcw55          1/1     Running   1          9h

NAME                            READY   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/colorapp-blue   1/1     1            1           13h
deployment.apps/colorapp-red    1/1     1            1           13h
deployment.apps/curler          1/1     1            1           9h

NAME                                       DESIRED   CURRENT   READY   AGE
replicaset.apps/colorapp-blue-7b6dbc5c97   1         1         1       13h
replicaset.apps/colorapp-red-59b577f5bc    1         1         1       13h
replicaset.apps/curler-5bd7c8d767          1         1         1       9h

NAME                                AGE
mesh.appmesh.k8s.aws/appmesh-demo   13h
mesh.appmesh.k8s.aws/global         1d

NAME                                        AGE
virtualnode.appmesh.k8s.aws/colorapp-blue   13h
virtualnode.appmesh.k8s.aws/colorapp-red    13h
virtualnode.appmesh.k8s.aws/front           13h

NAME                                                                 AGE
virtualservice.appmesh.k8s.aws/colorapp.appmesh-demo.pvt.aws.local   13h
>>kubectl get all -n appmesh-system
NAME                                      READY   STATUS    RESTARTS   AGE
pod/appmesh-controller-84d46946b9-8k8bj   1/1     Running   0          27h
pod/appmesh-inject-5d8b86846-zqrn6        1/1     Running   0          27h

NAME                     TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)   AGE
service/appmesh-inject   ClusterIP   10.100.123.159   <none>        443/TCP   27h

NAME                                 READY   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/appmesh-controller   1/1     1            1           27h
deployment.apps/appmesh-inject       1/1     1            1           27h

NAME                                            DESIRED   CURRENT   READY   AGE
replicaset.apps/appmesh-controller-84d46946b9   1         1         1       27h
replicaset.apps/appmesh-inject-5d8b86846        1         1         1       27h
replicaset.apps/appmesh-inject-7bb9f6d7b8       0         0         0       27h

NAME                                AGE
mesh.appmesh.k8s.aws/appmesh-demo   13h
mesh.appmesh.k8s.aws/global         1d

请注意,应用程序Pod上的3/3,代表各边车容器已经注入完成。

此外,虚拟服务、路由程序、路由以及各虚拟节点等网格组件也都已经创建完成。接下来,大家可以前往App Mesh控制台验证其创建结果。

验证AWS Cloud Map

作为部署命令的一部分,我们已经将镜像推送至ECR,在AWS Cloud Map当中创建了命名空间,并通过添加服务发现属性完成了网格与DNS条目的创建。

大家可以使用以下命令验证上述设置是否正常:

aws servicediscovery discover-instances --namespace appmesh-demo.pvt.aws.local
 --service-name colorapp

如果一切正常,结果应被解析至后端服务。

测试应用程序

集群1中的front服务已经作为负载均衡器进行公开,现在可供我们直接使用。

>>kubectl get svc -n appmesh-demo
NAME    TYPE           CLUSTER-IP      EXTERNAL-IP                                                               PORT(S)        AGE
front   LoadBalancer   10.100.145.29   af3c595c8fb3b11e987a30ab4de89fc8-1707174071.us-east-1.elb.amazonaws.com   80:31646/TCP   5h47m

>>curl af3c595c8fb3b11e987a30ab4de89fc8-1707174071.us-east-1.elb.amazonaws.com/color
blue

大家也可以使用一个简单的curler Pod进行测试,具体如下:

>>kubectl -n appmesh-demo run -it curler --image=tutum/curl /bin/bash
root@curler-5bd7c8d767-x657t:/#curl front/color
blue

注意:要使其正常工作,我们需要在集群2节点组内的安全组中,将端口8080向集群1的安全组开放。详见以下截屏。

安全组

入站访问

OK!现在我们已经使用App Mesh与AWS Cloud Map成功对跨集群服务通信进行了测试。接下来我们要发出几条请求,并检查我们的X-Ray边办是否能够完成捕捉任务。

验证X-Ray控制台

在集群1中的curler Pod中运行以下命令:

$ for ((n=0;n<200;n++)); do echo "$n: $(curl front/color)"; done
1: red
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100     4  100     4    0     0    205      0 --:--:-- --:--:-- --:--:--   210
2: blue
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100     3  100     3    0     0    136      0 --:--:-- --:--:-- --:--:--   142
......
......
196: blue
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100     4  100     4    0     0    236      0 --:--:-- --:--:-- --:--:--   250
197: blue
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100     3  100     3    0     0    180      0 --:--:-- --:--:-- --:--:--   187
198: red
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100     4  100     4    0     0    212      0 --:--:-- --:--:-- --:--:--   222
199: blue

Let’s take a look at our X-Ray console:

Traces:

Service Map:

大家应该已经注意到了,该请求被Envoy代理所拦截。Envoy代理在本质上就是一个边车容器,与应用程序容器一道部署到位。

总结

在本演练中,我们在VPC内创建了两个EKS集群,在其中一个集群上创建了前端服务,另一集群则创建后端服务。我们还创建了一个涵盖两个集群的AWS App Mesh,并使用AWS Cloud Map的发现服务建立起通信通道。整套方法也可扩展至其他集群(不要求一定是EKS集群),包括ECS、EKS、Fargate以及EC2实例等的混合场景。

相关资源

AWS App Mesh说明文档 AWS CLI AWS Cloud Map 当前可支持App Mesh的AWS区域 Envoy Image Envoy说明文档 EKS

 

本篇作者

Sridhar Mallu

是一位高级客户经理。他专门研究容器化、DevOps、微服务等领域的技术,同时也是Kubernetes、EKS以及App Mesh等项目的贡献者