zoukankan      html  css  js  c++  java
  • kubernetes-canal 主机访问 service 异常问题分析

    问题描述:

    使用 canal 来做 Kubernetes CNI network provider, 在一次使用部署了新版本的 Kubernetes 平台环境上出现从本机访问应用的 service 异常,出现超时,查 iptables 规则发现在 nat 表的 POSTROUTING 链中多出几条规则, POSTROUTING 链中规则如下所示:

    iptables -vnL POSTROUTING -t nat
    Chain POSTROUTING (policy ACCEPT 33 packets, 2588 bytes)
     pkts bytes target     prot opt in     out     source               destination
    1673K  121M cali-POSTROUTING  all  --  *      *       0.0.0.0/0            0.0.0.0/0            /* cali:O3lYWMrLQYEMJtB5 */
    1673K  121M KUBE-POSTROUTING  all  --  *      *       0.0.0.0/0            0.0.0.0/0            /* kubernetes postrouting rules */
        0     0 MASQUERADE  all  --  *      !docker0  172.17.0.0/16        0.0.0.0/0
       18   936 RETURN     all  --  *      *      !192.168.64.0/20      192.168.66.0/24
     378K   26M RETURN     all  --  *      *       192.168.64.0/20      192.168.64.0/20
      294 15288 MASQUERADE  all  --  *      *       192.168.64.0/20     !224.0.0.0/4
        0     0 RETURN     all  --  *      *      !192.168.64.0/20      192.168.64.0/24
        1    52 MASQUERADE  all  --  *      *      !192.168.64.0/20      192.168.64.0/20
    

    其中 RETURN all -- * * !192.168.64.0/20 192.168.66.0/24 为多出来的规则。

    192.168.64.0/20 为集群 POD 网段,192.168.64.0/24 为本节点 PODCidr, 192.168.66.0/24 为 service 对应的 endpoint POD IP 所在节点的 PODCidr。

    从本机访问出去的流量不管目的地址是本节点还是跨节点都会匹配 OUTPUT 链,OUTPUT 链中有如下 hook 钩子,用来在 OUTPUT 链中实现 DNAT 功能。

    /* Before packet filtering, change destination */
    {
    	.hook	= iptable_nat_ipv4_local_fn,
    	.pf		= NFPROTO_IPV4,
    	.hooknum	= NF_INET_LOCAL_OUT,
    	.priority	= NF_IP_PRI_NAT_DST,
    },
    

    从本机访问 service ,OUTPUT 链中 DNAT 将 serivce IP + port 转换为 POD IP + port,从本机请求的报文走 DNAT 有如下函数处理流程:
    ip_local_out ----> iptable_nat_ipv4_local_fn -> nf_nat_ipv4_fn (match rule 并完成 DNAT )-> ip_route_me_harder(根据DNAT 后的目的地址重新查路由选择出接口) ---> dst_output

    返回流量有如下匹配,即目的 IP 不在集群 POD 网段,即做 SNAT:

    iptables -vnL  cali-nat-outgoing  -t nat
    Chain cali-nat-outgoing (1 references)
     pkts bytes target     prot opt in     out     source               destination
      587 46720 MASQUERADE  all  --  *      *       0.0.0.0/0            0.0.0.0/0            /* cali:Wd76s91357Uv7N3v */ match-set cali4-masq-ipam-pools src ! match-set cali4-all-ipam-pools dst
    

    有了上述前提条件描述之后,正常的请求流程应该是:

    1. 本机请求 service 之后 DNAT 为 POD IP(192.168.66.0), 重新查路由出接口为 flannel.x vxlan 接口,
    2. POSTROUTING 做 SNAT,修改源 IP 为flannel.x 的 IP, 从 vxlan 接口送出去,调用设备驱动发送函数 vxlan_xmit,
    3. vxlan 封装后调用 ip_local_output 再重新查路由选择出接口... ...
    4. 目的节点收到 vxlan 报文并解封装送至上的 POD,并根据目的 IP 为请求端 flannel.x 的 IP 返回,送至本节点vxlan 接口,vxlan封装送到请求节点,
    5. 请求节点根据连接跟踪做 SNAT, 将 POD IP + port 转换为 service IP + port ... ...

    但是如果在步骤 2 中没有做 SNAT,在步骤 4 中直接根据上的 IP 将报文送至请求端,而此时的请求节点不做 SNAT,请求进程收到源 IP 与自己请求的目的 IP 不匹配的报文不处理,且自己预期的报文一直等待不至,直至请求超时。

    解决问题

    分析了问题产生原因之后,推测问题产生原因为节点规则清理不干净导致(原有的 kubernetes 节点未清理即加入到新 kubernetes 集群,本节点所在的 Kubernetes 有过得重装)
    flannel 本身有做清理工作,在 defer 函数中删除创建的 iptables 规则,但是由于对于进程退出信号未捕获,导致未执行 defer 函数规则未做回收。

    defer func() {
    	teardownIPTables(ipt, rules)
    }()
    

    作者针对 flannel 回收 iptables 规则的问题在 flannel github 社区提交了 PR,见[1]。

    参考链接

    [1] flannel recycle unused iptable rules pr. https://github.com/coreos/flannel/issues/986
    [2] 洞悉linux下的Netfilter&iptables:网络地址转换原理之DNAT. http://blog.chinaunix.net/uid-23069658-id-3210931.html

  • 相关阅读:
    MVP模式与MVVM模式
    webpack的配置处理
    leetcode 287 Find the Duplicate Number
    leetcode 152 Maximum Product Subarray
    leetcode 76 Minimum Window Substring
    感知器算法初探
    leetcode 179 Largest Number
    leetcode 33 Search in Rotated Sorted Array
    leetcode 334 Increasing Triplet Subsequence
    朴素贝叶斯分类器初探
  • 原文地址:https://www.cnblogs.com/haoqingchuan/p/8940065.html
Copyright © 2011-2022 走看看