作为 Linux 用户,不管是 IT 开发,还是普通的爱好者,出于种种原因总是离不开虚拟机软件。由于某些原因 (其实就是高中那会痴迷仙剑,先是因为想在网吧电脑上玩仙剑三外传,但是当时仙三外安装过程中必须重启电脑,网吧电脑重启就自动还原了,于是只能研究哪个虚拟机可以比较好的支持3D游戏;后来又逐渐接触到了编程,想要通过给我当时使用的电子词典编译一个 DoxBox 玩原版的仙剑1……这样回头看来,今天会走上 IT 这条路就是因为仙剑也说不定哎😏)我很早就接触过各种虚拟机软件,到目前为止或多或少几乎使用过所有常见的虚拟机软件或平台,包括大家最熟悉的 VMWareVBox,windows 上曾经的 Virtual PC 和如今系统自带的 Hyper-V,MacOS 上的 Parallels Desktop,以及虚拟化平台 ESXiProxmox VE 等……这些软件在各自平台和特定使用场景下各有其优势,但是现在,我个人使用的 Linux 上唯一在用的虚拟机软件,就是今天的主角—— KVM

KVM的优点

  1. 安装方便。
    从 KVM 的全称:Kernel-based Virtual Machine 就可以看出,KVM 实际是 linux 内核提供的虚拟化架构,可将内核直接充当 hypervisor 来使用,只要不是过于老旧的电脑,现在主流的 Linux 发行版都是可以几乎0配置地使用 KVM。相比之下,VMWare 和 VBox 并不是每一个发行版的软件仓库中都会包含的,这时候需要去对应官网下载安装包手动安装;即使是仓库中有可以直接通过包管理安装,它们想要正常使用还需要编译内核模块,每次系统内核升级后还需要重新编译,某些情况下还有可能编译失败无法使用,而 KVM 的安装只需要一步:
    1
    2
    3
    4
    5
    6
    7
    8
    # debian系
    sudo apt install qemu-kvm

    # Redhat系
    sudo yum install qemu-kvm

    # 可选,仅当不加 sudo 执行 kvm 命令提示权限错误时使用
    sudo adduser $USER kvm

    更新:在现在最新的 Debian 仓库中,qemu-kvm只是个虚包:
    qemu_kvm.webp
    所以直接装 qemu-system-x86 就好

  2. 本身资源占用极低
    不管是哪种虚拟化方案,虚拟机软件本身也是要消耗一部分系统资源的。参看 QEMU和KVM的关系,KVM 使用 qemu 作为操作管理前端,占用的资源极低,不运行虚拟系统时 qemu 只占用20多mb的内存,尤其在配置比较低的电脑上可以省出更多的资源让宿主机或者虚拟机使用。

    KVM 也有一些图形化管理工具,比如经典的 virt-manager,还有新一点的 GNOME Boxes,但我觉得其实并不是很有必要,因为常规使用 KVM 的命令行操作足够简单,就我而言图形化操作并没有更方便,反而浪费了资源。

  3. 方便且强大的命令行操作
    这其实是 qemu 的优点,强大的命令行选项可以非常灵活地使用 KVM 虚拟机,而且可以方便地写成脚本,从而得到比图形化虚拟机高得多的效率。虽然 Vmware 和 VBox 也是可以通过命令行进行控制的,例如 Vmware 可以用 vmware -X "[path_to_virtual_pc]/[virtual_pc].vmx" 的方式启动一个创建好的虚拟机,VBox 更是可以通过 VBoxManage 命令实现更多的操作,但都还远远比不上 qemu。

常用命令

