Erlo

036.集群网络-K8S网络模型及Linux基础网络

时间:2020-03-22 10:30   阅读:28次   来源:博客园
页面报错
点赞
原文:https://www.cnblogs.com/itzgr/p/12544350.html

一 Kubernetes网络模型概述

1.1 Kubernetes网络模型

Kubernetes网络模型设计的一个基础原则是:每个Pod都拥有一个独立的IP地址,并假定所有Pod都在一个可以直接连通的、扁平的网络空间中。所以不管它们是否运行在同一个Node(宿主机)中,都要求它们可以直接通过对方的IP进行访问。设计这个原则的原因是,用户不需要额外考虑如何建立Pod之间的连接,也不需要考虑如何将容器端口映射到主机端口等问题。

实际上,在Kubernetes的集群里,IP是以Pod为单位进行分配的。一个Pod内部的所有容器共享一个网络堆栈(相当于一个网络命名空间,它们的IP地址、网络设备、配置等都是共享的)。按照这个网络原则抽象出来的为每个Pod都设置一个IP地址的模型也被称作IP-per-Pod模型。

由于Kubernetes的网络模型假设Pod之间访问时使用的是对方Pod的实际地址,所以一个Pod内部的应用程序看到的自己的IP地址和端口与集群内其他Pod看到的一样。它们都是Pod实际分配的IP地址。将IP地址和端口在Pod内部和外部都保持一致,也就不需要使用NAT来进行地址转换了。

Kubernetes的网络之所以这么设计,主要原因就是可以兼容过去的应用。当然,我们使用Linux命令“ipaddrshow”也能看到这些地址,和程序看到的没有什么区别。所以这种IP-per-Pod的方案很好地利用了现有的各种域名解析和发现机制。

为每个Pod都设置一个IP地址的模型还有另外一层含义,那就是同一个Pod内的不同容器会共享同一个网络命名空间,也就是同一个Linux网络协议栈。这就意味着同一个Pod内的容器可以通过localhost来连接对方的端口。这种关系和同一个VM内的进程之间的关系是一样的,看起来Pod内容器之间的隔离性减小了,而且Pod内不同容器之间的端口是共享的,就没有所谓的私有端口的概念了。如果应用必须要使用一些特定的端口范围,那么也可以为这些应用单独创建一些Pod。反之,对那些没有特殊需要的应用,由于Pod内的容器是共享部分资源的,所以可以通过共享资源互相通信,这显然更加容易和高效。针对这些应用,虽然损失了可接受范围内的部分隔离性,却也是值得的。

IP-per-Pod模式和Docker原生的通过动态端口映射方式实现的多节点访问模式有如下差别:

  • 主要区别是后者的动态端口映射会引入端口管理的复杂性,而且访问者看到的IP地址和端口与服务提供者实际绑定的不同(因为NAT的缘故,它们都被映射成新的地址或端口了),这也会引起应用配置的复杂化。
  • 同时,标准的DNS等名字解析服务也不适用了,甚至服务注册和发现机制都比较复杂,因为在端口映射情况下,服务自身很难知道自己对外暴露的真实的服务IP和端口,外部应用也无法通过服务所在容器的私有IP地址和端口来访问服务。

总的来说,IP-per-Pod模型是一个简单的兼容性较好的模型。从该模型的网络的端口分配、域名解析、服务发现、负载均衡、应用配置和迁移等角度来看,Pod都能够被看作一台独立的虚拟机或物理机。

按照这个网络抽象原则,Kubernetes对网络有如下要求。

  1. 所有容器都可以在不用NAT的方式下同别的容器通信。
  2. 所有节点都可以在不用NAT的方式下同所有容器通信,反之亦然。
  3. 容器的地址和别人看到的地址是同一个地址。

这些基本要求意味着并不是只要两台机器都运行Docker,Kubernetes就可以工作了。具体的集群网络实现必须满足上述基本要求,原生的Docker网络目前还不能很好地支持这些要求。

实际上,这些对网络模型的要求并没有降低整个网络系统的复杂度。如果程序原来在VM上运行,而那些VM拥有独立IP,并且它们之间可以直接透明地通信,那么Kubernetes的网络模型就和VM使用的网络模型一样。所以使用这种模型可以很容易地将已有的应用程序从VM或者物理机迁移到容器上。

当然,谷歌设计Kubernetes的一个主要运行基础就是其公有云GCE,GCE默认支持这些网络要求。另外,常见的其他公有云服务商如亚马逊等,其公有云环境也支持这些网络要求。

