Menu

  • Home
  • Work
    • Cloud
      • Virtualization
      • IaaS
      • PaaS
    • Java
    • Go
    • C
    • C++
    • JavaScript
    • PHP
    • Python
    • Architecture
    • Others
      • Assembly
      • Ruby
      • Perl
      • Lua
      • Rust
      • XML
      • Network
      • IoT
      • GIS
      • Algorithm
      • AI
      • Math
      • RE
      • Graphic
    • OS
      • Linux
      • Windows
      • Mac OS X
    • BigData
    • Database
      • MySQL
      • Oracle
    • Mobile
      • Android
      • IOS
    • Web
      • HTML
      • CSS
  • Life
    • Cooking
    • Travel
    • Gardening
  • Gallery
  • Video
  • Music
  • Essay
  • Home
  • Work
    • Cloud
      • Virtualization
      • IaaS
      • PaaS
    • Java
    • Go
    • C
    • C++
    • JavaScript
    • PHP
    • Python
    • Architecture
    • Others
      • Assembly
      • Ruby
      • Perl
      • Lua
      • Rust
      • XML
      • Network
      • IoT
      • GIS
      • Algorithm
      • AI
      • Math
      • RE
      • Graphic
    • OS
      • Linux
      • Windows
      • Mac OS X
    • BigData
    • Database
      • MySQL
      • Oracle
    • Mobile
      • Android
      • IOS
    • Web
      • HTML
      • CSS
  • Life
    • Cooking
    • Travel
    • Gardening
  • Gallery
  • Video
  • Music
  • Essay

KVM和QEMU学习笔记

17
Aug
2015

KVM和QEMU学习笔记

By Alex
/ in Virtualization
/ tags libvirt
0 Comments
简介
虚拟化基础知识
关于Hypervisor

Hypervisor,即虚拟机监管程序(virtual machine monitor ,VMM)。它可以是电脑上的软件、固件或者硬件,用于建立和执行虚拟机。拥有Hypervisor后,你可以执行一个或者多个虚拟机。这些虚拟机称为客户机(guest machine),相应的Hypervisor所在机器称为宿主机(host machine)。

传统的虚拟化技术都是基于Hypervisor的,它们被分为两类:

  1. bare-metal Hypervisor:裸机监管程序,直接运行在硬件上
  2. Hosted Hypervisor:被宿主监管程序,Hypervisor运行在操作系统之上,就像一个应用程序一样
特权级别和虚拟化类型

X86处理器定义了定义了0-3个特权级,数字越小,权限越高。

对于Linux来说,在没有虚拟化的情况下,内核态对应了0级,用户态对应3级。

传统的虚拟化技术都是在宿主机、客户机之间加一个Hypervisor。因此,当在Linux上运行Linux虚拟机时,两个内核都需要运行在0级。根据解决此冲突(对于Host来说整个Client是用户程序)的方式的不同,虚拟化被分为3种类型:

虚拟化类型 说明
半虚拟化

Paravirtualization。此类型的特点是:

  1. Hypervisor运行在内核态,对应0级特权
  2. 客户机的内核不运行在内核态,内核被修改,需要在0级执行的特权指令转调Hypervisor
  3. 客户机上的用户程序运行在3级
非硬件辅助全虚拟化

Full Virtualization without Hardware Assist。此类型的特点是:

  1. Hypervisor运行在内核态
  2. Hypervisor位客户机提供一个模拟的CPU
  3. 客户机内核不需要修改,运行在模拟CPU上的0级
  4. Hypervisor对客户机的CPU指令进行转译,变成正式CPU的指令
硬件辅助全虚拟化

Full Virtualization with Hardware Assist。由Intel VT或AMD-V实现,此类型的特点是:

  1. Hypervisor运行在新的-1级别
  2. 客户机内核直接运行在真实CPU的0级
KVM

KVM,即基于内核的虚拟机(Kernel-based Virtual Machine),是构建于支持虚拟化扩展(Intel VT 或者 AMD-V)的x86平台、Linux操作系统之上的,完整虚拟化解决方案。使用KVM,你可以运行多个Linux或者Windows系统镜像,这些虚拟机拥有私有的虚拟化设备,包括网卡、磁盘、显卡等。

KVM主要包含两个内核组件:

  1. 可加载的内核模块 kvm.ko,负责核心的虚拟化基础功能
  2. 针对处理器的模块:kvm-intel.ko或者kvm-amd.ko

从2.6.20版本的Linux内核开始,KVM的内核组件就被包含在其中。从QEMU 1.3开始,KVM的用户空间组件被包含在其中。要查看你的机器是否支持KVM,可以执行: lsmod | grep kvm 

QEMU

QEMU是一个基于通用目的开源仿真器/虚拟器软件。它可以模拟:

  1. CPU
  2. Intel e1000 PCI等网卡
  3. 基于PCI IDE接口的硬盘、光驱
  4. 软驱
  5. 串口
  6. AC97兼容声卡以及其它声卡
  7. PS/2 键盘鼠标
  8. VGA显卡

等多种外围设备。QEMU最多支持255 CPU的SMP。

当作为仿真器(Emulator,模拟器)使用时,它可以在真实机器(例如你的x86_64台式机)上模拟一台机器 + 操作系统 + 程序,而这台模拟的机器的体系结构(例如ARM板)与宿主机器不同。

而作为虚拟器(Virtualizer)使用时,它可以在宿主机器上直接执行客户机(虚拟机)的代码,因而虚拟机的性能接近于宿主机。QEMU通过下列方式之一来支持虚拟化:

  1. 在XEN监管程序(Hypervisor)之上执行
  2. 在支持KVM的Linux操作系统下运行。使用KVM时QEMU可以虚拟化x86、PowerPC、S390客户机

注意Emulator和Virtualizer的区别,最重要的一点是客户机的代码是直接执行(意味着宿主和客户机体系结构兼容),还是模拟执行,后者的效率要低得多。很多同学喜欢在PC上玩街机游戏,这也是通过模拟器(例如Winkawaks)实现的。

和Vmware、VirtualBox 之类的虚拟机管理软件不同,QEMU不提供图形化的管理界面。你可以使用第三方的图形前端,例如qtemu,但是命令行的丰富性让QEMU更适合在服务器上使用。

QEMU与KVM

单纯靠QEMU来模拟一系列硬件,因为存在指令转译,性能一般很差。而KVM可以基于Intel-VT、AMD-V实现硬件辅助的CPU虚拟化,客户机指令直接在真实CPU上运行。因此结合KVM可以很好的提高QEMU的CPU性能。另一方面KVM仅仅提供CPU的虚拟化,它无法构建一台完整的虚拟机。因此QEMU和KVM整合的需求就很明显了。

qemu-kvm项目就是来整合QEMU和KVM的,此项目在1.3.0版本开始正式合并到QEMU项目的master上。qemu-kvm(qemu-system-***)利用ioctl调用/dev/kvm,将有关CPU的部分交由KVM去做。

如果KVM内核模块存在、且CPU支持,你可以通过下面的选项启用KVM支持:

Shell
1
2
# 启用基于KVM的虚拟化加速
-enable-kvm
周围硬件的性能

CPU的性能问题解决了,但是QEMU模拟的其它硬件也存在同样的低效问题,于是Virtio被引入了。

Virtio是libvirt的一部分,它是一个关于网络、磁盘等设备的虚拟化标准,在此标准中客户机的设备驱动知道自己运行在虚拟化环境中,因而这些驱动可以和Hypervisor进行直接交互,获得接近于Native驱动的性能。

较新版本的Linux发行版都已经把Virtio编译进内核,因而客户机可以直接使用Virtio驱动。

与其它虚拟化技术的比较
Xen

KVM和XEN都是基于Hypervisor的虚拟化技术。它们的区别包括:

  1. Xen是裸机监管程序,而KVM某种程度上把Linux内核变成了Hosted Hypervisor
  2. Xen的整体性能高于KVM,但是I/O略差
  3. KVM要求CPU必须支持虚拟化技术,但Xen则没有此限制。这个限制在当前的硬件条件下,基本不是问题
  4. KVM的优势是它对Linux内核的整合程度,KVM本质上就是一个内核模块,因此你可以很容易的升级内核
VirtualBox

VirtualBox是标准的2类Hypervisor,KVM与它的区别包括:

  1. VirtualBox它与商用软件Vmware Workstation一样,都以图形界面为主,适合个人用户。但是在商用环境下,大部分虚拟机都是Headless的(不需要图形界面),此时VirtualBox的GUI则是劣势,GUI浪费了资源
  2. VirtualBox支持大量的宿主操作系统,例如Windows、Linux、Mac OS X。而KVM显然仅支持Linux
  3. 一般情况下,轻量级的KVM的性能要比VirtualBox好的多
关于LXC

LXC即Linux容器(Containers),这是一种操作系统层(传统虚拟机是硬件层)虚拟化技术,要由liblxc库及其多语言绑定、一系列控制容器的工具组成。LXC将整个应用,包括:软件本身代码、所需库、支撑软件,打包为一个“容器”。通过Linux内核的特性,可以实现容器与系统之间的隔离,这些特性包括:

  1. 内核命名空间(IPC、uts、mount、pid、network、user)
  2. Apparmor(限制每个应用程序访问的资源)和SELinux配置
  3. Seccomp(提供应用程序沙盒机制)策略
  4. Chroots(通过pivot_root调用)
  5. cgroups,即控制组(control groups),用来限制、控制、分离进程组的资源(CPU、内存、磁盘等),此特性最初的名字就叫“进程容器”

通过LXC,你可以创建尽可能接近标准Linux的环境,同时不需要独立的内核。

基于LXC的虚拟化技术和KVM相比,区别如下:

  1. LXC的优势在于轻量化和高性能,但是隔离性不高
  2. LXC支持任何体系结构,例如x86、ARM、PowerPC等
LXD

LXD基于LXC,可以认为是一个Container的Hypervisor,LXD一般创建自包含的操作系统用户空间。也就是说,LXD容器内运行的是一个操作系统,虽然存在用户空间和内核空间隔离,但是这个操作系统和宿主系统共享一个内核。

有测试数据表明:LXD相比KVM可以减少50+%的延迟;LXD启动实例的速度比KVM块90+%

Docker

近年来非常流行的容器软件,与LXD最大的不同是,Docker打包应用程序+自包含的文件系统,而不是操作系统用户空间。每个Docker容器,仅仅包含一个应用程序。曾经Docker也是基于lxc技术的,但是现在它使用自己的库ibcontainer。

Docker中的文件系统、网络都是抽象的,而LXD直接使用宿主机的文件系统、网络,LXD可以方便的设置IP地址。

Docker比起LXD更加轻量,可以实现更高的部署密度。

安装和配置
使用随系统自带的KVM

