KVM 集成 OpenvSwitch 虚拟交换机

KVM(Kernel-based Virtual Machine)是Linux内核中的一种虚拟化技术,它允许在同一台主机上运行多个虚拟机。

在默认情况下,KVM使用基于Linux bridge的网络虚拟化解决方案。Linux bridge是一种内核模块,可将多个网络接口桥接在一起,从而实现虚拟机与物理网络之间的通信。然而,Linux bridge功能相对有限,难以满足复杂网络虚拟化场景的需求。

与之相比,Open vSwitch是一种生产级别的软件交换机,被广泛应用于云计算、软件定义网络等领域。它提供了更加丰富和灵活的网络虚拟化功能,例如VLAN交换、QoS、镜像等,可以轻松实现网络隔离、负载均衡等高级功能。

因此,将KVM从默认的Linux bridge切换到Open vSwitch,可以大幅提升网络虚拟化的性能和功能。在接下来的博客中,我会详细介绍如何完成这一切换,包括Open vSwitch的安装、配置虚拟交换机、集成KVM等步骤。

在这里插入图片描述
操作系统版本:Ubuntu 22.04 LTS

安装 KVM

检查您的 CPU 是否支持虚拟化,运行以下命令,输出大于0,说明KVM与系统兼容,可以安装。

egrep -c 'vmx|svm' /proc/cpuinfo

使用apt命令安装qemu-kvm及相关工具

apt update -y
apt install -y qemu-kvm libvirt-daemon-system virtinst libvirt-clients bridge-utils

安装openvSwitch

apt update -y
apt install -y openvswitch-switch

创建KVM网络

默认KVM已经基于Linux Bridge 创建了一个名为default的NAT网络。

root@node1:~# brctl show
bridge name     bridge id               STP enabled     interfaces
virbr0          8000.525400f7e041       yes            

root@node1:~# 
root@node1:~# virsh net-list 
 Name      State    Autostart   Persistent
--------------------------------------------
 default   active   yes         yes

由于创建虚拟机时可以自由选择使用哪个网络,这里我们为KVM创建一个新的网络即可,原来的网络可以保持不变,或者配置后删除。

创建ovs网桥

在定义基于 OVS 的 libvirt 网络之前,您需要在 OVS 中创建虚拟交换机。

root@node1:~# ovs-vsctl add-br ovsbr0

然后验证它是否正确创建:

root@node1:~# ovs-vsctl show
654f0d05-ff5e-4979-a3ac-5b82b5f237a2
    Bridge ovsbr0
        Port ovsbr0
            Interface ovsbr0
                type: internal
    ovs_version: "2.17.0"

现在你可以开始使用 libvirt 了。

定义 libvirt 网络

由于 libvirt 默认使用 Linux bridge,任何创建新网络的 virsh 子命令都会基于它创建一个网络,因此您需要创建一个包含基于 OVS 的网络定义的 XML 文件,并将其导入到库虚拟机。

生成一个随机UUID

root@node1:~# uuidgen 
c654bba4-224b-46a6-b9fb-99c71087cd05

创建ovs网络定义文件

cat >ovs-network.xml<<EOF
<network>
  <name>ovs</name>
  <uuid>c654bba4-224b-46a6-b9fb-99c71087cd05</uuid>
  <forward mode='bridge'/>
  <bridge name='ovsbr0'/>
  <virtualport type='openvswitch'/>
</network>
EOF

注意:可以使用 uuidgen 为网络生成新的通用唯一标识符 (UUID)。

然后在libvirt中导入网络:

virsh net-define ovs-network.xml

仅在 libvirt 中定义网络不足以使网络可用。您必须启动网络并启用开机自动启动:

virsh net-start ovs
virsh net-autostart ovs

查看新创建的网络

# virsh net-list
Name    State   Autostart   Persistent
--------------------------------------------
default active  yes         yes
ovs     active  yes         yes

创建虚拟机

此时ovs网络已经准备就绪,我们使用精简的 cirros 镜像来创建2个虚拟机连接到该ovs网桥,该镜像仅有20M左右,非常适合用作测试。

下载镜像

wget https://download.cirros-cloud.net/0.6.2/cirros-0.6.2-x86_64-disk.img

复制镜像到镜像模板目录

mkdir -p /var/lib/libvirt/images/templates/
cp cirros-0.6.2-x86_64-disk.img /var/lib/libvirt/images/templates/

创建镜像磁盘目录,并复制镜像

mkdir -p /var/lib/libvirt/images/{cirros01,cirros02}
cp /var/lib/libvirt/images/templates/cirros-0.6.2-x86_64-disk.img /var/lib/libvirt/images/cirros01/
cp /var/lib/libvirt/images/templates/cirros-0.6.2-x86_64-disk.img /var/lib/libvirt/images/cirros02/

