在Ubuntu 20.04 Headless Server中安装和配置KVM

时间:2020-03-21 11:45:14  来源:igfitidea点击:

KVM是基于内核的虚拟机的缩写,是FreeBSD和Linux内核模块,它允许内核充当管理程序。
从内核版本2.6.20开始,KVM合并到Linux内核主线中。
使用KVM,我们可以轻松地在Linux机器上设置虚拟化环境,并托管各种来宾操作系统,包括Linux,Windows,BSD,Mac OS和许多其他操作系统。
在本教程中,我们将研究如何在Ubuntu 20.04无键鼠显示器服务器中安装和配置KVM。
我们还将看到如何使用Virsh命令行实用程序创建和管理KVM来宾计算机。

准备工作

在安装KVM之前,首先要确保系统的处理器支持硬件虚拟化。

如果系统支持硬件虚拟化,请继续以下步骤。

在Ubuntu 20.04 Headless Server中安装和配置KVM

就本教程而言,我将使用以下系统。

KVM虚拟服务器:

  • 操作系统– Ubuntu 20.04 LTS最低服务器(无GUI)
  • IP地址:192.168.225.52/24

远程客户端:

  • 操作系统– Ubuntu 20.04 GNOME Desktop

首先,让我们在Ubuntu服务器中安装KVM。

在Ubuntu 20.04 LTS中安装KVM

使用以下命令安装Kvm和所有必需的依赖项,以在Ubuntu 20.04 LTS服务器上设置虚拟化环境:

$sudo apt install qemu qemu-kvm libvirt-clients libvirt-daemon-system virtinst bridge-utils

其中

  • qemu-通用机器仿真器和虚拟器,
  • qemu-kvm-支持KVM的QEMU元软件包(即,xE硬件上的QEMU完全虚拟化),
  • libvirt-clients-libvirt库的程序,
  • libvirt-daemon-system-Libvirt守护程序配置文件,
  • virtinst-创建和克隆虚拟机的程序,
  • bridge-utils-用于配置Linux以太网桥的实用程序。

安装KVM后,启动libvertd服务(如果尚未启动):

$sudo systemctl enable libvirtd
$sudo systemctl start libvirtd

使用以下命令检查libvirtd服务的状态:

$systemctl status libvirtd

输出示例:

● libvirtd.service - Virtualization daemon
     Loaded: loaded (/lib/systemd/system/libvirtd.service; enabled; vendor preset: enabled)
     Active: active (running) since Sat 2017-07-04 08:13:41 UTC; 7min ago
TriggeredBy: ● libvirtd-ro.socket
             ● libvirtd-admin.socket
             ● libvirtd.socket
       Docs: man:libvirtd(8)
             https://libvirt.org
   Main PID: 4492 (libvirtd)
      Tasks: 19 (limit: 32768)
     Memory: 12.9M
     CGroup: /system.slice/libvirtd.service
             ├─4492 /usr/sbin/libvirtd
             ├─4641 /usr/sbin/dnsmasq --conf-file=/var/lib/libvirt/dnsmasq/default.conf --l>
             └─4642 /usr/sbin/dnsmasq --conf-file=/var/lib/libvirt/dnsmasq/default.conf --l>
May 04 08:13:42 ubuntuserver dnsmasq[4641]: compile time options: IPv6 GNU-getopt DBus i18n>
May 04 08:13:42 ubuntuserver dnsmasq-dhcp[4641]: DHCP, IP range 192.168.122.2 -- 192.168.12>
May 04 08:13:42 ubuntuserver dnsmasq-dhcp[4641]: DHCP, sockets bound exclusively to interfa>
May 04 08:13:42 ubuntuserver dnsmasq[4641]: reading /etc/resolv.conf
May 04 08:13:42 ubuntuserver dnsmasq[4641]: using nameserver 127.0.0.53#53
May 04 08:13:42 ubuntuserver dnsmasq[4641]: read /etc/hosts - 7 addresses
May 04 08:13:42 ubuntuserver dnsmasq[4641]: read /var/lib/libvirt/dnsmasq/default.addnhosts>
May 04 08:13:42 ubuntuserver dnsmasq-dhcp[4641]: read /var/lib/libvirt/dnsmasq/default.host>
May 04 08:13:42 ubuntuserver dnsmasq[4641]: reading /etc/resolv.conf
May 04 08:13:42 ubuntuserver dnsmasq[4641]: using nameserver 127.0.0.53#53