大部分的Linux发行版已经内置了KVM内核模块以及用户空间工具,使用这些内置组件是最容易、推荐的方式:

  1. KVM内核模块现在是Linux内核的一部分,除非你使用的是精简过的内核
  2. 用户空间组件,软件包名称一般是qemu-kvm或者kvm,例如:
    1. Ubuntu下可以执行 apt-get install qemu-kvm 安装
    2. CentOS下可以执行 yum install kvm安装
  3. 客户机驱动:Linux客户机的驱动包含在内核中;Windows客户机的驱动需要下载
手工构建KVM

安装QEMU的依赖包:

Shell
1
sudo apt-get install gcc libsdl1.2-dev zlib1g-dev libasound2-dev linux-kernel-headers pkg-config libgnutls-dev libpci-dev

下载用户空间组件: 

  1. QEMU 1.3或者更老版本的,在Sourceforge下载
  2. 新版本,在QEMU官网下载

注意:2.6.29以上版本的内核,可以和任何版本的qemu-kvm搭配使用。

构建和安装用户空间组件
Shell
1
2
3
4
5
tar xzf qemu-kvm-release.tar.gz
cd qemu-kvm-release
./configure --prefix=/usr/local/kvm
make
sudo make install
构建和安装KVM内核模块

如果你使用旧版本内核,或者内核精简了KVM,则需要此步骤:

Shell
1
2
3
4
5
tar xjf kvm-kmod-release.tar.bz2
cd kvm-kmod-release
./configure
make
sudo make install
启用内核模块
Shell
1
2
3
4
# 对于Intel CPU
sudo /sbin/modprobe kvm-intel
# 对于AMD CPU
sudo /sbin/modprobe kvm-amd
构建QEMU

从3.0.0开始QEMU的版本大跃进,每年major版本增加1,目前已经是5.x版本。

下载和构建
Shell
1
2
3
4
5
wget https://download.qemu.org/qemu-5.1.0.tar.xz
tar xvJf qemu-5.1.0.tar.xz
cd qemu-5.1.0/
./configure
make
配置项说明
Shell
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
./configure --help
 
# 方括号中是默认值
 
Standard options:
  --prefix=PREFIX          install in PREFIX [/usr/local]
  --interp-prefix=PREFIX   where to find shared libraries, etc.
                           use %M for cpu name [/usr/gnemul/qemu-%M]
  # 目标列表,默认所有
  # xxx-softmmu 生成qemu-system-xxx,用于运行xxx架构下的虚拟机
  # xxx-linux-user 生成qemu-xxx,用于模拟运行xxx架构下的应用程序,可以配合binfmt_misc和Docker联用
  --target-list=LIST       set target list (default: build everything)
                           Available targets: aarch64-softmmu alpha-softmmu
                           arm-softmmu avr-softmmu cris-softmmu hppa-softmmu
                           i386-softmmu lm32-softmmu m68k-softmmu
                           microblazeel-softmmu microblaze-softmmu
                           mips64el-softmmu mips64-softmmu mipsel-softmmu
                           mips-softmmu moxie-softmmu nios2-softmmu
                           or1k-softmmu ppc64-softmmu ppc-softmmu
                           riscv32-softmmu riscv64-softmmu rx-softmmu
                           s390x-softmmu sh4eb-softmmu sh4-softmmu
                           sparc64-softmmu sparc-softmmu tricore-softmmu
                           unicore32-softmmu x86_64-softmmu xtensaeb-softmmu
                           xtensa-softmmu aarch64_be-linux-user
                           aarch64-linux-user alpha-linux-user armeb-linux-user
                           arm-linux-user cris-linux-user hppa-linux-user
                           i386-linux-user m68k-linux-user
                           microblazeel-linux-user microblaze-linux-user
                           mips64el-linux-user mips64-linux-user
                           mipsel-linux-user mips-linux-user
                           mipsn32el-linux-user mipsn32-linux-user
                           nios2-linux-user or1k-linux-user
                           ppc64abi32-linux-user ppc64le-linux-user
                           ppc64-linux-user ppc-linux-user riscv32-linux-user
                           riscv64-linux-user s390x-linux-user sh4eb-linux-user
                           sh4-linux-user sparc32plus-linux-user
                           sparc64-linux-user sparc-linux-user
                           tilegx-linux-user x86_64-linux-user
                           xtensaeb-linux-user xtensa-linux-user
  --target-list-exclude=LIST exclude a set of targets from the default target-list
 
Advanced options (experts only):
  --cross-prefix=PREFIX    use PREFIX for compile tools []
  --cc=CC                  use C compiler CC [cc]
  --iasl=IASL              use ACPI compiler IASL [iasl]
  --host-cc=CC             use C compiler CC [cc] for code run at
                           build time
  --cxx=CXX                use C++ compiler CXX [c++]
  --objcc=OBJCC            use Objective-C compiler OBJCC [cc]
  --extra-cflags=CFLAGS    append extra C compiler flags QEMU_CFLAGS
  --extra-cxxflags=CXXFLAGS append extra C++ compiler flags QEMU_CXXFLAGS
  --extra-ldflags=LDFLAGS  append extra linker flags LDFLAGS
  --cross-cc-ARCH=CC       use compiler when building ARCH guest test cases
  --cross-cc-flags-ARCH=   use compiler flags when building ARCH guest tests
  --make=MAKE              use specified make [make]
  --install=INSTALL        use specified install [install]
  --python=PYTHON          use specified python [/usr/bin/python3]
  --sphinx-build=SPHINX    use specified sphinx-build []
  --smbd=SMBD              use specified smbd [/usr/sbin/smbd]
  --with-git=GIT           use specified git [git]
  --static                 enable static build [no]
  --mandir=PATH            install man pages in PATH
  --datadir=PATH           install firmware in PATH/qemu
  --docdir=PATH            install documentation in PATH/qemu
  --bindir=PATH            install binaries in PATH
  --libdir=PATH            install libraries in PATH
  --libexecdir=PATH        install helper binaries in PATH
  --sysconfdir=PATH        install config in PATH/qemu
  --localstatedir=PATH     install local state in PATH (set at runtime on win32)
  --firmwarepath=PATH      search PATH for firmware files
  --efi-aarch64=PATH       PATH of efi file to use for aarch64 VMs.
  --with-confsuffix=SUFFIX suffix for QEMU data inside datadir/libdir/sysconfdir [/qemu]
  --with-pkgversion=VERS   use specified string as sub-version of the package
  --enable-debug           enable common debug build options
  --enable-sanitizers      enable default sanitizers
  --enable-tsan            enable thread sanitizer
  --disable-strip          disable stripping binaries
  --disable-werror         disable compilation abort on warning
  --disable-stack-protector disable compiler-provided stack protection
  --audio-drv-list=LIST    set audio drivers list:
                           Available drivers: oss alsa sdl pa
  --block-drv-whitelist=L  Same as --block-drv-rw-whitelist=L
  --block-drv-rw-whitelist=L
                           set block driver read-write whitelist
                           (affects only QEMU, not qemu-img)
  --block-drv-ro-whitelist=L
                           set block driver read-only whitelist
                           (affects only QEMU, not qemu-img)
  --enable-trace-backends=B Set trace backend
                           Available backends: dtrace ftrace log simple syslog ust
  --with-trace-file=NAME   Full PATH,NAME of file to store traces
                           Default:trace-<pid>
  --disable-slirp          disable SLIRP userspace network connectivity
  --enable-tcg-interpreter enable TCG with bytecode interpreter (TCI)
  --enable-malloc-trim     enable libc malloc_trim() for memory optimization
  --oss-lib                path to OSS library
  # 为指定CPU构建
  --cpu=CPU                Build for host CPU [x86_64]
  --with-coroutine=BACKEND coroutine backend. Supported options:
                           ucontext, sigaltstack, windows
  --enable-gcov            enable test coverage analysis with gcov
  --gcov=GCOV              use specified gcov [gcov]
  --disable-blobs          disable installing provided firmware blobs
  --with-vss-sdk=SDK-path  enable Windows VSS support in QEMU Guest Agent
  --with-win-sdk=SDK-path  path to Windows Platform SDK (to build VSS .tlb)
  --tls-priority           default TLS protocol/cipher priority string
  --enable-gprof           QEMU profiling with gprof
  --enable-profiler        profiler support
  --enable-debug-stack-usage
                           track the maximum stack usage of stacks created by qemu_alloc_stack
  --enable-plugins
                           enable plugins via shared library loading
  --disable-containers     don't use containers for cross-building
  --gdb=GDB-path           gdb to use for gdbstub tests [/usr/bin/gdb]
 
Optional features, enabled with --enable-FEATURE and
disabled with --disable-FEATURE, default is enabled if available:
 
  system          all system emulation targets
  user            supported user emulation targets
  linux-user      all linux usermode emulation targets
  bsd-user        all BSD usermode emulation targets
  docs            build documentation
  guest-agent     build the QEMU Guest Agent
  guest-agent-msi build guest agent Windows MSI installation package
  pie             Position Independent Executables
  modules         modules support (non-Windows)
  module-upgrades try to load modules from alternate paths for upgrades
  debug-tcg       TCG debugging (default is disabled)
  debug-info      debugging information
  sparse          sparse checker
  safe-stack      SafeStack Stack Smash Protection. Depends on
                  clang/llvm >= 3.7 and requires coroutine backend ucontext.
 
  gnutls          GNUTLS cryptography support
  nettle          nettle cryptography support
  gcrypt          libgcrypt cryptography support
  auth-pam        PAM access control
  sdl             SDL UI
  sdl-image       SDL Image support for icons
  gtk             gtk UI
  vte             vte support for the gtk UI
  curses          curses UI
  iconv           font glyph conversion support
  vnc             VNC UI support
  vnc-sasl        SASL encryption for VNC server
  vnc-jpeg        JPEG lossy compression for VNC server
  vnc-png         PNG compression for VNC server
  cocoa           Cocoa UI (Mac OS X only)
  virtfs          VirtFS
  mpath           Multipath persistent reservation passthrough
  xen             xen backend driver support
  xen-pci-passthrough    PCI passthrough support for Xen
  brlapi          BrlAPI (Braile)
  curl            curl connectivity
  membarrier      membarrier system call (for Linux 4.14+ or Windows)
  fdt             fdt device tree
  kvm             KVM acceleration support
  hax             HAX acceleration support
  hvf             Hypervisor.framework acceleration support
  whpx            Windows Hypervisor Platform acceleration support
  rdma            Enable RDMA-based migration
  pvrdma          Enable PVRDMA support
  vde             support for vde network
  netmap          support for netmap network
  linux-aio       Linux AIO support
  linux-io-uring  Linux io_uring support
  cap-ng          libcap-ng support
  attr            attr and xattr support
  vhost-net       vhost-net kernel acceleration support
  vhost-vsock     virtio sockets device support
  vhost-scsi      vhost-scsi kernel target support
  vhost-crypto    vhost-user-crypto backend support
  vhost-kernel    vhost kernel backend support
  vhost-user      vhost-user backend support
  vhost-vdpa      vhost-vdpa kernel backend support
  spice           spice
  rbd             rados block device (rbd)
  libiscsi        iscsi support
  libnfs          nfs support
  smartcard       smartcard support (libcacard)
  libusb          libusb (for usb passthrough)
  live-block-migration   Block migration in the main migration stream
  usb-redir       usb network redirection support
  lzo             support of lzo compression library
  snappy          support of snappy compression library
  bzip2           support of bzip2 compression library
                  (for reading bzip2-compressed dmg images)
  lzfse           support of lzfse compression library
                  (for reading lzfse-compressed dmg images)
  zstd            support for zstd compression library
                  (for migration compression and qcow2 cluster compression)
  seccomp         seccomp support
  coroutine-pool  coroutine freelist (better performance)
  glusterfs       GlusterFS backend
  tpm             TPM support
  libssh          ssh block device support
  numa            libnuma support
  libxml2         for Parallels image format
  tcmalloc        tcmalloc support
  jemalloc        jemalloc support
  avx2            AVX2 optimization support
  avx512f         AVX512F optimization support
  replication     replication support
  opengl          opengl support
  virglrenderer   virgl rendering support
  xfsctl          xfsctl support
  qom-cast-debug  cast debugging support
  tools           build qemu-io, qemu-nbd and qemu-img tools
  bochs           bochs image format support
  cloop           cloop image format support
  dmg             dmg image format support
  qcow1           qcow v1 image format support
  vdi             vdi image format support
  vvfat           vvfat image format support
  qed             qed image format support
  parallels       parallels image format support
  sheepdog        sheepdog block driver support
  crypto-afalg    Linux AF_ALG crypto backend driver
  capstone        capstone disassembler support
  debug-mutex     mutex debugging support
  libpmem         libpmem support
  xkbcommon       xkbcommon support
  rng-none        dummy RNG, avoid using /dev/(u)random and getrandom()
  libdaxctl       libdaxctl support
