Linux 常见网络虚拟化
虚拟网卡:tun/tap
虚拟网卡(又称虚拟网络适配器),即用软件模拟网络环境,模拟网络适配器。
在计算机网络中,tun 与 tap 是操作系统内核中的虚拟网络设备。不同于普通靠硬件网络适配器实现的设备,这些虚拟的网络设备全部用软件实现,并向运行于操作系统上的软件提供与硬件的网络设备完全相同的功能。
tun 是网络层的虚拟网络设备,可以收发第三层数据报文包,如 IP 封包,因此常用于一些点对点 IP 隧道,例如 OpenVPN,IPSec 等。
tap 是链路层的虚拟网络设备,等同于一个以太网设备,它可以收发第二层数据报文包,如以太网数据帧。Tap 最常见的用途就是做为虚拟机的网卡,因为它和普通的物理网卡更加相近,也经常用作普通机器的虚拟网卡。
- 添加网卡
# 创建 tap
ip tuntap add dev tap0 mode tap
# 创建 tun
ip tuntap add dev tun0 mode tun
- 删除网卡
# 删除 tap
ip tuntap del dev tap0 mode tap
# 删除 tun
ip tuntap del dev tun0 mode tun
- 激活网卡
ip link set tun0 up
- 设置 ip
ip addr add 10.5.0.1/24 dev tun0
- 查看帮助
ip tuntap help
使用 tun/tap 设备的目的是实现把来自协议栈的数据包先交由某个打开了 /dev/net/tun 字符设备的用户进程处理后,再把数据包重新发回到链路中。你可以通俗地将它理解为这块虚拟化网卡驱动一端连接着网络协议栈,另一端连接着用户态程序,而普通的网卡驱动则是一端连接着网络协议栈,另一端连接着物理网卡。
最典型的 VPN 应用程序为例,程序发送给 tun 设备的数据包。

应用程序通过 tun 设备对外发送数据包后,tun 设备便会把数据包通过字符设备发送给 VPN 程序,VPN 收到数据包,会修改后重新封装成新报文,然后通过协议栈发送到物理网卡发送出去。
使用 tun/tap 设备传输数据需要经过两次协议栈,不可避免地会有一定的性能损耗,所以引入了新的网卡实现方式 veth.
虚拟网卡:veth
在 Linux Kernel 2.6 版本,Linux 开始支持网络名空间隔离同时也提供了专门的虚拟以太网(Virtual Ethernet,习惯简写做 veth)让两个隔离的网络名称空间之间可以互相通信。直接把veth 比喻成是虚拟网卡其实并不十分准确,如果要和物理设备类比,它应该相当于由交叉网线连接的一对物理网卡。形象化的理解如下:

veth 实际上不是一个设备,而是一对设备,因而也常被称作 veth pair。要使用 veth,必须在两个独立的网络名称空间中进行才有意义,因为 veth pair 是一端连着协议栈,另一端彼此相连的,在 veth 设备的其中一端输入数据,这些数据就会从设备的另外一端原样不变地流出.

- veth 操作
# 添加 veth
ip link add <veth name> type veth peer name <peer name>
# 删除 veth
ip link delete <veth name>
# 查看 veth
ip link show
# 将 veth 移到网络空间
ip link set <veth name> netns <netns name>
- 命名空间操作
#添加 ns
ip netns add <name>
#删除 ns
ip netns del <name>
#执行命令
ip netns exec <name> <cmd>
#遍历 ns
ip netns list
veth 通信不需要反复多次经过网络协议栈,这让 veth 比起 tap/tun 具有更好的性能。veth 实现了点对点的虚拟连接,可以通过 veth 连接两个 namespace,如果我们需要将多个 namespace 接入同一个二层网络时,就不能只使用 veth 了。在物理网络中,如果需要连接多个主机,我们会使用网桥,或者又称为交换机。Linux 也提供了网桥的虚拟实现。
虚拟交换机
使用 veth pair 将两个隔离的 netns 连接在了一起,在现实世界里等同于用一根网线把两台电脑连接在了一起,但是在现实世界里往往很少会有人这样使用。因为一台设备不仅仅只需要和另一台设备通信,它需要和很多很多的网络设备进行通信,如果还使用这样的方式,需要十分复杂的网络接线,并且现实世界中的普通网络设备也没有那么多网络接口。
那么,想要让某一台设备和很多网络设备都可以通信需要如何去做呢?在我们的日常生活中,除了手机和电脑,最常见的网络设备就是路由器了,我们的手机连上 WI-FI,电脑插到路由器上,等待从路由器的 DHCP 服务器上获取到 IP,他们就可以相互通信了,这便是路由器的二层交换功能在工作。Linux Bridge 最主要的功能就是二层交换,是对现实世界二层交换机的模拟.

