Kubernetes 网络名称空间与网桥(Bridge) 电脑版发表于:2022/4/27 22:20  >#Kubernetes 网络名称空间与网桥(Bridge) [TOC] ## 网络名称空间(namespace)简介 tn2>linux名称空间是一种linux内核功能,用于隔离虚拟化系统资源。仅限于命名空间的进程只能与属于同一命名空间的资源或进程进行交互。名称空间是Docker孤岛模型的重要组成部分。每种类型的资源都有名称空间,包括`net`(网络)、`mnt`(存储)、`uts`(主机名控制)和`user`(UID映射) 每个进程都有一个`/proc/[pid]/ns/`子目录,其中每个名称空间都包含一个条目,该名称空间支持由setns操作(2)。 (可通过如下命令进行查看) ```bash # ls -l /proc/$$/ns total 0 lrwxrwxrwx. 1 root root 0 Apr 27 11:20 ipc -> ipc:[4026531839] lrwxrwxrwx. 1 root root 0 Apr 27 11:20 mnt -> mnt:[4026531840] lrwxrwxrwx. 1 root root 0 Apr 27 11:20 net -> net:[4026531956] lrwxrwxrwx. 1 root root 0 Apr 27 11:20 pid -> pid:[4026531836] lrwxrwxrwx. 1 root root 0 Apr 27 11:20 user -> user:[4026531837] lrwxrwxrwx. 1 root root 0 Apr 27 11:20 uts -> uts:[4026531838] ``` tn2>在(net)网络名称空间中呢,network namespace主要提供了关于网络资源的隔离,包括网络设备、IPv4和IPv6协议栈、IP路由表、防火墙、/proc/net目录、/sys/class/net目录、套接字等。一个物理的网络设备最多存在于一个network namespace中,可以通过创建veth pair对在不同的network namespace间创建通道,以达到通信目的。 当然一般只会在用户空间隔离,包括docker也是通过用户空间进行隔离,并且它们所使用的是同一个内核。 ```bash # 主机是Ubuntu系统 uname -u # 运行centos容器 docker run -it --rm centos /bin/bash uname -u ```   | Namespace | 系统调用参数 | 隔离内容 | 内核版本 | | ------------ | ------------ | ------------ | ------------ | |UTS|CLONE_NEWUTS|主机名域名|2.6.19| |IPC|CLONE_NEWIPC|信号量、消息队列和共享内存|2.6.19| |PID|CLONE_NEWPID|进程编号|2.6.24| |Network|CLONE_NEWNET|网络设备、网络栈、端口|2.6.29| |Mount|CLONE_NEWNS|挂载点(文件系统)|2.3.19| |User|CLONE_NEWUSER|用户和用户组|3.8| tn2>查看网络名称空间的命令为: ```bash ip netns list ``` ## Veth虚拟网卡对 tn2>简单来讲它可以连接不同的网络名称空间进行网络通信,也可以连接网桥设备等。 由于它的创建是一对一对的所以其中的一个会分别插入需要通信的不同网络名称空间的两端。 我们可以通过如下命令来进行创建: ```bash ip link add <p1-name> type veth peer name <p2-name> ``` tn2>`p1-name`和`p2-name`是分配给两个连接端点的名称。在这对设备中的一个设备上传输的数据包会立即在另一个设备上接收。当任一设备关闭时,`pairis`的链接状态将关闭。 ```bash # 添加网卡虚拟对 ip link add p11 type veth peer name p22 # 添加net1网络名称空间 ip netns add net1 # 查看网卡 ip a # 列出所有网络名称空间 ip netns list # 绑定p11链接到net1网络上 ip link set p11 netns net1 # 查看net1网络名称空间下拥有的网卡 ip netns exec net1 ip a # 通过ethtool -S命令查找网卡对的另一半 ip netns exec net1 ethtool -S p11 # 再次查看所有的网卡信息 ip a ```   tn2>从上图得知在没绑定之前,通过`ip a`可以查看到虚拟网卡对`p11`和`p12`,在`p11`绑定了`net1`网络名称空间后,本地的`p11`虚拟网卡被`net1`网络名称空间拿走了。所以在`net1`下找到了`p11`虚拟网卡,接着我们通过`ethtool`查看`p11`链接到peer的索引为`4`的地方,也就ip a 下标第4的一个也是我们的`p22`。 tn>如果想要一步到位,一个虚拟网卡对应一个网络名称空间,可以通过下面的命令进行创建: `ip link add <p1-name> netns <p1-ns> type veth peer <p2-name> netns <p2-ns>` ## TAP与TUN设备 tn2>tap/tun 提供了一台主机内用户空间的数据传输机制。它虚拟了一套网络接口,这套接口和无力的接口无任何区别,可以配置IP,可以路由流量,不同的是,他的流量只在主机内流通。 作为网络设备,tap/tun也需要配套相应的驱动程序才能工作。tap/tun 驱动程序分两个部分,一个是字符设备驱动,一个是网卡驱动。这两部分驱动程序分工不太一样,字符驱动负责数据包和用户空间的传送,网卡驱动负责数据包在TCP/IP网络协议栈上的传输和处理。 tn>tap/tun有些许的不同,tun只操作三层的IP包,而tap操作二层的以太网帧。 tn2>在Linux中,用户空间和内核空间的数据传输有多种方式,字符设备就是其中的一种。tap/tun通过驱动程序和一个与在Linux内核2.6.x之后的版本中,tap/tun对应的设备文件分别为: - tap: /dev/tap0 - tun: /dev/net/tun tn2>设备文件即充当了用户空间和内核空间通信的接口。当应用程序打开设备文件时,驱动程序就会创建并注册相应的虚拟设备接口,一般以`tunX`或`tapX`命名。当应用程序关闭文件时,驱动也会自动删除 `tunX` 和`tapX`设备,还会删除已经建立起来的路由等信息。<br/> tap/tun 设备文件就像一个管道,一端连接着用户空间,一端连接着内核空间。当用户程序向 `/dev/net/tun` 或 `/dev/tap0` 写数据时,内核就可以从对应的 `tunX` 或 `tapX` 接口读到数据,反之,内核可以通过相反的方式向用户程序发送数据。  tn2>tap/tun是Linux内核2.4.x版本之后实现的虚拟网络设备,不同于无力网卡靠硬件板卡实现,tap/tun虚拟网卡完全由软件实现,功能和硬件实现完全没差别,它们都属于网络设备,都可配置IP,都归Linux网络设备管理模块统一管理。 >### 简单使用案例 tn2>程序A希望构造数据包发往`192.168.1.0/24`网段的主机`192.168.1.1`。  tn2>1.程序A构造数据包,目的地址上 `192.168.1.1`,通过socket A将这个数据包发给协议栈。 2.协议栈更具数据包的目的IP地址,匹配路由规则,发现要从tun0出去。 3.`tun0`发现自己的另一端应用程序B打开了,于是将数据发给程序B 4.程序B收到数据后,做一些跟业务相关的操作,然后构造一个新的数据包,源IP是`eth0`的IP,目的IP是`10.1.1.0/24`的网关`10.1.1.1`,封装原来的数据协议包,重新发给协议栈。 5.协议栈再根据本地路由,将这个数据包从eth0发出。 ## Veth Demo  tn2>veth pair(虚拟网卡对)试用于不同的network namespace 间进行通信,veth pair将一个network namespace数据发往另一个network namespace 的veth。 >### 清理网络空间 tn2>我们先清理刚刚创建的network namespace。 ```bash ip netns list ip netns delete net1 ip netns list ``` >### 开始 ```bash # 首先我们创建`ns1`和`ns2`名称空间 ip netns add ns1 ip netns add ns2 # 创建两个虚拟网络对 ip link add veth0 type veth peer name veth1 # 插入两端 ip link set veth0 netns ns1 ip link set veth1 netns ns2 ip netns exec ns1 ip a # 创建ip地址 ip netns exec ns1 ip add a 10.1.1.1/24 dev veth0 ip netns exec ns2 ip add a 10.1.1.2/24 dev veth1 # 查看配置IP情况 ip netns exec ns1 ifconfig -a ip netns exec ns2 ifconfig -a # 激活网卡 ip netns exec ns1 ip link set veth0 up ip netns exec ns2 ip link set veth1 up # ping测试 ip netns exec ns1 ping 10.1.1.2 ```  ## 抓包工具rpcapd tn2>官网项目地址:https://github.com/rpcapd-linux/rpcapd-linux 可通过如下命令在Ubuntu中安装,如果找不到`build-dep`和`libpcap`了,请更新或换源。 ```bash sudo apt-get build-dep libpcap git clone https://github.com/rpcapd-linux/rpcapd-linux.git cd /Home cd rpcapd/libpcap ./configure && make cd ../ make ./rpcapd -h ```  tn2>我们可以通过运行`./rpcapd -p 2002`来进行抓包并进行远程获取包的端口为`2002`。  tn>注意:需要注意防火墙的规则,可以通过如下操作来进行清理防火墙的规则。 ```bash $ iptables -F $ systemctl stop firewalld.service ``` tn2>然后我们可以打开我们的Wireshark进行连接。操作如下: 捕获-->选项-->管理接口-->远程接口--> +就可以进行添加与连接了。  tn2>如果添加不了,请重启Wireshark或检测ip与port是否正确。 tn>如果你是想去抓我们刚刚案例的包这样说抓不到的,因为你抓的说root网络空间下的包. ## 本地抓包 tn2>一般是在请求的过程中进行监听并打包成抓包文件,例如`veth.cap`。可通过如下命令进行抓包: ```bash tcpdump -i any -w veth.cap ``` tn2>按`Ctrl+C`之后会生成`veth.cap`的包,然后可以打开Wireshark进行分析。 tn>如果要收集刚我们案例下的包,可以通过在指定的网络名称空间下进行抓包。 ```bash ip netns exec ns1 tcpdump -i any -w veth1.cap ``` ## Linux Bridge 与网络名称空间的连接 tn2>接下来我们模拟docker的bridge网络模式,它大致的网络如下图所示:  tn2>我们接下来要模拟`ns2`通过Bridge模式向`ns1`发包,要做的如下图所示:  ```bash # 查看bridge brctl show # 如果没有可以通过如下命令进行安装 apt install -y bridge-utils # 清理网络名称空间 ip netns list ip netns delete ps1 ip netns delete ps2 # 创建一个Bridge ip link add br1 type bridge ip link set br1 up # 简写也可以:ip l a br1 type bridge # 列出所有的bridge网桥 brctl show # 然后激活一下 ip a s br1 up # 创建网络名称空间 ip netns add ns1 ip netns add ns2 # 创建虚拟网卡对 veth pair ip link add veth0 type veth peer name br1-veth0 ip link add veth1 type veth peer name br1-veth1 # 接着我们需要将网络名称空间与网桥通过veth连接起来 # 先插入一头到网络名称空间里面去 ip l set veth0 netns ns1 ip link set veth1 netns ns2 # 再插入一头到网桥里面去 ip link set br1-veth0 master br1 ip link set br1-veth1 master br1 # 都要激活 ip l s br1-veth0 up ip l s br1-veth1 up # 配置IP ip netns exec ns1 ip add a 10.1.1.2/24 dev veth0 ip netns exec ns2 ip a a 10.1.1.3/24 dev veth1 ip netns exec ns1 ip link set veth0 up ip netns exec ns2 ip link set veth1 up # 查看IP配置情况 ip netns exec ns1 ip a ip netns exec ns2 ip a # 解下来我们通过ns2来ping ns1 ip netns exec ns2 ping 10.1.1.2 ```  tn2>如果出ping不通的情况,有可能是你的防火墙出现了一些问题,请加上下面的命令再次尝试。 ```bash ip -n ns1 link set lo up ip -n ns2 link set lo up ``` ## 基于Linux Route路由转发 tn2>路由器与交换机的区别在于,交换机只能通过二层转发和在同一个ip网段下转发。而Route路由器是可以通过三层进行转发的,也就是通过ip进行转发,并且可以通过跨网段进行转发。 接下来我们模拟Linux Route路由器跨网段的转发请求。  ```bash # 设置转发 echo 1 >/proc/sys/net/ipv4/ip_forward # 添加命名空间 ip netns add ns1 ip netns add ns2 # 添加虚拟网卡对 ip link add v1 type veth peer name v1_r ip link add v2 type veth peer name v2_r # 设置路由端的虚拟网卡的网段 ip a a 10.1.1.1/24 dev v1_r ip a a 10.1.2.1/24 dev v2_r # 激活网卡 ip l s v1_r up ip l s v2_r up # 绑定网络名称空间端的网卡 ip l s v1 netns ns1 ip l s v2 netns ns2 # 设置ip ip netns exec ns1 ip a a 10.1.1.2/24 dev v1 ip netns exec ns2 ip a a 10.1.2.2/24 dev v2 # 激活一下 ip netns exec ns1 ifconfig v1 up ip netns exec ns2 ifconfig v2 up # 查看ns1与ns2网卡设置情况 ip netns exec ns1 ip a ip netns exec ns2 ip a # 设置包的出口 # ns1 的包从10.1.2.1出去 # ns2 的包从10.1.1.1出去 ip netns exec ns1 route add -net 10.1.2.0 netmask 255.255.255.0 gw 10.1.1.1 ip netns exec ns2 route add -net 10.1.1.0 netmask 255.255.255.0 gw 10.1.2.1 # 也可以这样 # ip netns exec ns1 route add -net 10.1.2.0 netmask 255.255.255.0 dev v1 # ip netns exec ns2 route add -net 10.1.1.0 netmask 255.255.255.0 dev v2 # 进行ping测试 ip netns exec ns1 ping 10.1.2.2 ```  ## 容器与容器跨主机通信 tn2>我们在第二台主机可以通过docker创建IP为`172.18.0.1`名为`net_18`网络,并且在`net_18`网络下运行一个容器,然后我们在第一台主机中默认的bridge下创建一个容器,通过添加相关的路由规则实现互联互通。 前提是需要这两台机子有一个口是通的。(大致示例图如下) 主机一ip是:`10.211.55.11` 主机二ip是:`10.211.55.12`  tn2>主机二运行如下命令。 ```bash # 创建网络 docker network create net_18 --subnet=172.18.0.0/16 # 查看网络 docker network list # 运行容器 docker run --name c2 --network=net_18 -td ikubernetes/myapp:v1 # 查看容器信息 docker inspect c2 ```  tn2>主机一运行如下命令。 ```bash # 运行容器 docker run --name c1 -td ikubernetes/myapp:v1 # 查看容器IP信息 docker inspect c1 ```  tn2>我们通过ping测试,发现并不能测试得通。 ```bash docker exec c1 ping 172.17.0.2 ```  tn2>我们通过第一台查看路由,发现并没有找到`172.18.0.0`的出处,所以我们只需要在主机上添加好相关路由即可。 ```bash route -n route add -net 172.18.0.0 netmask 255.255.0.0 gateway 10.211.55.12 ```  tn2>第二台主机上,我们也添加相关的路由规则 ```bash route -n route add -net 172.17.0.0 netmask 255.255.0.0 gateway 10.211.55.11 ```  tn2>再次ping就可以了  tn>注意:如果还ping不通的话,请在清理防火墙规则后再次尝试。(`iptables -F`) 因为有可能是由于iptables规则引起的。 ## IPIP模式 tn2>是路由器把一种网络层协议封装到另一个协议中以跨过网络传送到另一个路由器的处理过程。(像VPN) 如下图所示:  tn2>在包中封装两层IP从而可以达到tun1与tun2的通信,还不懂的话我们待会可以通过抓包来查看。 接下来我们可以通过如下命令进行Demo演示。 ```bash # 添加网络名称空间ns1和ns2 ip netns add ns1 ip netns add ns2 # 创建虚拟网卡对 ip l a v1 type veth peer name v1_r ip l a v2 type veth peer name v2_r # 绑定给路由器端网口绑定IP ip a a 10.10.10.1/24 dev v1_r ip a a 10.10.20.1/24 dev v2_r # 激活路由端的网卡 ip l s v1_r up ip l s v2_r up # 虚拟网卡对绑定到网络名称空间 ip l s v1 netns ns1 ip l s v2 netns ns2 # 创建虚拟网卡对的ip绑定到名称空间中 ip netns exec ns1 ip a a 10.10.10.2/24 dev v1 ip netns exec ns2 ip a a 10.10.20.2/24 dev v2 # 激活名称空间网卡 ip netns exec ns1 ifconfig v1 up ip netns exec ns2 ifconfig v2 up # 添加路由项 ip netns exec ns1 route add -net 10.10.20.0 netmask 255.255.255.0 gw 10.10.10.1 ip netns exec ns2 route add -net 10.10.10.0 netmask 255.255.255.0 gw 10.10.20.1 # 创建tun1和tun2 ip netns exec ns1 ip tunnel add tun1 mode ipip remote 10.10.20.2 local 10.10.10.2 ip netns exec ns2 ip tunnel add tun2 mode ipip remote 10.10.10.2 local 10.10.20.2 # 激活网卡 ip netns exec ns1 ifconfig tun1 up ip netns exec ns2 ifconfig tun2 up # 设置Peer ip netns exec ns1 ip a a 10.10.100.10 peer 10.10.200.10 dev tun1 ip netns exec ns2 ip a a 10.10.200.10 peer 10.10.100.10 dev tun2 # 开启内核转发 echo 1 >/proc/sys/net/ipv4/ip_forward # ping测试 ip netns exec ns1 ping 10.10.200.10 ```  tn2>抓包查看,是多封装了一层ip ```bash ip netns exec ns1 tcpdump -i any -w ipip.cap ```  ## OVS网络 tn2>在Openstack上,我们用得最多的是Linux+OVS Bridge的形式。  >### Ubuntu安装ovs工具 ```bash sudo apt-get install openvswitch-switch openvswitch-common ``` >### Demo案例 ```bash # 创建ovs bridge ovs-vsctl add-br ovs-br # 显示ovs ovs-vsctl show # 添加网络名称空间 ip netns a ns1 ip netns a ns2 # 添加虚拟网卡对 ip l a veth0 type veth peer name ovs-veth0 ip l a veth1 type veth peer name ovs-veth1 # 绑定到网络名称空间 ip l s veth0 netns ns1 ip l s veth1 netns ns2 # ovs绑定虚拟网卡对 ovs-vsctl add-port ovs-br ovs-veth0 ovs-vsctl add-port ovs-br ovs-veth1 ovs-vsctl show # 激活网卡 ip netns exec ns1 ip l s veth0 up ip netns exec ns2 ip l s veth1 up ip l s ovs-veth0 up ip l s ovs-veth1 up # 设置ip ip netns exec ns1 ip a a 10.1.1.2/24 dev veth0 ip netns exec ns2 ip a a 10.1.1.5/24 dev veth1 # 查看配置情况 ip netns exec ns1 ifconfig ip netns exec ns2 ifconfig # 测试 ip netns exec ns1 ping 10.1.1.5 ``` 