如果你手上只有一台没有桌面环境的Ubuntu服务器,又想在里面跑一个Ubuntu虚拟机,第一反应可能是VirtualBox或者VMware,但这两个在纯命令行下都不算友好,尤其是远程SSH进去操作的时候,基本上等于没法用。我上周正好把一个Ubuntu虚拟机完整跑在了命令行环境里,用的就是QEMU,全程没有图形界面,从安装QEMU到创建磁盘、装系统、配置网络、日常开机管理,全部是终端命令。这篇就是那次成功过程的一份完整备忘,顺便把关键参数和踩坑点一起写清楚。内容偏实操,适合需要在服务器上折腾虚拟机的运维、后端,或者想在本地终端里体验QEMU的爱好者。
1. 为什么选纯命令行 + QEMU这套方案
1.1 这次需求到底是什么
先说下我遇到的实际场景:一台已经装好Ubuntu Server的物理机,没有任何桌面环境,只能通过SSH远程操作。我需要在这台机器上再跑一个Ubuntu虚拟机,用来做构建环境和隔离测试。也就是说,虚拟机必须能在无显示器、无桌面、无回环设备的情况下正常工作,而且我更希望所有操作都能被记录下来、能重复执行,方便后续复用。
如果只用VirtualBox,虽然也能通过VBoxManage命令行实现类似功能,但VBox的服务管理、内核模块、GUI依赖在服务器上往往会有额外的负担。VMware Workstation在纯服务器场景下就更别扭了,它主要面向带桌面的宿主机,命令行管理能力一般。QEMU本身就是从命令行起家的虚拟化工具,参数丰富、可控性强,配合Linux内核自带KVM加速,性能接近原生,非常适合这种纯终端环境。
所以这次选型几乎没有犹豫:宿主机Ubuntu,虚拟机客户机也是Ubuntu,虚拟化方案直接上QEMU/KVM。
1.2 QEMU在命令行场景的优势
QEMU的全称是Quick EMUlator,本质上是一个开源的机器模拟器,既能做纯软件模拟(TCG模式),也能在支持硬件虚拟化的CPU上配合KVM做硬件加速。和VirtualBox、VMware相比,QEMU最明显的特点就是“无头”运行能力极强,所有配置都通过命令行参数传递,不依赖任何图形库。
举个例子,VirtualBox创建一个虚拟机需要先定义虚拟机名称、内存、磁盘类型等,再配置网络模式,这些虽然都有对应的VBoxManage命令,但整体设计还是围绕GUI环境来的。QEMU则完全相反,一条qemu-system-x86_64命令就把CPU、内存、磁盘、网卡、显示设备全部定义完了,这台虚拟机本质上就是一个进程,kill掉进程就关机,写进脚本里就能反复启动。
另外QEMU支持非常广泛的设备模拟和架构模拟。x86_64、ARM、RISC-V都能跑,比如热词里提到的“qemu模拟arm64”,就可以用qemu-system-aarch64跨架构跑ARM系统,这在嵌入式开发和交叉编译场景里很方便。虽然这次我跑的是同架构x86_64,但QEMU的扩展能力让我后续想要实验ARM环境的时候,不需要再装第二套工具。
1.3 从零到能用的命令流程
在没有图形界面的条件下,完整的实施路径大概是这样的:
- 在宿主机安装QEMU相关软件包。
- 确认CPU虚拟化支持,保证KVM可用。
- 用qemu-img创建虚拟磁盘镜像。
- 下载Ubuntu安装镜像。
- 启动QEMU进入安装界面,这里可以用文本模式或者VNC远程安装。
- 安装完成后,正常启动虚拟机。
- 配置SSH端口转发,从宿主机直接访问虚拟机。
- 做快照、备份和日常管理。
每一步都有对应命令,不需要鼠标,也不需要打开任何窗口。下面我按这个顺序把细节展开,命令和参数会尽量完整,方便你直接照着执行。
2. 环境准备与依赖安装
2.1 安装QEMU相关软件包
在Ubuntu上安装QEMU很简单,一条apt命令就能搞定:
sudo apt update sudo apt install -y qemu-system-x86 qemu-utils这里解释下两个包的区别:qemu-system-x86是QEMU主程序包,提供qemu-system-x86_64和qemu-system-i386命令,也就是x86架构的系统模拟器。qemu-utils包含qemu-img等配套工具,创建磁盘、转换格式、制作快照都靠它。如果以后还想玩ARM架构,可以再装qemu-system-arm、qemu-system-aarch64,这是后话。
安装完成后,可以用qemu-system-x86_64 --version确认版本。如果输出正常,就说明主体已经装好了。
不建议图省事直接apt install qemu,因为有些老版本Ubuntu里这个元包可能不会带全你需要的工具,分开装更稳。
2.2 确认CPU虚拟化与KVM可用
QEMU虽然能纯软件模拟,但纯模拟的性能非常差,装个系统能等半天。所以只要CPU支持硬件虚拟化,就一定要用KVM。Intel叫VT-x,AMD叫SVM,在Linux下统一通过/dev/kvm设备暴露出来。
先检查CPU标志位:
egrep -c '(vmx|svm)' /proc/cpuinfo如果输出大于0,说明CPU支持硬件虚拟化。然后看KVM设备是否存在:
ls -l /dev/kvm正常会输出crw-rw---- 1 root kvm 10, 232 ... /dev/kvm这样的内容。如果这个文件不存在,大概率是宿主机本身跑在虚拟机里,没有开启嵌套虚拟化,或者BIOS里没开VT功能,这种情况后面会再说。
确认/dev/kvm存在后,就可以在QEMU启动命令里加-enable-kvm参数。加上这个参数后,虚拟机会从TCG纯模拟模式切换到KVM硬件加速模式,CPU指令直接跑在物理CPU上,性能损耗小很多。
2.3 把当前用户加入kvm组
/dev/kvm的权限默认是root用户或者kvm组才能访问。如果直接用普通用户跑QEMU,经常会遇到Could not access KVM kernel module: Permission denied,所以最好把当前用户加进kvm组:
sudo usermod -aG kvm $USER newgrp kvmnewgrp kvm是为了让当前终端立即生效,不用重新登录。加完组后再执行ls -l /dev/kvm或者干脆跑一次qemu-system-x86_64 -enable-kvm测试一下,不再报权限错误就正常了。
这一步看起来简单,但不少人忽略掉,导致后面所有QEMU命令都失败。我建议一上来就先把用户加进组,后面省得折腾。
3. 创建磁盘镜像并完成系统安装
3.1 用qemu-img创建虚拟磁盘
安装系统前要先准备一块“虚拟硬盘”。QEMU默认支持多种镜像格式,最常用的是qcow2。创建命令:
qemu-img create -f qcow2 ubuntu-server.qcow2 20G-f qcow2指定格式为qcow2,20G是虚拟磁盘的最大容量。但其实qcow2是稀疏分配的,刚创建时几乎不占宿主机磁盘空间,只有虚拟机往里面写入数据时才会慢慢增长,所以哪怕你填50G也没关系,实际占用是按需增长的。
文件名叫ubuntu-server.qcow2,放在一个固定的工作目录里。为了后续管理方便,我习惯把所有虚拟机文件都放在~/vm/下面:
mkdir -p ~/vm cd ~/vm qemu-img create -f qcow2 ubuntu-server.qcow2 20G用qemu-img info ubuntu-server.qcow2可以查看镜像信息,包括虚拟大小、实际占用、cluster size等。这个命令后面排查问题也经常用。
为什么不用raw格式?raw是裸镜像,性能确实稍微好一点,但不支持快照、不支持稀疏增长后的自动回收,而且占空间。qcow2支持快照、压缩、加密、后备镜像,功能全得多,对个人使用来说建议直接选qcow2。
3.2 准备Ubuntu安装镜像
接下来需要一个Ubuntu的安装ISO。如果宿主机有桌面环境,直接下载ISO并用QEMU的图形窗口安装就行。但这次是纯命令行环境,更推荐用Ubuntu Server版ISO,因为它的安装器支持文本模式,在终端里也能完成安装。
下载ISO我一般用国内镜像源,速度比官网快很多。清华镜像站、阿里云镜像站都有稳定的Ubuntu版本目录。以Ubuntu 24.04为例:
cd ~/vm wget https://mirrors.tuna.tsinghua.edu.cn/ubuntu-releases/24.04/ubuntu-24.04.2-live-server-amd64.iso如果你的网络环境对HTTPS有限制,也可以把清华镜像源的https改成http。ISO的校验值在镜像站里都有,强烈建议下载完做一下SHA256校验,避免下载损坏导致安装失败:
echo "<官方校验值> ubuntu-24.04.2-live-server-amd64.iso" | sha256sum -c -3.3 启动QEMU图形安装
如果你本地有X11图形环境,或者用VNC远程连过去,可以先走图形安装流程。命令如下:
qemu-system-x86_64 \ -name ubuntu-server \ -m 2048 \ -smp 2 \ -enable-kvm \ -cpu host \ -drive file=ubuntu-server.qcow2,format=qcow2,if=virtio \ -cdrom ubuntu-24.04.2-live-server-amd64.iso \ -boot d \ -netdev user,id=net0,hostfwd=tcp::2222-:22 \ -device virtio-net-pci,netdev=net0 \ -display default解释几个关键参数:
-m 2048:给虚拟机分配2GB内存。-smp 2:分配2个CPU核心。-enable-kvm:启用KVM硬件加速,不加这个性能会差很多。-cpu host:让虚拟机使用与宿主机相同型号的CPU,最大化兼容性和性能。-drive file=...,format=qcow2,if=virtio:使用virtio磁盘接口,比默认的IDE模式快不少。-cdrom ...:挂载安装ISO。-boot d:从光驱引导。-netdev user,id=net0,hostfwd=tcp::2222-:22:使用用户态网络,并把宿主机的2222端口转发到虚拟机的22端口。-display default:弹出图形窗口,仅适用于有桌面的场景。
如果是在无桌面的服务器上,把-display default换成-display vnc=:1,然后用VNC客户端连接宿主机IP的5901端口,就能看到图形安装界面。
3.4 纯文本模式安装的完整命令
不走图形还有个办法,就是用QEMU的curses文本显示模式,直接把VM的显示屏输出到当前终端:
qemu-system-x86_64 \ -name ubuntu-server \ -m 2048 \ -smp 2 \ -enable-kvm \ -cpu host \ -drive file=ubuntu-server.qcow2,format=qcow2,if=virtio \ -cdrom ubuntu-24.04.2-live-server-amd64.iso \ -boot d \ -netdev user,id=net0,hostfwd=tcp::2222-:22 \ -device virtio-net-pci,netdev=net0 \ -display cursesUbuntu Server的安装器本身支持文本界面,用curses模式就能看到安装菜单,用键盘上下左右选择即可完成全部安装。安装过程中出现的彩色界面会被映射成字符界面,虽然不如图形界面直观,但功能不打折。
安装到选择磁盘那一步,能看到这块20G的virtio磁盘,直接选中并继续就行。网络建议不配静态IP,先让DHCP跑起来,后面再通过端口转发访问。
安装完成后虚拟机会提示重启。重启前要记得手动关闭QEMU,否则ISO还挂着,可能又会进到安装界面。用curses模式时,QEMU的monitor组合键是Ctrl+a c,按下后能进入monitor命令行,输入quit退出。或者等安装器提示重启时,直接把ISO从命令行中去掉再启动。
4. 日常启动、网络访问与管理优化
4.1 正常启动虚拟机的命令
系统装好后,启动命令就简化了,不再需要-cdrom和-boot d,核心是磁盘和网络:
qemu-system-x86_64 \ -name ubuntu-server \ -m 2048 \ -smp 2 \ -enable-kvm \ -cpu host \ -drive file=ubuntu-server.qcow2,format=qcow2,if=virtio \ -netdev user,id=net0,hostfwd=tcp::2222-:22 \ -device virtio-net-pci,netdev=net0 \ -daemonize \ -display none加-daemonize后,QEMU进程会进入后台运行,终端不会阻塞,非常适合服务器环境。-display none表示不创建任何显示界面,反正系统安装完了,我们已经不需要屏幕了,通过SSH访问就行。
如果启动时希望看到虚拟机启动日志,可以临时去掉-daemonize,用-display curses或-nographic观察启动状态。习惯上,我推荐第一次启动还是用curses模式盯着看,确认系统能正常引导,再改成后台运行。
4.2 SSH端口转发和网络方案
因为使用了-netdev user这种用户态网络,虚拟机默认是在一个NAT网络里,外部无法直接访问虚拟机IP。端口转发就是通过宿主机的某个端口,把流量转到虚拟机内部。上面的hostfwd=tcp::2222-:22就是把宿主机2222端口转发到虚拟机的22端口。
之后从宿主机登录虚拟机:
ssh -p 2222 ubuntu@127.0.0.1如果你在局域网其他机器上,也可以直接SSH到宿主机IP的2222端口,同样能访问到虚拟机。
user网络模式的优点是零配置,但它不支持宿主机与虚拟机之间的双向访问,虚拟机里看不到宿主机,而且网络性能一般。如果以后跑更重的服务,建议换成桥接网络,让虚拟机和宿主机处在同一个局域网里。桥接需要创建/etc/network/interfaces.d/br0配置,再用-netdev bridge,id=net0,配置会复杂一些,适合对网络隔离和性能有要求的场景。
4.3 快照、克隆与备份
QEMU镜像最大的好处之一就是支持内置快照。虚拟机运行中,可以通过monitor执行快照,也可以在关机状态下用命令操作。
关机状态下手动创建快照:
qemu-img snapshot -c clean-install ubuntu-server.qcow2 qemu-img snapshot -l ubuntu-server.qcow2-c是create,-l是list。回滚到某个快照用-a:
qemu-img snapshot -a clean-install ubuntu-server.qcow2需要注意,qemu-img snapshot只适合在虚拟机未运行或使用内置快照时使用。如果你需要更灵活的备份,可以先把虚拟机关机,再直接复制qcow2文件,这是最原始也是最可靠的方案。
如果想基于现有虚拟机快速创建多个实例,可以使用qcow2的后备镜像功能:
qemu-img create -f qcow2 -b ubuntu-server.qcow2 -F qcow2 ubuntu-test-1.qcow2这样ubuntu-test-1.qcow2会以ubuntu-server.qcow2为基础镜像,只记录差异数据,非常节省空间。多个测试实例共享同一个基础镜像,适合批量创建环境。
4.4 磁盘扩容与回收
创建镜像时设了20G,用到后期可能会不够。qcow2扩容很简单:
qemu-img resize ubuntu-server.qcow2 40G但这只是让虚拟磁盘从“最大20G”变成“最大40G”,虚拟机内部的文件系统和分区并不会自动跟着变大。进入虚拟机后,需要用growpart扩展分区,再用resize2fs扩展文件系统:
sudo growpart /dev/vda 1 sudo resize2fs /dev/vda1具体分区路径要以虚拟机里lsblk看到的为准,如果根分区是vda1就这么操作。磁盘扩容和高位块分配都是在线完成的,不需要关机。
另外,qcow2文件会随着使用越来越大,即使删除了虚拟机内部的文件,宿主机上镜像文件也不会自动变小。想回收空间,可以在虚拟机内部用fstrim或者zerofree清空空闲块,关机后在宿主机上执行:
qemu-img convert -O qcow2 ubuntu-server.qcow2 ubuntu-server-compact.qcow2把压缩后的文件替换原来的即可。这个操作相当于把qcow2里空洞部分重新整理,能明显减小文件体积。
5. 高频问题排查与性能调优
5.1 KVM权限问题
这是最常见的问题,报错通常是:
Could not access KVM kernel module: Permission denied failed to initialize KVM: Permission denied原因就是当前用户没有权限访问/dev/kvm。解决方法就是前面说的,把用户加入kvm组,然后重新登录或者newgrp kvm。如果/dev/kvm本身不存在,则需要检查宿主机CPU虚拟化是否开启,或者宿主机本身是不是虚拟机,是否需要开启嵌套虚拟化。
手动确认一下:
lsmod | grep kvm如果什么都没输出,说明kvm模块没有加载,可以试试:
sudo modprobe kvm_intelAMD CPU则用modprobe kvm_amd。服务器重启后这些模块一般是自动加载的,手动modprobe只是在应急时用。
5.2 启动黑屏或无法连接
黑屏可能由几个原因导致。
一是-display default在无桌面的SSH环境里根本弹不出窗口,所以一旦离开图形环境,就要立刻切换成-display curses或-display none。二是curses模式下,QEMU把终端切到字符界面,如果你直接在一个不支持交互的终端里运行,可能会显示不出来。建议用正常的SSH终端工具,比如Windows Terminal、iTerm2、XShell这类。
三是如果加了-daemonize和-display none,虚拟机就完全隐藏了,这时候你只能通过端口去访问。如果SSH连不上,可以先去掉-daemonize并改成curses,启动后看虚拟机内部的报错信息,比如ssh服务没起来、防火墙拦截等。
还有一个容易忽视的地方:hostfwd=tcp::2222-:22这个参数,在虚拟机内部使用非22端口的SSH时不起作用。如果安装系统时改了SSH端口,这里要对应修改。
5.3 频繁卡顿与性能调优
如果确认KVM已经启用,虚拟机还是慢,可以从几个方向调:
-cpu host:让虚拟机直接使用宿主机CPU型号,比默认的qemu64虚拟CPU性能好很多。-smp:分配合理的CPU核心数,不要超过宿主机物理核心数,否则会导致CPU竞争。-m:分配足够内存,但别把宿主机内存全部吃光,建议留2GB给宿主机。-drive cache=none或cache=writeback:磁盘缓存模式会影响IO性能。如果追求数据安全,用cache=none;追求速度和模拟环境,可以在磁盘参数里加cache=writeback。- 使用virtio驱动:磁盘和网卡都用virtio要比默认的IDE和e1000快得多,这点在创建命令里已经体现了。
如果追求极致性能,可以再加-no-reboot之类的参数避免意外重启,或者使用-overcommit mem-lock=on锁住内存,但这些要根据实际场景来,不是默认配置。
5.4 镜像导出与迁移
QEMU虚拟机的迁移很简单,因为整个虚拟机就是那几个文件:qcow2镜像、可能还有启动脚本和快照。把qcow2文件拷贝到另一台机器,用同样的命令行参数启动,虚拟机就过去了。
但如果跨平台迁移,比如从x86_64迁到ARM64,那就别想了,架构不同无法直接运行,只能用QEMU的跨架构模拟。倒是可以提一下,如果只是备份重装,可以用qemu-img convert把qcow2转成raw或者其他格式:
qemu-img convert -f qcow2 -O raw ubuntu-server.qcow2 ubuntu-server.raw这样可以方便地做块级别备份,或者上传到云平台。反过来,也可以把raw转回qcow2。
6. 个人经验与后续扩展
实际用下来,QEMU在纯命令行环境下给我的感受是“一旦摸清参数,就再也不想开图形界面了”。所有操作都能写成脚本,备份、创建、销毁、重建,一条命令完成,不需要点任何窗口。
最后分享一个小技巧。如果你需要经常启动和停止这台虚拟机,可以在~/.bashrc里加一个alias或者写个简单脚本:
alias vm-start='cd ~/vm && qemu-system-x86_64 -name ubuntu-server -m 2048 -smp 2 -enable-kvm -cpu host -drive file=ubuntu-server.qcow2,format=qcow2,if=virtio -netdev user,id=net0,hostfwd=tcp::2222-:22 -device virtio-net-pci,netdev=net0 -daemonize -display none'之后每次只需要输入vm-start就能后台启动虚拟机,配合ssh -p 2222 ubuntu@127.0.0.1直接进入系统。
QEMU能玩的东西还有很多,比如在x86宿主机上用qemu-system-aarch64模拟ARM64系统、用9p共享目录、用-usbdevice透传外部设备等。这次先把最核心的“Ubuntu宿主机上用命令行走一个Ubuntu虚拟机”这条链路走通,以后遇到需要虚拟化隔离的场景,这套方法可以原样复用。