香烟之歌 發表於 2020-3-1 20:25:00

Kubernetes 网络架构及相关网卡

<h2 id="前言">前言</h2>
<p>因为 Kubernetes 的网络可以使用第三方网络插件,所以给我们提供了多样化的网络解决方案,让我们可以根据自身情况选择自己需要的网络方案。</p>
<p><strong>CNM &amp; CNI 阵营:</strong></p>
<ul>
<li>
<p>容器网络发展到现在,形成了两大阵营,就是 Docker 的 CNM 和 Google、CoreOS、Kuberenetes 主导的 CNI。首先明确一点,CNM 和 CNI 并不是网络实现,他们是网络规范和网络体系,从研发的角度他们就是一堆接口,你底层是用 Flannel 也好、用 Calico 也好,他们并不关心,CNM 和 CNI 关心的是网络管理的问题。</p>
</li>
<li>
<p>CNM (Docker LibnetworkContainer Network Model)</p>
</li>
<li>
<p>CNI(Container Network Interface)</p>
</li>
</ul>
<p><strong>Kubernetes 网络设计模型:</strong></p>
<ul>
<li>在 Kubernetes 网络中存在两种 IP(Pod IP 和 Service Cluster IP),Pod IP 地址是实际存在于某个网卡(可以是虚拟设备)上的,Service Cluster IP 它是一个虚拟 IP,是由 kube-proxy 使用 Iptables 规则重新定向到其本地端口,再均衡到后端 Pod 的。</li>
</ul>
<p><strong>基本原则:</strong></p>
<ul>
<li>每个 Pod 都拥有一个独立的 IP 地址(IPper Pod),而且假定所有的 pod 都在一个可以直接连通的、扁平的网络空间中。</li>
</ul>
<p><strong>设计原因:</strong></p>
<ul>
<li>用户不需要额外考虑如何建立 Pod 之间的连接,也不需要考虑将容器端口映射到主机端口等问题。</li>
</ul>
<p><strong>网络要求:</strong></p>
<ul>
<li>所有的容器都可以在不用 NAT 的方式下同别的容器通讯;所有节点都可在不用 NAT 的方式下同所有容器通讯;容器的地址和别人看到的地址是同一个地址。</li>
</ul>
<h2 id="k8s-网络主要解决以下网络通信问题">K8S 网络主要解决以下网络通信问题:</h2>
<ul>
<li>
<p>同一 pod 下容器与容器的通信;</p>
</li>
<li>
<p>同一节点下不同的 pod 之间的容器间通信;</p>
</li>
<li>
<p>不同节点下容器之间的通信;</p>
</li>
<li>
<p>集群外部与内部组件的通信;</p>
</li>
<li>
<p>pod 与 service 之间的通信;</p>
</li>
</ul>
<h3 id="1容器间通信">1、容器间通信:</h3>
<p>同一个 Pod 的容器共享同一个网络命名空间,它们之间的访问可以用</p>
<p>localhost 地址 + 容器端口就可以访问。</p>
<p><img src="https://img2018.cnblogs.com/blog/443934/202003/443934-20200301212302880-340058066.png" alt="" loading="lazy"></p>
<h3 id="2同一-node-中-pod-间通信">2、同一 Node 中 Pod 间通信:</h3>
<p>同一 Node 中 Pod 的默认路由都是 docker0 的地址,由于它们关联在同一个 docker0(cni0)网桥上,地址网段相同,所有它们之间应当是能直接通信的。</p>
<p><img src="https://img2018.cnblogs.com/blog/443934/202003/443934-20200301212621736-1719576417.png" alt="" loading="lazy"></p>
<h3 id="3不同-node-中-pod-间通信">3、不同 Node 中 Pod 间通信:</h3>
<p>不同 Node 中 Pod 间通信要满足 2 个条件:</p>
<p><strong><em>*Pod 的 IP 不能冲突*</em>;</strong> <strong>将 Pod 的 IP 和所在的 Node 的 IP 关联起来,通过这个关联让 Pod 可以互相访问</strong>。所以就要用到 flannel 或者 calico 的网络解决方案。</p>
<p>对于此场景,情况现对比较复杂一些,这就需要解决 Pod 间的通信问题。在 Kubernetes 通过 flannel、calico 等网络插件解决 Pod 间的通信问题。以 flannel 为例说明在 Kubernetes 中网络模型,flannel 是 kubernetes 默认提供网络插件。Flannel 是由 CoreOs 团队开发社交的网络工具,CoreOS 团队采用 L3 Overlay 模式设计 flannel, 规定宿主机下各个 Pod 属于同一个子网,不同宿主机下的 Pod 属于不同的子网。</p>
<p><img src="https://img2018.cnblogs.com/blog/443934/202003/443934-20200301212544014-2053270236.png" alt="" loading="lazy"></p>
<h2 id="查看宿主机网卡">查看宿主机网卡</h2>
<pre><code>1 packet dropped by kernel
# ifconfig
cni0: flags=4163&lt;UP,BROADCAST,RUNNING,MULTICAST&gt;mtu 1450
      inet 10.244.3.1netmask 255.255.255.0broadcast 0.0.0.0
      inet6 fe80::1c39:e0ff:fefd:bc01prefixlen 64scopeid 0x20&lt;link&gt;
      ether 1e:39:e0:fd:bc:01txqueuelen 1000(Ethernet)
      RX packets 215461844bytes 49255741900 (45.8 GiB)
      RX errors 0dropped 0overruns 0frame 0
      TX packets 210219198bytes 99380196541 (92.5 GiB)
      TX errors 0dropped 0 overruns 0carrier 0collisions 0