好吧,已启用并启动libvertd服务!现在让我们完成其余的配置。

使用KVM设置网桥网络

桥接网络与其他VM共享主机的真实网络接口,以连接到外部网络。
因此,每个VM可以直接绑定到任何可用的IPv4或者IPv6地址,就像物理计算机一样。

默认情况下,KVM会设置一个专用虚拟网桥,以便所有VM都可以在主机内相互通信。
它提供自己的子网和DHCP以配置来宾网络,并使用NAT访问主机网络。

使用“ ip”命令查看KVM默认虚拟接口的IP地址:

$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: enp0s3: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000
    link/ether 08:00:27:8a:52:94 brd ff:ff:ff:ff:ff:ff
    inet 192.168.225.52/24 brd 192.168.225.255 scope global dynamic enp0s3
       valid_lft 39559sec preferred_lft 39559sec
    inet6 2409:4072:6c0f:431d:a00:27ff:fe8a:5294/64 scope global mngtmpaddr noprefixroute 
       valid_lft forever preferred_lft forever
    inet6 fe80::a00:27ff:fe8a:5294/64 scope link 
       valid_lft forever preferred_lft forever
3: enp0s8: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000
    link/ether 08:00:27:10:7c:c1 brd ff:ff:ff:ff:ff:ff
    inet 192.168.225.60/24 brd 192.168.225.255 scope global dynamic enp0s8
       valid_lft 39559sec preferred_lft 39559sec
    inet6 2409:4072:6c0f:431d:a00:27ff:fe10:7cc1/64 scope global mngtmpaddr noprefixroute 
       valid_lft forever preferred_lft forever
    inet6 fe80::a00:27ff:fe10:7cc1/64 scope link 
       valid_lft forever preferred_lft forever
4: enp0s9: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000
    link/ether 08:00:27:5d:61:28 brd ff:ff:ff:ff:ff:ff
    inet 192.168.225.51/24 brd 192.168.225.255 scope global dynamic enp0s9
       valid_lft 39559sec preferred_lft 39559sec
    inet6 2409:4072:6c0f:431d:a00:27ff:fe5d:6128/64 scope global mngtmpaddr noprefixroute 
       valid_lft forever preferred_lft forever
    inet6 fe80::a00:27ff:fe5d:6128/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:f1:98:9e 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: virbr0-nic: <BROADCAST,MULTICAST> mtu 1500 qdisc fq_codel master virbr0 state DOWN group default qlen 1000
    link/ether 52:54:00:f1:98:9e brd ff:ff:ff:ff:ff:ff

如我们所见,KVM默认网络virbr0使用192.168.122.1/24 IP地址。
所有VM都将使用192.168.122.0/24 IP范围内的IP地址,并且主机操作系统将可访问192.168.122.1.
我们应该能够从来宾OS内SSH进入主机OS(位于192.168.122.1),并使用scp来回复制文件。

如果仅从主机本身访问内部的VM,那就可以了。
但是,我们无法从网络中的其他远程系统访问VM。
因为他们使用不同的IP范围,例如:在我的情况下为:192.168.225.0/24.
为了从其他远程主机访问VM,我们必须设置一个在主机网络上运行并使用主机网络上任何外部DHCP服务器的公共网桥。
用外行术语来说,我们将使所有VM都使用主机系统使用的相同IP系列。

在建立公共桥接网络之前,出于性能和安全原因,我们应该禁用Netfilter。

默认情况下,当前在网桥上启用Netfilter。

要禁用netfilter,请创建一个名为/etc/sysctl.d/bridge.conf的文件:

$sudo vi /etc/sysctl.d/bridge.conf

添加以下行:

net.bridge.bridge-nf-call-ip6tables=0
net.bridge.bridge-nf-call-iptables=0
net.bridge.bridge-nf-call-arptables=0

保存并关闭文件。

然后创建另一个名为/etc/udev/rules.d/99-bridge.rules的文件:

$sudo vi /etc/udev/rules.d/99-bridge.rules

添加以下行:

ACTION=="add", SUBSYSTEM=="module", KERNEL=="br_netfilter", RUN+="/sbin/sysctl -p /etc/sysctl.d/bridge.conf"

这将设置必要的标志,以在系统启动的适当位置禁用网桥上的netfilter。
保存并关闭文件。
重新引导系统以使这些更改生效。

接下来,我们应该禁用KVM为其本身安装的默认网络。

使用“ ip link”命令查找KVM默认网络接口的名称:

$ip link

输出示例:

