一次网络不通“争吵”引发的思考

简介: 一次网络不通“争吵”引发的思考

作者: 郑明泉、余凯


为啥争吵,吵什么?


"你到底在说什么啊,我K8s的ecs节点要访问clb的地址不通和本地网卡有什么关系..." 气愤语气都从电话那头传了过来,这时电话两端都沉默了。过了好一会传来地铁小姐姐甜美的播报声打断了刚刚的沉寂「乘坐地铁必须全程佩戴口罩,下一站西湖文化广场...」。


pod需要访问clb的443的监听, 但是如果是集群内(集群内后面都指的K8s的节点或者POD)访问就会出现如下报错Connection refused:



所以就捋了一下客户链路如下:



具体现象是什么

无论是节点node还是pod里访问192.168.1.200:443都是不通的,但是访问192.168.1.200:80却是正常的。同时集群外的ECS192.168.3.100访问192.168.1.200:443和192.168.1.200:80都是正常的。


进一步分析看看

CLB1的IP192.168.1.200被绑定到了K8s的node节点的kube-ipvs0网卡上,这个是一张dummy 网卡,参考dummy interface。由于 SVC1 是LoadBalancer类型的,同时复用了这个CLB1,关联endpoint是POD1192.168.1.101:80,那么就可以解释为何访问192.168.1.200:80是正常,是由于kube-proxy根据SVC1的配置创建ipvs规则同时挂载了可被访问的后端服务。而集群里访问192.168.1.200:443都是不通的,因为IP被绑定到dummy网卡后,就不会再出节点去访问到CLB1,同时没有443对应ipvs规则,所以直接是拒绝的。


这个时候如果节点里没有ipvs规则(ipvs优先于监听)但是又能访问通的话, 可以检查一下是否本地有监听0.0.0.0:443的服务,那么这个时候所有网卡IP+443都能通,但是访问的是本地服务,而不是真正的CLB后端的服务。



是否有办法解决呢


最建议的方式

最好的方式拆分, 集群内和集群外的服务分开两个CLB使用。


阿里云svc注解的方式

SVC1使用这个注解service.beta.kubernetes.io/alibaba-cloud-loadbalancer-hostname,进行占位,这样就不会绑定CLB的IP到kube-ipvs0的网卡上,集群内访问CLB的IP就会出集群访问CLB,但是需要注意如果监听协议为TCP或UDP,集群内访问CLB IP时将会存在回环访问问题。详细信息,请参见客户端无法访问负载均衡CLB[1]


需要CCM版本在 v2.3.0及以上版本才支持这个注解, 具体参考:通过Annotation配置传统型负载均衡CLB [ 2]



demo:


apiVersion: v1
kind: Service
metadata:
  annotations:
    service.beta.kubernetes.io/alibaba-cloud-loadbalancer-hostname: "${your_service_hostname}"
  name: nginx-svc
  namespace: default
spec:
  ports:
  - name: http
    port: 80
    protocol: TCP
    targetPort: 80
  selector:
    app: nginx
  type: LoadBalancer


集群内访问 ExternalTrafficPolicy 策略有影响吗?


我们都知道K8s的nodeport和loadbalancer模式是可以调整外部流量策略的,那么图中的「外部策略为Local/Cluster,所有集群节点创建IPVS规则是有区别的」该如何解释呢, 以及集群内访问nodePort/CLBIP的时候会发生什么。



以下都是针对svc的internalTrafficPolicy都是Cluster或者缺省的情况,这个ServiceInternalTrafficPolicy特性在1.22的K8s中默认开启,具体参考service-traffic-policy [ 3]


体到阿里云容器在不同网络CNI情况下的数据链路,可以参考下面的文章:


此处我们只讨论ipvs TrafficPolicy Local在Kubernetes 从1.22升级到1.24的行为变化。


Kubernetes 1.24 IPVS的变化

