0x01 虚拟机(VM)安装及启动
1. 选择一个发行版,下载其安装镜像
选择格式为 .iso 的安装镜像进行下载。
2. 制作根文件系统(rootfs)镜像
总体思路:启动一个 QEMU 虚拟机,以 rootfs 镜像文件为硬盘,以安装镜像 iso 文件为光盘。设置虚拟机从光盘启动,将系统安装至硬盘。
1# create an empty rootfs image file
2qemu-img create -f qcow2 rootfs.qcow2 128G
3
4# boot from CD-ROM, so that OS can be installed into the rootfs image
5qemu-system-x86_64 \
6 -m 4096 \
7 -boot d \
8 -enable-kvm \
9 -cdrom ../ubuntu-16.04.2-server-amd64.iso \
10 -drive file=rootfs.qcow2,if=virtio \
11 -vnc :12 \
12 -daemonize
解释两个参数:
-
-vnc
,涉及 VNC 连接端口号:One can add the
-vnc :X
option to have QEMU redirect the VGA display to the VNC session. SubstituteX
for the number of the display (0 will then listen on 5900, 1 on 5901…). -
-boot
,涉及启动方式:1-boot [order=drives][,once=drives][,menu=on|off][,splash=sp_name] 2[,splash-time=sp_time][,reboot-timeout=rb_timeout][,strict=on|off] 3 Specify boot order drives as a string of drive letters. Valid drive 4 letters depend on the target achitecture. The x86 PC uses: a, b 5 (floppy 1 and 2), c (first hard disk), d (first CD-ROM), n-p 6 (Etherboot from network adapter 1-4), hard disk boot is the default.
3. 用安装好的 rootfs 镜像启动 VM 作为后续工作环境
虚拟机网络准备工作
由于后续在该环境上的多种操作(如下载代码,更新或安装软件包等)会涉及到网络,因此与上一步的启动方式不同,这里启动 QEMU 虚拟机需要配置网络。这里简要描述一下 QEMU 虚拟机的网络配置。如 QEMU 文档 所述,QEMU 虚拟机的网络配置分两部分:
- 虚拟机内部的虚拟网络设备(Virtual Network Device),就是一张插在虚拟主板上的虚拟网卡。
- 与虚拟网卡交互的网络后端(Network Backend),在主机侧与虚拟机的虚拟网卡对接,帮助处理虚拟网卡与外部网络以及主机上其他网络设备之间的关系。
QEMU 支持多种网络后端 。这里我们的思路如下:
- 网络后端我们选择 TAP ,需要我们在主机上创建一个 TAP 设备;
- 将该 TAP 设备与连接外网的网络设备以某种方式连接起来。这里分两种情况:
- 若我们正在本机上操作,我们可以直接将两者加入同一个网桥中。
- 若我们正在通过 SSH 远程操作一台服务器,则切不可随意操作正在与外网相连的网络设备,否则我们与服务器之间的 SSH 连接很可能会断掉,从而失去对服务器的操作能力!这种情况下,我们可以在主机上额外创建一个由虚拟设备组成的子网,让 TAP 设备接入该子网,并通过该子网的网关将 TAP 设备的流量路由到对外的网络设备上。
需要在主机上进行的相关操作总结如下:
1# 建立网桥
2brctl addbr br0
3# 给网桥设置虚拟机子网的网关 IP
4ip addr add 192.168.122.1/24 dev br0
(过时)
1# 创建 TAP 设备 tap0(一个 VM 创建一个) 2ip tuntap add dev tap0 mod tap 3 4# 建立网桥 5brctl addbr br0 6 7# 将各 TAP 设备加入网桥: 8brctl addif br0 tap0 9 10# 确保所有设备都已开启 11ip link set br0 up 12ip link set tap0 up 13 14# 给网桥设置虚拟机子网的网关 IP 15ip addr add 192.168.122.1/24 dev br0
启动虚拟机
我们要做的是在启动 QEMU 虚拟机时创建一个 TAP 网络后端,并让它接入上述的网桥,让它们在数据链路层相连。通过查询 qemu-system-x86 --help
或 man qemu-system-x86(1)
,发现其实只要一个简单的配置即可:
1# 若网桥的名称刚好是 br0,则其实 br= 参数也不需要
2-nic bridge,br=br0
其不仅等同于下述一大串配置,简化了命令:
1# 创建一个 id 为 AAA 的 TAP 网络后端,并使其连接的 BBB 设备
2-netdev tap,id=AAA,ifname=BBB,br=br0
3# 创建一个类型为 CCC 虚拟网络设备,对应 AAA 网络后端
4-device CCC,netdev=AAA
5# AAA、BBB、CCC 及未指明的参数皆由 QEMU 自动配置
还可以用同一个命令启动多个虚拟机,而不必考虑多个网络后端有重名和重复 ID 的问题。最终完整的虚拟机启动命令:
1#!/bin/bash
2
3VM_NAME=ubuntu-qemu-vm
4DRIVE=rootfs.qcow2
5NET_BRIDGE=br0
6VNC_DISPLAY=:14
7
8sudo qemu-system-x86_64 \
9 -name $VM_NAME \
10 -m 4096 \
11 -smp 32 \
12 -drive file=$DRIVE,if=virtio,index=0 \
13 -enable-kvm -k en-us \
14 -nic bridge,br=$NET_BRIDGE \
15 -vnc $VNC_DISPLAY \
16 -daemonize
启动完成后,需要在 VM 内部进行网络配置(或者根据不同的发行版,将与以下操作等效的命令固化在相关的配置文件中):
1# 给虚拟网卡配置子网 IP
2ip addr add 192.168.122.10/24 dev eth0
3
4# 配置默认路由,将所有流量导向子网网关
5ip route add default via 192.168.122.1 dev eth0
另外,有的发行版没有自带 SSH 服务器,需要在 VM 内另行安装,以便让外界能够通过 SSH 或 SFTP 连接 VM:
1sudo apt install openssh-server openssh-sftp-server
0x02 用新内核启动
-
将内核代码拷入虚拟机中
-
安装编译内核代码所需的开发环境
-
从
/boot
中找到当前内核的 config,拷贝至<kernel_src_dir>/.config
-
make ARCH=... menuconfig
一下,直接保存退出(据说是可以自动修复某些 config 中的问题) -
编译内核及模块:
1make zImage -jxx # 编内核 2make modules -jxx # 编模块 3 4# 同时编译两者 5make -j$(nproc) 6 7# 交叉编译时要配置 ARCH 和 CROSS_COMPILE 参数 8make ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- -jxx
-
将新内核和模块安装到系统中:
1sudo make modules_install # 安装模块 2sudo make install # 安装内核 3 4# 与编译不同,make install 不包含 make modules_install
-
遇到过这样一种情况:虚拟机镜像一开始分配的不够大导致
/boot
分区容量有限,make install
时mkinitramfs
报错:No space left on device。经查,发现/boot/initrd.img-XXX
文件非常大。最后查明是生成/boot/initrd.img-XXX
的时候会带上/lib/modules/<kernel_version>
下的内核模块,而这些内核模块没有剥离调试信息从而导致的。可以在安装模块时自动剥离 :1sudo make INSTALL_MOD_STRIP=1 modules_install
也可以安装后手动剥离 :
1cd /lib/modules/<new_kernel> 2find . -name *.ko -exec strip --strip-unneeded {} +
-
内核其他安装项(来源 ):
1sudo make headers_install INSTALL_HDR_PATH=/usr 2sudo make firmware_install INSTALL_FW_PATH=/some/path 3# For other options 4make help
-
-
设置 grub/grub2,从新安装的内核启动。
- 建议启用 grub 启动菜单并加入一定的等待时间(修改
/etc/grub2.cfg
中timeout
变量)。这样,若新内核有问题启动失败,我们就仍有机会切换回旧内核启动,而不会陷入“重启→失败→重启→……”的循环。 - CentOS 上可以使用
grubby
来设置默认内核版本,其他发行版可考虑grub2-set-default 0
- 建议启用 grub 启动菜单并加入一定的等待时间(修改
-
重启