在Ubuntu 20.04 Headless Server中安装和配置KVM
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控制台访问