网络模型

  • 四种网络模型
    1、隔离模型:虚拟机之间组建网络,该模式无法与宿主机通信,无法与其他网络通信,相当于虚拟机只是连接到一台交换机上。
    2、路由模型:相当于虚拟机连接到一台路由器上,由路由器(物理网卡),统一转发,但是不会改变源地址。
    3、NAT模型:在路由模式中,会出现虚拟机可以访问其他主机,但是其他主机的报文无法到达虚拟机,而NAT模式则将源地址转换为路由器(物理网卡)地址,这样其他主机也知道报文来自那个主机,在docker环境中经常被使用。
    4、桥接模型:在宿主机中创建一张虚拟网卡作为宿主机的网卡,而物理网卡则作为交换机。

隔离模型

隔离模型

如上图所示,Guest1和Guest2都是在宿主机上创建的虚拟机,虚拟机的网卡分为前半段和后半段,前半段位于虚拟机上,后半段在宿主机上,按照图中所示,前半段就是eth0,它是在虚拟机内部看到的网卡名字,而后半段就是vnet0和vnet1,它们是在宿主机上看到的网卡名字。实际上,在Guest1上所有发往eth0的数据就是直接发往vnet0,是由vnet0进行数据的传送处理。
在隔离模式下,宿主机创建一个虚拟交换机vSwitch,然后把vnet0和vnet1接入到该虚拟交换机,交换机也可以叫做bridge,因为vnet0和vnet1在一个网桥内,所以可以互相通信,而虚拟机的eth0是通过后半段进行数据传输,所以只要虚拟机的前半段ip在一个网段内,就可以互相通信,这就是隔离模式。

路由模型

路由模型

在隔离模型的基础上,将宿主机的一块虚拟网卡virnet0加入到虚拟网桥中,这样virnet0就可以和虚拟机通信,通过将虚拟机的默认网关设置为virnet0的IP地址,然后在宿主机中打开IP地址转发,使得虚拟机可以访问宿主机。不过此时虚拟机仅仅可以将报文发送到外部网络,因为外部网络没有路由到虚拟机中,所以外部网络无法将报文回传给虚拟机。

NAT模型

NAT模型

NAT模型其实就是SNAT的实现,路由中虚拟机能将报文发送给外部主机,但是外部主机因找不到通往虚拟机的路由因而无法回应请求。但是外部主机能同宿主机通信,所以在宿主机上添加一个NAT转发,从而在外部主机请求虚拟机时,将虚拟机的IP地址转换为宿主机上的某个地址,从而实现外部网络与虚拟机的通信,其实际上只是通过iptables的nat表的POSTROUTING链实现地址转换罢了。

桥接模型

桥接模型

在宿主机中创建一个桥设备,把宿主机的eth0放在桥上,这样Guest1上的eth0将报文发给vnet0,再直接发给宿主机上的eth0,将源地址改为宿主机上的eth0的地址。
当响应报文到达物理机上的eth0时如何判断此响应报文是发给虚拟机的还是物理机自己的?
物理机会先创建一个虚拟网卡,在物理机上打开混杂模式(无论mac地址是不是自己的都将接收响应报文),如果mac地址是自己的则转发给虚拟网卡,如果不是自己的则转发给vnet0,这就是桥接模型,因为物理机的网卡具有桥的功能所以叫做桥接模型。

网络应用

桥接模式

在宿主机上创建一个虚拟网卡br0,并将物理网卡enp8s0

1
2
[root@chobon ~]## cd /etc/sysconfig/network-scripts/
[root@chobon network-scripts]# cp ifcfg-etp8s0 ifcfg-br0

修改br0

1
2
3
4
5
6
7
8
9
[root@chobon network-scripts]# vim ifcfg-br0
DEVICE=br0
TYPE=Bridge
ONBOOT=yes
NM_CONTROLLED=yes
BOOTPROTO=static
IPADDR=192.168.124.101
NETMASK=255.255.255.0
GATEWAY=192.168.124.1

