4. 容器虚拟化网络
基础网络
Linux 内核目前支持6种名称空间:
- UTS
- User
- Mount
- IPC
- PID
- Net
在现在的内核系统之上,默认有这6种名称空间只要有相关的用户空间中工具可支持都是可直接操作的。
所谓网络空间,主要用于实现协议栈、网络设备。比如物理机有四块网卡,而这些网卡设备可以单独关联到不同的网络空间来使用的。假如现在网络名称空间大于物理网卡数量怎么办?每个名称空间内部的进程也需要通过网络进行通信,在KVM 虚拟网络中可以使用虚拟网卡设备,用纯软件的方式来模拟一组设备来使用,Linux 内核级支持两种级别设备的模拟,一种是二层设备,一种是三层设备。二层设备是工作在链路层能封装物理报文实现在各网络设备之间实现报文转发的组件,而这个功能是完全能在Linux 之上利用内核当中对二层虚拟设备的支持创建虚拟网卡接口的,而且这种虚拟网卡接口很独特,每一个网卡接口都是成对出现的,可以模拟为一根网线的两头,其中一头插在主机之上,一头可以插在交换机上模拟,Linux内核原生支持二层网桥设备,就是用软件来构建一个交换机(bridge-utils)就模拟了一个主机连接到交换机。
从网络设备通信的物理设备到网卡都是用纯软件的方式来实现,能够在一台主机上用软件的方式实现,所以成为网络虚拟化技术中的一种简单实现。有一个著名的程序:OVS(OpenVSwitch)
在同一个物理机上的两个网络名称空间想要通信,就是在同一个主机上建立一个虚拟机交换机,让两个容器各自用纯软件的方式建一对虚拟网卡,一半接入到容器,另一半接入到虚拟交换机。
在KVM使用中,最简单的网络方式就是桥接,但是在大规模的网络环境中,使用桥接会造成网络风暴。如果不桥接又能与外部通信应该使用nat技术,nat网络。
如上图, C1 与 C2 通信, C1将网关指向S1地址,C1和S1在同一网络地址,C1连接到虚拟机交换机S1上,S1配置有独立的网络地址,在主机H1中打开核心转发功能。在数据包离开H1之前将源IP改成物理主机的IP地址,这里就是做SNAT 规则,送达H2的物理网卡,H2同时也打开核心转发功能,就能将数据包送至C2,反之亦然。这里的通信是经由两次转换。这种方式好处在于网络易于管理,坏处在于效率很低。解决这种效率低下的方案就是使用 叠加网络:Overlay Network
docker 网络
Four network container archetypes
- Closed container: 封闭式容器,只有lo接口
- Bridged container:nat桥接式容器,通过容器接口连接到docker0上,默认172.17.0.0/16
- Joined container:联盟式容器,让两个容器有一分部名称空间是隔离的:文件系统、用户、PID隔离,但是 UTS、NET和IPC是同享同一组,所以两个容器使用同一组网络设备,lo 可通过lo通信。
- Open container:开放式容器,开放的网卡是物理网络接口,和物理机同享同一组。
如果在使用 docker 时,没有指定则采用默认的 nat 桥接网络模式。
[root@docker ~]#docker network ls
NETWORK ID NAME DRIVER SCOPE
6382b35955e0 bridge bridge local
337e74124039 host host local
9b426bb867c7 none null local
=== 查看网络详情 ===
[root@docker ~]#docker network inspect bridge
[root@docker ~]#ifconfig docker0
docker0: flags=4099<UP,BROADCAST,MULTICAST> mtu 1500
inet 172.17.0.1 netmask 255.255.0.0 broadcast 172.17.255.255
inet6 fe80::42:78ff:fee0:86af prefixlen 64 scopeid 0x20<link>
ether 02:42:78:e0:86:af txqueuelen 0 (Ethernet)
RX packets 28 bytes 3473 (3.3 KiB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 37 bytes 2819 (2.7 KiB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
手动操作网络名称空间
可参考:https://www.cnblogs.com/hukey/p/6569132.html
这里举一个简单的示例:
===创建网络名称空间===
[root@localhost ~]#ip netns add r1
[root@localhost ~]#ip netns add r2
[root@localhost ~]#ip netns ls
r2
r1
===创建一对网卡===
[root@localhost ~]#ip link add name veth1.1 type veth peer name veth1.2
===将网卡设备挪到名称空间===
[root@localhost ~]#ip link set veth1.1 netns r1
[root@localhost ~]#ip link set veth1.2 netns r2
===修改网卡名===
[root@localhost ~]#ip netns exec r1 ip link set veth1.1 name eth0
[root@localhost ~]#ip netns exec r2 ip link set veth1.2 name eth0
===为网卡添加IP地址===
[root@localhost ~]#ip netns exec r1 ifconfig eth0 10.0.0.2/24 up
[root@localhost ~]#ip netns exec r2 ifconfig eth0 10.0.0.3/24 up
===测试网络===
[root@localhost ~]#ip netns exec r1 ping 10.0.0.3
PING 10.0.0.3 (10.0.0.3) 56(84) bytes of data.
64 bytes from 10.0.0.3: icmp_seq=1 ttl=64 time=0.190 ms
64 bytes from 10.0.0.3: icmp_seq=2 ttl=64 time=0.069 ms
Closed container
使用 --network none
创建封闭式容器
[root@docker ~]#docker run --name t1 -it --network none --rm busybox:latest
/ # ifconfig
lo Link encap:Local Loopback
inet addr:127.0.0.1 Mask:255.0.0.0
UP LOOPBACK RUNNING MTU:65536 Metric:1
RX packets:0 errors:0 dropped:0 overruns:0 frame:0
TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:0 (0.0 B) TX bytes:0 (0.0 B)
Bridged container
docker 默认网络模型采用 nat 桥
[root@docker ~]#docker run --name t1 -it --rm busybox:latest
/ # ifconfig
eth0 Link encap:Ethernet HWaddr 02:42:AC:11:00:02
inet addr:172.17.0.2 Bcast:172.17.255.255 Mask:255.255.0.0
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
RX packets:5 errors:0 dropped:0 overruns:0 frame:0
TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:0
RX bytes:426 (426.0 B) TX bytes:0 (0.0 B)
lo Link encap:Local Loopback
inet addr:127.0.0.1 Mask:255.0.0.0
UP LOOPBACK RUNNING MTU:65536 Metric:1
RX packets:0 errors:0 dropped:0 overruns:0 frame:0
TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:0 (0.0 B) TX bytes:0 (0.0 B)
Joined container
联盟式容器是指使用某个已存在容器的网络接口的容器,接口被联盟内的各容器共享使用;因此,联盟式容器彼此间完全隔离,例如:
联盟式容器彼此间虽然共享同一个网络名称空间,但其他名称空间如 User、Mount等还是隔离的
联盟式容器彼此间存在端口冲突的可能性,因此,通常只会在多个容器上的程序需要程序loopback接口相互通信、或对某已存的容器的网络属性进行监控时才使用此种模式的网络模型。
示例:
【启动第一个容器】
[root@docker ~]#docker run --name b1 -it --rm busybox
/ # echo 'hello world.' > /tmp/index.html
/ # httpd -h /tmp/
/ # netstat -ntplu
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name
tcp 0 0 :::80 :::* LISTEN 10/httpd
【启动第二个容器】
[root@docker ~]#docker run --name b2 --network container:b1 -it --rm busybox
/ # netstat -ntplu
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name
tcp 0 0 :::80 :::* LISTEN -
/ # wget -O - -q http://localhost:80
hello world.
Open container
使用开放式容器,容器和物理机使用同一网络名称空间。
[root@docker ~]#docker run --name b1 --network host -it --rm busybox:latest
暴露容器中的服务
注意:如果一个容器中需要暴露多个端口,-p 可以使用多次。
示例:
【-p <containerPort>】
[root@docker ~]#docker run --name b1 --rm -d -p 80 hukey/httpd:v0.2
[root@docker ~]#docker port b1
80/tcp -> 0.0.0.0:32769
[root@docker ~]#curl http://192.168.118.44:32769
<h1>busybox httpd server.</h1>
【-p <hostPort:containerPort>】
[root@docker ~]#docker run --name b1 --rm -d -p 80:80 hukey/httpd:v0.2
4b0fe96b26428661e423b85f20795a9447315034e0d332bd877c45f0bd9c435d
[root@docker ~]#docker port b1
80/tcp -> 0.0.0.0:80
[root@docker ~]#curl http://192.168.118.44/
<h1>busybox httpd server.</h1>
【-p <ip>::<containerPort>】
[root@docker ~]#docker run --name b1 --rm -d -p 192.168.118.44::80 hukey/httpd:v0.2
bb357aed7163c1131d0461f7a31dbd9ef1d4f85ab4c56bc24b4df291c7106bb1
[root@docker ~]#docker port b1
80/tcp -> 192.168.118.44:32768
[root@docker ~]#curl 192.168.118.44:32768
<h1>busybox httpd server.</h1>
【-p <ip>:<hostPort>:<containerPort>】
[root@docker ~]#docker run --name b1 --rm -d -p 192.168.118.44:80:80 hukey/httpd:v0.2
49cb13e4f8e646ba23f29535d7995c5d6a4ce9a32cf45a7e2ae9c6df6083bd1b
[root@docker ~]#docker port b1
80/tcp -> 192.168.118.44:80
[root@docker ~]#curl 192.168.118.44:80
<h1>busybox httpd server.</h1>
修改docker默认网络
{
"registry-mirrors": ["http://hub-mirror.c.163.com"],
"bip": "10.0.0.1/16" # 重新定义网络地址
}
定义完成后,重新启动docker服务。
创建docker网络
docker network create -d bridge --subnet "172.26.0.0/16" --gateway "172.26.0.1" mybr0
# 创建容器并使用新建的 mybr0
[root@docker ~]#docker run --name t1 -it --net mybr0 busybox:latest
/ # ifconfig
eth0 Link encap:Ethernet HWaddr 02:42:AC:1A:00:02
inet addr:172.26.0.2 Bcast:172.26.255.255 Mask:255.255.0.0