为了使集群内的业务通过 CLB 访问 LoadBalancer 类型的 Service 时链路更短,性能更好,社区版本的 Kube-Proxy 在 IPVS 模式下会将 CLB IP 绑定到本地 dummy 网卡,使得该流量在节点发生短路,不再经过 CLB,直接在本地转发到 Endpoint。但这种优化行为和腾讯云 CLB 的健康检查机制会产生冲突,下面将做具体分析,并给出对应解法。
同样,用户使用容器服务 TKE 时,会遇到因 CLB 回环问题导致服务访问不通或访问 Ingress 存在几秒延时的现象。本文档介绍该问题的相关现象、原因,并提供解决方法。
CLB 回环问题可能导致存在以下现象:
说明:避免四层回环问题需要 CLB 支持 健康检查源 IP 支持非 VIP,该功能目前处于内测中,如需使用可通过 提交工单 来联系我们。
解决使用 Service 时可能遇到的回环问题,步骤如下:
检查 kube-proxy 的版本是否是最新版本,如果不是请参照如下步骤升级:
为所有的 Service 添加注解:service.cloud.tencent.com/prevent-loopback: "true"
效果:
解决使用 Ingress 时可能遇到的回环问题,步骤如下:
提交工单 申请开通 CLB 7层 SNAT 和 Keep Alive 能力的白名单。
注意:该能力将启用长连接,CLB 与后端服务之间使用长连接,CLB 不再透传源 IP,请从 XFF 中获取源 IP。为保证正常转发,请在 CLB 上打开安全组默认放通或者在 CVM 的安全组上放通 100.127.0.0/16。更多请参考 配置监听器。
利用 TkeServiceConfig 的能力增强 Ingress 的配置能力,对于存量的 Ingress,需要添加一个 annotation:ingress.cloud.tencent.com/tke-service-config-auto: "true"
,Ingress Annotation 说明
目的:为该 Ingress 自动生成对应的 TkeServiceConfig,提供 Ingress 额外的配置
效果:该 Ingress 会生成一个名为:
在生成名为:spec.loadBalancer.l7Listeners[].keepaliveEnable
,字段值为1。注意每一个端口都需要添加该字段,如下图所示:
更多请参考 Ingress 使用 TkeServiceConfig 配置 CLB。
根本原因在于 CLB 将请求转发到后端 RS 时,报文的源目的 IP 都在同一节点内,而 Linux 默认忽略收到源 IP 是本机 IP 的报文,导致数据包在子机内部回环,如下图所示:
使用 TKE CLB 类型的 Ingress,会为每个 Ingress 资源创建一个 CLB 以及80、443的7层监听器规则(HTTP/HTTPS),并为 Ingress 每个 location 绑定对应 TKE 各个节点某个相同的 NodePort 作为 RS(每个 location 对应一个 Service,每个 Service 都通过各个节点的某个相同 NodePort 暴露流量),CLB 根据请求匹配 location 转发到相应的 RS(即 NodePort),流量经过 NodePort 后会再经过 Kubernetes 的 iptables 或 ipvs 转发给对应的后端 Pod。集群中的 Pod 访问本集群的内网 Ingress,CLB 将请求转发给其中一台节点的对应 NodePort:
如上图,当被转发的这台节点恰好也是发请求的 Client 所在节点时:
访问集群内 Ingress 的故障现象大多为几秒延时,原因是7层 CLB 如果请求 RS 后端超时(大概4s),会重试下一个 RS,所以如果 Client 设置的超时时间较长,出现回环问题的现象就是请求响应慢,有几秒的延时。如果集群只有一个节点,CLB 没有可以重试的 RS,则现象为访问不通。
当使用 LoadBalancer 类型的内网 Service 时暴露服务时,会创建内网 CLB 并创建对应的4层监听器(TCP/UDP)。当集群内 Pod 访问 LoadBalancer 类型 Service 的 EXTERNAL-IP
时(即 CLB IP),原生 Kubernetes 实际上不会去真正访问 LB,而是直接通过 iptables 或 ipvs 转发到后端 Pod (不经过 CLB),如下图所示:
因此原生 Kubernetes 的逻辑不存在回环问题。但在 TKE 的 ipvs 模式下,Client 访问 CLB IP 的包会真正到 CLB,如果在 ipvs 模式下,Pod 访问本集群 LoadBalancer 类型 Service 的 CLB IP 将存在回环问题,情况跟上述内网 Ingress 回环类似,如下图所示:
不同的是,四层 CLB 不会重试下一个 RS,当遇到回环时,现象通常是联通不稳定。如果集群只有一个节点,那将导致完全不通。
为什么 TKE 的 ipvs 模式不用原生 Kubernetes 类似的转发逻辑(不经过 LB,直接转发到后端 Pod)?
背景是因为以前 TKE 的 ipvs 模式集群使用 LoadBalancer 内网 Service 暴露服务,内网 CLB 对后端 NodePort 的健康探测会全部失败,原因如下:
kube-ipvs0
的 dummy 网卡,该网卡仅仅用来绑定 VIP (内核自动为其生成 local 路由),不用于接收流量。kube-ipvs0
),就将其丢弃掉。所以 CLB 的探测报文永远无法收到响应,也就全部探测失败,虽然 CLB 有全死全活逻辑(全部探测失败视为全部可以被转发),但也相当于探测未起到任何作用,在某些情况下将造成一些异常。为解决上述问题,TKE 的修复策略是:ipvs 模式不绑定 EXTERNAL-IP 到 kube-ipvs0
。也就是集群内 Pod 访问 CLB IP 的报文不会进入 INPUT 链,而是直接出节点网卡,真正到达 CLB,这样健康探测的报文进入节点时将不会被当成本机 IP 而丢弃,同时探测响应报文也不会进入 INPUT 链导致出不去。
虽然这种方法修复了 CLB 健康探测失败的问题,但也导致集群内 Pod 访问 CLB 的包真正到了 CLB,由于访问集群内的服务,报文又会被转发回其中一台节点,也就存在了回环的可能性。
说明:相关问题已提交至 社区,但目前还未有效解决。
使用公网 Ingress 和 LoadBalancer 类型公网 Service 不存在回环问题,主要是公网 CLB 收到的报文源 IP 是子机的出口公网 IP,而子机内部无法感知自己的公网 IP,当报文转发回子机时,不认为公网源 IP 是本机 IP,也就不存在回环。
有。CLB 会判断源 IP,如果发现后端 RS 也有相同 IP,就不考虑转发给这个 RS,而是选择其他 RS。但是源 Pod IP 跟后端 RS IP 并不相同,CLB 也不知道这两个 IP 是在同一节点,所以同样可能会转发过去,也就可能发生回环。
如果将 Client 与 Server 通过反亲和性部署,避免 Client 跟 Server 部署在同一节点,能否规避 CLB 回环问题?
默认情况下,LB 通过节点 NodePort 绑定 RS,可能转发给任意节点 NodePort,此时 Client 与 Server 是否在同一节点都可能发生回环。但如果为 Service 设置 externalTrafficPolicy: Local
, LB 就只会转发到有 Server Pod 的节点,如果 Client 与 Server 通过反亲和调度在不同节点,则此时不会发生回环,所以反亲和 + externalTrafficPolicy: Local
可以规避回环问题(包括内网 Ingress 和 LoadBalancer 类型内网 Service)。
TKE 通常用的 Global Router 网络模式(网桥方案),还有一种是 VPC-CNI(弹性网卡方案)。目前 LB 直通 Pod 只支持 VPC-CNI 的 Pod,即 LB 不绑 NodePort 作为 RS,而是直接绑定后端 Pod 作为 RS,如下图所示:
这样即可绕过 NodePort,不再像之前一样可能会转发给任意节点。但如果 Client 与 Server 在同一节点,同样可能会发生回环问题,通过反亲和可以规避。
反亲和与 externalTrafficPolicy: Local
的规避方式不太优雅。一般来讲,访问集群内的服务避免访问本集群的 CLB,因为服务本身在集群内部,从 CLB 绕一圈不仅会增加网络链路的长度,还会引发回环问题。
访问集群内服务尽量使用 Service 名称,例如 server.prod.svc.cluster.local
,通过这样的配置将不会经过 CLB,也不会导致回环问题。
如果业务有耦合域名,不能使用 Service 名称,可以使用 coredns 的 rewrite 插件,将域名指向集群内的 Service,coredns 配置示例如下:
apiVersion: v1
kind: ConfigMap
metadata:
name: coredns
namespace: kube-system
data:
Corefile: |2-
.:53 {
rewrite name roc.oa.com server.prod.svc.cluster.local
...
如果多个 Service 共用一个域名,可以自行部署 Ingress Controller (例如 nginx-ingress):
本页内容是否解决了您的问题?