• kubernetes NodePort网络踩坑


    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端口
      $ curl 192.168.1.1:30285

      正常,这就很诡异了

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

      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 |grep LISTEN

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

      # sysctl -w net.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通信失败,这里就不展开了

     
  • 相关阅读:
    第五周进度条
    《掌握需求过程》阅读笔记01
    第三周进度条
    问题账户需求分析
    2016年秋季阅读个人计划
    梦断代码阅读笔记03
    软件工程概论课程总结
    Python爬取上交所一年大盘数据
    Python爬取6271家死亡公司数据,看十年创业公司消亡史
    python:王思聪究竟上了多少次热搜?
  • 原文地址:https://www.cnblogs.com/37yan/p/12376227.html
Copyright © 2020-2023  润新知