1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN mode DEFAULT group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
2: enp0s3: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP mode DEFAULT group default qlen 1000
    link/ether 08:00:27:8a:52:94 brd ff:ff:ff:ff:ff:ff
3: enp0s8: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP mode DEFAULT group default qlen 1000
    link/ether 08:00:27:10:7c:c1 brd ff:ff:ff:ff:ff:ff
4: enp0s9: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP mode DEFAULT group default qlen 1000
    link/ether 08:00:27:5d:61:28 brd ff:ff:ff:ff:ff:ff
5: virbr0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN mode DEFAULT group default qlen 1000
    link/ether 52:54:00:1f:a2:e7 brd ff:ff:ff:ff:ff:ff
6: virbr0-nic: <BROADCAST,MULTICAST> mtu 1500 qdisc fq_codel master virbr0 state DOWN mode DEFAULT group default qlen 1000
    link/ether 52:54:00:1f:a2:e7 brd ff:ff:ff:ff:ff:ff

如我们在上面的输出中看到的,条目“ virbr0”和“ virbr0-nic”是KVM网络。

让我们使用以下命令删除默认的KVM网络:

$virsh net-destroy default

输出示例:

Network default destroyed

使用以下命令取消定义默认网络:

$virsh net-undefine default

输出示例:

Network default has been undefined

如果以上命令由于某种原因无法使用,则可以使用以下命令禁用和取消定义KVM默认网络:

$sudo ip link delete virbr0 type bridge
$sudo ip link delete virbr0-nic

现在,再次运行“ ip link”以验证virbr0和virbr0-nic接口是否被实际删除:

$ip link
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN mode DEFAULT group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
2: enp0s3: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP mode DEFAULT group default qlen 1000
    link/ether 08:00:27:8a:52:94 brd ff:ff:ff:ff:ff:ff
3: enp0s8: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP mode DEFAULT group default qlen 1000
    link/ether 08:00:27:10:7c:c1 brd ff:ff:ff:ff:ff:ff
4: enp0s9: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP mode DEFAULT group default qlen 1000
    link/ether 08:00:27:5d:61:28 brd ff:ff:ff:ff:ff:ff

看到了吗?
KVM默认网络不见了。

现在,让我们设置KVM公共桥,以在创建新VM时使用。

说明:

请勿将无线网络接口卡用于网桥。
大多数无线隔行扫描不支持桥接。
始终使用有线网络接口进行无缝连接!

要在主机中创建网桥,请编辑/etc/netplan/00-installer-config.yaml文件并添加网桥详细信息。

这是我的Ubuntu 20.04 LTS服务器中00-installer-config.yaml文件的默认内容。

$cat /etc/netplan/00-installer-config.yaml
# This is the network config written by 'subiquity'
network:
  ethernets:
    enp0s3:
      dhcp4: true
    enp0s8:
      dhcp4: true
    enp0s9:
      dhcp4: true
  version: 2

如我们所见,我的Ubuntu服务器中有三个有线网络接口,分别是enp0s3,enp0s8和enp0s9.

编辑此文件之前,请备份现有的/etc/netplan/00-installer-config.yaml文件:

$sudo cp /etc/netplan/00-installer-config.yaml{,.backup}

然后使用我们喜欢的编辑器编辑默认配置文件:

$sudo vi /etc/netplan/00-installer-config.yaml

像下面这样添加/修改它:

# This is the network config written by 'subiquity'
network:
  ethernets:
    enp0s3:
      dhcp4: false
      dhcp6: false
    enp0s8:
      dhcp4: false
      dhcp6: false
    enp0s9:
      dhcp4: false
      dhcp6: false
  bridges:
    br0:
      interfaces: [ enp0s3 ]
      addresses: [192.168.225.52/24]
      gateway4: 192.168.225.1
      mtu: 1500
      nameservers:
        addresses: [8.8.8.8,8.8.4.4]
      parameters:
        stp: true
        forward-delay: 4
      dhcp4: no
      dhcp6: no
  version: 2

在此,网桥网络接口“ br0”连接到主机的网络接口“ enp0s3”。
br0的IP地址是192.168.225.52.
网关是192.168.225.1.
我使用Google DNS服务器(8.8.8.8和8.8.4.4)连接到Internet。
确保空格缩进与上面完全相同。
如果线路缩进不正确,则桥接网络接口将不会激活。
替换与网络匹配的上述值。

修改网络配置文件后,保存并关闭它。
通过运行以下命令使更改生效:

