kubernetes NodePort网络踩坑 - 三木燕 - 博客园

标签: | 发表时间:2020-07-13 23:32 | 作者:
出处:https://www.cnblogs.com

node节点信息:

系统:centos7.6     

内核:3.10   

IP地址:192.168.1.1

应用环境:

因为需要跑一个nginx的应用叫做http-proxy做流量转发,公网入口是阿里云的SLB然转发到http-proxy的NodePor 端口上,也就是192.168.1.1:30285

spec:
  clusterIP: 172.30.253.123
  externalTrafficPolicy: Cluster
  ports:
    - name: http
      nodePort: 30285
      port: 8080
      protocol: TCP
      targetPort: 8080

刚配好一切正常,过了几分钟SLB开始报健康检查错误,手动检查了一下发现3、4请求之后必然会有一次timeout

排查过程:

  1. 先从公网请求一下
    $ curl proxy.public.com

    几次请求中必然会有一次timeout

  1. 首先容器本地确定是否是nginx本身的问题
    $ curl localhost:8080

    正常

  2. 在内网环境请求NodePort端口
    $ curl192.168.1.1:30285

    正常,这就很诡异了

  3. 在宿主机本地抓包
    # tcpdump port30285

    11:08:36.186722 IP 100.122.64.147.30042 > 192.168.1.1:30285: Flags [S], seq 868295361, win 28480, options [mss 1424,sackOK,TS val 1875975334 ecr 0,nop,wscale 9], length 0
    11:08:37.236652 IP 100.122.64.147.30042 > 192.168.1.1:.30285: Flags [S], seq 868295361, win 28480, options [mss 1424,sackOK,TS val 1875976384 ecr 0,nop,wscale 9], length 0
    11:08:39.284640 IP 100.122.64.147.30042 > 192.168.1.1:.30285: Flags [S], seq 868295361, win 28480, options [mss 1424,sackOK,TS val 1875978432 ecr 0,nop,wscale 9], length
    可以看到有收到来自SLB发来第一握手syn包,但是服务端没有回应ack

  4. 在容器本地看一下syn drop
    $ netstat -s |grepLISTEN

    280 SYNs to LISTEN sockets dropped
    果然有而且在一直增加,查阅了相关资料后发现有可能是启用了tcp_tw_recycle参数,前一段时间因time_wait确实优化过这个参数。。。果断关掉

    # sysctl -wnet.ipv4.tcp_tw_recycle=0

    然后一切正常了

为什么会这样?

 

复习一下tcp的四次挥手:

第一次挥手:主动关闭方发送一个FIN+ACK报文,此时主动方进入FIN_WAIT1状态,主动方停止发送数据但仍然能接收数据

第二次挥手:被动方收到FIN+ACK,发送一个ACK给对方,此时被动方进入CLOSE-WAIT状态,被动方仍然可以给主动方发送数据

第三次挥手:主动方收到ACK后,此时主动方进入FIN_WAIT2状态,被动方确定没有数据要发后就会发送FIN+ACK报文

第四次挥手:主动方收到FIN+ACK,此时主动方进入TIME-WAIT状态,发送一个ACK给被动方,方被动方进入CLOSED状态

 

 

linux系统中的3个参数:

参数 默认状态 作用 条件 影响 风险 建议
net.ipv4.tcp_timestamps
开启 记录TCP报文的发送时间 双方都要开启 影响客户端服务端    开启
net.ipv4.tcp_tw_recycle 关闭
4.1内核已删除
把TIME-WAIT状态超时时间设置为成rto,以实现快速回收 要启用net.ipv4.tcp_timestamps 影响客户端服务端 tcp_tw_recycle和tcp_timestamps同时开启的条件下,60s内同一源ip主机的socket connect请求中的timestamp必须是递增的,否则数据会被linux的syn处理模块丢弃 内网环境切没有NAT的时候看情况打开,没什么必要就不要打开了
net.ipv4.tcp_tw_reuse 关闭 TIME-WAIT状态1秒之后可以重用端口 要启用net.ipv4.tcp_timestamps 影响客户端   比如负载均衡连接后端服务器时,可以在负载均衡服务器上开启

