TKE 标准集群指南

最佳实践

API 文档

诚邀爱技术、爱分享的你,成为文档内容共建者> HOT
文档中心 > 容器服务 > 故障处理 > Service&Ingress 网络无法访问排障处理

Service 提供公网或内网服务无法访问

提供公网服务或者内网服务的 Service,如果出现无法访问或者 CLB 端口状态异常的情况,建议您进行如下检查:

  1. 参考 查看节点安全组配置 检查集群中节点的安全组是否正确放通30000-32768端口区间。
  2. 如果是公网服务,则进一步检查节点是否有公网带宽(仅针对 传统账户类型)。
  3. 如果 Service 的 type 为 loadbalancer 类型,可忽略 CLB,直接检查 NodeIP + NodePort 是否可以访问。
  4. 检查 Service 是否可以在集群中正常访问。

Ingress 提供公网服务无法访问

提供公网服务的 Ingress 如果出现无法访问的情况,建议您进行如下检查:

  1. 若请求返回504,请参考 查看节点安全组配置 检查集群中节点的安全组是否正确放通30000-32768端口区间。
  2. 检查 Ingress 绑定的 CLB 是否设置了未放通443端口的安全组。
  3. 检查 Ingress 后端服务 Service 是否可以在集群中正常访问。
  4. 若请求返回404,请检查 Ingress 转发规则是否正确设置。

集群内 Service 无法访问

在 TKE 集群内,Pod 之间一般是通过 Service 的 DNS 名称 my-svc.my-namespace.svc.cluster.local 来进行互访,如果在 Pod 内发生 Service 无法访问的情况,建议您进行如下检查:

  1. 检查 Service 的 spec.ports 字段是否正确。
  2. 测试 Service 的 ClusterIP 是否可通。若可通,则说明集群内 DNS 解析存在问题,可参考 集群 DNS 解析异常排障处理 进一步检查。
  3. 测试 Service 的 Endpoint 是否可通。若不通,可参考 集群中不同节点上的容器(Pod)无法互访 进一步检查。
  4. 检查当前 Pod 所在节点上的 iptables 或者 ipvs 转发规则是否完整。

因 CLB 回环问题导致服务访问不通或访问 Ingress 存在延时

背景信息

为了使集群内的业务通过 CLB 访问 LoadBalancer 类型的 Service 时链路更短,性能更好,社区版本的 Kube-Proxy 在 IPVS 模式下会将 CLB IP 绑定到本地 dummy 网卡,使得该流量在节点发生短路,不再经过 CLB,直接在本地转发到 Endpoint。但这种优化行为和腾讯云 CLB 的健康检查机制会产生冲突,下面将做具体分析,并给出对应解法。同样,用户使用容器服务 TKE 时,会遇到因 CLB 回环问题导致服务访问不通或访问 Ingress 存在几秒延时的现象。

现象描述

CLB 回环问题可能导致存在以下现象:

  • 无论是 IPtables 或是 IPVS 模式,访问本集群内网 Ingress 会出现4秒延时或不通。
  • IPVS 模式下,集群内访问本集群 LoadBanacer 类型的内网 Service 出现完全不通,或者联通不稳定。

规避方法

说明:

避免四层回环问题需要 CLB 支持 健康检查源 IP 支持非 VIP,该功能目前处于内测中,如需使用可通过 提交工单 来联系我们。

解决使用 Service 时可能遇到的回环问题,步骤如下:

  1. 检查 kube-proxy 的版本是否是最新版本,如果不是请参照如下步骤升级:

    1. 解决该问题需要 kube-proxy 支持把 LB 地址绑定到 IPVS 网卡,可以在 TKE Kubernetes Revision 版本历史 里找到支持该能力的版本号,例如:v1.20.6-tke.12、v1.18.4-tke.20、v1.16.3-tke.25、v1.14.3-tke.24、v1.12.4-tke.30。后续更大的版本号也支持该能力:
    2. 确定集群的版本:您可以在集群里面的基本信息页查看到当前集群的版本号,如下图所示的集群是1.18.4的版本:
    3. 找到 kube-system 命名空间下面名为 kube-proxy 的 DaemonSet,更新其镜像的版本号,选择支持该能力的版本号,或者大于该版本号的版本。例如,1.18 版本的集群要选择的镜像版本号要大于 v1.18.4-tke.20。如下图所示:
  2. 为所有的 Service 添加注解:
    service.cloud.tencent.com/prevent-loopback: "true"
    效果如下:

    • kube-proxy 将据此信息将 CLB VIP 绑定到本地,可解决回环问题。
    • service-controller 将调用 CLB 接口,将其健康探测 IP 改为 100.64 网段 IP,可解决健康检查问题。

问题原因

问题根本原因在于 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:
img

如上图,当被转发的这台节点恰好也是发请求的 Client 所在节点时:

  1. 集群中的 Pod 访问 CLB,CLB 将请求转发到任意一台节点的对应 NodePort。
  2. 报文到达 NodePort 时,目的 IP 是节点 IP,源 IP 是 Client Pod 的真实 IP, 因为 CLB 不进行 SNAT,会将真实源 IP 透传过去。
  3. 由于源 IP 与目的 IP 都在这台机器内,因此将导致回环,CLB 将收不到来自 RS 的响应。

访问集群内 Ingress 的故障现象大多为几秒延时,原因是7层 CLB 如果请求 RS 后端超时(大概4s),会重试下一个 RS,所以如果 Client 设置的超时时间较长,出现回环问题的现象就是请求响应慢,有几秒的延时。如果集群只有一个节点,CLB 没有可以重试的 RS,则现象为访问不通。

常见问题

为什么公网 CLB 不存在回环问题?

使用公网 Ingress 和 LoadBalancer 类型公网 Service 不存在回环问题,主要是公网 CLB 收到的报文源 IP 是子机的出口公网 IP,而子机内部无法感知自己的公网 IP,当报文转发回子机时,不认为公网源 IP 是本机 IP,也就不存在回环。

CLB 是否有避免回环机制?

有。CLB 会判断源 IP,如果发现后端 RS 也有相同 IP,就不考虑转发给这个 RS,而是选择其他 RS。但是源 Pod IP 跟后端 RS IP 并不相同,CLB 也不知道这两个 IP 是在同一节点,所以同样可能会转发过去,也就可能发生回环。

Client 与 Server 反亲和部署能否规避?

如果将 Client 与 Server 通过反亲和性部署,避免 Client 跟 Server 部署在同一节点,能否规避 CLB 回环问题?

默认情况下,LB 通过节点 NodePort 绑定 RS,可能转发给任意节点 NodePort,此时 Client 与 Server 是否在同一节点都可能发生回环。但如果为 Service 设置 externalTrafficPolicy: Local, LB 就只会转发到有 Server Pod 的节点,如果 Client 与 Server 通过反亲和调度在不同节点,则此时不会发生回环,所以反亲和 + externalTrafficPolicy: Local 可以规避回环问题(包括内网 Ingress 和 LoadBalancer 类型内网 Service)。

VPC-CNI 的 LB 直通 Pod 是否也存在 CLB 回环问题?

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.example.com server.prod.svc.cluster.local
        ...

如果多个 Service 共用一个域名,可以自行部署 Ingress Controller (例如 nginx-ingress):

  1. 用上述 rewrite 的方法将域名指向自建的 Ingress Controller。
  2. 将自建的 Ingress 根据请求 location (域名+路径) 匹配 Service,再转发给后端 Pod。整段链路不经过 CLB,同意能规避回环问题。
目录