$sudo netplan --debug  apply

现在检查是否已将IP地址分配给网桥接口:

$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: enp0s3: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel master br0 state UP group default qlen 1000
    link/ether 08:00:27:8a:52:94 brd ff:ff:ff:ff:ff:ff
3: enp0s8: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000
    link/ether 08:00:27:10:7c:c1 brd ff:ff:ff:ff:ff:ff
    inet6 2409:4072:48b:ab02:a00:27ff:fe10:7cc1/64 scope global mngtmpaddr noprefixroute 
       valid_lft forever preferred_lft forever
    inet6 fe80::a00:27ff:fe10:7cc1/64 scope link 
       valid_lft forever preferred_lft forever
4: enp0s9: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000
    link/ether 08:00:27:5d:61:28 brd ff:ff:ff:ff:ff:ff
    inet6 2409:4072:48b:ab02:a00:27ff:fe5d:6128/64 scope global mngtmpaddr noprefixroute 
       valid_lft forever preferred_lft forever
    inet6 fe80::a00:27ff:fe5d:6128/64 scope link 
       valid_lft forever preferred_lft forever
7: br0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default qlen 1000
    link/ether 08:00:27:8a:52:94 brd ff:ff:ff:ff:ff:ff
    inet 192.168.225.52/24 brd 192.168.225.255 scope global br0
       valid_lft forever preferred_lft forever
    inet6 fe80::a00:27ff:fe8a:5294/64 scope link 
       valid_lft forever preferred_lft foreve

如我们在上面的输出中看到的,桥接网络接口br0被分配了IP地址192.168.225.52,并且enp0s3条目现在具有“ master br0”条目。
这意味着enp0s3属于网桥。

我们也可以使用“ brctl”命令显示网桥状态:

$brctl show br0

输出示例:

bridge name    bridge id       STP enabled interfaces
br0     8000.0800278a5294   yes     enp0s3

现在,我们应该配置KVM以使用此桥。
为此,创建一个名为host-bridge.xml的XML文件:

$vi host-bridge.xml

添加以下行:

<network>
  <name>host-bridge</name>
  <forward mode="bridge"
  <bridge name="br0"
</network>

运行以下命令以启动新创建的网桥,并将其作为虚拟机的默认网桥:

$virsh net-define host-bridge.xml
$virsh net-start host-bridge
$virsh net-autostart host-bridge

要验证网桥是否处于活动状态并已启动,请运行:

$virsh net-list --all

输出示例:

Name          State    Autostart   Persistent
-----------------------------------------------
 host-bridge   active   yes         yes

恭喜你!我们已经成功设置了KVM桥接器,它现在处于活动状态。

使用Virsh创建和管理KVM虚拟机

我们使用Virsh命令行实用程序来管理虚拟机。

virsh程序用于从命令行创建,列出,暂停,重新启动,关闭和删除VM。

默认情况下,虚拟机文件和其他相关文件存储在/var/lib/libvirt /位置下。
存储ISO镜像的默认路径是/var/lib/libvirt/boot /。
我们当然可以在安装新VM时更改这些位置。

列出所有虚拟机

首先,让我们检查是否存在任何虚拟机。

要查看所有可用虚拟机的列表,请运行:

$sudo virsh list --all

创建KVM虚拟机

让我们创建一个具有2 GB 内存,1个CPU内核,10 GB Hdd的Ubuntu 18.04虚拟机。
为此,请运行:

$sudo virt-install --name Ubuntu-18.04 --ram=2048 --vcpus=1 --cpu host --hvm --disk path=/var/lib/libvirt/images/ubuntu-18.04-vm1,size=10 --cdrom /home/theitroad/ubuntu18.iso --network bridge=br0 --graphics vnc

让我们分解上面的命令,看看每个选项的作用。

  • --name Ubuntu-18.04:虚拟机的名称
  • --ram = 2048:将2 GB 内存分配给VM。
  • --vcpus = 1:指示虚拟机中CPU核心的数量。
  • --cpu host:通过将主机的CPU配置公开给来宾,优化VM的CPU属性。
  • --hvm:请求完整的硬件虚拟化。
  • --disk path =/var/lib/libvirt/images/ubuntu-18.04-vm1,size = 10:保存VM硬盘的位置及其大小。在这种情况下,我分配了10 GB的硬盘大小。
  • --cdrom /home/theitroad/ubuntu18.iso:我们拥有实际的Ubuntu安装程序ISO镜像的位置。
  • --network bridge = br0:指示VM使用网桥网络。如果未配置网桥网络,请忽略此参数。
  • --graphics vnc:允许VNC从远程客户端访问VM。

