操作系统、虚拟机、容器网络
操作系统、虚拟机、容器网络
虚拟机的网络通信原理
引言
从服务器集群到单台服务器(host),从主机到虚拟机(vm),从虚拟机到容器组(pod),从 容器组到单个容器(docker),从容器到多进程,从进程到多线程,资源(主要指计算、存储和网络)的划分粒度越来越细,这使得资源能做到相互隔离,资源的配置也更加灵活。然而,也随之带来了一系列的技术问题:比如,同宿主上的 vm 是如何通信的?跨 host 间的 vm 是如何通信的?vm 和 host 是如何通信的?进程间、线程间又是如何通信、协作的?等等。今天,我们就来探究一下 linux 系统中虚拟机的网络通信原理。
一般的技术文章或者书上将 vm 的网络连接方式分为三种:桥接(bridged)、NAT模式和 host-only 模式。然而,这种分类方法并不友好。首先,单从名称看,你还是不知道具体的网络连接方式。其次,NAT 模式和 host-only 模式有区别也有联系,容易混淆。所以,这里我们将 linux 系统中 vm 的网络连接方式分成两大类,分别是物理网卡模式和虚拟网卡模式。
物理网卡模式
物理网卡模式又分为非 NAT 方式和 NAT 方式。
- 非 NAT 方式
上图中,主机通过 VMware 虚拟出了 3 台虚拟机,3 台虚拟机直接和虚拟交换机相连,而虚拟交换机则与主机的物理网卡相连。想要理解这种方式则需要明确以下三点:
- 虚拟机1、2、3 通过虚拟交换机之间与主机网卡相连,也就是说不需要主机内核参与,只是借用了主机的物理网卡;
- “虚拟交换机”是属于 VMware 的虚拟设备,不属于虚拟机1,也不属于虚拟机2和虚拟机3;
- 每台虚拟机也有自己的虚拟网卡,才能与虚拟机交换机通信,图中并没有标出来。
- NAT 方式
我们知道,NAT(network adress treanslate,网络地址转换)能解决私有网络地址不足的问题,在 VM 的通信网络中同样可以利用这一技术。DHCP(Dynamic Host Configuration Protocol,动态主机配置协议)能够给不同的 VM 分配 IP 地址。上图中,vmnet0、NAT、DHCP 都是属于 VMware 的虚拟设备。
虚拟网卡模式
这里,我们介绍另一种 VM 的网络通信方式 - 虚拟网卡模式。VMware 在创建 VM 的时候,同时创建了一个叫“虚拟网卡”的虚拟设备。VMware 管辖下的所有 VM 通过和虚拟交换机相连,虚拟交换机和虚拟网卡连接。理解这种通信方式,需要明确以下一点:
- 这种网络对虚拟机来说很封闭,因为 VM 只能连接主机,如果想要和外界通信,需要主机具备路由/交换功能,只能通过在主机上安装路由或代理软件实现;
上文中我们介绍了 Linux 系统中 VM 的两种通信模式:“物理网卡模式”和“虚拟网卡模式”。其实,这两种通信模式还可以对应另外两个别名,分别是“硬直通”和“软交换”,大家喜欢前者还是后者呢?
Docker学习笔记:Docker 网络配置
图: Docker - container and lightweight virtualization
Dokcer 通过使用 Linux 桥接提供容器之间的通信,docker0 桥接接口的目的就是方便 Docker 管理。当 Docker daemon 启动时需要做以下操作:
- creates the docker0 bridge if not present
- # 如果 docker0 不存在则创建
- searches for an IP address range which doesn’t overlap with an existing route
- # 搜索一个与当前路由不冲突的 ip 段
- picks an IP in the selected range
- # 在确定的范围中选择 ip
- assigns this IP to the docker0 bridge
- # 绑定 ip 到 docker0
6.1 Docker 四种网络模式
四种网络模式摘自 Docker 网络详解及 pipework 源码解读与实践
docker run 创建 Docker 容器时,可以用 –net 选项指定容器的网络模式,Docker 有以下 4 种网络模式:
- host 模式,使用 –net=host 指定。
- container 模式,使用 –net=container:NAMEorID 指定。
- none 模式,使用 –net=none 指定。
- bridge 模式,使用 –net=bridge 指定,默认设置。
host 模式
如果启动容器的时候使用 host 模式,那么这个容器将不会获得一个独立的 Network Namespace,而是和宿主机共用一个 Network Namespace。容器将不会虚拟出自己的网卡,配置自己的 IP 等,而是使用宿主机的 IP 和端口。
例如,我们在 10.10.101.105/24 的机器上用 host 模式启动一个含有 web 应用的 Docker 容器,监听 tcp 80 端口。当我们在容器中执行任何类似 ifconfig 命令查看网络环境时,看到的都是宿主机上的信息。而外界访问容器中的应用,则直接使用 10.10.101.105:80 即可,不用任何 NAT 转换,就如直接跑在宿主机中一样。但是,容器的其他方面,如文件系统、进程列表等还是和宿主机隔离的。
container 模式
这个模式指定新创建的容器和已经存在的一个容器共享一个 Network Namespace,而不是和宿主机共享。新创建的容器不会创建自己的网卡,配置自己的 IP,而是和一个指定的容器共享 IP、端口范围等。同样,两个容器除了网络方面,其他的如文件系统、进程列表等还是隔离的。两个容器的进程可以通过 lo 网卡设备通信。
none模式
这个模式和前两个不同。在这种模式下,Docker 容器拥有自己的 Network Namespace,但是,并不为 Docker容器进行任何网络配置。也就是说,这个 Docker 容器没有网卡、IP、路由等信息。需要我们自己为 Docker 容器添加网卡、配置 IP 等。
bridge模式
图: The Container World | Part 2 Networking
bridge 模式是 Docker 默认的网络设置,此模式会为每一个容器分配 Network Namespace、设置 IP 等,并将一个主机上的 Docker 容器连接到一个虚拟网桥上。当 Docker server 启动时,会在主机上创建一个名为 docker0 的虚拟网桥,此主机上启动的 Docker 容器会连接到这个虚拟网桥上。虚拟网桥的工作方式和物理交换机类似,这样主机上的所有容器就通过交换机连在了一个二层网络中。接下来就要为容器分配 IP 了,Docker 会从 RFC1918 所定义的私有 IP 网段中,选择一个和宿主机不同的IP地址和子网分配给 docker0,连接到 docker0 的容器就从这个子网中选择一个未占用的 IP 使用。如一般 Docker 会使用 172.17.0.0/16 这个网段,并将 172.17.42.1/16 分配给 docker0 网桥(在主机上使用 ifconfig 命令是可以看到 docker0 的,可以认为它是网桥的管理接口,在宿主机上作为一块虚拟网卡使用)
6.2 列出当前主机网桥
1 |
|
6.3 查看当前 docker0 ip
1 |
|
在容器运行时,每个容器都会分配一个特定的虚拟机口并桥接到 docker0。每个容器都会配置同 docker0 ip 相同网段的专用 ip 地址,docker0 的 IP 地址被用于所有容器的默认网关。
6.4 运行一个容器
1 |
|
以上, docker0 扮演着 52f811c5d3d6 container 这个容器的虚拟接口 vethQCDY1N interface 桥接的角色。
使用特定范围的 IP
Docker 会尝试寻找没有被主机使用的 ip 段,尽管它适用于大多数情况下,但是它不是万能的,有时候我们还是需要对 ip 进一步规划。Docker 允许你管理 docker0 桥接或者通过-b选项自定义桥接网卡,需要安装bridge-utils软件包。
基本步骤如下:
- ensure Docker is stopped
- # 确保 docker 的进程是停止的
- create your own bridge (bridge0 for example)
- # 创建自定义网桥
- assign a specific IP to this bridge
- # 给网桥分配特定的 ip
- start Docker with the -b=bridge0 parameter
- # 以 -b 的方式指定网桥
1 |
|
参考文档: Network Configuration
6.5 不同主机间容器通信
不同容器之间的通信可以借助于 pipework 这个工具:
1 |
|
安装相应依赖软件
1 |
|
桥接网络
桥接网络可以参考 日常问题处理 Tips 关于桥接的配置说明,这里不再赘述。
1 |
|
可以删除 docker0,直接把 docker 的桥接指定为 br0。也可以保留使用默认的配置,这样单主机容器之间的通信可以通过 docker0,而跨主机不同容器之间通过 pipework 新建 docker 容器的网卡桥接到 br0,这样跨主机容器之间就可以通信了。
- ubuntu
1 |
|
- CentOS 7/RHEL 7
1 |
|
pipework
不同容器之间的通信可以借助于 pipework 这个工具给 docker 容器新建虚拟网卡并绑定 IP 桥接到 br0
1 |
|
如果删除了默认的 docker0 桥接,把 docker 默认桥接指定到了 br0,则最好在创建容器的时候加上–net=none,防止自动分配的 IP 在局域网中有冲突。
1 |
|
使用ip netns添加静态路由,避免创建容器使用–privileged=true选项造成一些不必要的安全问题:
1 |
|
在其它宿主机进行相应的配置,新建容器并使用 pipework 添加虚拟网卡桥接到 br0,测试通信情况即可。
另外,pipework 可以创建容器的 vlan 网络,这里不作过多的介绍了,官方文档已经写的很清楚了,可以查看以下两篇文章: