关于AWS网络架构的思考

目录:
AWS概述
EMR Serverless
AWS VPC及其网络
关于AWS网络架构的思考
AWS IRSA 原理与使用
AWS S3 和 Lambda 使用
LaunchTemplate + AutoScalingGroup 实践

在AWS K8S中部署的业务,有不同的流量路径。

流量进入

客户端专用请求

普通的客户端流量流向从前到后是:

  1. 客户端
  2. 企业网关
  3. AWS Network LoadBalancer(监听 80 和 443)
  4. 两个 TargetGroup,分别负责转发 80 请求和 443 请求。TargetGroup 的类型为 Instance
  5. Ingress Nginx Service,该服务是 Load Balancer 类型
  6. Ingress 通过路由规则将流量转发给业务 service,再经过 4 层的负载均衡将流量发给 pod

通过以上步骤客户端流量到达了服务端。其中1~5 步一般由企业通用平台负责完成,业务只需要定义好 ingress 路由规则即可。

这种场景下,流量路径为:Client -> NLB:443 -> TargetGroup -> NodeIp:NodePort -> kube-proxy -> Nginx Ingress Controller Pod: 443 -> Ingress rules -> Backend service -> Business Pod

有几个点需要注意:

  • Client 和 NLB 之间通过 VPC PrivateLink 进行连接(client endpoint -> nlb endpoint service)。
  • Ingress Nginx Service 类型为 LoadBalancer,手动指定 NodePort 端口,方便 NLB 或防火墙配置:
type: LoadBalancer
 selector:
   app.kubernetes.io/name: ingress-nginx
 ports:
   - name: http
     port: 80
     targetPort: 80
     nodePort: 30080
     protocol: TCP
   - name: https
     port: 443
     targetPort: 443
     nodePort: 30443
     protocol: TCP
  • NodePort 是 Kubernetes 在每个 Node 上暴露的转发端口,当流量进入 Node 时,kube-proxy 负责将此端口上的流量转发到 Ingress Nginx Controller Pod:443,再通过 Ingress 规则来转发给对应的 Backend Service。
  • TargetGroup 中会注册哪些 instance 节点取决于 ingress nginx service 中的 externalTrafficPolicy 参数。cluster 会将所有的 instance 节点全部注册上,local 只会注册有 ingress pod 的节点。

生产环境踩的大坑:当 ingress-nginx service 中添加 aws-load-balancer-target-group-attributes: deregistration_delay.connection_termination.enabled=true 属性时,instance 节点无法被注册到 TargetGroup 中,导致 TG 中的节点数逐渐减少而无法再被注册。仅剩的少量节点无法承接高峰期的巨大流量,触发 traffic limit。

原因如下:
Kubernetes 里内置的老式 AWS 云提供逻辑——legacy cloud provider ,也叫 in-tree cloud provider。它不是你单独安装的一个“Controller”,而是 Kubernetes 自己的控制平面里一部分代码,负责把 Service type: LoadBalancer 映射成 AWS 负载均衡资源,它无法理解 AWS Load Balancer Controller 的那套 NLB/ALB 细粒度注解。只有使用 AWS Load Balancer Controller 管理 ALB/NLB 时才支持。

网络请求

对于其他第三方从网络上进入的流量,需要通过 API Gateway 来转发到内部网络。其流量从前到后的路径是:

  1. API GW
  2. VPC Link (绑定 NLB)
  3. AWS Network LoadBalancer(监听 80 和 443)
  4. 两个 TargetGroup,分别负责转发 80 请求和 443 请求。TargetGroup 的类型为 Instance
  5. 业务 Service 为 NodePort 类型,指定 NodePort

通过以上步骤,网络流量就可以达到服务端。这部分全部都由业务自己管理,其中第 4 步中 当 instance 扩缩容时也需要自己管理,及时注册和分离 target 中的节点。

当业务服务为 NodePort 类型时,第 2 步中 VPC Link 关联的 NLB 需要手动创建(包括后面的 targetGroup),当流量通过这个手动创建的 NLB 流向 Node:NodePort 后,kube-proxy 负责将其转发给 NodePort 类型的 Business Service Pod:443。

API Gateway 的 VPC Link 是不能绑定到已经使用的 NLB 的,无法复用客户端专用请求的 NLB。

这种场景下,流量路径为:API Gateway -> NLB:443 -> NodeIp:NodePort -> kube-proxy -> Business Service Pod: 443

可以注意到,通过 NodePort 转发的流量会直接进入服务的 Pod,就不走 Ingress 路由了,这与客户端专用请求路径是不一样的。