第一台虚拟机

要创建虚拟机,首先要创建一个虚拟磁盘,然后从光驱启动此虚拟机:

Shell
1
2
3
4
5
6
7
8
9
10
11
12
mkdir -p ~/Vmware/KVM
 
# 以qcow2格式创建一个16G的虚拟磁盘,注意,默认不会预先分配空间
qemu-img create -f qcow2 ~/Vmware/KVM/centos7-base.img 16G
 
# 指定光盘镜像,从光驱启动虚拟机
# -hda 第一块硬盘的镜像
# -cdrom 光驱的镜像,你可以把宿主的/dev/cdrom传入,这样可以使用物理光驱
# -boot 指定启动顺序,d表示第一个光驱,c表示第一块硬盘
# -m 为虚拟机分配多少内存,默认单位M,默认128M
qemu-system-x86_64 -enable-kvm -hda ~/Vmware/KVM/centos7-base.img  -boot d -m 512
                   -cdrom ~/Software/OS/CentOS-7-x86_64-Minimal-1503-01.iso

上述命令执行完毕之后,会弹出一个窗口,该窗口相当于虚拟机的显示器。你可以在其中完成操作系统的安装。安装完毕后,执行下面的命令,即可启动虚拟机:

Shell
1
qemu-system-x86_64 -enable-kvm -hda ~/Vmware/KVM/centos7-base.img -m 512

后续几个章节,我们深入学习客户机硬件的定制,以满足不同应用场景的需要、提高客户机的性能。

配置CPU

使用选项 -cpu 选项可以选择客户机使用的CPU,执行 qemu-system-x86_64 -cpu help 可以列出QEMU支持的CPU名称、可用的CPUID标记。

你可以这样配置一个CPU:

Shell
1
2
-cpu SandyBridge,+erms,+smep,+fsgsbase,+pdpe1gb,+rdrand,+f16c,+osxsave,+dca,+pcid,+pdcm,\
     +xtpr,+tm2,+est,+smx,+vmx,+ds_cpl,+monitor,+dtes64,+pbe,+tm,+ht,+ss,+acpi,+ds,+vme

+表示启用CPU特性,如果要禁用CPU特性,可以使用 - 。

SMP配置

所谓对称多处理(Symmetrical Multi-Processing) ,是指在一个计算机上汇集了一组处理器,各处理器共享内存子系统以及总线结构。在PC机上QEMU最多可以模拟255个CPU。

你可以这样配置SMP: -smp 1,sockets=1,cores=1,threads=1 。这个配置表示主板上有一个CPU插槽、1个CPU、每个CPU具有1核心、每个核心具有1个硬件线程(超线程)。

配置磁盘

你可以在宿主机上创建一个磁盘镜像文件,然后供客户机使用。客户机磁盘I/O都将针对此文件。镜像文件可以有几种格式。

Raw镜像

这种镜像的特点是格式简单,性能较好。

你的文件系统(例如Ext3)必须支持稀疏文件(sparse file),才能避免不必要的磁盘空间占用。稀疏文件是一种高效使用磁盘空间的技术,当文件大小很大,而其绝大部分块都是空白(未使用)的时,可以基于文件元数据来表示那些空白的块(而不是真实的硬盘空间)。

创建Raw镜像:

Shell
1
2
3
4
5
6
7
8
qemu-img create -f raw hda.img 1G
 
# 查看镜像信息
qemu-img info hda.img
# image: hda.img
# file format: raw
# virtual size: 1.0G (1073741824 bytes)
# disk size: 0

你也可以使用dd命令产生Raw镜像,例如:

Shell
1
2
3
4
# 产生非稀疏文件:块大小1MB,写入1024个块,虚拟大小1G,实际大小1G
dd if=/dev/zero of=hda.img bs=1024k count=1024
# 产生稀疏文件:块大小1MB,写入0个块,虚拟大小1G,实际大小0
dd if=/dev/zero of=hda.img bs=1024k count=0 seek=1024
qcow2镜像

qcow2镜像的动态增长的,即使文件系统不支持稀疏文件,它也会尽可能的小。qcow2支持Copy-on-write、镜像、压缩、加密。 

正是由于qcow2支持Copy-on-write,我们才可以使用backing file——用一个镜像保存针对另外一个镜像的改变,而后面那个镜像不需要被改动。这是多虚拟机公用一个Base镜像,以及Snapshot的基础。

qcow2原理

qcow2镜像文件的结构如下图所示:

qcow2fmt

qcow2镜像文件由一个头、几张表、数据簇组成。所有数据都存放在数据簇(Data Clusters)中,每个数据簇是512字节的扇区。为了方便管理这些数据簇,qcow2建立了两级表:L1、L2。其中L1表的条目指向L2表,而L2表的条目指向数据簇。

要定位数据,需要3个偏移量构成的数组:

  1. 通过位于Header中的L1表指针  +offset[0],得到L2表的指针
  2. L2表指针 + offset[1],得到数据簇指针
  3. 数据簇指针 + offset[2],得到目标数据的指针
创建qcow2镜像

你可以这样创建一个qcow2镜像:

Shell
1
qemu-img create -f qcow2 hda-back.img 16G
转为backing file

然后,在未来某个时刻把它作为backing file使用:

Shell
1
qemu-img create -f qcow2 -o backing_file=hda-back.img hda.img
压缩、加密和扩展

镜像hda.img在一开始是空白的,所有数据都是从hda-back.img中获取,一旦发生写入操作,hda.img就开始有数据而hda-base.img保持不变。

使用下面的命令可以压缩一个qcow2镜像:

Shell
1
qemu-img convert -c -f qcow2 -O qcow2 hda.img hda.compressed.img

使用下面的命令可以为一个qcow2镜像设加密:

Shell
1
2
qemu-img convert -o encryption -f qcow2 -O qcow2  hda.img hda.encrypted.img
# 提示输入密码

使用压缩镜像启动虚拟机时,必须在Monitor中输入密码才可以。

使用下面的命令,可以扩展一个qcow2镜像的大小:

Shell
1
qemu-img resize hda.img +10G

注意:扩大得到的空间,不会被分区或者格式化。 

清理空白

要移除镜像中的spare space,直接qcow2-to-qcow2转换即可,压缩(-c)可选:

Shell
1
qemu-img convert -O qcow2 source.qcow2 shrunk.qcow2
变基rebase

rebase操作用于改变一个镜像的backing镜像:

Shell
1
2
3
4
5
6
7
8
9
10
11
# -u 表示unsafe模式,在此模式下,仅仅改变backing文件的路径,不对文件内容进行检查
#    用于backing文件移动的情况
# -p 表示safe模式,在此模式下,执行真正的rebase操作。backing文件的内容可能和之前
#    不同,qemu-img会小心处理,确保VM可见的内容不变。为达成这一点,新旧backing
#    文件的差异,会合并到被改变镜像中
                    # 格式
qemu-img rebase -u  -f qcow2  
  # 新的backing文件位置                                      新backing文件格式
  -b /home/alex/Vmware/libvirt/images/sdd/xenial-base.qcow2 -F qcow2
  # 被处理镜像文件
  /home/alex/Vmware/libvirt/images/sdd/xenial-100.qcow2
格式转换

你可以把一个镜像的格式在Raw和qcow2之间进行转换:

Shell
1
2
# 把Raw格式的hda.img转换为qcow2格式的hda.qcow2
qemu-img convert -f raw -O qcow2 hda.img hda.qcow2
使用快照

快照(Snapshot)是Copy-on-write的一种应用。QEMU支持两种快照:

  1. 内部快照(internal snapshot):在qcow2镜像的snapshot table中维护的快照,所有快照都存放在一个镜像文件中
  2. 外部快照(external snapshot):与Backing file很类似,在外部文件中创建新的镜像,原先的镜像只读
内部快照

内部快照的原理是:

  1. 创建一个Snapshot后,在Snapshot Table中新增一项,复制L1 Table
  2. 当L2 Table或者Data Cluster发生改变,则把改变前的数据复制一份(Copy-on-write),由新创建的Snapshot的L1 Table来管理
  3. L2 Table或者Data Cluster的变化,直接写到原始位置
  4. 要删除快照,很简单,直接把Snapshot Table对应项、以及复制的L1-L2-DS删除即可
  5. 要加载快照,则需要依据L1-L2-DS信息,将其合并到镜像的L1-L2-DS信息中

可以使用Monitor来创建、加载、删除内部快照:

Shell
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# 保存一个内部快照
(qemu) savevm snapshot-1
 
qemu-img info hda.img
# 输出如下:
#Snapshot list:
#ID        TAG                 VM SIZE                DATE       VM CLOCK
#1         snapshot-1             112M 2016-09-07 18:05:48   00:00:21.536
#Format specific information:
#    compat: 1.1
#    lazy refcounts: false
 
