aws appmesh 在ecs中部署和配置appmesh服务网格

appmesh配置ecs

参考资料

  • https://docs.amazonaws.cn/app-mesh/latest/userguide/getting-started-ecs.html

需要操作:

  • 授权ecs任务中部署的envoy代理读取虚拟节点配置
  • 更新ecs任务定义使用envoy代理
  • 使用xray跟踪envoy请求

注意点:

  • envoy容器需要凭证和appmesh服务进行通信(ec2类型可以使用元数据或任务角色,fargate只能使用任务角色)

  • 创建任务定义集成appmesh,启用appmesh,和之前创建的mesh关联,确保使用awsvpc网络模式

  • 任务定义中容器必须等待envoy代理引导和启动之后才能启动,设置dependon参数

appmesh 示例存储库,https://github.com/aws/aws-app-mesh-examples

中国区存储库的使用方式:

  • 修改资源为aws-cn
  • 修改终端节点为amazonaws.com.cn
  • 绕过80/8080/443端口

本次部署的架构类似之前的ec2部署appmesh,详情参考这篇文章

创建ecs应用

配置ecs任务定义

我们使用fargate部署测试服务,方便起见我们使用amazonlinux镜像(最好是手动安装工具之后打包成image),并开启ecs exec功能

yum install procps-ng -y
yum install bind-utils -y
yum install nginx -y
yum install telnet -y
docker commit c6d40d5fb469 xxxxxx.dkr.ecr.cn-north-1.amazonaws.com.cn/amazonlinux
docker push xxxxxx.dkr.ecr.cn-north-1.amazonaws.com.cn/amazonlinux:latest

https://docs.amazonaws.cn/en_us/AmazonECS/latest/developerguide/ecs-exec.html

注意:不能为现有任务打开 ECS Exec,只能为新任务打开 ECS Exec,会话的空闲超时时间为20分钟

需要为ecs task role配置一定权限

为了在ecs中使用appmesh,需要满足以下条件

  • 确保ecs 任务定义中已经配置了appmesh的容器
  • 确保使用了服务发现,实际上就是通过dns找到该服务,在eks里可以直接使用coredns,在ec2上需要手动配置dns解析(cloudmap),ecs可以通过开启服务发现自动注册cloudmap

在这里插入图片描述

ecs服务配置服务发现的过程

当创建服务时,涉及到负载均衡器,服务发现,自动扩缩,创建删除网卡,cw告警日志和ecs exec时,都需要使用ecs服务角色,信任的对象为ecs.amazonaws.com服务

https://docs.aws.amazon.com/cli/latest/reference/ecs/create-service.html

控制服务发现的是--service-registries参数,有以下注意事项

https://docs.amazonaws.cn/AmazonECS/latest/developerguide/service-discovery.html

  • 服务发现的每个服务限制任务数量在1000以内
  • 仅支持向私有dns命名空间注册服务
  • 需要配置vpc的dns解析
  • 自动创建的cloudmap资源需要手动删除

注意:以下cli操作只是为了了解整个服务发现创建的流程,实际上如果使用控制台,会自动创建cloudmap的ns和service,不需要手动配置

使用命令行创建cloudmap,这里注意使用的命令是servicediscovery,创建名为ecs-mesh的名称空间,默认还会创建一个route53的私有托管域

aws servicediscovery create-private-dns-namespace \
    --name ecs-mesh.local \
    --vpc vpc-086d798b56f59e2ae

之后创建的ecs服务如果指定命名空间,会自动将服务名称注册到该托管域中

在这里插入图片描述

创建出来的私有托管域,注意,该托管域无法直接进行编辑,只能通过cloudmap进行设置

在这里插入图片描述

创建servicea,这个namespace-id是cloudmap的namespaceid

aws servicediscovery create-service \
    --name servicebv1 \
    --namespace-id  ns-ngtw4luqvwo5pgnw \
    --dns-config "NamespaceId=ns-ngtw4luqvwo5pgnw,RoutingPolicy=WEIGHTED