创建镜像元数据文件:

cat >cirros.meta<<EOF
{
"instance-id": "10",
"local-hostname": "cirros"
}
EOF

cat >cirros.user<<EOF
#!/bin/sh
echo DATASOURCE_LIST="nocloud" > /etc/cirros-init/config
EOF

说明:通过DATASOURCE_LIST="nocloud"参数指定cirros镜像在非云环境运行,防止连接不存在的元数据服务器出现启动缓慢问题:

checking http://169.254.169.254/2009-04-04/instance-id
failed 1/20: up 5.14. request failed
failed 2/20: up 7.18. request failed
failed 3/20: up 9.19. request failed

运行第一个虚拟机

virt-install \
  --name cirros01 \
  --vcpus 1 \
  --memory 256 \
  --disk path=/var/lib/libvirt/images/cirros01/cirros-0.6.2-x86_64-disk.img \
  --os-variant cirros0.5.2 \
  --import \
  --autostart \
  --noautoconsole \
  --network network:ovs \
  --cloud-init user-data="/root/cirros.user",meta-data="/root/cirros.meta"

运行第二个虚拟机

virt-install \
  --name cirros02 \
  --vcpus 1 \
  --memory 256 \
  --disk path=/var/lib/libvirt/images/cirros02/cirros-0.6.2-x86_64-disk.img \
  --os-variant cirros0.5.2 \
  --import \
  --autostart \
  --noautoconsole \
  --network network:ovs \
  --cloud-init user-data="/root/cirros.user",meta-data="/root/cirros.meta"

说明:

  • --network:必选,指定新建虚拟机使用ovs网络
  • --cloud-init:可选,防止cirros虚拟机启动过慢

查看创建的虚拟机

root@node1:~# virsh list
 Id   Name       State
--------------------------
 5    cirros01   running
 6    cirros02   running

为cirros01虚拟机配置IP地址

root@node1:~# virsh console cirros01
Connected to domain 'cirros01'
Escape character is ^] (Ctrl + ])

login as 'cirros' user. default password: 'gocubsgo'. use 'sudo' for root.
cirros login: cirros
Password: 
$ 
$ sudo ip a add 10.0.0.10 dev eth0

为cirros02虚拟机配置IP地址

root@node1:~# virsh console cirros02
Connected to domain 'cirros02'
Escape character is ^] (Ctrl + ])

login as 'cirros' user. default password: 'gocubsgo'. use 'sudo' for root.
cirros login: cirros
Password: 
$ 
$ sudo ip a add 10.0.0.11 dev eth0

测试在cirros01虚拟机访问cirros02虚拟机

root@node1:~# virsh console cirros01
Connected to domain 'cirros01'
Escape character is ^] (Ctrl + ])

login as 'cirros' user. default password: 'gocubsgo'. use 'sudo' for root.
cirros login: cirros
Password: 
$ 
$ sudo ip a add 10.0.0.10 dev eth0
$ 
$ 
$ ping 10.0.0.11 -c 4
PING 10.0.0.11 (10.0.0.11) 56(84) bytes of data.
64 bytes from 10.0.0.11: icmp_seq=1 ttl=64 time=0.904 ms
64 bytes from 10.0.0.11: icmp_seq=2 ttl=64 time=0.729 ms
64 bytes from 10.0.0.11: icmp_seq=3 ttl=64 time=1.12 ms
64 bytes from 10.0.0.11: icmp_seq=4 ttl=64 time=0.847 ms

--- 10.0.0.11 ping statistics ---
4 packets transmitted, 4 received, 0% packet loss, time 3005ms
rtt min/avg/max/mdev = 0.729/0.900/1.122/0.142 ms
$ 

ovs连接外网

上面我们测试了将两台虚拟机连接到同一个openvSwitch 虚拟交换机,两台虚拟机能够直接在二层相互通信,下面介绍将物理网卡添加到ovs网桥,实现ovs网桥下的虚拟机访问外网。

最终网络如下图所示:
在这里插入图片描述

查看主机网卡默认配置

root@node1:~# cat /etc/netplan/00-installer-config.yaml
# This is the network config written by 'subiquity'
network:
  version: 2
  ethernets:
    ens33:
      dhcp4: false
      addresses:
        - 192.168.72.41/24
      nameservers:
        addresses:
          - 223.5.5.5
          - 223.6.6.6
      routes:
        - to: default
          via: 192.168.72.8
root@node1:~# 

修改主机网卡配置,将ens33主网卡IP迁移到网桥端口,并且将ens33网卡加入ovs网桥中

