qemu搭配rootfs启动虚拟机及其网络配置

rootfs配置

相较于busybox 的方式,这种方式的优点在于系统结构完整,拥有完整的操作系统的使用体验,并且可以通过在host上将rootfs.img 镜像挂载到指定目录,实现在host上对rootfs的操作。此外,这种方式下,可以检测到qemu挂载的设备。

  1. Ubuntu-20.04-base ,下载一个适用于Ubuntu的base包,其中包含一些基础的目录结构以及文件。

  2. 创建一个镜像来装载base包中的文件。

    1
    2
    3
    4
    # 大小可以稍大一些,避免出现空间不足的问题,这里实际创建大小约11G左右
    dd if=/dev/zero of=rootfs.img bs=10240 count=1M
    # 对其进行格式化
    mkfs.ext4 -F -L linuxroot rootfs.img
  3. 挂载镜像,将base包放入镜像中。

    1
    2
    3
    4
    5
    6
    7
    # 需要管理员权限
    sudo mkdir /mnt/tmpdir
    # 挂载镜像到/mnt/tmpdir 目录
    sudo mount -o loop rootfs.img /mnt/tmpdir/
    # 将下载好的base包解压到该目录中
    tar -zxvf ubuntu-base-20.04.1-base-amd64.tar.gz -C /mnt/tmpdir/

  4. 挂载好镜像以后,我们需要在rootfs上面安装软件,为了能够使用apt命令去安装软件,因此需要在chroot切换根目录环境中之前,把所需的DNS配置以及各种内存文件系统挂载上去。

    1
    2
    3
    4
    5
    cp /etc/resolv.conf /mnt/tmpdir/etc/
    mount -t proc /proc /mnt/tmpdir/proc
    mount -t sysfs /sys /mnt/tmpdir/sys
    mount -o bind /dev /mnt/tmpdir/dev
    mount -o bind /dev/pts /mnt/tmpdir/dev/pts
  5. 切换根文件系统,修改根目录

    1
    sudo chroot /mnt/tmpdir
  6. 安装必要的软件。以下的软件如果不全部安装,则在启动虚拟机时,会启动失败。以下软件全部安装大概需要800MB+的空间,因此最初的磁盘不能创建过小。

    1
    2
    3
    4
    5
    6
    apt-get update
    apt-get install language-pack-en-base sudo \
    ssh net-tools ethtool wireless-tools \
    ifupdown network-manager iputils-ping \
    rsyslog htop vim xinit xorg alsa-utils \
    --no-install-recommends
  7. 设置root密码,否则开机后无法登陆。

    1
    2
    3
    4
    5
    # 根据提示为root用户设置密码
    passwd root

    # 如果添加新用户,也可以使用这种方式设置新用户的密码。
    passwd <user>
  8. 配置必要的路由信息和主机名。

    1
    2
    echo "host" > /etc/hostnames
    echo "127.0.0.1 localhost" > /etc/hosts

    至此基本的配置已经结束。如果有需要可以自行通过apt-get工具下载所需的软件,或是修改本地的配置文件。按下Ctrl D即可退出chroot的根目录,回到之前的根目录。

  9. 取消文件系统的挂载

    1
    2
    3
    4
    5
    sudo umount /mnt/tmpdir/proc/
    sudo umount /mnt/tmpdir/sys/
    sudo umount /mnt/tmpdir/dev/pts/
    sudo umount /mnt/tmpdir/dev/
    sudo umount /mnt/tmpdir/

在配置好上述rootfs的基本配置后,通过下述命令可以启动qemu虚拟机

1
qemu-system-x86_64 --enable-kvm -s -kernel ./vmlinux -hda ./rootfs.img -m 4096M -nographic -append "root=/dev/sda console=ttyS0 $CMDLINE"

qemu网络问题

qemu常用的上网方式有两种: Usermode Networking(默认上网方式,类似于VMware中的NAT)Bridged Networking(桥接模式),前者的好处是不需要在qemu启动过程中进行任何设置,是默认的上网方式,但是缺点是主机无法ping通虚拟机;后者主机与虚拟机之间可以互相通信,但是需要在host上开启一个虚拟网卡,负责转发网络包,且需要在qemu启动命令行中进行参数设置。

虚拟机网卡问题

  • 在打开虚拟机后,可能会出现使用命令 ifconfig -a 只有 lo开头的网卡。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    # 出现这样的情况是因为没有网卡驱动,因为qemu默认使用的e1000,但是内核的默认编译选项中相应的驱动配置方式为手动加载,因此在没有手动加载的前提下,没有驱动无法识别网卡。

    # 两种方式:
    # 1- 将e1000 网卡驱动编译进内核
    # .config 文件原始状态
    CONFIG_E1000=m
    CONFIG_E1000E=m

    #将其修改为自动编译进内核
    CONFIG_E1000=y
    CONFIG_E1000E=y
    # 2- 将e1000网卡驱动手动加载
    # 下载e1000 网卡驱动
    # 解压后进入 e1000根目录/src
    # 执行 make install

    但是第二种方法会有一个问题,e1000 网卡驱动不适用于 kernel版本>5.4的内核

Usermode Networking