由于部署私有云的场景也非常普遍,所以在私有云中运行Kubernetes+Docker集群之前,需要自己搭建出符合Kubernetes要求的网络环境。有很多开源组件可以帮助我们打通Docker容器和容器之间的网络,实现满足Kubernetes要求的网络模型。当然,每种方案都有适合的场景,需要根据自己的实际需要进行选择。

提示:Kubernetes的网络依赖于Docker,Docker的网络又离不开Linux操作系统内核特性的支持。

二 Docker网络基础

Docker本身的技术依赖于近年来Linux内核虚拟化技术的发展,所以Docker对Linux内核的特性有很强的依赖。Docker通常使用到的与Linux网络有关的主要技术有:网络命名空间(Network Namespace)、Veth设备对、网桥、ipatables和路由。

2.1 网络命名空间

为了支持网络协议栈的多个实例,Linux在网络栈中引入了网络命名空间,这些独立的协议栈被隔离到不同的命名空间中。

处于不同命名空间中的网络栈是完全隔离的,彼此之间无法通信。通过对网络资源的隔离,就能在一个宿主机上虚拟多个不同的网络环境。Docker正是利用了网络的命名空间特性,实现了不同容器之间的网络隔离。在Linux的网络命名空间中可以有自己独立的路由表及独立的iptables设置来提供包转发、NAT及IP包过滤等功能。

为了隔离出独立的协议栈,需要纳入命名空间的元素有进程、套接字、网络设备等。进程创建的套接字必须属于某个命名空间,套接字的操作也必须在命名空间中进行。同样,网络设备也必须属于某个命名空间。因为网络设备属于公共资源,所以可以通过修改属性实现在命名空间之间移动。

  • 网络命名空间的实现

Linux的网络协议栈相对复杂,为了支持独立的协议栈,相关的这些全局变量都必须被修改为协议栈私有。最好的办法就是让这些全局变量成为一个Net Namespace变量的成员,然后为协议栈的函数调用加入一个Namespace参数。这就是Linux实现网络命名空间的核心。

同时,为了保证对已经开发的应用程序及内核代码的兼容性,内核代码隐式地使用了命名空间中的变量。程序如果没有对命名空间有特殊需求,就不需要编写额外的代码,网络命名空间对应用程序而言是透明的。

在建立了新的网络命名空间,并将某个进程关联到这个网络命名空间后,就出现了类似于下图所示的内核数据结构,所有网站栈变量都被放入了网络命名空间的数据结构中。这个网络命名空间是其进程组私有的,和其他进程组不冲突。

clipboard

在新生成的私有命名空间中只有回环设备(名为“lo”且是停止状态),其他设备默认都不存在,若需要其他设备,则要手工建立。

从网络角度,每个namespace提供了一份独立的网络协议栈(网络设备接口、IPV4、IPV6、IP路由、防火墙规则、sockets等)。一个设备(Linux Device)只能位于一个namespace中,不同namespace中的设备可以利用veth pair进行桥接。

clipboard

namespace可实现隔离的资源:

资源

含义

uts_ns

UTS为Unix Timessharing System的简称,包含内存名称、脚本、版本、底层体系结构等信息。

ipc_ns

所有与进程通信(IPC)有关的信心。

nmt_ns

当前装载的文件系统。

pid_ns

有关进程ID的信息。

user_ns

资源配额的信息。

net_ns

网络信息。

Docker容器中的各类网络栈设备都是Docker Daemon在启动时自动创建和配置的。

所有的网络设备(物理的或虚拟接口、桥等在内核里都叫作NetDevice)都只能属于一个命名空间。

注意,物理设备(连接实际硬件的设备)通常只能关联到root这个命名空间中。虚拟的网络设备(虚拟的以太网接口或者虚拟网口对)则可以被创建并关联到一个给定的命名空间中,而且可以在这些命名空间之间移动。

同时,由于网络命名空间代表的是一个独立的协议栈,所以它们之间是相互隔离的,彼此无法通信,在协议栈内部都看不到对方。

若需要打破这种限制,让处于不同命名空间的网络相互通信,甚至和外部的网络进行通信,则需要应用Veth设备对。Veth设备对的一个重要作用就是打通互相看不到的协议栈之间的壁垒,类似一个通道,一端连着这个网络命名空间的协议栈,一端连着另一个网络命名空间的协议栈。所以如果想在两个命名空间之间通信,就必须有一个Veth设备对。