# 加载内部快照
(qemu) loadvm snapshot-1
 
# 删除内部快照
(qemu) delvm snapshot-1
外部快照

外部快照与内部快照相反:内部快照是原数据变化,外部快照则是新文件变化。

可以使用Monitor来管理外部快照:

Shell
1
snapshot_blkdev ide0-hd0 snapshot.img qcow2
配置客户机磁盘

有了磁盘镜像文件后,你需要为qemu-system-*指定参数,给客户机增加磁盘。有几种不同的配置方式:

Shell
1
2
3
4
5
6
7
8
9
10
# 最简单的方式
-hda hda.img
 
# 使用-drive配置块设备,可以指定if为virtio来提升性能
-drive file=hda.img,index=0,media=disk,if=virtio
 
# 使用-device配置通用设备
-drive file=hda.img,if=none,id=virtio-disk0,format=qcow2,cache=none 
# 可以指定virtio-blk-pci来提升性能
-device virtio-blk-pci,scsi=off,bus=pci.0,addr=0x4,drive=virtio-disk0,bootindex=1
配置网络

QEMU中的网络,包含两部分的内容:

  1. 客户机使用的虚拟网络设备
  2. 和上述虚拟设备通信的网络后端,这些后端负责把虚拟设备的数据包发到宿主机的网络中

要创建一个网络后端,可以指定如下选项:

Shell
1
2
3
4
# TYPE为后端类型:user、tap、bridge、socket、vde等
# id为一个标识符,将虚拟网络设备和网络后端关联在一起
# 如果客户机有多个虚拟网络设备,则每一个都需要自己的网络后端
-netdev TYPE,id=NAME,...

QEME支持多种网络后端。

USER后端

如果没有指定网络选项,QEMU默认会模拟单张Intel e1000 PCI网卡,该网卡基于user后端(SLIRP)连接到宿主机:

Shell
1
2
3
4
5
6
# 不指定网络
qemu
# 等价配置。自0.12开始废弃的配置方式 -net nic相当于-device DEVNAME;-net TYPE相当于-netdev TYPE
qemu -hda disk.img -net nic -net user
# 等价配置。-netdev指定网络后端,-device指定虚拟网络设备,后者通过netdev字段引用后端的ID
qemu -netdev user,id=network0 -device e1000,netdev=network0

在客户机看来:

  1. 本身的IP地址被分配为 10.0.2.15+
  2. 分配IP的虚拟DHCP为 10.0.2.2
  3. 虚拟DNS服务器为 10.0.2.3
  4. 虚拟Samba服务器为 10.0.2.4,客户机可以通过此服务器访问宿主机的文件系统

用户模式网络可以很方便的访问网络资源。但是它有很多限制:

  1. 默认的,它运作方式类似于防火墙,且不允许任何入站流量。这个限制可以通过端口重定向解决
  2. 仅仅支持TCP、UDP协议,对于ICMP则不支持
  3. 性能比较差

为了支持入站请求,你可以使用端口重定向(Redirecting ports)——把针对宿主机某个端口的请求转发给客户机的某个端口。映射后,客户机可以对外提供SSH、HTTP等服务:

Shell
1
2
3
4
5
# 把宿主机的7080端口重定向到客户机的80端口;把宿主机的7022端口重定向到客户机的22端口
qemu-system-x86_64 -redir tcp:7080::80 -redir tcp:7022::22 -hda ~/Vmware/KVM/centos7-base.img -m 512 
 
# 从宿主机SSH到客户机
ssh root@127.0.0.1 -p 7022

你可以不使用默认的10.0.2网段:

Shell
1
-netdev user,id=network0,net=192.168.5.0/24,dhcpstart=192.168.5.9 
客户机OS配置

依据客户机安装的操作系统,可能需要进行一些配置,才能正常使用网络。以CentOS 7 Minimal + 用户模式网络为例,需要修改以下配置文件:

/etc/sysconfig/network
1
2
3
NETWORKING=yes
# 如果不使用IPV6
NETWORKING_IPV6=no

/etc/sysconfig/network-scripts/ifcfg-ens3
1
2
3
4
# 如果不使用IPV6
IPV6INIT=no
# 开机启动此网卡,默认不启动
ONBOOT=yes

网关、DNS不需要设置。修改完这些配置文件后,重启客户机网络: /etc/init.d/network restart  。然后执行 yum update 测试一下能否正常联网(不要使用ping测试)

TAP后端

QEMU的TAP后端利用宿主机的TAP设备,为客户机提供完整的桥接网络支持,如果外部需要使用标准端口连接到客户机, 或者多个客户机需要相互通信,可以使用该方式。 TAP后端还具有以下优势:

  1. 非常好的性能
  2. 可以配置以支持各种网络拓扑

但是,你需要在宿主机上进行网络拓扑的配置,而且各种系统的配置不同。

使用TAP后端前,你需要确认你的宿主机的内核支持TAP网络接口: /dev/net/tun 文件存在则说明支持。如果没有这样的文件,可以尝试手工创建:

Shell
1
2
3
sudo mkdir /dev/net
sudo mknod /dev/net/tun c 10 200
sudo /sbin/modprobe tun
基于TAP的私有桥接网络

如果你想创建几个客户机之间的私有网络,可以使用该方式。未参与进来的客户机、真实网络无法看到此网络。

如果你不是root,则你需要 /dev/kvm 的读写权限。

首先,添加一个以太网桥设备:

Shell
1
2
3
4
5
6
7
8
9
10
11
12
13
sudo ip link add br0 type bridge
# 也可以使用:sudo brctl addbr br0添加网桥
# 要删除网桥,执行: ip link delete br0
# 注意:网桥会在重启后消失
 
# 启用此网桥
sudo ip link set br0 up
 
# 为网桥分配IP地址
sudo ip addr add 10.0.0.1 dev br0
 
# 在宿主机添加一条直接路由,便于它能和客户机通信
sudo ip route add 10.0.0.0/8 dev br0

创建一个创建TAP设备并桥接到网桥的脚本:

/usr/bin/qemu-ifup
Shell
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#!/bin/sh
 
switch=br0
 
if [ -n "$1" ];then
        # tunctl -u `whoami` -t $1
        # 添加一个tap设备,在我的机器上不需要,原因见下面
        # ip tuntap add $1 mode tap user `whoami`
        # 不知道从什么时候开始,QEMU会在执行此脚本之前就创建好tap设备,因此会报下面的错误
        # ioctl(TUNSETIFF): Device or resource busy
        # 启动tap设备
        ip link set $1 up
        # brctl addif $switch $1
        # 将网桥和tap设备进行桥接
        ip link set $1 master $switch
        exit 0
else
        echo "Error: no interface specified"
        exit 1
fi

创建一个生成随机MAC地址的脚本:

/usr/bin/qemu-genmac
Shell
1
2
3
#!/bin/bash
# generate a random mac address for the qemu nic
printf 'DE:AD:BE:EF:%02X:%02X\n' $((RANDOM%256)) $((RANDOM%256))

启动客户机的脚本:

/usr/bin/qemu-start
Shell
1
2
3
4
5
6
7
8
9
#!/bin/bash
# $1 base name of virtual disk
# $2 memory size
# $3 tap device id
 
mac=`/usr/bin/qemu-genmac`
src=/usr/bin/qemu-ifup
sudo qemu-system-x86_64 -enable-kvm -device e1000,netdev=$3,mac=$mac -netdev tap,id=$3,script=$src,downscript=no \
                        -hda ~/Vmware/KVM/$1.img -m $2

为上面的脚本文件添加可执行权限:

Shell
1
2
3
sudo chmod +x /usr/bin/qemu-ifup-br0
sudo chmod +x /usr/bin/qemu-genmac
sudo chmod +x /usr/bin/qemu-start-br0

执行下面的命令,启动一台客户机(或者更多虚拟机,但是命令中的tap0要更换为不同的名字):

Shell
1
/usr/bin/qemu-start centos7-base 512 tap0

修改客户机的IP地址,使用10.0.0.0/8网段:

/etc/sysconfig/network-scripts/ifcfg-ens3
1
2
3
4
5
6
7
8
9
10
11
12
13
14
TYPE=Ethernet
BOOTPROTO=static
DEFROUTE=yes
PEERDNS=yes
PEERROUTES=yes
IPV4_FAILURE_FATAL=no
IPV6INIT=no
NAME=ens3
UUID=d9f47102-b177-4a27-ae98-86f6939d6680
DEVICE=ens3
ONBOOT=yes
IPADDR=10.0.0.10
PREFIX=8
GATEWAY=10.0.0.1

好了,你现在可以互相ping客户机和宿主机,应该可以正常连通了。 

私有桥接下访问互联网

上一节介绍的这种基于TAP的私有桥接网络,可以让客户机、宿主机相互连通,但是客户机无法访问互联网。

要解决此问题,你可以选择以下方法之一:

  1. 让客户机通过宿主机暴露的HTTP/SOCKS代理上网
  2. 配置宿主机的路由规则,设置好源地址转换即可:
    Shell
    1
    2
    3
    4
    # 宿主机需要启用IP转发功能,这样它就可以像路由器那样中转IP封包了
    sudo sysctl -w net.ipv4.ip_forward=1
    # 对客户机网段进行源地址转换
    sudo iptables -t nat -A POSTROUTING  -s 10.0.0.0/255.0.0.0 ! -d 10.0.0.0/255.0.0.0 -j MASQUERADE 
公共桥接网络

此方式和私有桥接网络类似,主要区别是,除了TAP设备桥接到网桥之外,以太网卡(例如eth0)也桥接到网桥(例如br1)。

你可以通过发行版的配置文件来配置网桥:

/etc/network/interfaces
1
2
3
4
5
6
7
8
9
10
11
# 注意网络管理器组件的影响
# 去掉 auto eth0,改为:
auto br1
 
# 配置br1
iface br1 inet dhcp
    bridge_ports    eth0
    bridge_stp      off
    bridge_maxwait  0
    bridge_fd       0
    # 这里附加上原来属于eth0的配置

或者基于脚本来配置: 

Shell
1
2
3
4
5
6
7
sudo ip link add br1 type bridge
sudo ip link set br1 up
sudo ip link set eth0 master br1 
 
# DHCP
sudo killall dhclient && sudo ip addr flush dev eth0
sudo dhclient br1

无论用哪种方式,都应该注意到eth0的IP地址需要转移给br1,这样才能确保网络正常运作——br1必须在链路层接收到相关ARP请求,并决定是否需要转发给客户机,eth0没有这种转发能力。

如果eth0所在网络是基于DHCP的,那么客户机配置为DHCP后,会自动获取公共IP地址。否则,需要手工设置客户机的IP地址。 