以下均以kube-proxy的IPVS模式为例:


  • 当externalTrafficPolicy为Cluster模式或缺省的时候,ipvs规则里的nodePort/CLBIP后端会挂载所有的Endpoint的IP,这时候集群内访问会丢失源IP,因为节点会做一层SNAT。
  • 当externalTrafficPolicy是Local的时候
  • 当节点上有对应service的Endpoint的时候,ipvs规则里的nodePort/CLBIP后端只挂载自己节点的Endpoint的IP,集群内访问会保留源IP。
  • 当节点上没有对应service的Endpoint的时候
  • 在1.24之前的版本是会挂空的后端的,集群内访问会拒绝。
  • 在1.24之后的K8s集群里,当节点上没有对应service的Endpoint的时候,ipvs规则里的nodePort/CLB IP后端会挂载所有的Endpoint的IP,这时候集群内访问会丢失源IP,因为节点会做一层SNAT。社区调整了Local策略后端服务的规则挂载策略,具体参考社区PR[4]


https://github.com/kubernetes/kubernetes/pull/97081/commits/61085a75899a820b5eebfa71801e17423c1ca4da


集群外访问SLB


集群外访问SLB的话,CCM只会挂载Local类型的节点,情况跟1.24 kubernetes前一样,这里不做过多阐述,请见上面连接。


集群外访问NodePort