上面命令的示例输出为:

WARNING Graphics requested but DISPLAY is not set. Not running virt-viewer.
WARNING No console to launch for the guest, defaulting to --wait -1
Starting install...
Allocating 'ubuntu-18.04-vm1'                                                                                                                      |  10 GB  00:00:06     
Domain installation still in progress.
Waiting for installation to complete.

该消息将一直显示,直到我们通过任何VNC应用程序从远程系统连接到VM并完成OS安装为止。

由于我们的KVM主机系统(Ubuntu服务器)没有GUI,因此我们无法继续安装来宾OS。
因此,我将使用带有GUI的备用计算机在VNC客户端的帮助下完成来宾OS的安装。

我们在这里完成了Ubuntu服务器。
以下步骤应在客户端系统上执行。

通过VNC客户端从远程系统访问虚拟机

转到具有图形桌面环境的远程系统,并安装任何尚未安装的VNC客户端应用程序。
我有一个安装了Remmina远程桌面客户端的Ubuntu桌面。

SSH进入KVM主机系统:

$ssh Hyman@theitroad

其中

  • theitroad是KVM主机(Ubuntu 20.04服务器)中用户的名称
  • 192.168.225.52是KVM主机的IP地址。

使用以下命令查找正在运行的VM所使用的VNC端口:

$sudo virsh dumpxml Ubuntu-18.04 | grep vnc

用虚拟机名称替换“ Ubuntu-18.04”。

输出示例:

<graphics type='vnc' port='5900' autoport='yes' listen='127.0.0.1'>

VNC端口号为5900。

在终端上键入以下SSH端口转发命令:

$ssh Hyman@theitroad -L 5900:127.0.0.1:5900

启动VNC客户端应用程序,然后选择“ VNC”协议,然后在地址列中键入“ localhost:5900”,最后按ENTER键:

现在,VNC应用程序将为我们显示猜测的OS安装窗口。

只需继续安装来宾操作系统即可。
安装完成后,关闭VNC应用程序窗口。

列出正在运行的虚拟机

运行“ virt list”命令以查看正在运行的VM的列表:

$sudo virsh list

输出示例:

Id   Name           State
-----------------------------
 2    Ubuntu-18.04   running

如我们所见,Ubuntu 18.04 VM当前正在运行,其ID为2.

启动虚拟机

要启动VM,请运行:

$sudo virsh start Ubuntu-18.04

我们还可以使用VM的ID来启动它:

$sudo virsh start 2

重新启动虚拟机

要重新启动正在运行的VM,请执行以下操作:

$sudo virsh reboot Ubuntu-18.04

或者,

$sudo reboot 2

暂停虚拟机

要暂停正在运行的VM,请执行以下操作:

$sudo suspend Ubuntu-18.04

或者,

$sudo suspend 2

恢复虚拟机

要恢复挂起的VM,请执行以下操作:

$sudo virsh resume Ubuntu-18.04

或者,

$sudo resume 2

关闭虚拟机

要关闭正在运行的VM,请执行以下操作:

$sudo virsh shutdown Ubuntu-18.04

或者,

$sudo shutdown 2

删除虚拟机

要完全删除VM,请执行以下操作:

$sudo virsh undefine Ubuntu-18.04
$sudo virsh destroy Ubuntu-18.04

Virsh有很多命令和选项。
要了解所有这些内容,请参阅virsh帮助部分:

$virsh --help

以图形方式管理KVM来宾

记住所有virsh命令几乎是不可能的。
如果我们是Linux管理员,则可能很难通过命令行执行所有Kvm管理操作。
不用担心!有一些基于Web的工具可用于以图形方式管理KVM来宾计算机。
以下教程详细说明了如何使用Cockpit和Virt-manager管理Kvm来宾。

  • 使用Cockpit Web控制台管理KVM虚拟机
  • 如何使用Virt-Manager管理KVM虚拟机

为虚拟机启用Virsh控制台访问

创建KVM guest虚拟机后,我可以通过SSH,VNC客户端,Virt-viewer,Virt-manager和Cockpit Web控制台等访问它们。
但是我无法使用“ virsh console”命令访问它们。
要使用“ virsh控制台”访问KVM guest虚拟机,请参考以下教程:

  • 如何为KVM guest虚拟机启用Virsh控制台访问