基于TAP的桥接的简化配置

现在QEMU支持自动桥接TAP设备到宿主机的一个网桥,因此你不再需要编写脚本,修改网络后端为bridge即可:

Shell
1
-netdev bridge,id=tap0,br=br0

注意,使用上述选项时,QEMU需要读取配置文件/etc/qemu/bridge.conf,你只需在此文件中添加一行代码: allow br0 

你可以编写如下脚本自动创建网桥、配置iptables规则。示例:

Shell
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# Create private bridge link for QEMU
/sbin/ip link add br0 type bridge
/sbin/ip link set br0 up
/sbin/ip addr add 10.0.0.1 dev br0
/sbin/ip route add 10.0.0.0/8 dev br0
# NAT for 10.0.0.0/8
/sbin/iptables -t nat -A POSTROUTING  -s 10.0.0.0/255.0.0.0 ! -d 10.0.0.0/255.0.0.0  -j MASQUERADE
 
 
# Create public bridge link for QEMU
/sbin/ip link add br1 type bridge
/sbin/ip link set br1 up
/sbin/ip link set eth0 master br1
/usr/bin/killall dhclient && /sbin/ip addr flush dev eth0
/sbin/dhclient br1
macvtap直连

建议和libvirt一起使用macvtap。 

基于libvirt的桥接

在使用libvirt时,客户机(Domain)的网络接口配置可以简化为:

XML
1
2
3
4
5
6
<interface type='bridge'>
    <mac address='DE:AD:BE:EF:F1:00'/>
    <source bridge='br0'/>
    <target dev='tap0'/>
    <model type='virtio'/>
</interface>
基于libvirt虚拟局域网的桥接

可以使用libvrit的虚拟局域网,这样宿主机上不会为客户机创建专门的tap设备,那些手工编写的脚本也全都不需要了。虚拟网络配置示例:

XHTML
1
2
3
4
5
6
7
8
9
10
11
12
<network>
  <name>default</name>
  <uuid>9bae4de8-ca58-48c5-ba58-109aebf8b954</uuid>
  <forward mode='nat'>
  </forward>
  <bridge name='virbr0' stp='on' delay='0'/>
  <ip address='10.0.0.1' netmask='255.0.0.0'>
    <dhcp>
      <range start='10.0.0.100' end='10.0.0.200'/>
    </dhcp>
  </ip>
</network>

客户机(Domain)的网络接口配置示例:

XML
1
2
3
4
5
<interface type='network'>
    <mac address='DE:AD:BE:EF:F1:00'/>
    <source network='default'/>
    <model type='virtio'/>
</interface>

另外,libvirt的虚拟网络提供了DHCP功能,因此客户机的IP地址不需要静态设置。

其它配置
SMBIOS

SMBIOS即DMI表,存放了X86系统硬件信息,这个表依据DMI type分为数十个段,type0是BIOS、type1是系统信息、type2是主板信息……

QEMU支持模拟这些信息,例如:

Shell
1
2
# 设置客户机的type1信息
-smbios type=1,manufacturer=OpenStack Foundation,product=OpenStack Nova,version=2011,serial=8059dfb4,uuid=1f8ee7f308
内存

要设置客户机的内存容量,可以使用 -m ,默认单位MB。

客户机没必要占据着空闲的内存不用,因此我们一般启用内存实际大小的动态调整功能,例如:

Shell
1
-device virtio-balloon-pci,id=balloon0,bus=pci.0,addr=0x5
半虚拟化和virtio

在本文的第一章,谈到周围硬件性能的时候,我们提及了virtio——它是规定了虚拟设备的前端驱动与宿主机硬件的后端驱动之间通信接口的标准,并且知道目前的很多Linux发行版已经把virtio驱动编译进内核了。前面的章节我们也使用了很多virtio驱动,包括磁盘、网络、内存相关的。

基于virtio驱动的虚拟设备,我们成为“半虚拟化设备”,因为这些设备驱动知道自己工作在虚拟化模式下。为客户机配置半虚拟化设备,可以提高内存、硬盘、网络方面的性能,由其对于网络,性能提升很明显。

除了virtio,Vmware Tools也属于半虚拟化驱动,QEMU客户机也可以利用Vmware Tools(例如-vga指定vmware)。virtio驱动的具体实现包括:virtio-blk、virtio-net、virtio-pci、virtio-balloon、virtio-console等。

半/全虚拟化的区别如下:

  1. 在全虚拟化状态下,Guest OS不知道自己是虚拟机,于是像发送普通的IO一样发送数据,被Hypervisor拦截,转发给真正的硬件。
  2. 在半虚拟化状态下,Guest OS知道自己是虚拟机(需安装半虚拟化驱动),所以数据直接发送给半虚拟化设备,经过特殊处理,发送给真正的硬件
virtio-balloon

这是一个特殊的半虚拟化设备,它能够动态(不需要重启客户机)的调整客户机的内存大小。如果你指定了-m参数,则不能调整的比-m更大。使用选项 -balloon virtio 可以添加Ballooning设备。

virtio-blk

要基于半虚拟化来访问磁盘,可以使用选项: -drive file=vda.qcow2,if=virtio ,使用virto_blk驱动的硬盘,在客户机里对应的设备文件是/dev/vda(而IDE硬盘是/dev/hda、基于SATA的硬盘则显示为/dev/sda) 。

可以使用驱动virtio-blk-data-plane进一步提高性能(I/O性能较virtio-blk能提高10-20%),此驱动自QEMU 1.4开始引入。与传统的virtio-blk不同的是,virtio-blk-data-plane为每个块设备独立分配一个线程用于I/O处理,此线程不需要和QEMU执行线程同步、竞争锁。此驱动基于宿主机的原生AIO响应客户机的请求。启用此驱动的选项示例:

Shell
1
2
-drive if=none,id=drive0,cache=none,aio=native,format=raw,file=vda.img
-device virtio-blk-pci,drive=drive0,scsi=off,x-data-plane=on

但是,启用virtio-blk-data-plane后,存储迁移(storage migration)、热拔插、I/O限流(throttling) 等功能无法使用。而且该驱动仅支持Raw格式的磁盘。

virtio-net

要基于半虚拟化来访问网络,可以使用选项: -device virtio-net-pci,netdev=network0 。你应当总是考虑启用半虚拟化网卡,因为性能会有很大的提升。

宿主机网卡的某些特性可能会影响virtio的性能,例如:

  1. TSO(TCP Segmentation Offload):通过网络设备进行TCP段的分割,从而来提高网络性能
  2. GSO(Generic Segmentation Offload):类似,用TCPv6、UDP等传输层协议

你可以开关这些特性来测试对客户机网络性能的影响。要检查宿主机网卡是否支持、开启这些特性,可以执行命令: ethtool -k eth0 。

配置NBD

网络块设备(Network Block Device)是一种把虚拟块设备通过TCP/IP暴露出去,供远程共享访问的技术。

暴露NBD
通过套接字暴露

你可以通过UNIX套接字来暴露:

Shell
1
qemu-nbd -t -k /home/alex/Vmware/KVM/.images/fedora-108 fedora-108/hda.img

 也可以通过普通套接字来暴露:

Shell
1
qemu-nbd  -p 1025 fedora-108/hda.img 
挂载到NBD设备

甚至是把镜像直接挂载到宿主机的NBD设备中:

Shell
1
2
3
4
5
6
7
8
9
10
11
12
13
14
# 在宿主机上启用NBD内核模块,最多16个分区:
sudo modprobe nbd max_part=16
# 查看NBD设备文件
ls /dev/nbd*
# 输出/dev/nbd0 ... /dev/nbd15
 
# 挂载
sudo qemu-nbd -c /dev/nbd0 fedora-108/hda.img
 
# 查看nbd0的分区情况
sudo fdisk -l /dev/nbd0
#  Device Boot Start End Blocks Id System
#  /dev/nbd0p1 * 2048 1026047 512000 83 Linux
#  /dev/nbd0p2 1026048 33554431 16264192 8e Linux LVM
使用NBD

客户机可以直接使用NBD作为磁盘:

Shell
1
2
3
4
# 使用UNIX套接字:
qemu-system-x86_64 -hda nbd:unix:/home/alex/Vmware/KVM/.images/fedora-108
# 使用普通套接字
qemu-system-x86_64 -hda nbd:10.0.0.1:1025
迁移

QEMU支持离线或者在线的迁移,你可以在Monitor中使用迁移命令。当迁移完毕后,虚拟机会在目标主机上继续运行。

AMD和Intel宿主机之间可以随意的迁移虚拟机,64位虚拟机只能迁移到64位宿主机上,32位则没有限制。某些老旧的Intel CPU不支持NX(禁止执行比特位),这种CPU处于启用NX的宿主机群中,会导致问题,你需要禁止客户机的NX: -cpu qemu64,-nx 。

QEMU的迁移功能具有以下特性:

  1. 极短暂的客户机停机时间
  2. 如果迁移成功,则客户机在目标主机上运行;如果迁移失败,则客户机继续在源主机上运行
  3. 几乎对硬件没有依赖
使用共享存储

使用共享存储时,QEMU迁移会很便利,因为不牵涉到磁盘映像的移动。共享存储包括:NFS、NBD、SAN等。 我们以NBD为例说明:

  1. 启动供源、目的虚拟机共享的NBD服务: qemu-nbd -p 1025 --share=2 fedora-108/hda.img 
  2. 确保源、目的虚拟机的配置,它们要具有相同的网络环境
  3. 启动源虚拟机:
    Shell
    1
    2
    sudo qemu-system-x86_64 -netdev bridge,id=tap0,br=br0 -device virtio-net-pci,netdev=tap0,mac=DE:AD:BE:EF:F1:08
                            -hda nbd:10.0.0.1:1025 -monitor stdio -enable-kvm  
  4. 源虚拟机运作一段时间后,其宿主机的硬件需要维护,因此准备迁移。在另外一台宿主机上启动目的虚拟机,并监听migration端口:
    Shell
    1
    2
    # qemu选项同源虚拟机,附加:
    -incoming tcp:0:4444

     注意,这个监听端口是开在宿主机上的。实际上,以-incoming启动目的虚拟机后,虚拟机是处于Stopped状态的

  5. 登录到源虚拟机,确认它与目的虚拟机的宿主机之间的网络是畅通的
  6. 在源虚拟机的Monitor中,发起迁移命令: (qemu) migrate -d tcp:10.0.0.1:4444 
  7. 在迁移过程中,可以通过 info migrate 查看迁移状态,完毕后会显示Migration status: completed,并列出迁移消耗的时间、停机时间
  8. 迁移完成后,源虚拟机变为Stopped,而目的虚拟机开始运行,获得源虚拟机的全部瞬时状态
不使用共享存储

