Kubernetes集群中访问LoadBalancer暴露出去的SLB地址不通
1.踩坑记录
k8s集群通过Nginx Ingress提供公网服务,集群内网有部分服务通过公网地址调用,导致部分节点、Pod无法访问公网地址的坑~具体描述如下:
该问题导致线上支付业务受到影响。。。都是钱啊~
2.详细过程
2.1 问题描述
集群为阿里云ACK标准版集群,Ingress通过Service的SLB提供服务。
在Kubernetes集群中有部分节点能访问集群暴露出去的Local类型SLB,但是也有部分节点不能访问,且Ingress出现该问题较多。
2.2 问题原因
SLB设置了externalTrafficPolicy: Local
类型,这种类型的SLB地址
只有在Node中部署了对应的后端Pod,才能被访问。因为SLB的地址是集群外使用,如果集群节点和Pod不能直接访问,请求不会到SLB,会被当作Service的扩展IP地址,被kube-proxy
的iptables
或ipvs
转发。
如果刚好集群节点或者Pod所在的节点上没有相应的后端服务Pod,就会发生网络不通的问题,而如果有相应的后端服务Pod,是可以正常访问。
2.3 解决方案
PLAN A
- 在Kubernetes集群内通过
ClusterIP
或者服务名
访问。 - 其中Ingress的服务名为:
nginx-ingress-lb.kube-system
PLAN B
将
LoadBalancer
的Service
中的externalTrafficPolicy
修改为Cluster
,但是在应用中会丢失源IP,Ingress的服务修改命令如下。若是
Terway
的
ENI
或者
ENI
多IP的集群,将LoadBalancer的Service中的externalTrafficPolicy修改为Cluster,并且添加ENI直通的annotation,例如
annotation: service.beta.kubernetes.io/backend-type:"eni"
,具体格式如下,可以保留源IP,并且在集群内访问也没有问题。
3.深入了解Kubernetes外部流量策略
3.1 摘要
external-traffic-policy
,顾名思义外部流量策略
,那这个配置有什么作用呢?以及external是指什么东西的外部呢,集群、节点、Pod?今天我们就来了解一下这个概念吧。3.2 什么是external-traffic-policy
在k8s的
Service对象
(申明一条访问通道)中,有一个externalTrafficPolicy
字段可以设置。有2个值可以设置:Cluster
或者Local
。Cluster
表示:流量可以转发到其他节点上的Pod。Local
表示:流量只发给本机的Pod。
图示一下:
3.3 这2种模式有什么区别
存在这2种模式的原因就是,当前节点的
Kube-proxy
在转发报文的时候,会不会保留原始访问者的IP
。.3.3.1 选择Cluster
注:这个是
默认模式
,Kube-proxy
不管容器实例在哪,公平转发
。Kube-proxy
转发时会替换掉报文的源IP。即:容器收的报文,源IP地址,已经被替换为上一个转发节点的了。原因是
Kube-proxy
在做转发的时候,会做一次SNAT (source network address translation)
,所以源IP变成了节点1的IP地址。ps:
SNAT
确保回去的报文可以原路返回,不然回去的路径不一样,客户会认为非法报文的。(我发给张三的,怎么李四给我回应?丢弃!)这种模式
好处
是负载均衡会比较好
,因为无论容器实例怎么分布在多个节点上,它都会转发过去。当然,由于多了一次转发
,性能会损失一丢丢
。3.3.2 选择Local
这种情况下,只转发给本机的容器,
绝不跨节点转发
。Kube-proxy
转发时会保留源IP
。即:容器收到的报文,看到源IP地址还是用户的。缺点
是负载均衡可能不是很好
,因为一旦容器实例分布在多个节点上,它只转发给本机,不跨节点转发流量。当然,少了一次转发,性能会相对好一丢丢。注:这种模式下的Service类型只能为
外部流量
,即:LoadBalancer 或者 NodePort 两种,否则会报错。同时,由于本机不会跨节点转发报文,所以要想所有节点上的容器有负载均衡,就需要上一级的Loadbalancer来做了。
不过流量还是会不太均衡,如上图,Loadbalancer看到的是2个后端(把节点的IP),每个Node上面几个Pod对Loadbalancer来说是不知道的。
想要解决负载不均衡的问题:可以给Pod容器设置反亲和,让这些容器平均的分布在各个节点上(不要聚在一起)。
像下面这样,负载均衡情况就会好很多~
3.4 两种模式该怎么选
- 要想
性能(时延)好
,当然应该选Local 模式
喽,毕竟流量转发少一次SNAT嘛。- 不过注意,选了这个就得考虑好怎么处理好负载均衡问题(ps:通常我们使用Pod间反亲和来达成)。
- 如果你是从外部LB接收流量的,那么使用:Local模式 + Pod反亲和,一般是足够的。
- 想要
简单化
,降低运维复杂成本,当然选Local 模式
,毕竟一个配置搞定了,不用考虑那么多反亲和的问题。