,DnsRecords=[{Type=A,TTL=60}]"

编写服务发现的配置文件,这里注意需要手动创建一个名为servicea,文件中的arn无法在控制台上直接找到,只能通过service的id手动拼接

在这里插入图片描述

// serviceA-config.json
{
    "serviceRegistries": [
            {
                "registryArn": "arn:aws-cn:servicediscovery:cn-north-1:xxxxxx:service/srv-sqvht7gsx7ikq7um",
                "containerName": "simpleweb"
            }
        ]
}

创建服务,在创建服务的时候指定服务发现配置

aws ecs create-service \
    --cluster workfargate \
    --service-name serviceA \
    --task-definition testservice \
    --desired-count 1 \
    --network-configuration "awsvpcConfiguration={subnets=[subnet-027025e9d9760acdd	],securityGroups=[sg-096df1a0cb9a6d7e9],assignPublicIp=ENABLED}" \
    --platform-version LATEST \
    --launch-type FARGATE \
    --cli-input-json file://serviceA-config.json

在cloudmap控制台查看服务已经注册成功

在这里插入图片描述

配置ecs服务

创建前端服务serviceA

创建cloudmap解析

aws servicediscovery create-service \
    --name servicebv1 \
    --namespace-id  ns-ngtw4luqvwo5pgnw \
    --dns-config "NamespaceId=ns-ngtw4luqvwo5pgnw,RoutingPolicy=WEIGHTED
,DnsRecords=[{Type=A,TTL=60}]"

指定服务发现配置

// serviceA-config.json
{
    "serviceRegistries": [
            {
                "registryArn": "arn:aws-cn:servicediscovery:cn-north-1:xxxxxx:service/srv-sqvht7gsx7ikq7um",
                "containerName": "simpleweb"
            }
        ]
}

创建前端服务serviceA,在创建服务的时候指定服务发现配置

打包testcurl镜像