结论:对于服务端来说,客户端通过SNAT上网时的timestamp递增性无可保证,所以当服务端tcp_tw_recycle生效时会出现连接异常

 

k8s的NodePort网络:  

service网络的实体是kube-proxy维护iptables规则,先看一下流程

  1. 在nat主链拦截SERVICES自定义链
    # iptables -t nat  -nL PREROUTING
    KUBE-SERVICES  all  --  0.0.0.0/0            0.0.0.0/0            /* kubernetes service portals */
    其他nat主链同样有KUBE-SERVICES自定义链
  2. 拦截NodePort自定义链
    # iptables -t nat -nL KUBE-SERVICES

    KUBE-NODEPORTS all -- 0.0.0.0/0 0.0.0.0/0 /* kubernetes service nodeports; NOTE: this must be the last rule in this chain */ ADDRTYPE match dst-type LOCAL

  3. 拦截端口流量
    # iptables -t nat -nL KUBE-NODEPORTS

    KUBE-MARK-MASQ tcp -- 0.0.0.0/0 0.0.0.0/0 /* default/http-proxy:http1 */ tcp dpt:30285

    KUBE-SVC-NKX6PXTXGL4F5LBG  tcp  --  0.0.0.0/0            0.0.0.0/0            /* default/http-proxy:http1 */ tcp dpt:30285

  4. 拦截端口流量打标记
    # iptables -t nat -nL KUBE-MARK-MASQ

    MARK       all  --  0.0.0.0/0            0.0.0.0/0            MARK or 0x1

  5. 打标记并根据标记做SNAT
    # iptables -t nat -nL POSTROUTING

    KUBE-POSTROUTING  all  --  0.0.0.0/0            0.0.0.0/0            /* kubernetes postrouting rules */

    # iptables -t nat -nL KUBE-POSTROUTING

    MASQUERADE  all  --  0.0.0.0/0            0.0.0.0/0            /* kubernetes service traffic requiring SNAT */ mark match 0x1/0x1

  6. 第二步拦截端口流量到SCV自定义链
    # iptables -t nat -nL KUBE-SVC-NKX6PXTXGL4F5LBG

    KUBE-SEP-4DYOPOZ4UKLHEHIS  all  --  0.0.0.0/0            0.0.0.0/0            /* default/http-proxy:http1 */

    # iptables -t nat -nL KUBE-SEP-4DYOPOZ4UKLHEHIS

    DNAT       tcp  --  0.0.0.0/0            0.0.0.0/0            /* default/http-proxy:http1 */ tcp to:10.128.0.74:8081

     

结论:可以看到第五步kube-proxy会做SNAT的操作,这也就不难解释从SLB过来的流量为什么会不正常了。至于为什么要做SNAT主要是防止路由来回路径不一致会导致tcp通信失败,这里就不展开了

 

相关 [kubernetes nodeport 网络] 推荐:

kubernetes NodePort网络踩坑 - 三木燕 - 博客园

- -
系统:centos7.6     . IP地址:192.168.1.1. 因为需要跑一个nginx的应用叫做http-proxy做流量转发,公网入口是阿里云的SLB然转发到http-proxy的NodePor 端口上,也就是192.168.1.1:30285. 刚配好一切正常,过了几分钟SLB开始报健康检查错误,手动检查了一下发现3、4请求之后必然会有一次timeout.

Kubernetes Service iptables 网络通信验证

- - 三点水
Kubernetes gives Pods their own IP addresses and a single DNS name for a setof Pods, and can load-balance across them.. K8s Service会为每个 Pod 都设置一个它自己的 IP,并为一组 Pod 提供一个统一的 DNS 域名,还可以提供在它们间做负载均衡的能力.