Linux Bridge ,由 brctl 命令创建和管理。Linux Bridge 创建以后,真实的物理设备(如 eth0)或是虚拟的设备(veth 或者 tap)都能与 Linux Bridge 配合工作。
- 安装方式
# centos
yum install -y bridge-utils
# ubuntu
apt-get install -y bridge-utils
- 新建一个网桥
brctl addbr <bridge>
- 添加一个设备(例如 eth0)到网桥
brctl addif <bridge> eth0
- 显示当前存在的网桥及其所连接的网络端口
brctl show
- 启动网桥
ip link set <bridge> up
- 删除网桥
ip link del <bridge>
增加 Linux Bridge 时会自动增加一个同名虚拟网卡在宿主机器上,因此我们可以通过 ip link 命令操作这个虚拟网卡,实际上也就是操作网桥,并且只有当这个虚拟网卡状态处于 up 的时候,网桥才会转发数据。
虚拟组网
物理网络的拓扑结构是相对固定的。云原生时代的分布式系统的逻辑拓扑结构变动频率,譬如服务的扩缩、断路、限流,等等,都可能要求网络跟随做出相应的变化。正因如此,软件定义网络(Software Defined Network,SDN)的需求在云计算和分布式时代变得前所未有地迫切,SDN 的核心思路是在物理的网络之上再构造一层虚拟化的网络。SDN 里位于下层的物理网络被称为 Underlay,它着重解决网络的连通性与可管理性,位于上层的逻辑网络被称为 Overlay,它着重为应用提供与软件需求相符的传输服务和网络拓扑。
vlan
交换机是一个 L2 设备,插在同一个交换机的网络设备组成了一个 L2 网络,L2 网络之间通过MAC 地址通信,同时这个 L2 网络也是一个广播域。同属于一个广播域的两个设备想要通信,一设备须得向网络中的所有设备发送请求信息,只有对应 MAC 地址的设备才是真正的接收方,但实际上却是数据帧传遍整个网络,所有设备都会收到,且直接丢弃。如此一来,将造成一系列不好的后果:网络整体带宽被占用、潜在的信息安全风险、占用 CPU 资源……因此,VLAN 应运而生!
Vlan(Virtual Local Area Network)即虚拟局域网,是一个将物理局域网在逻辑上划分成多个广播域技术。通过在交换机上配置 Vlan,可以实现在同一 Vlan 用户可以进行二层互访,在不同 Vlan 间的用户被二层隔离,这样既能够隔离广播域,又可以提升网络安全性。

VLAN 究竟能够解决什么问题?
- 限制广播域。广播域被限制在一个局域网内,节省了带宽,提高了网络处理能力。
- 增强局域网的安全性。不同局域网内的报文在传输时是相互隔离的,即一个 VLAN 内的用户不能和其它 VLAN 内的用户直接通信,如果不同 VLAN 要进行通信,则需要通过路由器或三层交换机等三层设备。
- 灵活构建虚拟工作组。用局域网可以划分不同的用户到不同的工作组,同一工作组的用户也不必局限于某一固定的物理范围,网络构建和维护更方便灵活。
不过 VLAN 也并非没有缺点。
1、随着虚拟化技术的发展,一台物理服务器往往承载了多台虚拟机,公有云或其它大
型虚拟化云数据中心动辄需容纳上万甚至更多租户,VLAN 技术最多支持 4000 多个
VLAN,逐渐无法满足需求。
2、公有云提供商的业务要求将实体网络租借给多个不同的用户,这些用户对于网络的
要求有所不同,而不同用户租借的网络有很大的可能会出现 IP 地址、MAC 地址的重
叠。传统的 VLAN 并没有涉及这个问题,因此需要一种新的技术来保证在多个租户网
络中存在地址重叠的情况下依旧能有效通信的技术。
3、虚拟化技术使得单台主机可以虚拟化出多台虚拟机同时运行,而每台虚拟机都会有
其唯一的 MAC 地址。这样,为了保证集群中所有虚机可以正常通信,交换机必须保存
每台虚机的 MAC 地址,这样就导致了交换机中的 MAC 表异常庞大,从而影响交换机
的转发性能。
vxlan
VXLAN 是另一种网络虚拟化技术,有点类似于 VLAN,但功能更强大。在传统的 VLAN 网络中,共享同一底层 L2 网段的 VLAN 不能超过 4096 个。只有 12 比特用于对 Ethernet Frame 格式中的 VLAN ID 字段进行编码。VXLAN 协议定义了 8 个字节的 VXLAN Header,引入了类似 VLAN ID 的网络标识,称为 VNI(VXLAN Network ID),由 24 比特组成,这样总共是 1600 多万个,从而满足了大规模不同租户之间的标识、隔离需求。
VXLAN 是基于 L3 网络构建的虚拟 L2 网络,是一种 Overlay 网络。VXLAN 不关心底层物理网络拓扑,它将 Ethernet Frame 封装在 UDP 包中,只要它能承载 UDP 数据包,就可以在远端网段之间提供以太网 L2 连接。

每个 VXLAN 节点上的出站 L2 Ethernet Frame 都会被捕获,然后封装成 UDP 数据包,并通过 L3 网络发送到目标 VXLAN 节点。当 L2 Ethernet Frame 到达 VXLAN 节点时,就从 UDP 数据包中提取(解封装),并注入目标设备的网络接口。这种技术称为隧道。因此,VXLAN 节点会创建一个虚拟 L2 网段,从而创建一个 L2 广播域。

