Linux Bridge模拟在docker中的应用

Linux Bridge模拟在docker中的应用,第1张

Bridge是一种虚拟网络设备,所以具备虚拟网络设备的所有特性,比如可以配置 IP、MAC 等。除此之外,Bridge 还是一个虚拟交换机,具有交换机所有的功能。

对于普通的网络设备,就像一个管道,只有两端,数据从一端进,从另一端出,如物理网卡从外面网络中收到数据转发给内核网络协议栈,从网络协议栈过来的数据转发到外部网络。而 Bridge 有多个端口,数据可以从多个端口进,从多个端口出,原理和交换机类似。

Bridge 的这个特性让它可以接入其他的网络设备,比如物理设备、虚拟设备。Bridge 通常充当主设备,其他设备为从设备,这样的效果就等同于物理交换机的端口连接了一根网线。Bridge是和主机的网络协议栈相连的,也就是说通过bridge的网络数据,是要经过host主机的内核协议栈的进行处理的(我的理解就是net_filter通过iptables设置的rules进行处理)

veth-pair 就是一对的虚拟设备接口,它都是成对出现的。一端连着协议栈,一端彼此相连着

正因为有这个特性,它常常充当着一个桥梁,连接着各种虚拟网络设备。例如在docker中,他们连接容器所处网络namespace和bridge。

此图中veth-pair一个是连接在bridge上的veth,另一个是连接在容器网络namespace上的eth0。veth和eth0彼此相连,veth通过bridge与host的网络协议栈相连,eth0通过容器namespace和容器的网络协议栈相连。这里的容器是在host内部的容器,不考虑跨节点的容器。

安装docker成功后,我们可以看到docker在host机器上默认的创建一个docker0的bridge,这个bridge也是容器的默认的连接方式。在这里我们将用将创建网络namespace来模拟容器,让namespace和我们创建好的bridge连接起来,容器之间可以相互访问,容器可以和host所在网络访问。

首先我们要打开host机器上的ip_forwarding功能,这样host的物理网卡和bridge之间才能forward数据包。IP_FORWARD可以使连接在同一个网络协议栈上的网络接口间进行数据包的转发,适合host上有多块物理网卡,虚拟设备接口,结合iptables的 forward链一起使用。例如主机网络协议栈上连接了30.0/24这个物理网卡和88.0/24这个bridge虚拟设备,一个数据包从30.0/24这块网卡进入网络协议栈,数据包的destination是88.0/24这个网段上的某一个IP地址,内核协议栈发现这个包是去bridge子网的,于是就会把这个数据包forward给bridge连在网络协议栈上的端口并进行处理。如果forward功能没有打开,数据包无法转发到bridge,只能在drop掉。

这个重启后就失效了,要想永久有效请修改文件/etc/sysctl.conf

创建一个bridge br0,激活这个device,并给他分配一个IP地址及掩码192.168.88.1/24。

创建一个网络的namespace ns0,然后在这个网络namespace中执行bash命令(另外起一个terminal做这个事情),如果你还不清楚什么是linux内核namespace,请google相关资料。

执行命令后,我这个terminal已经进入到ns0这个namespace了,这和docker容器的网络namespace是一致的。通过ip命令查询,现在这个命令空间里面只有一个loopback的网络设备,没有其他网络设备相连。然后通过命令使loopback设备active

接下来我们就要创建veth pair,一边和这个ns0连接,一边和br0连接,并给他们分配IP地址。(这些 *** 作不要在ns0里执行bash命令的terminal里面做)

这里创建一个veth pair,veth0和veth0p,并且把veth0和ns0相连,并分配和br0同一个网段的IP地址192.168.88.2,启动veth0p这个设备。返回到ns0下bash的terminal,可以看到多出一个网卡信息并分配到IP地址,但是这个dev是处于LOWERLAYDOWN的状态,这是由于pair另一端还没有接入到br0.

接下来就是把veth0连接到br0上,并启动这个设备。

我们可以看到br0上有一个veth设备连接上来,返回去看ns0下的bash,我们可以看到veth0p的状态已经变成UP。

现在br0的IP是192.168.88.1,ns0的IP地址为192.168.88.2,我们可以在ns0下去ping 192.168.88.1是可以通的,我们可以通过同样的步骤在创建另外一个namespace ns1并分配IP192.168.88.3。ns0,ns1, br0都是可以相互连接的,这里就不重复创建了。