1.24 Kubernetes之前版本

  • 访问有Endpoint的节点的NodePort,可以通,可以保留源IP

  • Nginx分布在cn-hongkong.10.0.4.174和cn-hongkong.10.0.2.84节点。



    从外部10.0.3.72节点访问有后端pod所在节点的cn-hongkong.10.0.2.84的30479端口,可以访问。



    cn-hongkong.10.0.0.140节点上是有相关的IPVS的规则的,但是只有该节点上后端Pod IP。



    通过conntrack表可以到,这是由于在cn-hongkong.10.0.0.140节点上,相关的链路被dnat,最后是由pod cn-hongkong.10.0.2.84节点上的 的nginx-7d6877d777-tzbf7 10.0.2.87返回源,所有的相关转化都在该节点上,所以TCP四层建连可以成功。



    • 访问没有Endpoint的节点的NodePort,不能通,因为节点上没有相关的ipvs转发规则


    从外部10.0.3.72节点访问无后端pod所在节点的cn-hongkong.10.0.0.140的30479端口,不可以访问。



    查看该cn-hongkong.10.0.0.140节点,并没有相关的ipvs转发规则,所以无法进行dnat,访问会失败。



    1.24 Kubernetes版本之后(含)

    访问有Endpoint节点的NodePort,可以通,可以保留源IP


    访问没有Endpoint节点的NodePort:

    • terway ENIIP or host网络:不通


    Nginx分布在cn-hongkong.10.0.2.77和cn-hongkong.10.0.0.171 节点。



    从外部10.0.3.72节点访问无后端pod所在节点的cn-hongkong.10.0.5.168的30745端口,可以看到,访问失败。



    cn-hongkong.10.0.5.168节点上是有相关的IPVS的规则的,并且会把所有的后端Pod IP加到IPVS规则中。



    通过conntrack表可以到,这是由于在cn-hongkong.10.0.5.168节点上,相关的链路被dnat,最后是由pod cn-hongkong.10.0.2.77节点上的nginx-79fc6bc6d-8vctc 10.0.2.78返回源,源在接受这个链路后,会发现和自己的五元组不匹配,直接丢弃,三次握手必然失败,所以建连失败。



    • flannel网络:可以通,但是保留不了源IP


    Nginx分布在cn-hongkong.10.0.2.86。



    从外部访问cn-hongkong.10.0.4.176的31218端口,可以访问成功。



    cn-hongkong.10.0.4.176记录了src是10.0.3.72,并做了dnat为172.16.160.135,期望它返回给10.0.4.176的58825端口。



    后端ep所在节点cn-hongkong.10.0.2.86,conntrack表记录了src是10.0.4.176,sport是58825。所以可以看到应用pod是记录的源IP是10.0.4.176,丢失了源IP。



    集群内访问SLB或者NodePort


    1.24 Kubernetes之前版本

  • 有Endpoint的节点上访问,可以通,可以保留源IP

  • Nginx分布在ap-southeast-1.192.168.100.209和ap-southeast-1.192.168.100.208节点,ap-southeast-1.192.168.100.210节点没有Nginx pod。



    从集群任意节点(本例就在209节点)访问有后端pod所在节点的ap-southeast-1.192.168.100.209的NodePort  31565端口,可以访问。



    从有后端pod所在节点ap-southeast-1.192.168.100.209访问SLB 8.222.252.252 的80端口,可以访问。



    ap-southeast-1.192.168.100.209节点上是有NodePort 和SLB 的IPVS的规则的,但是只有该节点上后端Pod IP。



    通过conntrack表可以到,这是由于在ap-southeast-1.192.168.100.209 节点上,相关的链路被dnat,最后是由pod 在ap-southeast-1.192.168.100.209 节点上的 的nginx-7d6877d777-2wh4s 192.168.100.222返回源,所有的相关转化都在该节点上,所以TCP四层建连可以成功。



    • 没有Endpoint的节点上访问,不能通,因为节点上没有相关的ipvs转发规则


    从集群任意节点(本例就在210节点)访问没有后端pod所在节点的ap-southeast-1.192.168.100.210 的NodePort 31565端口或者SLB,不可以访问。


    也进一步证实,集群内访问关联svc的SLB不出节点,即使SLB有其他监听端口,访问SLB其他端口也会拒绝。



    查看该ap-southeast-1.192.168.100.210 节点,并没有相关的ipvs转发规则,所以无法进行dnat,访问会失败。



    1.24 Kubernetes版本之后(含)

  • 有Endpoint节点上访问,可以通,可以保留源IP

  • 与上文的1.24 Kubernetes之前版本集群内访问一致,可以参考上文描述。

    • 没有Endpoint节点上访问:


    Nginx分布在cn-hongkong.10.0.2.77和cn-hongkong.10.0.0.171节点,所以在没有Nginx的cn-hongkong.10.0.4.141节点上测试。



    分别有以下几种情况:

    • terway或后端为hostNetwork
    • 节点访问的通 NodePort(源 IP 是 ECS IP,不需要做 SNAT),无法保留源IP


    可以看到没有Endpoint的节点的NodePort 110.0.4.141:30745 的IPVS 的规则添加的Nginx的所有后端POD nginx-79fc6bc6d-8vctc 10.0.2.78  和 nginx-79fc6bc6d-j587w 10.0.0.172。



    集群内节点自身访问没有后端pod所在节点的cn-hongkong.10.0.4.141 的NodePort 30745/TCP端口,可以访问。



    通过conntrack表可以到,在cn-hongkong.10.0.4.141节点上,相关的链路被dnat,最后是由后盾Nginx pod nginx-79fc6bc6d-8vctc 10.0.2.78返回源。



    而在nginx-79fc6bc6d-8vctc 10.0.2.78 所在的节点cn-hongkong.10.0.2.77上的conntrack表记录的是10.04.141访问10.0.2.78,并期望10.0.2.78直接返回10.0.4.141的的39530端口。



    集群内有endpoint 节点访问没有后端pod所在节点的ap-southeast-1.192.168.100.131 的NodePort 32292端口,不可以访问,与上文1.24 Kubernetes版本之后(含) 集群外访问一致,可以参考上文描述。


    • 节点访问不通 SLB IP(源 IP 是 SLB IP,没有人做 SNAT)


    可以看到没有Endpoint的节点的SLB IP 的IPVS 的规则添加的Nginx的所有后端POD nginx-79fc6bc6d-8vctc 10.0.2.78  和 nginx-79fc6bc6d-j587w 10.0.0.172。



    没有Endpoint的节点上访问 SLB 47.243.247.219,访问确是超时。



    通过conntrack表可以到,在没有ep的节点访问SLB的IP,可以看到期望的是后端pod返回给SLB IP。而SLB IP 在节点上已经被kube-ipvs虚拟占位了,所以没有做snat,造成无法访问。



    • flannel并且后端为普通pod,可以访问通,但是保留不了源IP


    Nginx分布在cn-hongkong.10.0.2.86。



    在cn-hongkong.10.0.4.176访问SLB 47.242.86.39 是可以访问成功的。



    cn-hongkong.10.0.4.176节点的conntrack表可以看到是src和dst都是47.242.86.39,但是期望的是 nginx pod172.16.160.135 返回给 10.0.4.176 的54988端口,47.242.86.39 snat成10.0.4.176。



    后端ep所在节点cn-hongkong.10.0.2.86,conntrack表记录了src是10.0.4.176,sport是54988。所以可以看到应用pod是记录的源IP是10.0.4.176,丢失了源IP。



    相关链接:

    [1] 客户端无法访问负载均衡CLB

    https://help.aliyun.com/document_detail/55206.htm

    [2] 通过Annotation配置传统型负载均衡CLB

    https://www.yuque.com/r/goto?url=https%3A%2F%2Fhelp.aliyun.com%2Fzh%2Fack%2Fack-managed-and-ack-dedicated%2Fuser-guide%2Fadd-annotations-to-the-yaml-file-of-a-service-to-configure-clb-instances

    [3] service-traffic-policy

    https://kubernetes.io/zh-cn/docs/concepts/services-networking/service-traffic-policy/

    [4] 社区PR

    https://github.com/kubernetes/kubernetes/pull/97081/commits/61085a75899a820b5eebfa71801e17423c1ca4da

    相关实践学习
    深入解析Docker容器化技术
    Docker是一个开源的应用容器引擎,让开发者可以打包他们的应用以及依赖包到一个可移植的容器中,然后发布到任何流行的Linux机器上,也可以实现虚拟化,容器是完全使用沙箱机制,相互之间不会有任何接口。Docker是世界领先的软件容器平台。开发人员利用Docker可以消除协作编码时“在我的机器上可正常工作”的问题。运维人员利用Docker可以在隔离容器中并行运行和管理应用,获得更好的计算密度。企业利用Docker可以构建敏捷的软件交付管道,以更快的速度、更高的安全性和可靠的信誉为Linux和Windows Server应用发布新功能。 在本套课程中,我们将全面的讲解Docker技术栈,从环境安装到容器、镜像操作以及生产环境如何部署开发的微服务应用。本课程由黑马程序员提供。     相关的阿里云产品:容器服务 ACK 容器服务 Kubernetes 版(简称 ACK)提供高性能可伸缩的容器应用管理能力,支持企业级容器化应用的全生命周期管理。整合阿里云虚拟化、存储、网络和安全能力,打造云端最佳容器化应用运行环境。 了解产品详情: https://www.aliyun.com/product/kubernetes
    相关文章
    |
    运维 测试技术
    6月27日阿里云故障说明
    6月27日下午,我们在运维上的一个操作失误,导致一些客户访问阿里云官网控制台和使用部分产品功能出现问题。故障于北京时间2018年6月27日16:21左右开始,16:50分开始陆续恢复。对于这次故障,没有借口,我们不能也不该出现这样的失误!我们将认真复盘改进自动化运维技术和发布验证流程,敬畏每一行代码,敬畏每一份托付。
    11756 2
    |
    存储 运维 Kubernetes
    【深度】阿里巴巴万级规模 K8s 集群全局高可用体系之美
    台湾作家林清玄在接受记者采访的时候,如此评价自己 30 多年写作生涯:“第一个十年我才华横溢,‘贼光闪现’,令周边黯然失色;第二个十年,我终于‘宝光现形’,不再去抢风头,反而与身边的美丽相得益彰;进入第三个十年,繁华落尽见真醇,我进入了‘醇光初现’的阶段,真正体味到了境界之美”。
    【深度】阿里巴巴万级规模 K8s 集群全局高可用体系之美
    |
    运维 Kubernetes 监控
    Log/Trace/Metric 完成 APIServer 可观测覆盖
    12 月 11 日,OpenAI 出现了全球范围的故障,影响了 ChatGPT/API/Sora/Playground/Labs 等服务,持续时间超过四个小时。究其背后原因,主要是新部署的服务产生大量的对 K8s APIServer 的请求,导致 APIServer 负载升高,最终导致 DNS 解析不能工作,影响了数据面业务的功能。面对 APIServer 这类公用基础组件,如何通过 Log/Trace/Metric 完成一套立体的覆盖体系,快速预警、定位根因,降低不可用时间变得非常重要。
    501 96
    Log/Trace/Metric 完成 APIServer 可观测覆盖
    |
    SQL 运维 算法
    链路诊断最佳实践:1 分钟定位错慢根因
    目前阿里云 ARMS 已经基于 LLM 大模型实现了单链路智能诊断,综合调用链、方法栈、异常堆栈、SQL、指标等多模态数据,结合链路诊断领域专家经验,有效识别单次请求的错慢根因,并给出相应的优化建议。
    777 100
    |
    Kubernetes 网络协议 Nacos
    OpenAI 宕机思考丨Kubernetes 复杂度带来的服务发现系统的风险和应对措施
    Kubernetes 体系基于 DNS 的服务发现为开发者提供了很大的便利,但其高度复杂的架构往往带来更高的稳定性风险。以 Nacos 为代表的独立服务发现系统架构简单,在 Kubernetes 中选择独立服务发现系统可以帮助增强业务可靠性、可伸缩性、性能及可维护性,对于规模大、增长快、稳定性要求高的业务来说是一个较理想的服务发现方案。希望大家都能找到适合自己业务的服务发现系统。
    567 94
    |
    消息中间件 运维 监控
    智能运维,由你定义:SAE自定义日志与监控解决方案
    通过引入 Sidecar 容器的技术,SAE 为用户提供了更强大的自定义日志与监控解决方案,帮助用户轻松实现日志采集、监控指标收集等功能。未来,SAE 将会支持 istio 多租场景,帮助用户更高效地部署和管理服务网格。
    664 51
    |
    弹性计算 Prometheus 运维
    一文详解阿里云可观测体系下标签最佳实践
    在当今数字化转型加速的时代,企业 IT 系统的复杂度与日俱增,如何高效地管理和监控这些系统成为了一项挑战。阿里云作为全球领先的云计算服务商,提供了一整套全面的可观测性解决方案,覆盖从业务、端侧(小程序、APP、H5 等)、应用、中间件、容器/ECS 等全栈的监控体系,旨在帮助企业构建强大而灵活的可观测性体系。其中,标签(Tag)作为一种核心组织和管理手段,在阿里云可观测体系中扮演着至关重要的角色。本文将深入探讨阿里云可观测系列产品中标签的应用,以及如何运用标签在阿里云可观测产品体系下进行体系化建设并给出相关最佳实践。
    1247 197
    |
    运维 Cloud Native Devops
    一线实战:运维人少,我们从 0 到 1 实践 DevOps 和云原生
    上海经证科技有限公司为有效推进软件项目管理和开发工作,选择了阿里云云效作为 DevOps 解决方案。通过云效,实现了从 0 开始,到现在近百个微服务、数百条流水线与应用交付的全面覆盖,有效支撑了敏捷开发流程。
    19846 30
    |
    资源调度 分布式计算 Kubernetes
    Koordinator 支持 K8s 与 YARN 混部,小红书在离线混部实践分享
    Koordinator 支持 K8s 与 YARN 混部,小红书在离线混部实践分享
    |
    存储 数据采集 监控
    阿里云故障洞察提效 50%,全栈可观测建设有哪些技术要点
    本文分享了阿里云可观测平台服务作为全球分布的超大业务系统,同时也作为服务全球企业用户的可观测平台提供方,在故障洞察提效中遇到的业务挑战,以及 6 个关键技术点和 2 个应用案例。
    22129 133
    阿里云故障洞察提效 50%,全栈可观测建设有哪些技术要点