docker0: flags=4099&lt;UP,BROADCAST,MULTICAST&gt;mtu 1500
      inet 172.17.0.1netmask 255.255.0.0broadcast 0.0.0.0
      ether 02:42:3a:fe:ce:d7txqueuelen 0(Ethernet)
      RX packets 0bytes 0 (0.0 B)
      RX errors 0dropped 0overruns 0frame 0
      TX packets 0bytes 0 (0.0 B)
      TX errors 0dropped 0 overruns 0carrier 0collisions 0

eth0: flags=4163&lt;UP,BROADCAST,RUNNING,MULTICAST&gt;mtu 1500
      inet 18.16.200.142netmask 255.255.255.0broadcast 18.16.200.255
      inet6 fe80::4e56:dbf1:fdb1:bbd9prefixlen 64scopeid 0x20&lt;link&gt;
      ether 52:54:00:fb:f2:44txqueuelen 1000(Ethernet)
      RX packets 271704820bytes 128411272052 (119.5 GiB)
      RX errors 0dropped 0overruns 0frame 0
      TX packets 234410728bytes 75423059029 (70.2 GiB)
      TX errors 0dropped 0 overruns 0carrier 0collisions 0

flannel.1: flags=4163&lt;UP,BROADCAST,RUNNING,MULTICAST&gt;mtu 1450
      inet 10.244.3.0netmask 255.255.255.255broadcast 0.0.0.0
      inet6 fe80::8087:1ff:fe29:ed7cprefixlen 64scopeid 0x20&lt;link&gt;
      ether 82:87:01:29:ed:7ctxqueuelen 0(Ethernet)
      RX packets 52059332bytes 8640899916 (8.0 GiB)
      RX errors 0dropped 0overruns 0frame 0
      TX packets 38918760bytes 6548881752 (6.0 GiB)
      TX errors 0dropped 20 overruns 0carrier 0collisions 0

lo: flags=73&lt;UP,LOOPBACK,RUNNING&gt;mtu 65536
      inet 127.0.0.1netmask 255.0.0.0
      inet6 ::1prefixlen 128scopeid 0x10&lt;host&gt;
      looptxqueuelen 1(Local Loopback)
      RX packets 23487bytes 1343648 (1.2 MiB)
      RX errors 0dropped 0overruns 0frame 0
      TX packets 23487bytes 1343648 (1.2 MiB)
      TX errors 0dropped 0 overruns 0carrier 0collisions 0