这种情况下,源虚拟机的磁盘镜像需要拷贝到目标宿主机中。因而需要更长的时间、更多的网络带宽消耗。步骤如下:

  1. 查看源虚拟机的磁盘镜像信息: qemu-img info fedora-108/hda.img 
  2. 在目的机器上创建与之大小(Virtual size)一致的空磁盘镜像: qemu-img create -f qcow2 fedora-108-m/hda.img 16G 
  3. 使用与共享存储一样的步骤进行迁移,只是源、目的虚拟机使用各自的磁盘镜像
监控与调试

前面的章节我们已经多次使用QEMU的监控功能,通过使用QEMU的HMI(Monitor)可以在(qemu)提示符下进行各种监控操作,包括查看虚拟机信息、动态添加设备、执行迁移等等。在《QEMU命令与快捷键》一章我们会详细的讲解HMI命令,本章主要介绍监控相关的QEMU配置

基于HMI(Monitor)监控

你可以通过多种方式使用Monitor:

  1. 默认的,可以在QEMU的虚拟机窗口中,按Ctrl + Alt + 2切换到Monitor
  2. 可以使用 -monitor stdio ,让Monitor重定向到启动虚拟机的Terminal
  3. 可以启动一个TCP监听 -monitor tcp::4444,server,nowait ,这样你可以 telnet hostip:4444 访问Monitor
  4. 可以通过字符设备: -chardev stdio,id=x -monitor chardev=x 访问Monitor
基于QMP监控

非交互式监控时,QEMU监控协议(QEMU Monitor Protocol)是更好的选择,这是一个基于JSON格式的协议。要启用QMP,你可以:

  1. 基于stdio: -qmp stdio 
  2. 基于TCP: -qmp tcp:localhost:4444,server 
  3. 基于UNIX Socket: -qmp unix:./qmp-sock,server 
最佳实践

以下列出一些应用基于QEMU/KVM的虚拟化方案时的最佳实践:

  1. 使用半虚拟化驱动virtio
    1. 性能好:延迟低、吞吐量高
    2. 纯虚拟设备的劣势:需要高吞吐能力的设备在硬件方面会有特殊的实现,这些纯虚拟设备是没法利用的
    3. 网络、块设备、内存,都可以使用virtio
    4. 兼容性较差
  2. 虚拟机最好直接使用块设备做存储
    1. 性能好、无需管理宿主机的文件系统、无需管理稀疏文件
    2. I/O 缓存以4K为边界
    3. 如果没有条件使用块设备,只能使用镜像文件
    4. 宿主机最好使用ext3文件系统,ext4的barrier会影响性能
    5. Raw格式镜像的性能优于qcow2
    6. 选择正确的缓存策略,缓存模式推荐none,I/O调度器推荐Deadline I/O scheduler
  3. CPU配置
    1. 每个客户机相当于一个进程,而每个客户机的虚拟CPU相当于一个线程。因此超配CPU是可行的
    2. CPU超配可能带来额外的上下文切换,影响性能
    3. 要保证客户机获得足够的时间片,可以利用cgroup的cpu.cfs_period_us、cpu.cfs_quota_us来干预CFS调度器的行为
    4. Pin CPU:可以将虚拟CPU Pin到一个物理CPU,或者一组共享缓存的物理CPU,便于缓存共享。缺点是Pin导致其它空闲CPU可能得不到利用
  4. 内存配置
    1. 使用内核特性KSM(Kernel Same Page Merging),KSM通过扫描将相同的内存区域设置为共享,并且Copy-on-write。共享内存节约可以内存空间,但是内存扫描同时影响性能
    2. 尽量避免使用swap,可以设置/proc/sys/vm/swappiness=0
  5. 网络配置
    1. 使用tap类型的网络后端
    2. 启用PCI passthough可以提高性能,但是影响迁移
QEMU命令与快捷键
HMI

HMI即 Human Monitor Interface,是QEMU在运行客户机时提供的一个console(下面我们称此console为Monitor),它让你可以和运行中的虚拟机进行交互,你可以获得内存Dump、列出虚拟设备树、获取屏幕截图等操作。

访问HMI

默认情况下QEMU使用SDL来显示客户机的视频输出,此所谓图形模式。如果启用-nographic选项则会禁用图形模式。

在图形模式下,你可以使用以下方式之一访问HMI:

  1. 在客户机的虚拟控制台(客户机弹窗)访问HMI,按Ctrl + Alt + 2可以切换到Monitor,在其中你可以调用HMI命令
  2. 指定-monitor stdio,则启动虚拟机的Terminal变为Monitor

在基于-nographic的非图形模式下,Monitor、虚拟串口都被重定向到stdio,你可以Ctrl + a c来切换。你可以同时把虚拟串口配置为系统控制台,这样你可以通过单个窗口完成客户机登录、HMI操作

HMI命令
命令 说明
info

显示客户机的相关信息,示例:

Shell
1
2
3
4
5
6
7
8
info kvm           # 显示KVM支持情况
info pci           # 显示PCI信息
info qtree         # 显示QEMU系统总线树
info network       # 显示网络设备信息
info block         # 显示块设备信息
info blockstatus   # 显示块设备读写统计信息
info snapshots     # 显示快照信息
info migrate       # 显示迁移状态
memsave Dump客户机内存到宿主机的文件
screendump 屏幕截图
sendkey 键盘控制,示例: sendkey ctrl-alt-f1 
quit 退出客户机addr=0xM.0xN
system_powerdown 关闭虚拟机电源
system_reset 重启虚拟机
system_wakeup 唤醒休眠中的虚拟机
savevm

保存一个虚拟机快照,示例: savevm blankos 

loadvm 从快照加载虚拟机,示例: loadvm blankos 
delvm 删除一个虚拟机快照
snapshot_blkdev_internal 创建一个内部的块设备(主要指硬盘)快照,示例:
Shell
1
2
3
info block
# ide0-hd0: /home/alex/Vmware/KVM/fedora-108/hda.img (qcow2)
snapshot_blkdev_internal  ide0-hd0 blankos
snapshot_delete_blkdev_internal 删除一个内部的块设备快照
snapshot_blkdev 创建一个外部的块设备快照,示例:
Shell
1
snapshot_blkdev ide0-hd0 blankos.img

如果指定了文件参数,则此文件成为新的root镜像

migrate 执行虚拟机迁移
migrate_cancel 取消虚拟机迁移
migrate_set_speed 限制迁移带宽消耗
qemu-system-x86_64

该命令即QEMU模拟器,使用它可以指定硬件设备,并从虚拟磁盘镜像启动一台客户机。

常用选项
选项 说明
-machine

指定虚拟的客户机的类型及其属性,选项格式:

Shell
1
-machine [type=]name[,prop=value[,...]]

其中type为机器类型,可以调用 qemu-system-x86_64 -machine help 获得完整机器类型列表,每种机器都标注了主板芯片组的类型

你可以指定多个可选的属性:

accel=accels1[:accels2[:...]]    启用加速器,可用的包括kvm、xen、tcg,加速器可以指定多个,后面的是备选

-cpu 指定虚拟的CPU类型,可以通过 qemu-system-x86_64 -cpu help 查看可用CPU列表
-smp

虚拟一个SMP系统,在PC机最多虚拟255CPU,选项格式:

Shell
1
-smp [cpus=]n[,cores=cores][,threads=threads][,sockets=sockets][,maxcpus=maxcpus]

你可以指定多个属性:
cpus    处理器个数
cores     每个处理器的核心数
threads    每个核心的线程数
sockets    CPU插槽数
maxcpus    最大可热拔插的CPU数

-global 设置驱动属性为指定的值,选项格式: -global driver.prop=value ,示例:
Shell
1
-global ide-drive.physical_block_size=4096

使用该选项,你可以改变由机型(machine)预定义的设备属性,如果要添加设备,请使用-device 

-boot 设置客户机的磁盘启动顺序,选项格式:
Shell
1
2
-boot [order=drives][,once=drives][,menu=on|off][,splash=sp_name]
      [,splash-time=sp_time][,reboot-timeout=rb_timeout][,strict=on|off]

drives值指定为磁盘符号构成的字符串,这些符号的形式取决于客户机的架构,在X86 PC上:
        a  软盘1;b 软盘2;c 第一个硬盘;d 第一个光驱;n-p 四个以太网卡

你可以指定多个属性:
order    磁盘启动顺序
once      仅生效一次的启动顺序
menu    交互式启动,显示菜单
splash    显示一个开机画面,图片必须是JPEG/BMP格式且分辨率支持SVGA模式
splash-time  开机画面显示的时间
reboot-timeout    如果启动失败,多少ms后重启

-m 设置客户机的内存大小,单位MB
-mem-path 从一个临时文件来创建客户机内存
可以同时指定  -mem-prealloc  来预分配内存
-soundhw 启用声卡,选项格式:
Shell
1
2
3
4
5
6
7
8
-soundhw card1[,card2,...]
# 或者
-soundhw all
 
# 显示可用硬件列表
qemu-system-x86_64 -soundhw help
# 示例
qemu-system-x86_64 -soundhw ac97 disk.img
-balloon

控制KVM的Automatic Ballooning功能。virtio balloon设备可以减少KVM客户机的内存大小,该特性用于主持客户机内存的over-committing——宿主机只有2G内存的情况下,创建两台2G内存的客户机。只要客户机实际使用的内存不到2G,那么多余的部分就可以返还给宿主机

选项格式:

Shell
1
2
3
4
# 禁用balloon设备
-balloon none
# 启用balloon设备,可以指定一个PCI地址
-balloon virtio[,addr=addr]
-device driver 添加一个设备驱动,并指定驱动属性,可用的属性取决于具体的驱动,选项格式: 
Shell
1
-device driver[,prop[=value][,...]]

要获得可用驱动、属性列表,可以: -device help  和 -device driver,help 

对于连接到PCI总线的设备,可以指定:
bus=pci.x ,此设备连接到第x+1个总线上
addr=0xM.0xN  此设备是总线上的第M个设备,这里使用设备的第N个Function,如果只有一个Function,则.0xN省略

该选项可以用于添加客户机的多种虚拟设备并进行细节上的配置(代替部分选项例如-boolean、-net nic),例如:

Shell
1
2
3
4
5
6
7
8
9
10
# 添加e1000网卡,以network0为后端
-device e1000,netdev=network0
# 添加基于Virtio的网卡,等价于 -net nic,model=virtio ...
-device virtio-net-pci,netdev=network0,id=net0,mac=DE:AD:BE:EF:F1:08,bus=pci.0,addr=0x3
 
# 启用virtio balloon设备(收回客户机空闲内存),等价于-balloon ...
-device virtio-balloon-pci,id=balloon0,bus=pci.0,addr=0x5
 
