虚拟化网络
Network Namespace是linux内核提供的功能,是实现网络虚拟化的重要功能,它能创建多个隔离的网络空间,它们有独自网络栈信息。不管是虚拟机还是容器,运行的时候仿佛自己都在独立的网络中。而且不同Network Namespace的资源相互不可见,彼此之间无法通信。
实例1
物理机有4块物理网卡,创建4个名称空间NS,而这些网卡设备是可以单独关联至某个单独的名称空间使用
这4个网卡分别对应唯一一个名称空间。各名称空间相互隔绝互不可见,因此一个设备对应一个名称空间。
- 可直接连接外网,因为跟物理网卡绑定
- 每个名字空间可以配置ip地址
//容器端网卡if19,ip
[root@node0 ~]# docker run -it --rm busybox
/ # ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever
18: eth0@if19: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue
link/ether 02:42:ac:11:00:02 brd ff:ff:ff:ff:ff:ff
inet 172.17.0.2/16 brd 172.17.255.255 scope global eth0
valid_lft forever preferred_lft forever
//真机端网卡if18,ip
[root@node0 ~]# ip a
...
19: vethb965cf0@if18: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master docker0 state UP group default
link/ether 5e:0c:5b:7f:a7:53 brd ff:ff:ff:ff:ff:ff link-netnsid 0
inet6 fe80::5c0c:5bff:fe7f:a753/64 scope link
valid_lft forever preferred_lft forever
//ping通
[root@node0 ~]# docker run -it --rm busybox
/ # ping baidu.com
PING baidu.com (220.181.38.148): 56 data bytes
64 bytes from 220.181.38.148: seq=0 ttl=127 time=46.925 ms
64 bytes from 220.181.38.148: seq=1 ttl=127 time=43.828 ms
64 bytes from 220.181.38.148: seq=2 ttl=127 time=45.866 ms
^C
--- baidu.com ping statistics ---
3 packets transmitted, 3 packets received, 0% packet loss
round-trip min/avg/max = 43.828/45.539/46.925 ms
实例2
但如果我们所拥有的名称空间数量超过物理网卡数量呢?此时我们可以使用虚拟网卡设备,用纯软件的方式来模拟一组设备来使用。
Linux内核级支持2种级别设备的模拟,一种是二层设备(交换机),一种是三层设备(路由器)。
二层设备模拟的网络接口设备是成对出现的
此时再创建一个名称空间,配置相同网段,这两个名称空间能相互通信
单节点容器间通信
同一个物理机上的两个容器想通信,我们的办法就是在这台主机上建立一个虚拟交换机,而后让两个容器各自用纯软件的方式创建一对虚拟网卡,一半在容器上,一半在虚拟交换机上,从而实现通信。如下图所示:
//拉2个容器
[root@node0 ~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
11b7dded48a2 busybox:latest "sh" 13 minutes ago Up 13 minutes pedantic_turing
5f614be4d2c7 busybox "sh" 24 minutes ago Up 24 minutes gallant_banach
//查看容器1的ip
[root@node0 ~]# docker run -it --rm busybox
/ # ip a
...
18: eth0@if19: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue
link/ether 02:42:ac:11:00:02 brd ff:ff:ff:ff:ff:ff
inet 172.17.0.2/16 brd 172.17.255.255 scope global eth0
valid_lft forever preferred_lft forever
//查看容器2的ip并ping,通了
[root@node0 ~]# docker run -it --rm busybox:latest
/ # ping 172.17.0.2
PING 172.17.0.2 (172.17.0.2): 56 data bytes
64 bytes from 172.17.0.2: seq=0 ttl=64 time=0.183 ms
64 bytes from 172.17.0.2: seq=1 ttl=64 time=0.209 ms
^C
--- 172.17.0.2 ping statistics ---
2 packets transmitted, 2 packets received, 0% packet loss
round-trip min/avg/max = 0.183/0.196/0.209 ms
/ # ip a
...
22: eth0@if23: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue
link/ether 02:42:ac:11:00:03 brd ff:ff:ff:ff:ff:ff
inet 172.17.0.3/16 brd 172.17.255.255 scope global eth0
valid_lft forever preferred_lft forever
同一台主机创建4个容器,2个虚拟交换机每两个容器连接一个交换机,如下图:
这时我们再添加一个容器利用linux内核功能充当路由器实现路由转发
不同节点容器间通信
要实现c1和c5的通信,用桥接容易产生广播风暴,因此尽量避免桥接方式通信
使用NAT技术。通过DNAT将容器的端口暴露到宿主机上,通过访问宿主机的端口来实现访问容器内部的目的,而在请求端我们需要做SNAT将数据包通过宿主机的真实网卡转发出去。
由于NAT转换需要两次,所以效率比较低
此时我们可以采用一种叫做Overlay Network(叠加网络)的技术来实现不同节点间容器的相互通信功能。
Overlay Network会将报文进行隧道转发,也就是在报文发出去之前要为其添加一个IP首部,也就是上图的1.1和1.2这部分,这里的1.1是源,1.2是目标,当宿主机2收到报文后解封装发现要找的目标容器是C2,于是把包转发给C2。