常用的命令其实只有两个:

  1. 虚拟机磁盘镜像操作命令 qemu-img
    使用虚拟机软件创建虚拟机安装操作系统,最重要的步骤就是对虚拟磁盘的操作,其他像 cpu 、内存、网络等设置都可以随时调整修改,而虚拟磁盘一旦创建,系统和几乎所有数据都存储在其中,虚拟机的迁移主要也就是磁盘镜像的迁移。通过 qemu-img 可以实现创建、检查、转换、调整虚拟磁盘镜像文件,多数情况下只需要用到其创建( create )的功能,典型用法如下:

    1
    qemu-img create -f raw disk 8G

    上面命令将在当前目录下创建一个容量上限为8G名为 disk 的虚拟磁盘镜像文件。-f 参数的含义是 format,用于指定虚拟磁盘镜像的格式,常用的格式一般是 qcow2raw,两者的区别主要在于空间占用和使用时的 io 效率(RAW 与 QCOW2 的区别);记得命令的顺序是先指定创建镜像的名称(disk),然后再指定其最大容量(8G)
    create image

  2. 启动KVM
    下面仅列出使用 kvm 命令启动虚拟机时常用的参数:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    kvm
    -m 2G # 必选,含义:memory,用于指定虚拟机的占用的最大内存
    -cpu host # 可选,指定虚拟机模拟的 cpu 型号,可选型号列表可以用'kvm -cpu help'命令查看;我习惯用host,代表使用物理机的cpu型号
    -smp 3 # 可选,设置虚拟cpu的核心数
    -hda disk # 必选,用于指定虚拟机使用的虚拟磁盘镜像文件;当有多个磁盘需要使用时可继续指定 -hdb disk2 ……
    -cdrom ~/Download/debian.iso # 指定虚拟机cd光驱使用的镜像,一般只在安装虚拟机系统时需要
    -nic user,hostfwd=tcp::8022-:22 # 可选,用于实现端口映射,这里的例子是把虚拟机的22端口映射到了宿主机的8022端口,下面有详细的应用
    -nographic # 可选,关闭虚拟机的图形输出,在已经配置好远程访问或者远程桌面而不需要虚拟机本身的图形显示时很有用
    -vga vmware # 可选,指定虚拟机内使用的虚拟显卡型号,选择 vmware 模式可以解决某些情况下虚拟机内系统无法调整分辨率的问题

    可以看到,实际使用 kvm 时需要关系的命令参数并不多,下面通过几个例子做详细说明

最简单的使用场景——试用 Linux LiveCD

作为 Linux 系统爱好者,经常会下载一些有趣的 Linux 发行版来体验,多数情况下都不会直接物理安装到机器上,而是通过虚拟机进行体验。多数 Linux 发行版的安装镜像都包含了 LiveCD 模式,如果是使用 kvm 进行体验,命令则非常简单:

1
kvm -m 2G -cdrom ~/Downloads/MX-19.3_x64.iso

因为试用 LiveCD 并不需要硬盘,所以只要指定虚拟机使用的内存大小和系统镜像 iso 文件即可,效果如下:
live_cd

创建一个可以方便进行网络通讯的 Linux 虚拟机

有时候我们需要创建 Linux 虚拟机,默认情况下虚拟机软件一般都是使用 NAT 模式,这样一来虚拟机和宿主机实际上并不属于同一个局域网下,所以并不能简单地通过 ip 进行访问。解决方案一般有两种,一种是将网络模式从 NAT 改为 Bridge(桥接),另一种则是通过端口映射将虚拟机的某些端口直接映射到宿主机上。如果是使用 VMWare 或者 VBox,不管是哪种方法相对来说都还是比较麻烦的,而使用 qemu-kvm 命令的参数,则可以很方便地完成端口映射。下面以 debian10 虚拟机为例:

  1. 首先创建虚拟机磁盘

    1
    qemu-img create -f raw disk 8G		# 因为不准备安装图形桌面,所以8G的磁盘空间就够用了
  2. 指定磁盘镜像和安装镜像,启动虚拟机并安装系统

    1
    kvm -m 2G -hda disk -cdrom ~/Downloads/debian-10.6.0-amd64-netinst.iso

    debian 的网络安装镜像在安装过程中会提示选择安装组件,可以勾选 ssh 组建;或者可以安装好系统后通过包管理安装 openssh-server,这样 Linux 就可以通过 ssh 进行远程登陆了

    安装好系统后,确认 ssh 服务打开,即可关闭虚拟机

  3. 设置端口映射参数启动虚拟机

    1
    kvm -m 2G -hda disk -nic user,hostfwd=tcp::8022-:22

    通过 hostfwd 设置端口映射规则,注意前面一个是宿主机的端口,后一个是虚拟机内的端口;
    现在在宿主机的终端内输入命令:

    1
    ssh [user]@127.0.0.1 -p 8022

    即可通过访问本机内部的 8022 端口,实现对虚拟机 22 端口的 ssh 登陆:
    debian

  4. 根据需要可以继续追加端口映射规则
    继续上面的例子,我在 debian 虚拟机中安装了 docker,并部署了 portainer.io 这个基于 web 的 docker 图形化管理工具,运行在虚拟机的 9000 端口上。现在我想将其映射到宿主机的 8088 端口上:

    1
    kvm -m 2G -hda disk -nic user,hostfwd=tcp::8022-:22,hostfwd=tcp::8088-:9000

    这样,只需要通过在本机的浏览器中访问 http://127.0.0.1:8088 即可方便地对虚拟机内的 docker 进行图形化管理:
    docker

配合 Windows 远程桌面使用 Linux 缺乏的软件