# 添加基于Virtio的硬盘(前端)
-device virtio-blk-pci,scsi=off,bus=pci.0,addr=0x4,drive=drive-virtio-disk0
-name 设置客户机的名称
-uuid 设置客户机的UUID
块设备选项
-fd* -fda、-fdb指定0、1软盘的镜像文件,你可以使用主机的软盘,例如/dev/fd0
-hd* -hda、-hdb、-hdc、-hdd指定0、1、2、3硬盘的镜像
-cdrom 指定光驱镜像,你可以可以使用主机的光驱,例如/dev/cdrom
-drive

定义一个新的磁盘驱动器,选项格式: -drive option[,option[,option[,...]]] 

你可以使用以下子选项:
file    在宿主机上的磁盘镜像文件
if    指定磁盘接口类型,可用的类型包括ide, scsi, sd, mtd, floppy, pflash, virtio
bus=bus,unit=unit 依据bus号、unit号来定义此磁盘驱动器被连接在何处
index    依据针对磁盘接口类型的序号来定义此磁盘驱动器被连接在何处
media    媒体类型,可选disk或cdrom
snapshot    是否启用快照功能,on/off
cache    在访问磁盘上的数据块时如何使用宿主机的缓存功能,none/writeback/unsafe/directsync/writethrough
aio    threads基于pthread的异步I/O;native基于Linux原生的异步I/O
format     指定磁盘格式,而不是去检测file,可选值raw/qcow2
serial    分配给磁盘的串号
addr    如果if=virtio,该选项指定磁盘控制器的PIC地址
readonly    设置磁盘为只读

cache的默认取值是writeback,该选项意味着,一旦数据进入宿主机的页缓存,QEMU就向客户机报告“写入已完成”。如果客户机程序正确的flush磁盘缓存,此选项是安全的。否则,宿主机断电将会导致客户机数据损坏。
为了防止上述数据丢失,你可以考虑设置cache为writethrough,这样只有宿主机把缓存刷出到磁盘后QEMU才会报告“写入已完成”,但是这样设置会导致严重的性能问题
directsync:类似于writethrough,只是绕过宿主机的页缓存
unsafe:宿主机可以缓存客户机的所有disk IO,客户机的sync请求被忽略

代替-cdrom的配置: -drive file=file,index=2,media=cdrom 
代替 -hda, -hdb, -hdc, -hdd的配置:

Shell
1
2
3
4
-drive file=file,index=0,media=disk
-drive file=file,index=1,media=disk
-drive file=file,index=2,media=disk
-drive file=file,index=3,media=disk
-mtdblock 指定主板内置闪存的镜像文件
-sd 指定SD卡镜像
-snapshot 写入到临时文件,而非硬盘镜像文件,这样,原始硬盘文件就不会被改变
显示选项
-display 选择一个显示类型:
curses    基于curses输出,如果客户机的图形设备支持文本模式,QEMU基于curses/ncurses接口显示输出;如果客户机图形设备运行在图形模式或者不支持文本模式,则不显示
none    不显示视频输出,客户机仍然可以模拟一个图形卡但是其输出不会显示给用户。该选项与-nographic不同,后者具有附加效果——改变串口、并口数据的目的地
gtk    在一个GTK窗口中显示视频输出
vnc    启动一个VNC服务器
-vnc 配置VNC,例如 -vnc 0.0.0.0:10 
-nographic

通常情况下,QEMU基于SDL库来显示VGA输出,如果使用该选项,则QEMU成为完全的命令行程序

尽管如此,QEMU还是把虚拟的串口重定向到控制台、与monitor复用。你可以基于串口控制台来调试虚拟机的内核

你可以在console和monitor之间切换

-curses

在文本模式下,直接在当前Terminal显示VGA输出,在图形模式下则什么都不显示,仅提示“1024 x 768 Graphic mode”之类的信息

-no-frame 不显示虚拟机窗口的外框、标题栏
-vga 指定虚拟的VGA显卡类型,可用的包括:
cirrus    默认,Cirrus Logic GD5446显卡,对于Windows,所有Win95之后的系统都能够识别此卡
std    支持Bochs VBE扩展的标准VGA扩展,如果客户机OS支持VESA 2.0 VBE扩展(例如XP)并且你希望使用高分辨率
vmware    Vmware的SVGA-II兼容显卡
qxl    使用spice协议时推荐此卡
none    禁用VGA显卡
-full-screen 以全屏模式启动
-g 设置初始的分辨率和颜色深度,选项格式: -g widthxheight[xdepth] 
网络选项
-net nic

创建一个新的网卡并把它连接到一个VLAN,选项格式:

Shell
1
-net nic[,vlan=n][,macaddr=mac][,model=type] [,name=name][,addr=addr][,vectors=v] 

你可以指定以下属性:
vlan=n    虚拟局域网编号,默认0。虚拟局域网仅在同一个QEMU进程内部有效,加入到同一个vlan的网卡可以接收到彼此的数据
macaddr 改变此网卡的MAC地址
addr    设置设备地址(仅PCI卡)
name    设备名称,在monitor命令中使用
model    网卡型号,在PC上默认创建e1000。你可以使用 -net nic,model=help 列出所有可用的网卡型号

-netdev user
-net user
添加一个User网络后端,选项格式:
Shell
1
2
-netdev user,id=id[,option][,option][,...]
-net user[,option][,option][,...]

你可以指定以下属性:
vlan=n    连接到虚拟局域网
id,name    设备名称,在monitor命令中使用
net=addr[/mask]    在客户机看来,此后端的IP地址,默认10.0.2.0/24
host=addr    在客户机看来,宿主机的IP地址是多少,默认段内第二个IP,例如10.0.2.2
restrict=on|off    如果启用,则客户机被隔离,这意味着客户机不能访问宿主机或者联网
hostname    内置DHCP服务器报告的客户机的名称
dhcpstart    内置DHCP服务器能分配的IP地址的其实值,默认段内第15各IP,例如10.0.2.15
dns    指定客户机看到的虚拟DNS服务器的地址,默认段内第三个IP,例如10.0.2.3
smb=dir[,smbserver=addr]    激活一个内置的SMB服务器,默认地址为段内第四个,例如10.2.2.4
hostfwd    重定向主机端口上的incoming TCP/UDP流量到客户机端口

-netdev tap
-net tap

添加一个TAP网络后端,连接宿主机的TAP网络接口到VLAN,选项格式:

Shell
1
2
-netdev tap,id=id[,fd=h][,ifname=name][,script=file][,downscript=dfile][,helper=helper]
-net tap[,vlan=n][,name=name][,fd=h][,ifname=name][,script=file][,downscript=dfile][,helper=helper]

你可以指定以下属性:
id    TAP设备的唯一标识,你只需要指定此标识,QEMU会自动在宿主机上创建对应的TAP设备
script    配置脚本,默认/etc/qemu-ifup。设置为no则禁用配置脚本
downscript    解除配置脚本,默认/etc/qemu-ifdown(空白文件)。设置为no则禁用配置脚本
fd    指定已经打开的宿主机TAP设备的句柄

-netdev bridge
-net bridge
添加一个TAP网络后端,连接宿主机的TAP网络接口到宿主机的一个网桥,这是TAP后端的script-free的简化版,选项格式:
Shell
1
2
-netdev bridge,id=id[,br=bridge][,helper=helper]
-net bridge[,vlan=n][,name=name][,br=bridge][,helper=helper]

你可以指定以下属性:
br    宿主机网桥名

此后端需要读取配置文件:

/etc/qemu/bridge.conf
1
allow br0
字符设备选项
-chardev

字符设备选项的通用格式为:

Shell
1
-chardev backend ,id=id [,mux=on|off] [,options]

backend 包括: null, socket, udp, msmouse, vc, ringbuf, file, pipe, console, serial, pty, stdio, braille, tty, parallel, parport, spicevmc.  spiceport
id    所有设备都必须有的标识符,可以是任何长度不超过127的字符串
mux=on|off    所有字符设备都可以进入多路复用模式,供多个前端使用。Ctrl + A和Ctrl + C用于切换前端
options    取决于后端

-chardev null 其行为类似于/dev/null
-chardev vc

连接到QEMU的文本控制台(text console),选项格式:

Shell
1
-chardev vc ,id=id [[,width=width] [,height=height]] [[,cols=cols] [,rows=rows]] 

width/height    控制台的宽度高度、单位像素

cols/rows    匹配文本控制台宽高

-chardev ringbuf

创建一个固定大小的环形缓冲区,选项格式: -chardev ringbuf ,id=id [,size=size] 

size    必须是2的幂,默认64K

-chardev pipe   创建一个双向的管道文件,选项格式: -chardev pipe ,id=id ,path=path 
-chardev file 记录来自客户端的流落到文件,选项格式: -chardev file ,id=id ,path=path 
-chardev console 发送来自客户端的流量到QEMU的标准输出
-chardev serial

发送来自客户端的流量到宿主机的一个串口设备,选项格式: -chardev serial ,id=id ,path=path 

path    宿主机的串口设备

-chardev pty 在宿主机上创建一个新的伪终端,并连接到它
-chardev tty

在Unix-like系统上可用,-chardev serial的别名

所谓TTY,即电传打字机,是由一个键盘、一个打印机组成的设备,在键盘上每打印一个字就会打印到纸张上。这个概念借用到UNIX领域,则打印的目标变成了屏幕。TTY可以用来指任何形式的Terminal,例如伪终端、虚拟控制台

Linux/Multiboot相关

-kernel

指定内核镜像,目标镜像可以是Linux内核或者multiboot格式

-append

指定内核命令行参数

-initrd 使用指定的文件作为初始内存盘(initial ram disk)
调试/专家选项
-serial

-serial dev    重定向虚拟串口到宿主机的字符设备dev,默认设备:图形模式下是vs;非图形模式下是stdio

你可以指定此选项最多4次,模拟最多4个串口;指定 -serial none 禁用所有串口

可用的宿主机字符设备有:
vc    虚拟控制台,可选的,指定宽高(像素/字符数):vc:800x600   vc80C:40Cb
stdio     标准输入输出,即启动QEMU的哪个Terminal
pty    伪终端
none  无设备
null    void设备
chardev:id    已命名的、通过-chardev选项配置的字符设备
/dev/tty    使用宿主机的tty

-monitor -monitor dev 重定向monitor到主机的字符设备dev,可用设备同上
-qmp -qmp dev    类似于-monitor但是以control模式开启 
-debugcon -debugcon dev    重定向调试控制台到宿主机字符设备
-pidfile 存储QEMU进程的PID到文件
-enable-kvm 启用基于KVM的全虚拟化支持 
-no-reboot 退出而不是重启
-no-shutdown 当客户机关机时,不退出QEMU而仅仅是停止模拟。你可以切换到Monitor并提交修改到磁盘镜像
-loadvm -loadvm file 从一个以保存的状态加载客户机
-daemonize

