【问题标题】:Source IP address translation for intra-cluster traffic集群内流量的源 IP 地址转换
【发布时间】:2018-10-26 21:15:51
【问题描述】:

我正在尝试深入研究 K8s 网络模型,并且我认为到目前为止我对它已经有了很好的理解,但是有一件事我无法理解。在Cluster Networking 指南中,提到了以下内容:

Kubernetes 对任何网络实现都提出了以下基本要求(除非任何有意的网络分段策略):

  • 所有容器都可以在没有 NAT 的情况下与所有其他容器通信
  • 所有节点都可以在没有 NAT 的情况下与所有容器通信(反之亦然)
  • 容器认为自己的 IP 是同一个 IP 其他人认为它是

第二个要点指定 x-node 容器通信应该可以在没有 NAT 的情况下进行。然而,当 kube-proxy 在 iptables 模式下运行时,情况并非如此。这是来自我的一个节点的 iptables 转储:

Chain POSTROUTING (policy ACCEPT)
target     prot opt source               destination         
KUBE-POSTROUTING  all  --  anywhere             anywhere             /* kubernetes postrouting rules */

Chain KUBE-POSTROUTING (1 references)
target     prot opt source               destination         
MASQUERADE  all  --  anywhere             anywhere             /* kubernetes service traffic requiring SNAT */ mark match 0x4000/0x4000

/* sample target pod chain being marked for MASQ */
Chain KUBE-SEP-2BKJZA32HM354D5U (1 references)
target     prot opt source               destination         
KUBE-MARK-MASQ  all  --  xx.yyy.zzz.109       anywhere             /* kube-system/heapster: */
DNAT       tcp  --  anywhere             anywhere             /* kube-system/heapster: */ tcp to:xx.yyy.zzz.109:8082

Chain KUBE-MARK-MASQ (156 references)
target     prot opt source               destination         
MARK       all  --  anywhere             anywhere             MARK or 0x4000

看起来 K8s 正在将标记的出站数据包的源 IP 更改为节点的 IP(对于 ClusterIP 服务)。他们甚至在Source IP for Services with Type=ClusterIP 中明确提到了这一点:

从集群内发送到 ClusterIP 的数据包永远不会是源数据包 如果您在 iptables 模式下运行 kube-proxy,则进行 NAT,即 自 Kubernetes 1.2 起默认。 如果客户端 pod 和服务器 pod 在 同一个节点,client_address 是客户端 pod 的 IP 地址。 但是,如果客户端 pod 和服务器 pod 位于不同的节点中,则 client_address 是客户端 pod 的 node flannel IP 地址。

首先说集群中的数据包从不经过 SNAT,然后继续说发送到其他节点中的 pod 的包实际上经过了 SNAT。我对此感到困惑 - 我是否误解了所有节点都可以在没有 NAT 要求的情况下与所有容器通信(反之亦然)

【问题讨论】:

    标签: kubernetes kube-proxy


    【解决方案1】:

    如果你读到point 2

    Pod 到 Pod 通信:这是本文档的主要重点。

    这仍然适用于集群中运行的所有容器和 Pod,因为它们都在 PodCidr 中:

    • 所有容器都可以在没有 NAT 的情况下与所有其他容器通信
    • 所有节点都可以与所有容器通信(反之亦然)
    • 如果没有 NAT,容器认为自己的 IP 是同一个 IP 其他人认为它是

    基本上,所有 pod 都有唯一的 IP 地址,并且在同一个空间中,并且可以在 IP 层与每个 pod 进行通信。

    此外,如果您查看某个 Kubernetes 节点上的路由,您会看到 Calico 的类似内容,其中 podCidr 为 192.168.0.0/16

    default via 172.0.0.1 dev ens5 proto dhcp src 172.0.1.10 metric 100
    172.17.0.0/16 dev docker0 proto kernel scope link src 172.17.0.1 linkdown
    172.31.0.0/20 dev ens5 proto kernel scope link src 172.0.1.10
    172.31.0.1 dev ens5 proto dhcp scope link src 172.0.1.10 metric 100
    blackhole 192.168.0.0/24 proto bird
    192.168.0.42 dev calixxxxxxxxxxx scope link
    192.168.0.43 dev calixxxxxxxxxxx scope link
    192.168.4.0/24 via 172.0.1.6 dev tunl0 proto bird onlink
    192.168.7.0/24 via 172.0.1.55 dev tunl0 proto bird onlink
    192.168.8.0/24 via 172.0.1.191 dev tunl0 proto bird onlink
    192.168.9.0/24 via 172.0.1.196 dev tunl0 proto bird onlink
    192.168.11.0/24 via 172.0.1.147 dev tunl0 proto bird onlink
    

    您会看到带有192.168.x.x 的数据包直接转发到连接到节点的隧道接口,因此那里没有 NAT。

    现在,当您从 PodCidr 外部连接时,您的数据包肯定是经过 NAT 的,比如说通过服务是通过外部主机。你也肯定会看到这样的 iptable 规则:

    # Completed on Sat Oct 27 00:22:39 2018
    # Generated by iptables-save v1.6.1 on Sat Oct 27 00:22:39 2018
    *nat
    :PREROUTING ACCEPT [65:5998]
    :INPUT ACCEPT [1:60]
    :OUTPUT ACCEPT [28:1757]
    :POSTROUTING ACCEPT [61:5004]
    :DOCKER - [0:0]
    :KUBE-MARK-DROP - [0:0]
    

    【讨论】:

    • 谢谢,但您的解释仍然与我在集群设置中看到的不符。我们使用 EKS 和 CNI(不是 Calico),我发布的 iptables 规则似乎伪装了所有出站数据包,这意味着从节点 A 到节点 B 的请求是 SNATed,即使 Pod A 可以直接调用 Pod B 的 IP 而无需 NAT ...
    • 您的ip route 从您的一个节点看起来是什么样的?另外,podCidr 是什么?
    • default via 11.212.103.1 dev eth011.212.103.0/25 dev eth0 proto kernel scope link src 11.212.103.7411.212.103.18 dev eni4a2a03f68cd scope link11.212.103.20 dev eni0503b781c46 scope link11.212.103.21 dev eni8f2af04efb8 scope link11.212.103.23 dev eni8dd2db3a03a scope link+ a few more169.254.169.254 dev eth0172.17.0.0/16 dev docker0 proto kernel scope link src 172.17.0.1 linkdown
    • 格式乱了,如果你愿意,我可以给你发消息。另外我如何确定 podCidr?
    • 有了这个:$ kubectl -n kube-system describe configmap kube-proxy | grep clusterCIDR
    猜你喜欢
    • 1970-01-01
    • 2019-04-24
    • 2018-05-05
    • 2019-02-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-08-31
    相关资源
    最近更新 更多