在上述过程后,启动的虚拟机可能会存在一个问题,无法上网,以下是可能出现的情况以及解决办法

  • 使用命令ifconfig 只有 lo网卡,但是使用ifconfig -a命令后,存在en 开头的网卡

    1
    2
    3
    4
    5
    6
    7
    8
    # 这种情况只是网卡(en开头)没有启用
    # 1. 为网卡指定IP地址,并启动网卡
    sudo ifconfig <网卡名> <ip地址> up

    # 2. 使用dhcp,为网卡自动分配IP地址
    sudo dhclient <网卡名>
    # 如果出现 dhclient: commond not found
    # 使用apt install isc-dhcp-client 安装dhclient

    经过上述的操作, 你会发现你的虚拟机已经可以上网了,但是会有一个问题,host无法ping通虚拟机。

    如果出现无法ping通百度的情况,请参考下面增加域名服务器地址的操作。

Bridged Networking

  1. 安装桥接模式必备工具

    1
    2
    sudo apt-get install bridge-utils     # 虚拟网桥工具
    sudo apt-get install uml-utilities # UML(User-mode Linux)工具
  2. 创建一张 TUN网卡

    1
    2
    3
    # 创建一张网卡给指定的用户使用
    sudo tunctl -t <网卡名> -u <用户名>
    例:sudo tunctl -t tap0 -u zxl
  3. 将网卡操作命令设置为任何人都有权使用

    1
    sudo chmod 0666 /dev/net/tun
  4. 为创建的网卡设置一个IP地址并启动网卡,不要与真实的IP 地址在同一个网段。例如,真实IP地址是192.168.1.2,那就给tap0设置为192.168.2.1:

    1
    sudo ifconfig tap0 192.168.2.1 up
  5. host需要为虚拟机开启IP数据包转发,即在192.168.1.* 网段192.168.2.*网段转发数据

    1
    2
    sudo echo 1 > /proc/sys/net/ipv4/ip_forward # 这里可能sudo的权限也不够,需要su切换到root用户进行操作。
    sudo iptables -t nat -A POSTROUTING -j MASQUERADE

    到这里,host的配置完毕。

  6. 启动虚拟机:

    1
    2
    3
    4
    qemu-system-x86_64 --enable-kvm -net nic -net tap,ifname=tap0,script=no,downscript=no -s -kernel ./vmlinux -hda ./rootfs.img -m 4096M -nographic -append "root=/dev/

    # -net nic - 不加任何参数表示使用默认的网卡类型e1000
    # -net tap,ifname=tap0,script=no,downscript=no - 指定网卡接口名称为tap0,设置host在启动客户机时自动执行的网络配置脚本和宿主机在客户机关闭时自动执行的网路配置脚本。由于qemu中运行自主系统,因此这里不适用系统脚本,全部为no。

    qemu网络通信方式:

    1. User mode stack:用户协议栈方式,这种方式的大概原理是在 QEMU 进程中实现一个协议栈,这个协议栈可以被视为一个主机与虚拟机之间的 NAT 服务器,它负责将 QEMU 所模拟的系统网络请求转发到外部网卡上面,从而实现网络通信。但是不能将外面的请求转发到虚拟机内部,并且虚拟机 VLAN 中的每个接口必须放在 10.0.2.0 子网中。
    2. socket: 为 VLAN 创建套接字,并把多个 VLAN 连接起来。
    3. TAP/bridge:最重要的一种通信方式,我们想要实现 QEMU 虚拟机和外部通信就需要使用这种方式。
    4. VDE:也是用于连接 VLAN 的,如果没有 VLAN 连接需求基本用不到。
    
  7. 进入虚拟机后,使用ifconfig -a

可以看到,ens3网卡没有启动。

  1. 给其设置一个IP地址,要求与tap0 在同一网段即可,例如 192.168.2.2

    1
    sudo ifconfig ens3 192.168.2.2 up

    之后就能发现,宿主机与虚拟机可以相互ping通。但是此时,虚拟机还不能上外网,因为虚拟机缺少网关。现在把虚拟机的tap0的地址,即192.168.2.1,设置为虚拟机的网关:(有可能在设置网关之前,哪个都ping不通,但是没有影响,设置完网关即可。)

    1
    sudo route add default gw 192.168.2.1

    这样,也可以ping通外网了,比如ping 115.239.211.112。但是ping www.baidu.com却不行,因为缺少DNS服务器!现在就把8.8.8.8指定为虚拟机的DNS服务器:

    1
    2
    3
    sudo vim /etc/resolv.conf
    # 追加域名服务器地址
    nameserver 8.8.8.8

写入文件之后,DNS立即生效了。现在,虚拟机既能上外网,又能与宿主机通信了!

详细见:安装qemu-kvm以及配置桥接网络Linux下qemu网络配置(不使用en网络接口)

参考资料

  1. KVM/Networkin
  2. QEMU doc
  3. QEMU 虚拟机网络模式
  4. qemu e1000网卡驱动
  5. 解决没有e1000 驱动
  6. 解决没有e1000驱动
  7. 下载安装e1000驱动
Author

FatAngle

Posted on

2022-09-13

Updated on

2023-06-30

Licensed under

Commentaires