相同VPC内的其他服务

对于相同 VPC 内的其他服务,通过 Route53 将通过域名发出的请求转发到 VPC Endpoint,通过 VPC PrivateLink 进入 NLB,后续流程与上文客户端专用请求第 3 步之后的相同。

LoadBalancer 与 NodePort

通过上文可知,不管是 LoadBalancer 类型的服务(ingress-nginx service),还是 NodePort 类型的服务(business service),当流量通过 NLB 进入 Node:NodePort 时,kube-proxy 都会将其转发到对应的服务的 pod 中,那两者有什么区别呢?

从本质上来说,两者其实是一样的。只不过 LoadBalancer 类型的服务会自动在云平台上创建负载均衡器(AWS NLB/ALB 等),并将 LB 的 Target 指向 Node: NodePort 或 PodIP: ContainerPort(取决于 target type)。

下面将业务服务由 NodePort 类型改成 Loadbalancer 类型:

apiVersion: v1
kind: Service
metadata:
  name: my-service
  annotations:
    service.beta.kubernetes.io/aws-load-balancer-type: nlb
spec:
  type: LoadBalancer
  selector:
    app: my-service
  ports:
    - name: http
      protocol: TCP
      port: 80
      targetPort: 8080
      nodePort: 30080
    - name: https
      protocol: TCP
      port: 443
      targetPort: 8081
      nodePort: 30443

注意这里的 nodePort 不能与已经使用的重复。

当在 AWS EKS 中部署该服务时, AWS Load Balancer Controller 会自动创建 NLB,并将所有 Node + NodePort 注册到 NLB 的 TargetGroup。业务只要将 API GW 的 VPC Link 关联上这个自动创建的 NLB 即可。当流量通过这个自动创建的 NLB 流向 Node: NodePort 后,kube-proxy 会将其转发给服务对应的 pod 的 8080 或 8081 端口。

这种方式完全不需要手动去创建 NLB、TargetGroup,也不需要通过 ASG 来注册 instance,极大地降低了运维成本。

ip 类型的 TargetGroup

上面说 LoadBalancer 类型的服务会自动在云平台上创建负载均衡器,并根据 target type 将 LB 的 Target 指向 Node: NodePort 或 PodIP: ContainerPort。示例中未设置 service.beta.kubernetes.io/aws-load-balancer-nlb-target-type 注解,因此取默认值 instance,target group 中注册的是 Node + NodePort。

如果想直接注册 PodIP: ContainerPort,需要设置:

service.beta.kubernetes.io/aws-load-balancer-nlb-target-type: ip

两种方式区别如下:

特性Target=instanceTarget=ip
NLB 流量目标Node IPPod IP
流量路径NLB → Node → PodNLB → Pod
延迟较高(额外跳转)较低
Pod 弹性伸缩依赖 kube-proxy自动注册/注销 Target Group
负载均衡精度粗(Node 级)精确(Pod 级)
网络策略粒度Node 级Pod 级

流量到互联网

对于出去的流量,在 AWS 中有两种方式,一种是通过 NAT 出,一种是通过 Internet Gateway 直接出。

普通的 VPC 的子网是私有子网,不能直接与 Internet 通信,因此需要通过 NAT 转发到网络上。具体请参考博主另一篇文章 AWS VPC 网络

由于流量从 NAT 出去的,所以网络的出口 ip 即 NAT 的 ip 地址。

如果 VPC 的子网是公有的,则可以直接与 Internet 通信,无需经过 NAT 转换。网络出口地址是 EC2 实例的 公有 ip 地址。

NAT 局限

正常服务到公网的流量走NAT就够了,但是如果服务需要大量建立与第三方某域名的连接,如代理服务,可能会出现 NAT 并发连接错误。举个例子来说,假设现在代理服务需要建立60万个连接来访问腾讯的某个域名,而该域名只能解析出5个ip地址。默认情况下,公有 NAT 网络只能关联2个弹性IP地址,每个弹性ip地址最多支持与唯一目标(由目标ip,端口和协议组合标识)建立55000个并发连接。因此两个弹性ip与5个目标ip最多同时建立 55000 * 2 * 5 = 550000 个连接。

在这种情况下,NAT 就会出现并发连接错误,即使只有55万个连接,这些连接也不是平均分配到不同目标的,显然也会出现并发连接错误。此时经 NAT 转发网络请求的方案是有问题的,可以考虑直接使用公有子网来访问网络,见前文–LaunchTemplate + AutoScalingGroup 实践。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值