您现在的位置是:首页 > 文章详情

【Kubernetes系列】第9篇 网络原理解析(上篇)

日期:2019-11-18点击:402

1. Linux网络基础

1.1 名词解释

  1. Network Namespace(网络命名空间):Linux在网络栈中引入网络命名空间,将独立的网络协议栈隔离到不同的命令空间中,彼此间无法通信;docker利用这一特性,实现不容器间的网络隔离。
  2. Iptables/Netfilter:Netfilter负责在内核中执行各种挂接的规则(过滤、修改、丢弃等),运行在内核模式中;Iptables模式是在用户模式下运行的进程,负责协助维护内核中Netfilter的各种规则表;通过分析进入主机的网络封包,将封包的表头数据提取出来进行分析,以决定该联机为放行或抵挡的机制。 由于这种方式可以直接分析封包表头数据,所以包括硬件地址(MAC), 软件地址 (IP), TCP, UDP, ICMP 等封包的信息都可以进行过滤分析。
  3. Veth设备对:Veth设备对的引入是为了实现在不同网络命名空间的通信。
  4. Bridge(网桥):网桥是一个二层网络设备,是最简单的CNI网络插件,它首先在Host创建一个网桥,然后再通过veth pair连接该网桥到container netns。另外,Bridge模式下,多主机网络通信需要额外配置主机路由
  5. Route(路由):Linux系统包含一个完整的路由功能,当IP层在处理数据发送或转发的时候会使用路由表来决定发往哪里。
  6. Container Network Interface (CNI) 最早是由CoreOS发起的容器网络规范,是 Kubernetes网络插件的基础。其基本思想为:Container Runtime在创建容器时,先创建好network namespace,然后调用CNI插件为这个netns配置网络,其后再启动容器内的进程

2. Kubernetes 网络模型

Kubernetes网络有一个重要的基本设计原则:

每个Pod拥有唯一的IP

这个Pod IP被该Pod内的所有容器共享,并且其它所有Pod都可以路由到该Pod。你可曾注意到,你的Kubernetes节点上运行着一些"pause"容器?它们被称作“沙盒容器(sandbox containers)",其唯一任务是保留并持有一个网络命名空间(netns),该命名空间被Pod内所有容器共享。通过这种方式,即使一个容器死掉,新的容器创建出来代替这个容器,Pod IP也不会改变。这种IP-per-pod模型的巨大优势是,Pod和底层主机不会有IP或者端口冲突。我们不用担心应用使用了什么端口。

这点满足后,Kubernetes唯一的要求是,这些Pod IP可被其它所有Pod访问,不管那些Pod在哪个节点。

2.1 节点内通信

第一步是确保同一节点上的Pod可以相互通信,然后可以扩展到跨节点通信、internet上的通信,等等。

Kubernetes_network_model_root_ns

Kubernetes Node(root network namespace)

在每个Kubernetes节点(本场景指的是Linux机器)上,都有一个根(root)命名空间(root是作为基准,而不是超级用户)-- root netns(root network namespace)。

主要的网络接口 eth0 就是在这个root netns下。

k8s_pod_netns

Kubernetes Node(pod network namespace)

类似的,每个Pod都有其自身的netns(network namespace),通过一个虚拟的以太网对连接到root netns。这基本上就是一个管道对,一端在root netns内,另一端在Pod的netns内。

我们把Pod端的网络接口叫 eth0,这样Pod就不需要知道底层主机,它认为它拥有自己的根网络设备。另一端命名成比如 vethxxx。你可以用 ifconfig 或者 ip a 命令列出你的节点上的所有这些接口。

image

Kubernetes Node(linux network bridge)

节点上的所有Pod都会完成这个过程。这些Pod要相互通信,就要用到linux的以太网桥 cbr0 了。Docker使用了类似的网桥,称为docker0。你可以用 brctl show 命令列出所有网桥。

gif_same_node_pod2pod_communication

Kubernetes Node(same node pod-to-pod communication)

假设一个网络数据包要由pod1到pod2

  1. 它由pod1中netns的eth0网口离开,通过vethxxx进入root netns。
  2. 然后被传到cbr0,cbr0使用ARP请求,说“谁拥有这个IP”,从而发现目标地址。
  3. vethyyy说它有这个IP,因此网桥就知道了往哪里转发这个包。
  4. 数据包到达vethyyy,跨过管道对,到达pod2的netns。

这就是同一节点内容器间通信的流程。当然也可以用其它方式,但是无疑这是最简单的方式,同时也是Docker采用的方式。

2.2 不同节点间通信

正如我前面提到,Pod也需要跨节点可达。Kubernetes不关心如何实现。我们可以使用L2(ARP跨节点),L3(IP路由跨节点,就像云提供商的路由表),Overlay网络,或者甚至信鸽。无所谓,只要流量能到达另一个节点的期望Pod就好。每个节点都为Pod IPs分配了唯一的CIDR块(一段IP地址范围),因此每个Pod都拥有唯一的IP,不会和其它节点上的Pod冲突。

大多数情况下,特别是在云环境上,云提供商的路由表就能确保数据包到达正确的目的地。我们在每个节点上建立正确的路由也能达到同样的目的。许多其它的网络插件通过自己的方式达到这个目的。

这里我们有两个节点,与之前看到的类似。每个节点有不同的网络命名空间、网络接口以及网桥。

gif1_cross_node_pod2pod_communication

Kubernetes Nodes with route table(cross node pod-to-pod communication)

假设一个数据包要从pod1到达pod4(在不同的节点上)

  1. 它由pod1中netns的eth0网口离开,通过vethxxx进入root netns。
  2. 然后被传到cbr0,cbr0通过发送ARP请求来找到目标地址。
  3. 本节点上没有Pod拥有pod4的IP地址,根据路由判断数据包由cbr0 传到主网络接口 eth0.
  4. 数据包的源地址为pod1,目标地址为pod4,它以这种方式离开node1进入电缆。
  5. 路由表有每个节点的CIDR块的路由设定,它把数据包路由到CIDR块包含pod4的IP的节点。
  6. 因此数据包到达了node2的主网络接口eth0。现在即使pod4不是eth0的IP,数据包也仍然能转发到cbr0,因为节点配置了IP forwarding enabled。节点的路由表寻找任意能匹配pod4 IP的路由。它发现了 cbr0 是这个节点的CIDR块的目标地址。你可以用route -n命令列出该节点的路由表,它会显示cbr0的路由,类型如下:
    route_tables
  7. 网桥接收了数据包,发送ARP请求,发现目标IP属于vethyyy。
  8. 数据包跨过管道对到达pod4。

这就是Kubernetes网络的基础。下次你碰到问题,务必先检查这些网桥、iptables规则表和路由表。

_

原文链接:https://yq.aliyun.com/articles/727476
关注公众号

低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。

持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。

转载内容版权归作者及来源网站所有,本站原创内容转载请注明来源。

文章评论

共有0条评论来说两句吧...

文章二维码

扫描即可查看该文章

点击排行

推荐阅读

最新文章