veth0b52cfb8: flags=4163&lt;UP,BROADCAST,RUNNING,MULTICAST&gt;mtu 1450
      inet6 fe80::bca4:22ff:fea7:349prefixlen 64scopeid 0x20&lt;link&gt;
      ether be:a4:22:a7:03:49txqueuelen 0(Ethernet)
      RX packets 5345585bytes 2672632806 (2.4 GiB)
      RX errors 0dropped 0overruns 0frame 0
      TX packets 5451377bytes 3371977575 (3.1 GiB)
      TX errors 0dropped 0 overruns 0carrier 0collisions 0

veth3867ca45: flags=4163&lt;UP,BROADCAST,RUNNING,MULTICAST&gt;mtu 1450
      inet6 fe80::7035:a5ff:fecd:e4d0prefixlen 64scopeid 0x20&lt;link&gt;
      ether 72:35:a5:cd:e4:d0txqueuelen 0(Ethernet)
      RX packets 4210336bytes 3083434674 (2.8 GiB)
      RX errors 0dropped 0overruns 0frame 0
      TX packets 4364899bytes 5908811645 (5.5 GiB)
      TX errors 0dropped 0 overruns 0carrier 0collisions 0

</code></pre>
<h2 id="docker0网卡">docker0网卡</h2>
<p>Docker 安装时会自动在 host 上创建三个网络:none,host,和bridge;详细说明可参考其它文档。</p>
<p>我们可用 docker network ls 命令查看:</p>
<pre><code># docker network ls
NETWORK ID          NAME                DRIVER            SCOPE
0ee6eb650f66      bridge            bridge            local
30a3e66f751c      host                host                local
2d1ae28eb78b      none                null                local
</code></pre>
<p>基于DRIVER是bridge的网络都会有一个对应的linux bridge被创建:</p>
<p>在默认环境中,一个名为docker0的linux bridge自动被创建好了,其上有一个 docker0 内部接口,IP地址为172.17.0.1/16(掩码为255.255.0.0)</p>
<p>再用docker network inspect指令查看bridge网络:其Gateway就是网卡/接口docker0的IP地址:172.17.0.1。</p>
<pre><code># docker network inspect bridge
[
    {
      "Name": "bridge",
      "Id": "0ee6eb650f66797ca4dde49db3985a4006affdf69f2e208791e11dd3f977a9ab",
      "Created": "2019-12-27T09:25:56.921594934+08:00",
      "Scope": "local",
      "Driver": "bridge",
      "EnableIPv6": false,
      "IPAM": {
            "Driver": "default",
            "Options": null,
            "Config": [
                {
                  "Subnet": "172.17.0.0/16",
                  "Gateway": "172.17.0.1"
                }
            ]
      },
      "Internal": false,
      "Attachable": false,
      "Containers": {},
      "Options": {
            "com.docker.network.bridge.default_bridge": "true",
            "com.docker.network.bridge.enable_icc": "true",
            "com.docker.network.bridge.enable_ip_masquerade": "true",
            "com.docker.network.bridge.host_binding_ipv4": "0.0.0.0",
            "com.docker.network.bridge.name": "docker0",
            "com.docker.network.driver.mtu": "1500"
      },
      "Labels": {}
    }
]

</code></pre>
<p>这时就会出现如何识别docker0的虚拟网卡和容器的对应关系,例如,图示中有两个容器和docker0中的两个接口:</p>
<p><img src="https://img2018.cnblogs.com/blog/443934/202003/443934-20200301203507574-179008623.png" alt="" loading="lazy"></p>
<p>安装Linux网桥管理工具<code>bridge-utils</code></p>
<pre><code># yum install bridge-utils

# brctl show
bridge name        bridge id                STP enabled        interfaces
docker0         8000.3a1d7362b4ee       no            veth65f9
                                             vethdda6
                                             vetha596