桌面软件生态匮乏,尤其是很多国产必备软件的缺失,是 Linux 用户永远的痛,这可能也是绝大多数 Linux 用户离不开 Windows 和不得不使用虚拟机的最大原因。虽然现在我们有 deepin\UOS 团队在为国产软件的适配不断努力着,但是毕竟其精力有限,目前还是有很多平时工作学习必须的软件无法良好地在 Linux 环境下运行。下面这个例子就是我长期以来解决 Windows 软件在 Linux 桌面下运行使用的方案

  1. 安装 Windows 系统
    创建磁盘镜像和安装过程不再赘述,和上面的命令无甚区别,无非是 Windows 虚拟机所使用的磁盘镜像需要创建地大一些。

    推荐尝试 WES7,可以理解为 WIN7 的裁剪版,下载地址可以在这里找到

  2. Windows系统的开启远程桌面访问
    win7

    如上图所示,进入 控制面板 > 系统和安全 > 系统 点击 远程设置,在弹出的对话框中切换到 远程 标签,将远程桌面的选项切换为 允许运行任意版本远程桌面的计算机连接,应用设置,然后关闭虚拟机。

  3. 配置虚拟机远程桌面的端口映射

    Windows 的远程桌面默认运行于 3389 端口,于是可以把 kvm 的启动命令改为:

    1
    kvm -m 2G -hda disk -nic user,hostfwd=tcp::3389-:3389 -nographic

    由于设置了 -nographic 参数,所以命令执行后不会再出现虚拟机界面。

  4. 使用 rdesktop 进行远程桌面连接

    rdesktop 是一个在 Unix/Linux 下访问 Windows 远程桌面的客户端程序。之所以推荐使用远程桌面的方式使用 windows 虚拟机,是因为可以利用远程桌面协议方便地实现诸如远程目录挂载、剪切板共享、打印机共享等功能,这些在 VMWare 和 VBox 上要么需要安装额外组件,要么需要进行复杂配置,都不是很方便;而且 rdesktop 默认不会捕捉鼠标键盘,在需要频繁在 Linux 和 Windows 虚拟机间来回操作的时候,鼠标捕捉与释放操作还是很影响效率的

    先通过包管理安装 rdesktop:

    1
    sudo apt install rdesktop

    然后用如下的命令启动远程桌面连接:

    1
    rdesktop 127.0.0.1 -u [windows 的用户名] -p [密码] -a 32 -x l -r clipboard:PRIMARYCLIPBOARD -r disk:UOS=/home/debuggerx -g 2560x1380

    在上面的命令中,先是指定了远程桌面的桌面色彩度为最高的32位(因为端口映射带宽很高,最高色彩可以提高显示效果);后面的 -x l 是告诉 rdesktop 远程机器的连接速度是 lan(局域网) 级别,这样可以提高流畅度和显示效果;-r clipboard:PRIMARYCLIPBOARD 的目的是开启双向剪切板共享;-r disk:UOS=/home/debuggerx 的效果是将 Linux 本机的 /home/debuggerx 目录作为网络驱动器挂载到 Windows 虚拟机,并在 Windows 中以 UOS 的盘符显示;最后的 -g 2560x1380 指定了远程桌面的显示大小,由于我的显示器分辨率为 2560x1440,底部 dock 栏高度大约为 60,所以这样设置后远程桌面的窗口正好能够填满屏幕且露出dock 栏
    效果如下:
    rdesktop

进阶玩法

关机脚本

远程桌面登录 Windows 以后,原本的关机按钮会变成注销,这是一种保护机制。为了可以方便地进行关机,可以在桌面上创建一个 关机.bat 的批处理,内容为:

1
shutdown -s -t 1

这样想要关闭虚拟机时只要双击这个脚本即可

脚本自动打开虚拟机并远程连接

前面说到,因为 qemu-kvm 的命令行非常强大且简单,所以很适合写成自动化脚本简化操作,比如我日常使用的脚本 (run.sh) 如下:

1
2
kvm -cpu host -smp 1 -m 3G -hda [bath_to_disk_file]/disk -nographic -nic user,hostfwd=tcp::3389-:3389 &
sleep 5 && rdesktop -T win 127.0.0.1:3389 -u [username] -p [password] -a 32 -x l -r clipboard:PRIMARYCLIPBOARD -r disk:UOS=/home/debuggerx -D -g 2560x1380

之后只要在终端执行 bash run.sh,就可以自动完成后台执行 KVM 打开 Windows 虚拟机,并自动登录远程桌面的操作了。

remoteapp

windows 的远程桌面有一个 remoteapp 功能,可以只远程启动一个软件而不是将整个桌面投射,最终可以实现如下效果
1.打开虚拟机,调用打开记事本,输入正常,记事本用的是win版搜狗,linux的gedit用的linux版搜狗:
remoteapp1
2.同时打开记事本和文件管理器,deepin的dock栏可以正常切换窗口:
remoteapp2
3.正常打开ps,直接打开修改home里的图片并保存:
remoteapp3