MacVLan
MACVLAN 允许对同一个网卡设置多个 IP 地址,还允许对同一张网卡上设置多个 MAC 地址,这也是 MACVLAN 名字的由来。原本 MAC 地址是网卡接口的“身份证”,应该是严格的一对一关系,而 MACVLAN 打破这层关系,方法是在物理设备之上、网络栈之下生成多个虚拟的 Device,每个 Device 都有一个 MAC 地址,新增 Device 的操作本质上相当于在系统内核中注册了一个收发特定数据包的回调函数,每个回调函数都能对一个 MAC 地址的数据包进行响应,当物理设备收到数据包时,会先根据 MAC 地址进行一次判断,确定交给哪个 Device 来处理。

IPVLan
Ipvlan 与 macvlan 非常相似,但又存在显著不同。Ipvlan 的子接口上并不拥有独立的 MAC 地址。所有共享父接口 MAC 地址的子接口拥有各自独立的 IP。

共享 MAC 地址会影响 DHCP 相关的操作。如果虚拟机、容器需通过 DHCP 获取网络配置,请确保它们在 DHCP 请求中使用各自独立的 ClientID;DHCP 服务器会根据请求中的 ClientID 而非 MAC 地址来分配 IP 地址。某些设备不支持分配多个 ip 地址所以 IPVlan 也没有实际大规模推广。
docker 网络分类
docker 常见的网络的分类如下,其中 bridge 网络、host 网络、container 网络、none 网络、overlay 网络、macvlan 网络、ipvlan 网络。其中 overlay 网络往往配合 swarm 和 k8s 来使用。
bridge 网络
bridge 驱动会在 Docker 管理的主机上创建一个 Linux 网桥。默认情况下,网桥上的容器可以相互通信。也可以通过 bridge 驱动程序配置,实现对外部容器的访问。桥接网络如下:

创建命令如下:
docker network create -d bridge bridgenet1
host 网络
如果启动容器的时候使用 host 模式,那么这个容器将不会获得一个独立的 Network Namespace,而是和宿主机共用一个 Network Namespace。容器将不会虚拟出自己的网卡,配置自己的 IP 等,而是使用宿主机的 IP 和端口。但是,容器的其他方面,如文件系统、进程列表等还是和宿主机隔离的。host 网络结构如下:

host 网络创建命令如下
docker run --name <container name> --network=host <image file>
container 网络
这个模式指定新创建的容器和引进存在的一个容器共享一个 network namespace ,而不是和宿主机共享。新创建的容器不会创建自己的网卡,配置自己的 ip,而是和一个指定的容器共享 ip,端口等,两个容器除了网络方面,其他的如文件系统、进程列表等还是隔离的。两个容器的进程可以通过 lo 网卡设备通信。容器网络原理如下:

容器网络创建命令参考如下:
docker run --name netcontainer2 --network container:netcontainer1 <image file>
none 网络
Docker 容器拥有自己的 Network Namespace,但是,并不为 Docker 容器进行任何网络配置。也就是说,这个 Docker 容器没有网卡、IP、路由等信息。需要我们自己为 Docker 容器添加网卡、配置 IP 等。
docker run --name <container name> --network none <image file>
overlay 网络
Overlay 驱动创建一个支持多主机网络的覆盖网络。在不改变现有网络基础设施的前提下,通过某种约定通信协议,把二层报文封装在 IP 报文之上的新的数据格式。Overlay 网络实际上是目前最主流的容器跨节点数据传输和路由方案,底层原理为 VXLAN。
Overlay 网络将多个 Docker 守护进程连接在一起,允许不同机器上相互通讯,同时支持对消息进行加密,实现跨主机的 docker 容器之间的通信,Overlay 网络将多个 Docker 守护进程连接在一起,使 swarm 服务能够相互通信。这种策略消除了在这些容器之间进行操作系统级路由的需要。下图是个典型的 overlay 网络:

overlay 网络的创建命令如下
docker network create -d overlay ovnet1
macvlan 网络
为每个容器的虚拟网络接口分配一个 MAC 地址,使其看起来是直接连接到物理网络的物理网络接口。需要在 Docker 主机上指定一个物理接口用于 macvlan 以及子网和网关 macvlan。您甚至可以 macvlan 使用不同的物理网络接口隔离您的网络。
macvlan 典型的拓扑如下:

macvlan 的创建命令如下
docker network create -d macvlan --subnet=172.16.10.0/24 --gateway=172.16.10.1 -o parent=eth0 mac1
ipvlan 网络
ipvlan 和 overlay 都可以实现不同主机上的容器之间的通讯,但是 ipvlan 是所有容器都在一个网段,相当于在一个 vlan 里面,然后可以通过不同的子接口对应不同网段,实现不同容器之间的通讯。而 overlay 可以实现不同网段之间的通讯。ipvlan 的 l2 网络示例如下:

ipvlan 的创建命令参考如下:
docker network create -d ipvlan --subnet=192.168.1.0/24 --gateway=192.168.1.1 -o ipvlan_mode=l2 -o parent=eth0 pub_net