修改enp8s0

1
2
3
4
5
6
7
8
[root@chobon network-scripts]# vim ifcfg-etp8s0
DEVICE=etp8s0
TYPE=Ethernet
UUID=62a2f66a-754e-4c46-810c-fd23abff3d5a
ONBOOT=yes
BRIDGE=br0
NM_CONTROLLED=yes
BOOTPROTO=dhcp

重启网络服务

1
[root@chobon network-scripts]# service network restart

如果接网线,插网孔的,这样一般的桥接网络就弄好了。但是如果是宿主机采用wireless上网的这个就行不通。

我一开始奔着桥接模型去整,发现一直网络不通,后来查阅KVM文档,才知道wireless网卡大部分不支持桥接。

NAT模式

NAT模式就比较简单了,因为libvirt安装好的时候就创建好了virbr0这个网卡,就是拿来用NAT用的。

  • 查看虚拟网卡
1
2
3
[root@chobon ~]# brctl show
bridge name bridge id STP enabled interfaces
virbr0 8000.525400231cef yes virbr0-nic

如果没有default的话,或者需要扩展自己的虚拟网络,可以使用命令重新安装NAT。

virsh net-define /usr/share/libvirt/networks/default.xml
此命令定义一个虚拟网络,default.xml的内容:

1
2
3
4
5
6
7
8
9
10
<network>
<name>default</name>
<bridge name="virbr0" />
<forward/>
<ip address="192.168.122.1" netmask="255.255.255.0">
<dhcp>
<range start="192.168.122.2" end="192.168.122.254" />
</dhcp>
</ip>
</network>

也可以修改xml,创建自己的虚拟网络。

如果安装的时候没有指定网络,可以在安装后编辑虚拟机xml配置

1
2
3
4
5
6
7
8
9
[root@chobon ~]#vi /etc/libvirt/qemu/linux-xx.xml
...
<interface type='network'>
<mac address='52:54:00:39:c5:c0'/>
<source network='default'/>
<model type='virtio'/>
<address type='pci' domain='0x0000' bus='0x00' slot='0x03' function='0x0'/>
</interface>
...
  • 新安装的虚拟机在命令里设置网络参数--network network=default
1
2
3
4
5
6
7
8
9
10
11
virt-install \
--virt-type=kvm \
--name=vm1_centos7 \
--vcpus=2 \
--memory=2048 \
--location=/kvm/iso/CentOS-7-x86_64-Minimal-1908.iso \
--disk path=/kvm/vfs/vm1.qcow2,size=40,format=qcow2 \
--network network=default \
--graphics none \
--extra-args='console=ttyS0' \
--force

查看虚拟机mac地址

1
2
[[email protected] ~]# virsh dumpxml vm1_centos7 | grep 'mac address'
<mac address='52:54:00:39:c5:c0'/>

拷贝mac给新虚拟机配置ip,修改网卡dhcp,在dhcp里增加一条ip绑定mac地址,方便以后管理虚拟机

  • virsh net-edit default
1
2
3
4
5
6
7
8
9
10
11
12
13
<network>
<name>default</name>
<uuid>3d041b43-48e1-4583-8ed9-f588761b6b3d</uuid>
<forward mode='nat'/>
<bridge name='virbr0' stp='on' delay='0'/>
<mac address='52:54:00:23:1c:ef'/>
<ip address='192.168.122.1' netmask='255.255.255.0'>
<dhcp>
<range start='192.168.122.2' end='192.168.122.100'/>
<host mac='52:54:00:39:c5:c0' name='vm1' ip='192.168.122.101'/><!--新增一条-->
</dhcp>
</ip>
</network>

修改后重新加载和激活配置:

  • virsh net-destroy default
  • virsh net-start default

或者用virsh net-update default

1
2
3
4
virsh net-update default add ip-dhcp-host \
"<host mac='52:54:00:39:c5:c0' \
name='vm1' ip='192.168.122.101' />" \
--live --config