FROM public.ecr.aws/docker/library/alpine:latest
RUN apk add --update curl && rm -rf /var/cache/apk/*
COPY ./entrypoint.sh .
RUN chmod +x entrypoint.sh
CMD ./entrypoint.sh
//./entrypoint.sh
while [ true ]; do
    sleep 3
    curl -v serviceb.ecs-mesh-local
done

serviceA使用testcurl镜像

aws ecs create-service \
    --cluster workfargate \
    --service-name serviceA \
    --task-definition mesh-serviceA:8 \
    --desired-count 1 \
    --network-configuration "awsvpcConfiguration={subnets=[subnet-027025e9d9760acdd	],securityGroups=[sg-096df1a0cb9a6d7e9],assignPublicIp=ENABLED}" \
    --platform-version LATEST \
    --launch-type FARGATE \
    --cli-input-json file://serviceA-config.json

在这里插入图片描述

创建后端服务serviceBv1

同理,创建cloudmap解析

aws servicediscovery create-service \
    --name servicebv1 \
    --namespace-id ns-ngtw4luqvwo5pgnw \
    --dns-config "NamespaceId=ns-ngtw4luqvwo5pgnw,RoutingPolicy=WEIGHTED
,DnsRecords=[{Type=A,TTL=60}]"

指定服务发现配置

// serviceBv1-config.json
{
    "serviceRegistries": [
            {
                "registryArn": "arn:aws-cn:servicediscovery:cn-north-1:xxxxxx:service/srv-rzhhkc5iwcmkkla5",
                "containerName": "simpleweb"
            }
        ]
}

创建后端服务serviceBv1,后端服务使用zhaojiew/simpleweb镜像,通过环境变量MY_PORT设置监听端口

aws ecs create-service \
    --cluster workfargate \
    --service-name serviceBv1 \
    --task-definition mesh-serviceBv1:3 \
    --desired-count 1 \
    --network-configuration "awsvpcConfiguration={subnets=[subnet-027025e9d9760acdd	],securityGroups=[sg-096df1a0cb9a6d7e9],assignPublicIp=ENABLED}" \
    --platform-version LATEST \
    --launch-type FARGATE \
    --cli-input-json file://serviceBv1-config.json
创建后端服务serviceBv2

同理,创建cloudmap解析

aws servicediscovery create-service \
    --name servicebv2 \
    --namespace-id  ns-ngtw4luqvwo5pgnw \
    --dns-config "NamespaceId=ns-ngtw4luqvwo5pgnw,RoutingPolicy=WEIGHTED
,DnsRecords=[{Type=A,TTL=60}]"

指定服务发现配置

// serviceBv2-config.json
{
    "serviceRegistries": [
            {
                "registryArn": "arn:aws-cn:servicediscovery:cn-north-1:xxxxxx:service/srv-ddh5y5tnqsmc3z5d",
                "containerName": "simpleweb"
            }
        ]
}

创建后端服务serviceBv2

aws ecs create-service \
    --cluster workfargate \
    --service-name serviceBv2 \
    --task-definition mesh-serviceBv2:2 \
    --desired-count 1 \
    --network-configuration "awsvpcConfiguration={subnets=[subnet-027025e9d9760acdd	],securityGroups=[sg-096df1a0cb9a6d7e9],assignPublicIp=ENABLED}" \
    --platform-version LATEST \
    --launch-type FARGATE \
    --cli-input-json file://serviceBv2-config.json

现在我们有3个服务,并且将80端口暴露

在这里插入图片描述

解析dns名称

# nslookup servicebv1.ecs-mesh.local
Server:         172.31.0.2
Address:        172.31.0.2#53

Non-authoritative answer:
Name:   servicebv1.ecs-mesh.local
Address: 172.31.24.182

尝试访问

$ curl servicebv2.ecs-mesh.local:8090
success

创建和配置appmesh

https://docs.aws.amazon.com/zh_cn/AmazonECS/latest/developerguide/create-task-definition-classic.html

通过上面的步骤我们已经将基本的服务框架启动了。

接下来我们需要将服务接入到网格中,在控制台上对ecs任务定义进行更新,开启集成appmesh

在这里插入图片描述

配置报错提示,按照提示进行配置

在这里插入图片描述

这里有个坑,问题在于创建mesh中的virtualnode的时候,dns名称必须进行设置,狗则

在这里插入图片描述

之后注入可以成功,并提示以下信息

在这里插入图片描述

之后我们需要分别更新每个服务的任务定义,启动新的任务,这里需要注意的是由于我们使用了同一个任务定义,每次都需要手动指定mesh中的virtualnode,原理可以参考ec2那篇的逻辑

代理注入之后实例无法在通过exec链接,推测可能是代理对请求进行了处理。。。。

修改之前的serviceBv1和v2的任务定义,使用nginx进行测试

在ec2上尝试请求后端v1,可见envoy已经接管请求

$ curl servicebv1.ecs-mesh.local:8090
HTTP/1.1 200 OK
date: Tue, 28 Feb 2023 14:28:58 GMT
server: envoy
content-length: 7
content-type: text/html; charset=UTF-8
x-envoy-upstream-service-time: 1

查看访问日志,意料之中解析不到dns名称,我们手动在cloudmap中创建serviceb的解析,并指向任意一个版本的后端,和ec2环境类似,这个解析并不走dns而只是由envoy进行转发操作

在这里插入图片描述

手动注册serviceb

在这里插入图片描述

之后成功访问到服务

在这里插入图片描述

由于制定了5050的权重因此两个版本的后端都能收到请求

在这里插入图片描述

修改为100:0,查看其中一个服务已经不在接受新的请求,说明我们的配置是生效的
在这里插入图片描述

这之后我们不需要再改动任何ecs应用,仅仅通过appmesh就能完成流控等复杂配置

实际上我们这样的客户端进行操作仍旧很难操作,可以直接使用ec2代替,对于mesh来说,底层应用是无所谓的

这个应该是目前所有文章中最难的测试之一,希望大家能有所收获

posted @ 2023-02-28 22:43  zhaojie10  阅读(7)  评论(0)    收藏  举报  来源