目前为止连接在bridge上的namespace都是可以相互访问,这个体现了bridge虚拟交换机的功能。如果我们还需要容器能访问host所在的网络,我们需要继续配置下面步骤。

在ns0下的bash命令行下设置默认路由,不属于192.168.88.0/24这个网段的数据包全部路由到默认网关br0 192.168.88.1.

由于192.168.88.0/24这个网段和host所在的网路不是一个网络,一切从88.0/24这个网络的数据包要访问外部网络都是要通过host的主机IP去访问的,对于远端服务连接它是不知道88.0/24这个网络的,他接收的数据包的src地址都是host的IP地址,在这里我们需要对88.0/24这个网段的数据包做SNAT。在host的terminal下通过iptables的命令设置。

iptables必须是enable的,并对NAT table的POSTROUTING chain添加一条规则,所有src地址为88.0/24这个网段的数据包,全部走host机器上的物理网卡,通过MASQUERADE选项修改src地址为网卡eno16777736的IP地址。你也可以用SNAT这个参数代替指定一个特殊IP地址。

请自行参考iptables的用法和原理,如果你的host主机上实现设置了其他iptables rules从而阻止了88.0/24这个网络的forward或者routing,需要自行检查一下,每一个机器的网络状态是不一样的没办法全部覆盖。这里推荐一个系列博客很详细的讲解了 iptables 。 

这里可以看到我们在ns0下的bash命令行,可以ping通host所在网络的机器30.134和internet上的baidu。现在就完成了整个模拟实验。

Neutron 默认使用 ML2 作为 core plugin,配置文件 /etc/neutron/neutron.conf 中 core_plugin

计算节点和控制节点都需要在各自的 neutron.conf 中配置 core_plugin

然后配置 ML2 的配置文件 /etc/neutron/plugins/ml2/ml2_conf.ini 中 mechanism_drivers

mechanism_drivers 可以同时指定多个。这里只指定了一个。

查看 linuxbridge 进程

控制节点:

计算节点:

在 Linux Bridge 环境中,一个数据包从 Instance 发送到物理网卡会经过下面几个类型的设备:

对于每个 local network,ML2 linux-bridge 会创建一个 bridge,Instance 的 tap 设备会连接到 bridge。位于同一个 local network 的 Instance 会连接到相同的 bridge,这样 Instance 之间就可以通讯了。

因为 local network 没有与物理网卡相连,所以 Instance 无法与宿主机之外的网络通信。

同时因为每个 local network 有自己的 bridge,bridge 之间是没有连通的,所以两个 local network 之间是不通的。

ML2 配置文件 /etc/neutron/plugins/ml2/ml2_conf.ini

type_drivers ML2 加载网络类型。

tenant_network_types 普通用户在自己的 Tenant(Project)中创建网络时,默认创建哪种 type 的网络。

tenant_network_types = vlan, local 意思是当没有 vlan 可创建时,使用 local。

检测 Neutron Agent 是否正常 管理员 -->系统 -->系统信息 -->网络代理

从用户管理创建网络

创建网络 项目 -->网络 -->网络

填写网络名称

填写子网信息。 网关 IP 可以不用填写。默认为子网地址的第一个 IP。即:172.16.10.1

添加子网 IP 范围。

点击网络名称,进去相信信息,可以看到子网和端口信息等。

可以看到在端口中已经创建了一个 port,名为 “(c45b69e6-04ba)”,IP 为 172.16.10.2。连接设备为 "network:dhcp"。

打开控制节点终端,使用 brctl show 查看 linux bridge 的状态。

可以看到 bridge 设备 brqd2fd4378-9e 和 tap 设备 tapc45b69e6-04

创建 Instance 并选择刚刚创建的网络。

创建 Instance 成功后可以发现已经分配 IP 地址。

在底层中 Neutron 会在 subnet 中创建一个 port,分配 IP 和 MAC 地址,并将 port 分配给 test。如下图

点进去可以看到详情

在宿主机上执行 brctl show 可以查看 bridge 的配置。

可以看到 bridge brqd2fd4378-9e 上连接了一个新的 tap 设备。

查看 Instance 信息。使用 virsh list 查看 Instance 运行中的列表。

使用 virsh edit 1 查看配置信息。

配置信息省略很多。重要的放在上面。

<mac address='fa:16:3e:19:e1:57'/> 是 Instance 网卡的 MAC 地址

<target dev='tapb337d11f-54'/> 是 Instance 虚拟网卡信息