如下命令需要使用root用户执行,同时需要iproute软件包提供相关命令。

  1 [root@k8smaster01 ~]# ip netns add mytestns			#创建命名空间
  2 [root@k8smaster01 ~]# ip netns exec mytestns <command>	#进入命名空间bash
  3 [root@k8smaster01 ~]# ip netns exec mytestns bash		#进入命名空间bash
  4 [root@k8smaster01 ~]# exit					#退出命名空间
  5 [root@k8smaster01 ~]# ip link set <device> netns mytestns	#转移设备

注意:因为一个设备只能属于一个命名空间,所以转移后在这个命名空间中就看不到这个设备了。在设备里面有一个重要的属性:NETIF_F_ETNS_LOCAL,如果这个属性为on,就不能被转移到其他命名空间中。Veth设备属于可以转移的设备,而很多其他设备如lo设备、vxlan设备、ppp设备、bridge设备等都是不可以转移的。

2.2 Veth设备对

引入Veth设备对是为了在不同的网络命名空间之间通信,利用它可以直接将两个网络命名空间连接起来。由于要连接两个网络命名空间,所以Veth设备都是成对出现的,很像一对以太网卡,并且中间有一根直连的网线。通常将其中一端称为另一端的peer。

在Veth设备的一端发送数据时,它会将数据直接发送到另一端,并触发另一端的接收操作。Veth设备对的示意图如下:

1575105169

  1 [root@k8smaster01 ~]# ip link add veth0 type veth peer name veth1	#创建veth设备对
  2 [root@k8smaster01 ~]# ip link show | grep veth			#当前查看veth
  3 [root@k8smaster01 ~]# ip netns add ns0
  4 [root@k8smaster01 ~]# ip netns add ns1				#创建命名空间
  5 [root@k8smaster01 ~]# ip link set veth0 netns ns0
  6 [root@k8smaster01 ~]# ip link set veth1 netns ns1			#veth移入命名空间
  7 [root@k8smaster01 ~]# ip netns exec ns0 ip link show		#进入命名空间查看veth
  8 [root@k8smaster01 ~]# ip netns exec ns0 ip addr add local 192.168.10.1/24 dev veth0
  9 [root@k8smaster01 ~]# ip netns exec ns1 ip addr add local 192.168.10.2/24 dev veth1	#设置对应的IP
 10 [root@k8smaster01 ~]# ip netns exec ns0 ifconfig veth0 up
 11 [root@k8smaster01 ~]# ip netns exec ns1 ifconfig veth1 up		#开启设备
 12 [root@k8smaster01 ~]# ip netns exec ns0 ping 192.168.10.2		#连通性测试

clipboard

提示:在Docker内部,Veth设备对也是连通容器与宿主机的主要网络设备。

  1 [root@k8smaster01 ~]# ip netns exec ns0 ethtool -S veth0
  2 NIC statistics:
  3      peer_ifindex: 9
  4 [root@k8smaster01 ~]# ip netns exec ns1 ip link | grep 9

clipboard

2.3 网桥

Linux可以支持多个不同的网络,它们之间能够相互通信,可通过网桥将这些网络连接起来并实现各网络中主机的相互通信。

网桥是一个二层的虚拟网络设备,把若干个网络接口“连接”起来,以使得网络接口之间的报文能够互相转发。网桥能够解析收发的报文,读取目标MAC地址的信息,和自己记录的MAC表结合,来决策报文的转发目标网络接口。

为了实现转发功能,网桥学习源MAC地址(二层网桥转发的依据就是MAC地址)。在转发报文时,网桥只需要向特定的网口进行转发,来避免不必要的网络交互。如果接受到未学习到的地址,就无法知道这个报文应该向哪个网络接口转发,就将报文广播给所有的网络接口(报文来源的网络接口除外)。

在实际的网络中,网络拓扑若出现改变,如设备被移动到另一个端口上,却没有发送任何数据,网桥设备就无法感知到这个变化,网桥还是向原来的端口转发数据包,在这种情况下数据就会丢失。所以网桥还要对学习到的MAC地址表加上超时时间(默认为5min)。如果网桥收到了对应端口MAC地址回发的包,则重置超时时间,否则过了超时时间后,就认为设备已经不在那个端口上了,它就会重新广播发送。

对于多网卡、多虚拟的设备,Linux的网桥提供了在这些设备之间互相转发数据的二层设备。Linux内核支持网口的桥接(目前只支持以太网接口)。但是与单纯的交换机不同,交换机只是一个二层设备,对于接收到的报文,要么转发,要么丢弃。运行着Linux内核的机器本身就是一台主机,有可能是网络报文的目的地,其收到的报文除了转发和丢弃,还可能被送到网络协议栈的上层(网络层),从而被自己(这台主机本身的协议栈)消化,所以既可以把网桥看作一个二层设备,也可以把它看作一个三层设备。