使用 Cilium 增强 Kubernetes 网络安全

- - IT瘾-dev
在本篇,我们分别使用了 Kubernetes 原生的网络策略和 Cilium 的网络策略实现了 Pod 网络层面的隔离. 不同的是,前者只提供了基于 L3/4 的网络策略;后者支持 L3/4、L7 的网络策略. 通过网络策略来提升网络安全,可以极大降低了实现和维护的成本,同时对系统几乎没有影响. 尤其是基于 eBPF 技术的 Cilium,解决了内核扩展性不足的问题,从内核层面为工作负载提供安全可靠、可观测的网络连接.

调试Kubernetes集群中的网络停顿问题

- - DockOne.io
我们曾经在这里中聊起过Kubernetes ( Kubernetes at GitHub : https://github.blog/2017-08-16. ithub/),在过去几年,Kubernetes在Github已经成为标准的部署模式. 目前在Github,我们在Kubernetes上运行着海量的面向内部团队以及面向C端的服务.

记一次 Kubernetes 网络故障深度追踪

- - DockOne.io
某天晚上,客户碰到了 Kubernetes 集群一直扩容失败,所有的节点都无法正常加入集群. 在经过多番折腾无解后,反馈到我们这里进行技术支持. 这个问题的整个排查过程比较有意思,所以对其中的排查思路和用到的方法进行整理分享. 运维同学在对客户的 Kubernetes 集群进行节点扩容时,发现新增的节点一直添加失败.

Kubernetes容器网络及Flannel插件详解

- - 掘金 后端
这是我参与「掘金日新计划 · 6 月更文挑战」的第2天, 点击查看活动详情. Kubernetes是一个开源容器调度编排引擎,管理大规模容器化应用,采用典型的Master-Worker主从分布式技术架构,由集中式管理节点(Master Node),分布式的工作节点(Worker Node)组成. 向下屏蔽底层差异化的分布式基础设施,以应用为中心构建云计算的基础操作系统能力(即云原生操作系统),面向用户提供云原生时代的云计算的新界面.

Kubernetes网络难懂?快来看这篇文章

- - IT瘾-dev
Kubernetes 是为运行分布式集群而建立的,分布式系统的本质使得网络成为 Kubernetes 的核心和必要组成部分,了解 Kubernetes 网络模型可以使你能够正确运行、监控和排查应用程序故障. 网络是非常复杂的,拥有许多概念,对于不熟悉这个领域的用户来说,这可能会有一定的难度,这里面有很多概念需要理解,并且还需要把这些概念整合起来形成一个连贯的整体,比如网络命名空间、虚拟接口、IP 转发、NAT 等概念.

Kubernetes & Microservice

- - 午夜咖啡
这是前一段时间在一个微服务的 meetup 上的分享,整理成文章发布出来. 谈微服务之前,先澄清一下概念. 微服务这个词的准确定义很难,不同的人有不同的人的看法. 比如一个朋友是『微服务原教旨主义者』,坚持微服务一定是无状态的 http API 服务,其他的都是『邪魔歪道』,它和 SOA,RPC,分布式系统之间有明显的分界.

Kubernetes学习(Kubernetes踩坑记)

- - Z.S.K.'s Records
记录在使用Kubernetes中遇到的各种问题及解决方案, 好记性不如烂笔头. prometheus提示 /metrics/resource/v1alpha1 404. 原因: 这是因为[/metrics/resource/v1alpha1]是在v1.14中才新增的特性,而当前kubelet版本为1.13.

kubernetes移除Docker?

- -
两周前,Kubernetes在其最新的Changelog中宣布1.20之后将要弃用dockershime,也就说Kubernetes将不再使用Docker做为其容器运行时. 这一消息持续发酵,掀起了不小的波澜,毕竟Kubernetes+Docker的经典组合是被市场所认可的,大量企业都在使用. 看上去这个“弃用”的决定有点无厘头,那么为什么Kubernetes会做出这样的决定.