root@node1:~# cat /etc/netplan/00-installer-config.yaml
# This is the network config written by 'subiquity'
network:
  ethernets:
    ens33:
      dhcp4: false
      dhcp6: false
  bridges:
    ovsbr0:
      openvswitch: {}
      interfaces: [ ens33 ]
      dhcp4: false
      dhcp6: false
      addresses: [192.168.72.41/24]
      routes:
        - to: default
          via: 192.168.72.8
      nameservers:
        addresses: ["223.5.5.5","223.6.6.6"]
      parameters:
        stp: false
        forward-delay: 4
  version: 2

验证配置文件,并应用配置使配置生效(谨慎操作,可能有SSH连接中断风险)

root@node1:~# netplan try
root@node1:~# netplan apply

查看OVS网桥,ens33网口成功添加到ovs网桥

root@node1:~# ovs-vsctl show
e2084c87-149e-428e-a7bd-89c644a0a9ce
    Bridge ovsbr0
        fail_mode: standalone
        Port ens33
            Interface ens33
        Port ovsbr0
            Interface ovsbr0
                type: internal
        Port vnet1
            Interface vnet1
        Port vnet0
            Interface vnet0
    ovs_version: "2.17.9"

查看主机IP,已经配置到OVS网桥接口ovsbr0

root@node1:~# ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default 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
    inet6 ::1/128 scope host 
       valid_lft forever preferred_lft forever
2: ens33: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq master ovs-system state UP group default qlen 1000
    link/ether 00:50:56:aa:61:b5 brd ff:ff:ff:ff:ff:ff
    altname enp2s1
3: ovs-system: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN group default qlen 1000
    link/ether da:1e:a6:0a:ff:8e brd ff:ff:ff:ff:ff:ff
4: ovsbr0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UNKNOWN group default qlen 1000
    link/ether 00:50:56:aa:61:b5 brd ff:ff:ff:ff:ff:ff
    inet 192.168.72.41/24 brd 192.168.72.255 scope global ovsbr0
       valid_lft forever preferred_lft forever
    inet6 fe80::250:56ff:feaa:61b5/64 scope link 
       valid_lft forever preferred_lft forever
5: virbr0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN group default qlen 1000
    link/ether 52:54:00:f7:e0:41 brd ff:ff:ff:ff:ff:ff
    inet 192.168.122.1/24 brd 192.168.122.255 scope global virbr0
       valid_lft forever preferred_lft forever
6: vnet0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel master ovs-system state UNKNOWN group default qlen 1000
    link/ether fe:54:00:81:1d:ee brd ff:ff:ff:ff:ff:ff
    inet6 fe80::fc54:ff:fe81:1dee/64 scope link 
       valid_lft forever preferred_lft forever
7: vnet1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel master ovs-system state UNKNOWN group default qlen 1000
    link/ether 0e:a2:61:58:2c:1a brd ff:ff:ff:ff:ff:ff
    inet6 fe80::ca2:61ff:fe58:2c1a/64 scope link 
       valid_lft forever preferred_lft forever
root@node1:~# 

连接到虚拟机,查看虚拟机已经自动获取到外网IP地址(物理网络有提供DHCP服务,否则需要手动配置IP),并且能够正常与外网通信。

root@node1:~# virsh console cirros01
Connected to domain 'cirros01'
Escape character is ^] (Ctrl + ])

$ 
$ 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
    inet6 ::1/128 scope host 
       valid_lft forever preferred_lft forever
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast qlen 1000
    link/ether 52:54:00:c7:81:b6 brd ff:ff:ff:ff:ff:ff
    inet 192.168.72.149/24 brd 192.168.72.255 scope global dynamic noprefixroute eth0
       valid_lft 42878sec preferred_lft 37478sec
    inet6 fe80::5054:ff:fec7:81b6/64 scope link 
       valid_lft forever preferred_lft forever
$ 
$ ping www.baidu.com -c 4
PING 183.2.172.185 (183.2.172.185) 56(84) bytes of data.
64 bytes from 183.2.172.185 (183.2.172.185): icmp_seq=1 ttl=53 time=7.58 ms
64 bytes from 183.2.172.185 (183.2.172.185): icmp_seq=2 ttl=53 time=8.47 ms
64 bytes from 183.2.172.185 (183.2.172.185): icmp_seq=3 ttl=53 time=8.24 ms
64 bytes from 183.2.172.185 (183.2.172.185): icmp_seq=4 ttl=53 time=8.13 ms

--- 183.2.172.185 ping statistics ---
4 packets transmitted, 4 received, 0% packet loss, time 3005ms
rtt min/avg/max/mdev = 7.576/8.104/8.472/0.329 ms
$ 

参考:https://www.redhat.com/sysadmin/libvirt-open-vswitch

Logo

华为开发者空间,是为全球开发者打造的专属开发空间,汇聚了华为优质开发资源及工具,致力于让每一位开发者拥有一台云主机,基于华为根生态开发、创新。

更多推荐