前言
关于QEMU的基本知识,可以参考其官方网站[1]。简单来说,QEMU自身支持“系统模拟”和“用户态模拟”;除此之外,QEMU可以配合KVM或Xen创建接近原始性能的虚拟机。
本笔记的主要参考资料是文献[4]。
本文采用文本形式记录命令行操作过程。对于那些输出不重要的执行步骤,本文仅给出命令本身;如果输出内容能够增进理解,本文会将命令与输出一并展示。
为避免混淆,除特别指出外,本文中所有“宿主机”均指运行实验虚拟机的外层机器,而不是笔者自己的实体机。
1. 从源码构建QEMU
获取QEMU的源码有两种方式:
- 从GitLab上clone源码仓库[2]。
- 从QEMU官网[3]下载源码包。
前者有利于我们切换查看不同分支、版本的源码,然而在编译阶段对于国内用户不太友好,无论是clone还是下载子模块(submodule)都非常耗时。因此,我们更推荐第二种方法,在确定版本后(如果是研究QEMU漏洞的话,需要先确定版本)直接下载源码包。
这里也给出从GitLab上clone源码仓库的步骤[10]:
git clone git://git.qemu-project.org/qemu.git
cd qemu
git submodule init
git submodule update --recursive
git submodule status --recursive
mkdir build
cd build
../configure
获取源码后即可进行编译。编译时间与当前机器性能有关。为了加快编译速度,建议仅针对自己打算用到的目标架构进行编译。
下面是我们在Ubuntu 18.04机器上下载v3.1.0
版本源码并仅针对x86_64
架构进行编译的步骤:
VERSION=3.1.0
sudo apt-get install -y git libglib2.0-dev libfdt-dev libpixman-1-dev zlib1g-dev gcc python
wget https://download.qemu.org/qemu-$VERSION.tar.xz
tar xf qemu-$VERSION.tar.xz
cd qemu-$VERSION
./configure --target-list="x86_64-softmmu" --python=`which python2`
make
make install
如果编译其他版本或针对其他目标架构进行编译,自行修改上述步骤即可。
编译完成后,执行qemu-system-x86_64
确认编译成功:
➜ ~ qemu-system-x86_64 --version
QEMU emulator version 3.1.0
Copyright (c) 2003-2018 Fabrice Bellard and the QEMU Project developers
2. 使用qemu-img管理磁盘镜像
为了运行虚拟机,QEMU需要使用磁盘镜像文件存储虚拟机文件系统。QEMU支持多种类型的磁盘镜像文件,并提供了qemu-img
工具来创建和管理它们。
执行qemu-img
查看支持的磁盘镜像类型:
➜ ~ qemu-img -h | grep Supported
Supported formats: blkdebug blklogwrites blkreplay blkverify bochs cloop copy-on-read dmg file host_cdrom host_device luks nbd null-aio null-co nvme parallels qcow qcow2 qed quorum raw replication sheepdog throttle vdi vhdx vmdk vpc vvfat
其中,最常用的两种类型是raw
和qcow2
。前者缺乏一些特性,但是方便快速测试;后者支持虚拟机快照、压缩和加密等特性,但是牺牲了一些性能[4]。
除此之外,还有一些常见的镜像类型也值得了解:
qcow
:旧版的QEMU镜像格式。支持文件备份、镜像文件压缩和加密等特性。dmg
:Mac磁盘镜像格式。支持密码保护、压缩等特性,除了用于创建虚拟机,还常用来分发软件。nbd
:网络块设备格式。常用于访问远程存储设备。vdi
:VirtualBox使用的磁盘镜像格式。vmdk
:VMware使用的磁盘镜像格式。vhdx
:Microsoft Hyper-V使用的镜像格式。支持大容量存储、数据损坏保护和读写优化等特性。
介绍完毕,开始行动。创建一个10GB大小的空白镜像文件,类型为raw
,并使用各种工具查看该镜像文件的属性:
➜ ~ qemu-img create -f raw debian.img 10G
Formatting 'debian.img', fmt=raw size=10737418240
➜ ~ ls -lah ./debian.img
-rw-r--r-- 1 root root 10G May 7 02:39 ./debian.img
➜ ~ file -s ./debian.img
./debian.img: data
➜ ~ qemu-img info ./debian.img
image: ./debian.img
file format: raw
virtual size: 10G (10737418240 bytes)
disk size: 0
3. 使用qemu-nbd处理磁盘镜像
关于Linux NBD和QEMU对NBD的使用,可以参考文献[8]和文献[9]。
我们已经创建了一个格式为raw
的空镜像文件。接下来需要在上面创建分区和文件系统,从而安装操作系统。
首先加载nbd
内核模块,然后将我们之前创建的debian.img
空镜像文件与/dev/nbd0
块设备关联起来:
modprobe nbd
qemu-nbd --format=raw --connect=/dev/nbd0 ./debian.img
接着在块设备上创建两个分区,分别用于swap和虚拟机操作系统的根分区:
➜ ~ sfdisk /dev/nbd0 << EOF
heredoc> ,1024,82
heredoc> ;
heredoc> EOF
Checking that no-one is using this disk right now ... OK
Disk /dev/nbd0: 10 GiB, 10737418240 bytes, 20971520 sectors
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
>>> Created a new DOS disklabel with disk identifier 0xd6d2dca3.
/dev/nbd0p1: Created a new partition 1 of type 'Linux swap / Solaris' and of size 512 KiB.
/dev/nbd0p2: Created a new partition 2 of type 'Linux' and of size 10 GiB.
/dev/nbd0p3: Done.
New situation:
Disklabel type: dos
Disk identifier: 0xd6d2dca3
Device Boot Start End Sectors Size Id Type
/dev/nbd0p1 2048 3071 1024 512K 82 Linux swap / Solaris
/dev/nbd0p2 4096 20971519 20967424 10G 83 Linux
The partition table has been altered.
Calling ioctl() to re-read partition table.
Syncing disks.
注:其实也可以用fdisk
代替sfdisk
来分区。操作不同,结果一致,这里不再展开。
完成后,查看分区后的块设备:
➜ ~ ls -la /dev/nbd0*
brw-rw---- 1 root disk 43, 0 May 7 02:57 /dev/nbd0
brw-rw---- 1 root disk 43, 1 May 7 02:57 /dev/nbd0p1
brw-rw---- 1 root disk 43, 2 May 7 02:57 /dev/nbd0p2
创建swap分区并在虚拟机操作系统根分区上建立EXT4文件系统:
➜ ~ mkswap /dev/nbd0p1
Setting up swapspace version 1, size = 508 KiB (520192 bytes)
no label, UUID=ef312e03-3f56-4408-8bfa-f65fd2ecb7ff
➜ ~ mkfs.ext4 /dev/nbd0p2
mke2fs 1.44.1 (24-Mar-2018)
Discarding device blocks: failed - Input/output error
Creating filesystem with 2620928 4k blocks and 655360 inodes
Filesystem UUID: 7e8c3c8a-ca64-43a1-9356-1ba1e75998dc
Superblock backups stored on blocks:
32768, 98304, 163840, 229376, 294912, 819200, 884736, 1605632
Allocating group tables: done
Writing inode tables: done
Creating journal (16384 blocks): done
Writing superblocks and filesystem accounting information: done
最后,看一下镜像文件的类型,已经发生改变:
➜ ~ file -s debian.img
debian.img: DOS/MBR boot sector; partition 1 : ID=0x82, start-CHS (0x0,32,33), end-CHS (0x0,48,48), startsector 2048, 1024 sectors; partition 2 : ID=0x83, start-CHS (0x0,65,2), end-CHS (0x119,106,17), startsector 4096, 20967424 sectors
现在我们有包含两个分区和文件系统的镜像文件了。
4. 使用debootstrap安装操作系统
我们将使用debootstrap
来引导一个Debian系统。
要确保上一节创建的块设备存在。如果重启过宿主机,则需要按照上一节开头部分再次使用qemu-nbd
来将debian.img
与块设备关联起来(不必再分区了)。
接下来安装debootstrap
:
apt install -y debootstrap
准备完成,可以开动了。
首先,将根分区对应的块设备(Network Block Device, NBD)挂载到当前文件系统下,并确保挂载成功(提问:为什么需要通过挂载nbd块设备间接挂载虚拟机镜像根文件系统,而非直接挂载虚拟机镜像?):
➜ ~ mount /dev/nbd0p2 /mnt
➜ ~ mount | grep mnt
/dev/nbd0p2 on /mnt type ext4 (rw,relatime)
接着,在挂载的根分区上安装最新版的Debian(这个过程可能会持续一段时间):
debootstrap --arch=amd64 --include="openssh-server vim" stable /mnt http://httpredir.debian.org/debian/
# 最后输出以下内容,说明安装成功:
# I: Base system installed successfully.
完成后,应该可以看到挂载点/mnt
目录结构已经是一个常见的Linux系统根目录:
➜ ~ ls /mnt
bin boot dev etc home lib lib64 lost+found media mnt opt proc root run sbin srv sys tmp usr var
将/dev
目录bind mount到镜像文件系统下,并确保nbd块设备也在其中:
➜ ~ mount --bind /dev /mnt/dev
➜ ~ ls /mnt/dev/ | grep nbd0
nbd0
nbd0p1
nbd0p2
chroot到镜像文件系统下。由于我默认使用了zsh,第一次操作失败:
➜ ~ chroot /mnt
chroot: failed to run command ‘/usr/bin/zsh’: No such file or directory
指定一个镜像文件系统中有的shell即可,第二次切换成功:
➜ ~ chroot /mnt /bin/bash
bash: warning: setlocale: LC_ALL: cannot change locale (en_US.UTF-8)
root@ubuntu:/# cat /etc/debian_version
11.3
把procfs和sysfs两个伪文件系统挂载到新的环境下:
mount -t proc none /proc
mount -t sysfs none /sys
安装Debian内核metapackage和grub2
:
apt install -y --force-yes linux-image-amd64 grub2
在根设备上安装GRUB,并更新GRUB配置:
root@ubuntu:/# grub-install /dev/nbd0 --force
Installing for i386-pc platform.
Installation finished. No error reported.
root@ubuntu:/# update-grub2
Generating grub configuration file ...
Found linux image: /boot/vmlinuz-5.10.0-13-amd64
Found initrd image: /boot/initrd.img-5.10.0-13-amd64
Found Ubuntu 18.04.6 LTS (18.04) on /dev/sda1
done
使用passwd
命令修改虚拟机镜像的root密码,我们修改为root
。
允许访问虚拟机镜像中的伪终端:
echo "pts/0" >> /etc/securetty
将systemd
调整到multi-user
:
root@ubuntu:/# systemctl set-default multi-user.target
Created symlink /etc/systemd/system/default.target → /lib/systemd/system/multi-user.target.
将根挂载点加入到fstab
文件,使之在重启之后依然保留(提问:文献[4]使用的是/dev/sda2
,这里为什么是sda2
?):
echo "/dev/sda2 / ext4 defaults,discard 0 0" > /etc/fstab
卸载之前挂载的文件系统(注意,不要在将卸载的挂载点目录下执行umount
,可能会执行失败),退出chroot环境:
umount /proc /sys /dev
exit
在镜像根分区上安装GRUB(提问:为什么这里又安装一次?):
➜ ~ grub-install /dev/nbd0 --root-directory=/mnt --modules="biosdisk part_msdos" --force
Installing for i386-pc platform.
Installation finished. No error reported.
更正GRUB配置文件中的设备名:
sed -i 's/nbd0p2/sda2/g' /mnt/boot/grub/grub.cfg
卸载nbd0
设备,并取消关联:
➜ ~ umount /mnt
➜ ~ qemu-nbd --disconnect /dev/nbd0
/dev/nbd0 disconnected
至此,我们完成了在虚拟机镜像中安装Debian操作系统。
提问:为什么在为虚拟机安装操作系统的过程中需要把宿主机上的/dev
和procfs、sysfs挂载到虚拟机根文件系统下?
5. 调整虚拟机镜像大小
我们将学习如何调整上一节创建的镜像文件、其中的分区和分区上的文件系统的大小。注意,对于创建可运行的虚拟机镜像来说,这一步是可选的。
在此之前,先安装一下必要的工具(不再列出Ubuntu自带的工具):
apt install -y kpartx
上一节操作完成后,debian.img
镜像文件大小已经发生了变化:
➜ ~ qemu-img info debian.img
image: debian.img
file format: raw
virtual size: 10G (10737418240 bytes)
disk size: 1.3G
我们为镜像文件增加2GB,并再次查看其大小:
➜ ~ qemu-img resize -f raw debian.img +2G
Image resized.
➜ ~ qemu-img info debian.img
image: debian.img
file format: raw
virtual size: 12G (12884901888 bytes)
disk size: 1.3G
注意,不是所有的镜像类型都支持调整大小。如果需要调整其他类型的镜像的大小,可能需要先将其用qemu-img
转换为raw
类型。
我们发现,镜像文件大小已经改变。接下来,我们将调整分区和分区文件系统的大小。
查看第一个未被使用的回环设备(回环设备用来将普通文件模拟成块设备,详见Linux用户手册[6]):
➜ ~ losetup -f
/dev/loop19
把镜像文件与上述回环设备关联起来:
losetup /dev/loop19 debian.img
从关联的回环设备读取分区信息,并创建设备映射,然后查看设备映射:
➜ ~ kpartx -av /dev/loop19
add map loop19p1 (253:0): 0 1024 linear 7:19 2048
add map loop19p2 (253:1): 0 20967424 linear 7:19 4096
➜ ~ ls -la /dev/mapper | grep loop
lrwxrwxrwx 1 root root 7 May 8 00:04 loop19p1 -> ../dm-0
lrwxrwxrwx 1 root root 7 May 8 00:04 loop19p2 -> ../dm-1
从根分区映射中获取信息:
➜ ~ tune2fs -l /dev/mapper/loop19p2
tune2fs 1.44.1 (24-Mar-2018)
Filesystem volume name: <none>
Last mounted on: /mnt
Filesystem UUID: 7e8c3c8a-ca64-43a1-9356-1ba1e75998dc
Filesystem magic number: 0xEF53
Filesystem revision #: 1 (dynamic)
Filesystem features: has_journal ext_attr resize_inode dir_index filetype extent 64bit flex_bg sparse_super large_file huge_file dir_nlink extra_isize metadata_csum
Filesystem flags: signed_directory_hash
Default mount options: user_xattr acl
Filesystem state: clean
Errors behavior: Continue
Filesystem OS type: Linux
Inode count: 655360
Block count: 2620928
Reserved block count: 131046
Free blocks: 2353841
Free inodes: 636395
First block: 0
Block size: 4096
Fragment size: 4096
Group descriptor size: 64
Reserved GDT blocks: 1024
Blocks per group: 32768
Fragments per group: 32768
Inodes per group: 8192
Inode blocks per group: 512
Flex block group size: 16
Filesystem created: Sat May 7 03:01:11 2022
Last mount time: Sat May 7 07:59:00 2022
Last write time: Sat May 7 08:34:14 2022
Mount count: 1
Maximum mount count: -1
Last checked: Sat May 7 03:01:11 2022
Check interval: 0 (<none>)
Lifetime writes: 1768 MB
Reserved blocks uid: 0 (user root)
Reserved blocks gid: 0 (group root)
First inode: 11
Inode size: 256
Required extra isize: 32
Desired extra isize: 32
Journal inode: 8
Default directory hash: half_md4
Directory Hash Seed: c681cdb3-cd48-4754-8504-8b1e8d3dab09
Journal backup: inode blocks
Checksum type: crc32c
Checksum: 0xb3c7927c
检查根分区文件系统:
➜ ~ e2fsck /dev/mapper/loop19p2
e2fsck 1.44.1 (24-Mar-2018)
/dev/mapper/loop19p2: clean, 18965/655360 files, 267087/2620928 blocks
删除根分区设备的日志,并确保日志已经移除:
➜ ~ tune2fs -O ^has_journal /dev/mapper/loop19p2
tune2fs 1.44.1 (24-Mar-2018)
➜ ~ tune2fs -l /dev/mapper/loop19p2 | grep "features"
Filesystem features: ext_attr resize_inode dir_index filetype extent 64bit flex_bg sparse_super large_file huge_file dir_nlink extra_isize metadata_csum
移除分区映射,解除回环设备关联:
➜ ~ kpartx -dv /dev/loop19
del devmap : loop19p2
del devmap : loop19p1
➜ ~ losetup -d /dev/loop19
再次将镜像文件与网络块设备关联:
qemu-nbd --format=raw --connect=/dev/nbd0 ./debian.img
使用fdisk
列出可用分区,删除根分区,重新创建,并确认修改:
➜ ~ fdisk /dev/nbd0
Welcome to fdisk (util-linux 2.31.1).
Changes will remain in memory only, until you decide to write them.
Be careful before using the write command.
Command (m for help): p
Disk /dev/nbd0: 12 GiB, 12884901888 bytes, 25165824 sectors
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disklabel type: dos
Disk identifier: 0xc45020cb
Device Boot Start End Sectors Size Id Type
/dev/nbd0p1 2048 3071 1024 512K 82 Linux swap / Solaris
/dev/nbd0p2 4096 20971519 20967424 10G 83 Linux
Command (m for help): d
Partition number (1,2, default 2): 2
Partition 2 has been deleted.
Command (m for help): n
Partition type
p primary (1 primary, 0 extended, 3 free)
e extended (container for logical partitions)
Select (default p): p
Partition number (2-4, default 2): 2
First sector (3072-25165823, default 4096):
Last sector, +sectors or +size{K,M,G,T,P} (4096-25165823, default 25165823):
Created a new partition 2 of type 'Linux' and of size 12 GiB.
Partition #2 contains a ext4 signature.
Do you want to remove the signature? [Y]es/[N]o: N
Command (m for help): w
The partition table has been altered.
Calling ioctl() to re-read partition table.
Syncing disks.
再次把镜像文件与上述回环设备关联起来:
losetup /dev/loop19 debian.img
再次从关联的回环设备读取分区信息,并创建设备映射:
➜ ~ kpartx -av /dev/loop19
add map loop19p1 (253:0): 0 1024 linear 7:19 2048
add map loop19p2 (253:1): 0 25161728 linear 7:19 4096
再次检查根分区文件系统:
➜ ~ e2fsck -f /dev/mapper/loop19p2
e2fsck 1.44.1 (24-Mar-2018)
Pass 1: Checking inodes, blocks, and sizes
Pass 2: Checking directory structure
Pass 3: Checking directory connectivity
Pass 4: Checking reference counts
Pass 5: Checking group summary information
/dev/mapper/loop19p2: 19007/655360 files (0.2% non-contiguous), 251765/2620928 blocks
调整根分区文件系统大小:
➜ ~ resize2fs /dev/nbd0p2
resize2fs 1.44.1 (24-Mar-2018)
Resizing the filesystem on /dev/nbd0p2 to 3145216 (4k) blocks.
The filesystem on /dev/nbd0p2 is now 3145216 (4k) blocks long.
重新创建文件系统日志(前面删除了):
➜ ~ tune2fs -j /dev/mapper/loop19p2
tune2fs 1.44.1 (24-Mar-2018)
Creating journal inode: done
最后移除分区映射,解除回环设备关联:
➜ ~ kpartx -dv /dev/loop19
del devmap : loop19p2
del devmap : loop19p1
➜ ~ losetup -d /dev/loop19
6. 使用qemu-system-*命令运行虚拟机
除了自制虚拟机镜像外,各大Linux发行版也都提供了预制镜像:
- https://cloud.centos.org/centos/
- https://cloud-images.ubuntu.com/
- https://cloud.debian.org/images/cloud/
- https://alt.fedoraproject.org/cloud/
- https://download.opensuse.org/repositories/Cloud:/Images:
我们可以直接下载预制镜像使用,例如:
wget https://cloud.debian.org/images/cloud/buster/latest/debian-10-nocloud-amd64.qcow2
wget https://cloud.centos.org/centos/7/images/CentOS-7-x86_64-GenericCloud.qcow2.xz
可以执行qemu-system-*
系列命令来获得支持的CPU架构:
qemu-system-x86_64 --cpu help
尝试启动一个Debian虚拟机实例(注意,命令中的index=2
是虚拟机操作系统所在的分区索引号):
# IP需替换为宿主机IP
qemu-system-x86_64 -name debian -vnc 172.16.56.199:0 -cpu Nehalem -m 1024 -drive format=raw,index=2,file=debian.img -daemonize
确认该实例在运行:
➜ ~ pgrep -lfa qemu
1684 qemu-system-x86_64 -name debian -vnc 172.16.56.199:0 -cpu Nehalem -m 1024 -drive format=raw,index=2,file=debian.img -daemonize
结束该实例:
pkill qemu
还可以尝试使用CentOS官方的预制镜像[7]启动一个虚拟机实例(大多数预制镜像使用第一分区或仅有一个分区,故不必指出索引号,-hda
与-drive
选项效果类似):
# IP需替换为宿主机IP
qemu-system-x86_64 -vnc 172.16.56.199:0 -m 1024 -hda CentOS-7-x86_64-GenericCloud.qcow2 -daemonize
7. 启动KVM加速的QEMU虚拟机
KVM主要由两个LKM内核模块组成,第一个是kvm.ko
,提供主要的虚拟化功能;第二个是kvm-intel.ko
或kvm-amd.ko
,分别对应不同的CPU厂商。
在一些Linux发行版中存在名为qemu-kvm
的软件包,它提供了一个名为kvm
的脚本,在Ubuntu上可以通过apt install -y qemu-kvm
来安装。该工具实际上是qemu-system-x86_64
命令的封装,自动为其加上了enable-kvm
参数,其内容通常如下:
#!/bin/sh
exec qemu-system-x86_64 -enable-kvm "$@"
为完成本节实验,需要确保宿主机支持硬件虚拟化功能。在笔者的环境中,宿主机本身就是一台虚拟机,因此需要在虚拟机管理器中开启该虚拟机的硬件虚拟化功能。可以在宿主机中执行命令查看CPU是否支持硬件虚拟化:
➜ ~ egrep "vmx|svm" /proc/cpuinfo | uniq
flags : fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush mmx fxsr sse sse2 ss syscall nx pdpe1gb rdtscp lm constant_tsc arch_perfmon nopl xtopology tsc_reliable nonstop_tsc cpuid pni pclmulqdq vmx ssse3 fma cx16 pcid sse4_1 sse4_2 x2apic movbe popcnt tsc_deadline_timer aes xsave avx f16c rdrand hypervisor lahf_lm abm 3dnowprefetch cpuid_fault invpcid_single pti ssbd ibrs ibpb stibp tpr_shadow vnmi ept vpid ept_ad fsgsbase tsc_adjust bmi1 avx2 smep bmi2 invpcid rdseed adx smap clflushopt xsaveopt xsavec xgetbv1 xsaves arat md_clear flush_l1d arch_capabilities
如上面的输出所示,输出包括vmx
,说明当前宿主机支持硬件虚拟化功能。
手动载入KVM内核模块,并确保载入成功:
➜ ~ modprobe kvm
➜ ~ lsmod | grep kvm
kvm_intel 253952 0
kvm 659456 1 kvm_intel
OK,环境准备完成,开始行动。
创建一个KVM支持的QEMU虚拟机实例:
# IP需替换为宿主机IP
qemu-system-x86_64 -name debian -vnc 172.16.56.199:0 -m 1024 -drive format=raw,index=2,file=debian.img -enable-kvm -daemonize
确认该实例在运行:
➜ ~ pgrep -lfa qemu
1930 qemu-system-x86_64 -name debian -vnc 172.16.56.199:0 -m 1024 -drive format=raw,index=2,file=debian.img -enable-kvm -daemonize
结束该实例:
pkill qemu
可以看到,实际上我们只是增加了-enable-kvm
选项而已。
8. 使用VNC连接到正在运行的虚拟机实例
首先启动一个虚拟机:
qemu-system-x86_64 -name debian -vnc 172.16.56.199:0 -m 1024 -drive format=raw,index=2,file=debian.img -enable-kvm -daemonize
接下来,就可以使用VNC客户端(例如VNC Viewer)连接172.16.56.199:5900
来访问虚拟机了。
9. 总结
从零开始创建并运行一个虚拟机的步骤如下:
apt install -y debootstrap
qemu-img create -f raw debian.img 10G
modprobe nbd
qemu-nbd --format=raw --connect=/dev/nbd0 ./debian.img
sfdisk /dev/nbd0 << EOF
,1024,82
;
EOF
mkswap /dev/nbd0p1
mkfs.ext4 /dev/nbd0p2
mount /dev/nbd0p2 /mnt
debootstrap --arch=amd64 --include="openssh-server vim" stable /mnt http://httpredir.debian.org/debian/
mount --bind /dev /mnt/dev
chroot /mnt /bin/bash
mount -t proc none /proc
mount -t sysfs none /sys
apt install -y --force-yes linux-image-amd64 grub2
grub-install /dev/nbd0 --force
update-grub2
passwd # change password to root
echo "pts/0" >> /etc/securetty
systemctl set-default multi-user.target
echo "/dev/sda2 / ext4 defaults,discard 0 0" > /etc/fstab
umount /proc /sys /dev
exit
grub-install /dev/nbd0 --root-directory=/mnt --modules="biosdisk part_msdos" --force
sed -i 's/nbd0p2/sda2/g' /mnt/boot/grub/grub.cfg
umount /mnt
qemu-nbd --disconnect /dev/nbd0
参考文献
- https://www.qemu.org
- https://gitlab.com/qemu-project/qemu.git
- https://download.qemu.org/
- KVM Virtualization Cookbook
- https://github.com/PacktPublishing/KVM-Virtualization-Cookbook.git
- https://man7.org/linux/man-pages/man4/loop.4.html
- https://cloud.centos.org/centos/7/images/CentOS-7-x86_64-GenericCloud.qcow2.xz
- https://zhuanlan.zhihu.com/p/50460919
- https://en.wikipedia.org/wiki/Network_block_device
- https://en.wikibooks.org/wiki/QEMU/Installing_QEMU