</code></pre>
<h2 id="flannel网络">flannel网络</h2>
<h3 id="flannel简介">flannel简介</h3>
<p>Flannel是CoreOS团队针对Kubernetes设计的一个网络规划服务,简单来说,它的功能是让集群中的不同节点主机创建的Docker容器都具有全集群唯一的虚拟IP地址。</p>
<p>在默认的Docker配置中,每个节点上的Docker服务会分别负责所在节点容器的IP分配。这样导致的一个问题是,不同节点上容器可能获得相同的内外IP地址。并使这些容器之间能够之间通过IP地址相互找到,也就是相互ping通。</p>
<p>Flannel的设计目的就是为集群中的所有节点重新规划IP地址的使用规则,从而使得不同节点上的容器能够获得“同属一个内网”且”不重复的”IP地址,并让属于不同节点上的容器能够直接通过内网IP通信。</p>
<p>Flannel实质上是一种“覆盖网络(overlaynetwork)”,也就是将TCP数据包装在另一种网络包里面进行路由转发和通信,目前已经支持udp、vxlan、host-gw、aws-vpc、gce和alloc路由等数据转发方式,默认的节点间数据通信方式是UDP转发。</p>
<h3 id="flannel网络-1">flannel网络</h3>
<p>flannel 的 IP 地址是通过 Etcd 管理的,在 k8s 初始化的时候指定 pod 大网的网段 <code>--pod-network-cidr=10.244.0.0/16</code>,flanneld 可以直接通过 Etcd 管理,如果启动的时候指定了 <code>--kube-subnet-mgr</code>,可以直接通过 k8s 的 apiserver 来获得一个小网段的租期,通过 <code>kubectl get-o jsonpath='{.spec.podCIDR}'</code> 可以获取对应节点的 CIDR 表示的网段,flannel 是以节点为单元划分小网段的,每个节点上的 pod 在这个例子当中是划分一个 10.244.x.0/24 的网段,所以总共能分配 255 个节点,每个节点上可以分配 253 个 pod。结构如下图所示,每个节点上都会有一个 flanneld 用于管理自己网段的租期。</p>
<p><img src="https://ggaaooppeenngg.github.io/zh-CN/2017/09/21/flannel-%E7%BD%91%E7%BB%9C%E6%9E%B6%E6%9E%84/flannel-02.png" alt="img" loading="lazy"></p>
<p>可以通过在 host 上 <code>cat /run/flannel/subnet.env</code> 查看同步下来的信息,例如:</p>
<pre><code># cat /run/flannel/subnet.env
FLANNEL_NETWORK=10.244.0.0/16
FLANNEL_SUBNET=10.244.3.1/24
FLANNEL_MTU=1450
FLANNEL_IPMASQ=true
</code></pre>
<p>说明当前节点分配的网段是 <code>10.244.0.1/24</code>。在每个节点上因为已经确定了网段,用 ipam 就可以管理这一范围 ip 地址的分配,所以本身 pod 的 IP 分配和中心 Etcd 没有太多联系。</p>
<h3 id="容器间跨宿主如何运行">容器间跨宿主如何运行</h3>
<p>如下图所示,集群范围内的网络地址空间为10.1.0.0/16,Machine A获取的subnet为10.1.15.0/24,且其中的两个容器IP分别为10.1.15.2/24和10.1.15.3/24,两者都在10.1.15.0/24这一子网范围内,对于下方的Machine B同理。</p>
<p><img src="https://img2020.cnblogs.com/blog/443934/202003/443934-20200310204652793-1427484406.png" alt="" loading="lazy"></p>
<p>如果上方Machine A中IP地址为10.1.15.2/24的容器要与下方Machine B中IP地址为10.1.16.2/24的容器进行通信,封包是如何进行转发的。从上文可知,每个主机的flanneld会将自己与所获取subnet的关联信息存入etcd中,例如,subnet 10.1.15.0/24所在主机可通过IP 192.168.0.100访问,subnet 10.1.16.0/24可通过IP 192.168.0.200访问。反之,每台主机上的flanneld通过监听etcd,也能够知道其他的subnet与哪些主机相关联。如上图,Machine A上的flanneld通过监听etcd已经知道subnet 10.1.16.0/24所在的主机可以通过Public 192.168.0.200访问,而且熟悉docker桥接模式的同学肯定知道,目的地址为10.1.16.2/24的封包一旦到达Machine B,就能通过cni0网桥转发到相应的pod,从而达到跨宿主机通信的目的。</p>
<p>因此,flanneld只要想办法将封包从Machine A转发到Machine B就OK了,而上文中的backend就是用于完成这一任务。不过,达到这个目的的方法是多种多样的,所以我们也就有了很多种backend. 在这里我们举例介绍的是最简单的一种方式hostgw : 因为Machine A和Machine B处于同一个子网内,它们原本就能直接互相访问。因此最简单的方法是:在Machine A中的容器要访问Machine B的容器时,我们可以将Machine B看成是网关,当有封包的目的地址在subnet 10.1.16.0/24范围内时,就将其直接转发至B即可。而这通过图中那条红色标记的路由就能完成,对于Machine B同理可得。由此,在满足仍有subnet可以分配的条件下,我们可以将上述方法扩展到任意数目位于同一子网内的主机。而任意主机如果想要访问主机X中subnet为S的容器,只要在本主机上添加一条目的地址为R,网关为X的路由即可。</p>
<h2 id="veth网卡">veth网卡</h2>
<p>Linux container 中用到一个叫做veth的东西,这是一种新的设备,专门为 container 所建。veth 从名字上来看是 Virtual ETHernet 的缩写,它的作用很简单,就是要把从一个 network namespace 发出的数据包转发到另一个 namespace。veth 设备是成对的,一个是 container 之中,另一个在 container 之外,即在真实机器上能看到的。<br>
VETH设备总是成对出现,送到一端请求发送的数据总是从另一端以请求接受的形式出现。创建并配置正确后,向其一端输入数据,VETH会改变数据的方向并将其送入内核网络子系统,完成数据的注入,而在另一端则能读到此数据。(Namespace,其中往veth设备上任意一端上RX到的数据,都会在另一端上以TX的方式发送出去)veth工作在L2数据链路层,veth-pair设备在转发数据包过程中并不串改数据包内容。</p>
<h3 id="veth设备特点">veth设备特点</h3>
<ul>
<li>veth和其它的网络设备都一样,一端连接的是内核协议栈</li>
<li>veth设备是成对出现的,另一端两个设备彼此相连</li>
<li>一个设备收到协议栈的数据发送请求后,会将数据发送到另一个设备上去</li>
</ul>
<h2 id="cni0网卡">cni0网卡</h2>
<p>查看cni0网卡对应的桥接网卡</p>
<pre><code># brctl show
bridge name        bridge id                STP enabled        interfaces
cni0                8000.1e39e0fdbc01        no                veth07cd1879
                                                        veth0b52cfb8
                                                        veth4238d279
                                                        veth6389b6d5
                                                        veth724d6510
                                                        veth78b32a65
                                                        veth96aa8f2a
                                                        vethad79f5c0
                                                        vethb4ae9fae
                                                        vethcaba2513
                                                        vethd9bb4726
</code></pre>
<h2 id="参考">参考:</h2>
<p>flannel 网络架构</p>
<p>Linux-虚拟网络设备-veth pair</p>
<p>flanneld,flannel和cni逐步深入</p>
<p><strong>Kubernetes 网络 -flannel 网络插件详解 </strong></p>
<p><strong>Kubernetes中的网络解析——以flannel为例</strong></p>
<p><strong>容器虚拟网卡与网桥docker0虚拟网卡的veth pair的配对</strong></p>
<p>技术干货|深入理解flannel</p>
<p>k8s网络之Flannel网络</p><br><br>
来源:https://www.cnblogs.com/hongdada/p/12391803.html
頁: [1]
查看完整版本: Kubernetes 网络架构及相关网卡