目录:
AWS概述
EMR Serverless
AWS VPC及其网络
关于AWS网络架构的思考
AWS IRSA 原理与使用
AWS S3 和 Lambda 使用
LaunchTemplate + AutoScalingGroup 实践
在AWS K8S中部署的业务,有不同的流量路径。
流量进入
客户端专用请求
普通的客户端流量流向从前到后是:
- 客户端
- 企业网关
- AWS Network LoadBalancer(监听 80 和 443)
- 两个 TargetGroup,分别负责转发 80 请求和 443 请求。TargetGroup 的类型为 Instance
- Ingress Nginx Service,该服务是 Load Balancer 类型
- 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 来转发到内部网络。其流量从前到后的路径是:
- API GW
- VPC Link (绑定 NLB)
- AWS Network LoadBalancer(监听 80 和 443)
- 两个 TargetGroup,分别负责转发 80 请求和 443 请求。TargetGroup 的类型为 Instance
- 业务 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=instance | Target=ip |
|---|---|---|
| NLB 流量目标 | Node IP | Pod IP |
| 流量路径 | NLB → Node → Pod | NLB → 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 实践。

6023

被折叠的 条评论
为什么被折叠?



