网络虚拟设备

Linux Veth

Veth是成对出现的虚拟网络设备,发送到Veth一端的虚拟设备请求会从另一端的虚拟设备中发出。在容器虚拟化中,经常会使用Veth连接不同的网络namespace

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# 创建两个网络namespace
ip netns add ns1
ip netns add ns2

# 创建一对Veth
ip link add veth0 type veth peer name veth1

# 分别将两个Veth移到两个namespace中
ip link set veth0 netns ns1
ip link set veth1 netns ns2

# 去ns1的namespace中查看网络设备
ip netns exec ns1 ip link

# 输出
1: lo: <LOOPBACK> mtu 65536 qdisc noop state DOWN mode DEFAULT group default qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
4: veth0@if3: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000
link/ether 7a:d3:b3:5e:97:50 brd ff:ff:ff:ff:ff:ff link-netnsid 1

n1和n2的namespace中,除了loopback的设备以外就只看到了一个网络设备。当请求发出到这个虚拟网络设备时,都会从另一个网络的namespace中出来。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# 配置每个veth的网络地址和namespace路由
ip netns exec ns1 ifconfig veth0 172.18.0.2/24 up
ip netns exec ns2 ifconfig veth1 172.18.0.3/24 up
ip netns exec ns1 route add default dev veth0
ip netns exec ns2 route add default dev veth1

# 通过veth一端出去的包,另一端直接收到
ip netns exec ns1 ping -c 1 172.18.0.3

# 输出
PING 172.18.0.3 (172.18.0.3) 56(84) bytes of data.
64 bytes from 172.18.0.3: icmp_seq=1 ttl=64 time=0.051 ms

--- 172.18.0.3 ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 0.051/0.051/0.051/0.000 ms

Linux Bridge

Bridge虚拟设备是用来桥接网络设备,相当于交换机,可以连接不同的网络设备,让请求到达Bridge时,可以通过报文中的mac地址进行广播或转发。

1
2
3
4
5
6
7
8
9
10
11
# 创建veth设备并将一端移动到namespace
ip netns add ns1
ip link add veth0 type veth peer name veth1
ip link set veth1 netns ns1

# 创建网桥
brctl addbr br0

# 挂载网络设备
brctl addif br0 enp1s0
brctl addif br0 veth0

Linux路由表

路由表是Linux内核的一个模块,通过定义路由表决定在某个网络namespacee中包的流向,从而定义请求会到哪个网络设备上

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
# 启动虚拟网络设备,并设置它在net namespace中的ip地址
ip link set veth0 up
ip link set br0 up
ip netns exec ns1 ifconfig veth1 172.18.0.2/24 up

# 分别设置ns1网络空间的路由和宿主机上的路由
# default代表0.0.0.0/0,即在net namespace中所有流量都经过veth1的网络设备流程
ip netns exec ns1 route add default dev veth1

# 在宿主机上将172.18.0.0/24的网段请求路由到br0网络
route add -net 172.18.0.0/24 dev br0

# 查看宿主机IP地址
ifconfig enp1s0

# 从namespace中访问宿主机的地址
ip netns exec ns1 ping -c 1 192.168.122.220

# 输出
PING 192.168.122.220 (192.168.122.220) 56(84) bytes if data.
64 bytes from 192.168.122.220: icmp_seq=1 ttl=64 time=0.031 ms

--- 192.168.122.220 ping statistics ---
1 packets trasmitted, 1 receivedm 0% packet look, time 0ms
rtt min/avg/max/mdev = 0.031/0.031/0.000 ms

Linux iptables

iptables 是对linux内核的netfilter模块进行操作和展示的工具,用来管理包的流动和转发。

iptables定义了一套链式的处理结构,在网络包传输的各个阶段可以使用不同的策略对包进行加工、转发或丢弃。

在容器虚拟化中经常用到MASQUERADE和DNAT两种策略,用于容器和宿主机外部的通信。

MASQUERADE

MASQUERADE策略可以将请求包中的源地址转换成一个网络设备的地址

1
2
3
4
5
# 打开ip转发
sysctl -w net.ipv4.conf.all.forwarding=1

# 对namespace中发出的包添加网络地址转换
iptables -t nat -A POSTROUTING -s 172.18.0.0/24 -o enp1s0 -j MASQUERADE

在namespace中请求宿主机外部地址时,将namespace中的源地址转换为宿主机的地址作为源地址。

DNAT

DNAT策略也是做网络地址转换的,不过它更换的是目标地址,经常用于将内部网络地址端口映射到外部去。

1
2
# 将宿主机上的80端口请求发送到namespace的ip上
iptables -t nat -A PREROUTING -p tcp -m tcp --dport 80 -j DNAT --to-destination 172.18.0.2:80

这样就可以将80端口收到的包转发到172.18.0.2:80,从而实现外部应用调用。