ping test1 的 IP 地址发现是可以 ping 通。

查看 brctl show

发现 brqd2fd4378-9e 中又计入进来一个 VIF,因为两个 VIF 挂载在同一个 Linux Bridge 上,所以可以通讯。

结构如下:

如果新分的 Instance 在计算节点中。不在控制节点。他们之间将不在互通。

因为 DHCP agent 在控制节点上运行,test2 在计算节点的 local 网络上,两者位于不同物理节点。由于 local 网络的流量只能局限在本节点之内,发送的请求无法到达计算节点。

上图 物理网卡 eth1 桥接到 brqXXXX,为 Instance 提供 flat 网络。

下图 创建多个 flat Network,就要准备多个物理机网卡。

在 /etc/neutron/plugins/ml2/ml2.conf.ini 配置文件中,修改 tenant_network_types 参数为 flat

:这里是指定普通用户使用 flat。因为 flat 网络与物理网卡一一对应。一般情况下租户网络不采用 flat。

flat_networks 定义一个 flat 网络,label 为 “default”

通过 physical_interface_mappings 指名 default 对应的物理网卡为 ens35

例如:对于 label 为 “default” 的 flat network,节点 A 可能使用 ens35,配置为:

而 B 节点则可以使用 ens33,配置为:

创建 flat 网络

绑定子网

查看 控制节点网络状态

Neutron 自动新建了 flat_net 对应的网桥 brq9e3013c8-93,以及 dhcp 的 tap 设备 tap50802894-1a。

此时 tap50802894-1a 和物理网卡 ens35 都已经连接到网桥 brq9e3013c8-93 上。

可以看到 Instance 的 tap 设备 tapc1241c3f-cb 已经连接到网桥

配置文件 /etc/neutron/dhcp_agent.ini 中的 dhcp_driver 和 interface_driver

dnsmasq 是一个提供 DHCP 和 DNS 服务的开源软件。

在实现环境中使用 ps 命令可以查看到 dnsmasq 进程。

DHCP agent 会为每个 network 创建一个目录 /opt/stack/data/neutron/dhcp/xxxx 用于存放该 network 的 dnsmasq 配置文件。

在二层网络上,VLAN 可以将一个交换机分割成几个独立的虚拟交换机。

类似,在三层网络上,Linux Network Namespace 可以将一个物理三层网络分割成几个独立的虚拟三层网络。

每个 namespace 都有自己独立的网络栈,包括 route table,firewall rule,network interface device等

Neutron 通过 dnsmasq 为每个 Network 提供单独的 DHCP 和路由服务。

使用 ip 查看所有 namespcae

使用 neutron 查看 net-list

查看某个 namespace 的详细配置

3 个 Instance 通过 tap 设备连接到名为 “vrqXXXX” 的 Linux Bridge。

在物理网卡 eth1 上创建 eth1.100 的 valn interface,eth1.100 连接到 brqXXXX。

这样,Instance 通过 eth1.100 发送到 eth1 的数据包就会打上 vlan100 的 tag。

如果在创建个 network vlan101,eth1 上就会相应的创建多个 vlan interface eht1.101 并连接新的 Linux Bridge “brqYYYY”。

配置文件 /etc/neutron/plugins/ml2/ml2_conf.ini 中设置 tenant_network_types 的值为 vlan

配置 vlan 的范围

意思是:配置定义了 lable 为 “default” 的 valn network,valn id 的范围是 3001~4000。这里配置的是普通用户使用的范围。

admin 可以使用 1~4096 的 valn network

再次指定 vlan network 与物理网卡的对应关系

配置子网

查看系统网桥

这里可以看到:

vlan100 对应的网桥为 brq2b85ebb9-a。

vlan interface 是 ens35.100 (我是用的是 Ubuntu 16.04 默认网卡名 ens 开始的。)

DHCP 的 tap 设备是 tapf85d61d8-c3。

在 计算节点查看 网桥信息

可以发现创建的 Instance 已经连接到 vlan100 对应的网桥 brq2b85ebb9-a 上。因为计算节点没有 DHCP 服务所以没有相应的 tap 设备。

另外 网桥的名字与控制节点是一样的,都是 brq2b85ebb9-a6,表示是在同一个 network 上。

下图是我创建 VLAN 后 两台 Instance 分别在控制节点和计算机点的网络图

此时两台 Instance 在同一 valn100 下。相互之间是可以 ping 通的。