Linux内核是通过一个虚拟的网桥设备(Net Device)来实现桥接的。这个虚拟设备可以绑定若干个以太网接口设备,从而将它们桥接起来。如下图所示,这种Net Device网桥和普通的设备不同,最明显的一个特性是还可以有一个IP地址。

clipboard

如上图所示,网桥设备br0绑定了eth0和eth1。对于网络协议栈的上层来说,只看得到br0就行。因为桥接是在数据链路层实现的,上层不需要关心桥接的细节,所以协议栈上层需要发送的报文被送到br0,网桥设备的处理代码判断报文该被转发到eth0还是eth1,或者两者皆转发;反之,从eth0或从eth1接收到的报文被提交给网桥的处理代码,在这里会判断报文应该被转发、丢弃还是被提交到协议栈上层。而有时eth0、eth1也可能会作为报文的源地址或目的地址,直接参与报文的发送与接收,从而绕过网桥。

Docker自动完成了对网桥的创建和维护。

新增一个网桥设备:

[root@k8smaster01 ~]# brctl #查看brctl模块

clipboard

提示:可通过# yum -y install bridge-utils安装brctl。

为网桥增加网口,在Linux中,一个网口其实就是一个物理网卡。

clipboard

  1 [root@k8smaster01 ~]# ip link add tap1 type veth peer name tap1_peer
  2 [root@k8smaster01 ~]# ip link add tap2 type veth peer name tap2_peer
  3 [root@k8smaster01 ~]# ip link add tap3 type veth peer name tap3_peer
  4 [root@k8smaster01 ~]# ip link add tap4 type veth peer name tap4_peer
  5 #创建veth pair
  6 [root@k8smaster01 ~]# ip netns add ns1
  7 [root@k8smaster01 ~]# ip netns add ns2
  8 [root@k8smaster01 ~]# ip netns add ns3
  9 [root@k8smaster01 ~]# ip netns add ns4
 10 #创建namespace
 11 [root@k8smaster01 ~]# ip link set tap1 netns ns1
 12 [root@k8smaster01 ~]# ip link set tap2 netns ns2
 13 [root@k8smaster01 ~]# ip link set tap3 netns ns3
 14 [root@k8smaster01 ~]# ip link set tap4 netns ns4
 15 #tap和namespace关联
 16 [root@k8smaster01 ~]# brctl addbr br1		#创建桥
 17 [root@k8smaster01 ~]# brctl addif br1 tap1_peer
 18 [root@k8smaster01 ~]# brctl addif br1 tap2_peer
 19 [root@k8smaster01 ~]# brctl addif br1 tap3_peer
 20 [root@k8smaster01 ~]# brctl addif br1 tap4_peer
 21 #把相应的tap添加至bright中
 22 [root@k8smaster01 ~]# ip netns exec ns1 ip addr add local 192.168.20.1/24 dev tap1
 23 [root@k8smaster01 ~]# ip netns exec ns2 ip addr add local 192.168.20.2/24 dev tap2
 24 [root@k8smaster01 ~]# ip netns exec ns3 ip addr add local 192.168.20.3/24 dev tap3
 25 [root@k8smaster01 ~]# ip netns exec ns4 ip addr add local 192.168.20.4/24 dev tap4
 26 #配置相应IP地址
 27 [root@k8smaster01 ~]# ip link set br1 up
 28 [root@k8smaster01 ~]# ip link set tap1_peer up
 29 [root@k8smaster01 ~]# ip link set tap2_peer up
 30 [root@k8smaster01 ~]# ip link set tap3_peer up
 31 [root@k8smaster01 ~]# ip link set tap4_peer up
 32 [root@k8smaster01 ~]# ip netns exec ns1 ip link set tap1 up
 33 [root@k8smaster01 ~]# ip netns exec ns2 ip link set tap2 up
 34 [root@k8smaster01 ~]# ip netns exec ns3 ip link set tap3 up
 35 [root@k8smaster01 ~]# ip netns exec ns4 ip link set tap4 up
 36 #将bright和tap设置为up
 37 [root@k8smaster01 ~]# ip netns exec ns1 ping 192.168.20.2		#互ping

clipboard

评论留言

还没有评论留言,赶紧来抢楼吧~~

吐槽小黑屋()

* 这里是“吐槽小黑屋”,所有人可看,只保留当天信息。

  • Erlo.vip2020-04-09 08:28:15Hello、欢迎使用吐槽小黑屋,这就是个吐槽的地方。
  • 返回顶部