在初始化后,让QEMU变成一个守护进程。使用该选项,可以让QEMU进程和当前Terminal解除关联

此选项在1.4之后不能和 -nographic 联用,但是可以和 -display none 联用

-readconfig 从文件读取配置
-writeconfig  把配置写入到文件,如果指定 - 则打印到屏幕
快捷键

在图形化模拟期间,你可以使用快捷键:

快捷键 说明
Ctrl-Alt 释放/获取鼠标键盘
Ctrl-Alt-f 切换全屏模式
Ctrl-Alt-+ 增大屏幕
Ctrl-Alt-- 减小屏幕
Ctrl-Alt-u 还原原始屏幕大小
Ctrl-Alt-n 切换到虚拟控制台n,标准控制台为:
1    客户机系统的显示
2    Monitor
3    串口

 如果你使用了-nographic,则可以使用以下快捷键:

快捷键 说明
Ctrl-a h 打印帮助
Ctrl-a x 退出模拟器
Ctrl-a s 保存磁盘数据文件(如果使用-snapshot)
Ctrl-a c 在控制台和Monitor之间切换
Ctrl-a Ctrl-a 发送Ctrl-a
qemu-nbd

用于创建QEMU网络块设备(Network Block Device)服务器,即通过NBD协议把磁盘镜像暴露出去。 命令格式: qemu-nbd [OPTION]... diskimgfile 。

常用选项如下表:

选项 说明
-p NBD服务监听端口,默认1024
-b NBD服务器绑定的网络接口,默认0.0.0.0
-k NBD绑定的UNIX socket路径
-o 访问镜像文件的偏移量
-f 镜像文件格式
-r 仅允许只读访问镜像
-P --partition=num,仅暴露分区num
-s 把diskimgfile作为外部快照使用,创建一个新的临时镜像,将其backing_file设置为diskimgfile,写操作都重定向到临时镜像
-l --load-snapshot=snapshot_param,加载diskimgfile中的一个内部快照,并暴露其为一个只读设备
snapshot_param可以是snapshot.id=id或者snapshot.name=name,或者直接写id/name
-n 禁用缓存
--cache=cache 设置缓存模式,支持的模式参考qemu-system-x86 -drive cache=
--aio=aio 选择AIO模式,threads或者native
-c --connect=dev连接diskimgfile到一个NBD设备
-d 断开指定的设备
-e --shared=num  此设备可以被最多num个客户端使用
-t 即使最后一个连接断开,也不退出
常见问题 
不支持virtio-9p-pci

报错信息:'virtio-9p-pci' is not a valid device model name

解决办法:参考下面的脚本构建QEMU:

Shell
1
2
3
apt install libattr1-dev
configure --prefix=/usr --enable-virtfs
make && make install
不支持SDL

报错信息:qemu-system-x86_64: -sdl: SDL support is disabled

解决办法:参考下面的脚本构建QEMU:

Shell
1
2
sudo apt install libsdl2-dev
./configure --prefix=/usr --enable-virtfs --enable-sdl
qcow2镜像损坏处理

报错信息:Image is corrupt; cannot be opened read/write

解决办法:

Shell
1
qemu-img check -r all /media/alex/v12n2/libvirt/images/xenial-23

 

 

← 类UNIX系统下使用Dnsmasq
基于Spring Test和Mockito进行单元测试 →

Leave a Reply Cancel reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code class="" title="" data-url=""> <del datetime=""> <em> <i> <q cite=""> <strike> <strong> <pre class="" title="" data-url=""> <span class="" title="" data-url="">

Related Posts

  • CoreOS知识集锦
  • Kata Containers学习笔记

Recent Posts

  • Investigating and Solving the Issue of Failed Certificate Request with ZeroSSL and Cert-Manager
  • A Comprehensive Study of Kotlin for Java Developers
  • 背诵营笔记
  • 利用LangChain和语言模型交互
  • 享学营笔记
ABOUT ME

汪震 | Alex Wong

江苏淮安人,现居北京。目前供职于腾讯云,专注容器方向。

GitHub:gmemcc

Git:git.gmem.cc

Email:gmemjunk@gmem.cc@me.com

ABOUT GMEM

绿色记忆是我的个人网站,域名gmem.cc中G是Green的简写,MEM是Memory的简写,CC则是我的小天使彩彩名字的简写。

我在这里记录自己的工作与生活,同时和大家分享一些编程方面的知识。

GMEM HISTORY
v2.00:微风
v1.03:单车旅行
v1.02:夏日版
v1.01:未完成
v0.10:彩虹天堂
v0.01:阳光海岸
MIRROR INFO
Meta
  • Log in
  • Entries RSS
  • Comments RSS
  • WordPress.org
Recent Posts
  • Investigating and Solving the Issue of Failed Certificate Request with ZeroSSL and Cert-Manager
    In this blog post, I will walk ...
  • A Comprehensive Study of Kotlin for Java Developers
    Introduction Purpose of the Study Understanding the Mo ...
  • 背诵营笔记
    Day 1 Find Your Greatness 原文 Greatness. It’s just ...
  • 利用LangChain和语言模型交互
    LangChain是什么 从名字上可以看出来,LangChain可以用来构建自然语言处理能力的链条。它是一个库 ...
  • 享学营笔记
    Unit 1 At home Lesson 1 In the ...
  • K8S集群跨云迁移
    要将K8S集群从一个云服务商迁移到另外一个,需要解决以下问题: 各种K8S资源的迁移 工作负载所挂载的数 ...
  • Terraform快速参考
    简介 Terraform用于实现基础设施即代码(infrastructure as code)—— 通过代码( ...
  • 草缸2021
    经过四个多月的努力,我的小小荷兰景到达极致了状态。

  • 编写Kubernetes风格的APIServer
    背景 前段时间接到一个需求做一个工具,工具将在K8S中运行。需求很适合用控制器模式实现,很自然的就基于kube ...
  • 记录一次KeyDB缓慢的定位过程
    环境说明 运行环境 这个问题出现在一套搭建在虚拟机上的Kubernetes 1.18集群上。集群有三个节点: ...
  • eBPF学习笔记
    简介 BPF,即Berkeley Packet Filter,是一个古老的网络封包过滤机制。它允许从用户空间注 ...
  • IPVS模式下ClusterIP泄露宿主机端口的问题
    问题 在一个启用了IPVS模式kube-proxy的K8S集群中,运行着一个Docker Registry服务 ...
  • 念爷爷
      今天是爷爷的头七,十二月七日、阴历十月廿三中午,老人家与世长辞。   九月初,回家看望刚动完手术的爸爸,发

  • 6 杨梅坑

  • liuhuashan
    深圳人才公园的网红景点 —— 流花山

  • 1 2020年10月拈花湾

  • 内核缺陷触发的NodePort服务63秒延迟问题
    现象 我们有一个新创建的TKE 1.3.0集群,使用基于Galaxy + Flannel(VXLAN模式)的容 ...
  • Galaxy学习笔记
    简介 Galaxy是TKEStack的一个网络组件,支持为TKE集群提供Overlay/Underlay容器网 ...
TOPLINKS
  • Zitahli's blue 91 people like this
  • 梦中的婚礼 64 people like this
  • 汪静好 61 people like this
  • 那年我一岁 36 people like this
  • 为了爱 28 people like this
  • 小绿彩 26 people like this
  • 彩虹姐姐的笑脸 24 people like this
  • 杨梅坑 6 people like this
  • 亚龙湾之旅 1 people like this
  • 汪昌博 people like this
  • 2013年11月香山 10 people like this
  • 2013年7月秦皇岛 6 people like this
  • 2013年6月蓟县盘山 5 people like this
  • 2013年2月梅花山 2 people like this
  • 2013年淮阴自贡迎春灯会 3 people like this
  • 2012年镇江金山游 1 people like this
  • 2012年徽杭古道 9 people like this
  • 2011年清明节后扬州行 1 people like this
  • 2008年十一云龙公园 5 people like this
  • 2008年之秋忆 7 people like this
  • 老照片 13 people like this
  • 火一样的六月 16 people like this
  • 发黄的相片 3 people like this
  • Cesium学习笔记 90 people like this
  • IntelliJ IDEA知识集锦 59 people like this
  • 基于Kurento搭建WebRTC服务器 38 people like this
  • Bazel学习笔记 37 people like this
  • PhoneGap学习笔记 32 people like this
  • NaCl学习笔记 32 people like this
  • 使用Oracle Java Mission Control监控JVM运行状态 29 people like this
  • Ceph学习笔记 27 people like this
  • 基于Calico的CNI 27 people like this
Tag Cloud
ActiveMQ AspectJ CDT Ceph Chrome CNI Command Cordova Coroutine CXF Cygwin DNS Docker eBPF Eclipse ExtJS F7 FAQ Groovy Hibernate HTTP IntelliJ IO编程 IPVS JacksonJSON JMS JSON JVM K8S kernel LB libvirt Linux知识 Linux编程 LOG Maven MinGW Mock Monitoring Multimedia MVC MySQL netfs Netty Nginx NIO Node.js NoSQL Oracle PDT PHP Redis RPC Scheduler ServiceMesh SNMP Spring SSL svn Tomcat TSDB Ubuntu WebGL WebRTC WebService WebSocket wxWidgets XDebug XML XPath XRM ZooKeeper 亚龙湾 单元测试 学习笔记 实时处理 并发编程 彩姐 性能剖析 性能调优 文本处理 新特性 架构模式 系统编程 网络编程 视频监控 设计模式 远程调试 配置文件 齐塔莉
Recent Comments
  • qg on Istio中的透明代理问题
  • heao on 基于本地gRPC的Go插件系统
  • 黄豆豆 on Ginkgo学习笔记
  • cloud on OpenStack学习笔记
  • 5dragoncon on Cilium学习笔记
  • Archeb on 重温iptables
  • C/C++编程:WebSocketpp(Linux + Clion + boostAsio) – 源码巴士 on 基于C/C++的WebSocket库
  • jerbin on eBPF学习笔记
  • point on Istio中的透明代理问题
  • G on Istio中的透明代理问题
  • 绿色记忆:Go语言单元测试和仿冒 on Ginkgo学习笔记
  • point on Istio中的透明代理问题
  • 【Maven】maven插件开发实战 – IT汇 on Maven插件开发
  • chenlx on eBPF学习笔记
  • Alex on eBPF学习笔记
  • CFC4N on eBPF学习笔记
  • 李运田 on 念爷爷
  • yongman on 记录一次KeyDB缓慢的定位过程
  • Alex on Istio中的透明代理问题
  • will on Istio中的透明代理问题
  • will on Istio中的透明代理问题
  • haolipeng on 基于本地gRPC的Go插件系统
  • 吴杰 on 基于C/C++的WebSocket库
©2005-2025 Gmem.cc | Powered by WordPress | 京ICP备18007345号-2