如果在创建一个 vlan101。如果两台 Instance1 和 Instance2 分别连在 vlan100 和 vlan101。此时两台 Instance 是不能 ping 通的。

如下图两个 vlan

两台 Instance1 和 Instance2 分别连在 vlan100 和 vlan101。此时两台 Instance 是不能 ping 通的。

因为 vlan 在二层是隔离的。如果想要互通,只能在三层通过路由转发。

通过 ip link add 可以创建多种类型的虚拟网络设备,在 man ip link 中可以得知有以下类型的device:

Virtual Ethernet Port Aggregator。它是HP在虚拟化支持领域对抗Cisco的VN-Tag的技术。

解决了虚拟机之间网络通信的问题,特别是位于同一个宿主机内的虚拟机之间的网络通信问题。

VN-Tag在标准的协议头中增加了一个全新的字段,VEPA则是通过修改网卡驱动和交换机,通过发夹弯技术回注报文。

TUN是Linux系统里的虚拟网络设备,它的原理和使用在 Kernel Doc 和 Wiki 做了比较清楚的说明。

TUN设备模拟网络层设备(network layer),处理三层报文,IP报文等,用于将报文注入到网络协议栈。

应用程序(app)可以从物理网卡上读写报文,经过处理后通过TUN回送,或者从TUN读取报文处理后经物理网卡送出。

创建:

创建之后,使用 ip addr 就会看见一个名为”tun-default”的虚拟网卡

可以对tun-default设置IP:

使用open/write等文件 *** 作函数从fd中进行读取 *** 作,就是在收取报文,向fd中写入数据,就是在发送报文。

TAP是Linux系统里的虚拟网络设备,它的原理和使用在 Kernel Doc 和 Wiki 做了比较清楚的说明。

不同于TUN的是,TAP设备模拟链路层设备(link layer),处理二层报文,以太网帧等。

TAP设备的创建过程和TUN类似,在ioctl设置的时候,将类型设置为IFF_TAP即可。

TAP设备与TUN设备的区别在于:

有时我们可能需要一块物理网卡绑定多个 IP 以及多个 MAC 地址,虽然绑定多个 IP 很容易,但是这些 IP 会共享物理网卡的 MAC 地址,可能无法满足我们的设计需求,所以有了 MACVLAN 设备,其工作方式如下:

MACVLAN 会根据收到包的目的 MAC 地址判断这个包需要交给哪个虚拟网卡。单独使用 MACVLAN 好像毫无意义,但是配合之前介绍的 network namespace 使用,我们可以构建这样的网络:

采摘

创建一个基于eth0的名为macv1的macvlan网卡:

macvlan支持三种模式,bridge、vepa、private,在创建的时候设置“mode XXX”:

bridge模式,macvlan网卡和物理网卡直接可以互通,类似于接入到同一个bridge。

vepa模式下,两个macvlan网卡直接不能直接通信,必须通过外部的支持“发夹弯”交换机才能通信。

private模式下,macvlan发出的广播包(arp等)被丢弃,即使接入了支持“发夹弯”的交换机也不能发现其它macvlan网卡,除非手动设置mac。

MACVTAP 是对 MACVLAN的改进,把 MACVLAN 与 TAP 设备的特点综合一下,使用 MACVLAN 的方式收发数据包,但是收到的包不交给 network stack 处理,而是生成一个 /dev/tapX 文件,交给这个文件:

由于 MACVLAN 是工作在 MAC 层的,所以 MACVTAP 也只能工作在 MAC 层,不会有 MACVTUN 这样的设备。

ipvlan和macvlan的区别在于它在ip层进行流量分离而不是基于mac地址,同属于一块宿主以太网卡的所有ipvlan虚拟网卡的mac地址都是一样的。

[图片上传失败...(image-d98b6f-1597455459947)]

veth设备是成对创建的:

创建之后,执行 ip link 就可以看到新创建的veth设备:

注意veth设备前面的ID, 58: 和 59: ,一对veth设备的ID是相差1的,并且系统内全局唯一。可以通过ID找到一个veth设备的对端。

veth设备理解

Intermediate Functional Block device,连接 ifb 中做了很详细的介绍。


欢迎分享,转载请注明来源:内存溢出

原文地址: https://outofmemory.cn/yw/5937881.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2023-03-09
下一篇 2023-03-09

发表评论

登录后才能评论

评论列表(0条)

保存