然后进入虚拟机里修改网卡eth0配置文件ifcfg-eth0设置成开机启动ONBOOT=yes

重启虚拟机网络服务就搞定了,不过这样还只能是虚拟机可以访问外部网络。

  • 通过端口转发,让外部网络可以访问虚拟机

宿主机Ip为192.168.124.21,虚拟机的Ip为192.168.122.101,通过宿主机10122端口访问虚拟机22端口

单个端口映射

iptables里添加下面命令,达到开机重启配置网络转发规则。

1
2
3
4
5
6
[[email protected] ~]# iptables -A INPUT -p tcp --dport 10122 -j ACCEPT
[[email protected] ~]# iptables -t nat -A PREROUTING -d 192.168.124.21 -p tcp -m tcp --dport 10122 -j DNAT --to-destination 192.168.122.101:22
[[email protected] ~]# iptables -t nat -A POSTROUTING -s 192.168.122.0/255.255.255.0 -d 192.168.122.101 -p tcp -m tcp --dport 22 -j SNAT --to-source 192.168.122.1

[[email protected] ~]# service iptables save #保存
[[email protected] ~]# service iptables restart #重启iptables

加了这三条发现虚拟机的端口还是没有映射出去,结果有了新的学习笔记Iptables学习笔记

端口没有映射成功的原因是KVM初始化的virbr0网卡在filter表里FORWARD链里创建的一条规则导致,默认virbr0网卡生成的转发规则不带NEW,而ssh发起的第一个包就是NEW,所以死活连不上。

1
2
3
4
5
[[email protected] ~]# iptables -nvL FORWARD
Chain FORWARD (policy ACCEPT 0 packets, 0 bytes)
pkts bytes target prot opt in out source destination
1 40 ACCEPT all -- virbr0 * 192.168.122.0/24 0.0.0.0/0
2 80 ACCEPT all -- * virbr0 0.0.0.0/0 192.168.122.0/24 ctstate RELATED,ESTABLISHED

第二条规则RELATED,ESTABLISHED少了一个NEW参数,修改保存即可

1
[[email protected] ~]# iptables -R FORWARD 2 -o virbr0 -d 192.168.122.0/24 -m conntrack --ctstate NEW,RELATED,ESTABLISHED -j ACCEPT

范围端口映射

范围端口映射规则

映射宿主机10001-19999到hostid为101的虚拟机1-9999端口,记得也要加上filter表转发规则里的NEW,不然ssh是没办法连接的

1
2
[[email protected] ~]# iptables -t nat -A PREROUTING -d 192.168.124.21 -p tcp -m tcp --dport 10001:19999 -j DNAT --to-destination 192.168.122.101:10001-19999
[[email protected] ~]# iptables -t nat -A POSTROUTING -s 192.168.122.0/255.255.255.0 -d 192.168.122.101 -p tcp -m tcp --dport 10001:19999 -j SNAT --to-source 192.168.122.1

遇到的问题

  • 网卡br0启动失败
    最开始的时候想在wireless上桥接网卡,br0死活启动不来,查看日志发现是NetworkManager管理网络导致br0起不来
    NetworkManager和配置的桥接网卡冲突导致问题

  • hdclient错误
    dhclient(3108) is already running – exiting
    hdclient -r && hdclient或者kill掉hdclient进程重新启动

常用指令

  • 显示节点上的虚拟网络
1
virsh net-list  --all
  • 显示一个虚拟网络的相关信息
1
virsh net-info net-name
  • 显示一个虚拟网络的XML描述
1
virsh net-dumpxml net-name
  • 从一个XML描述文件定义一个虚拟网络
1
virsh net-define network.xml  
  • 启动一个已经定义的虚拟网络:
1
virsh net-start net-name
  • 将一个虚拟网络设置为自动启动:
1
virsh net-autostart net-name  
  • 停用一个虚拟网络
1
virsh net-destroy net-name
  • 撤销一个虚拟网络
1
virsh net-undefine net-name