以下在x86平台上安装arm架构的虚拟机(包括aarch64),希望能帮到大家。
Qemu架构
Qemu 是纯软件实现的虚拟化模拟器,几乎可以模拟任何硬件设备,我们最熟悉的就是能够模拟一台能够独立运行操作系统的虚拟机,虚拟机认为自己和硬件打交道,但其实是和 Qemu 模拟出来的硬件打交道,Qemu 将这些指令转译给真正的硬件。
正因为 Qemu 是纯软件实现的,所有的指令都要经 Qemu 过一手,性能非常低,所以,在生产环境中,大多数的做法都是配合 KVM 来完成虚拟化工作,因为 KVM 是硬件辅助的虚拟化技术,主要负责 比较繁琐的 CPU 和内存虚拟化,而 Qemu 则负责 I/O 虚拟化,两者合作各自发挥自身的优势,相得益彰。
KVM
KVM(名称来自英语:Kernel-basedVirtual Machine的缩写,即基于内核的虚拟机),是一种用于Linux内核中的虚拟化基础设施,可以将Linux内核转化为一个hypervisor(管理程序)。KVM在2007年2月被导入Linux 2.6.20核心中,以可加载核心模块的方式被移植到FreeBSD(完整)。
关于kvm,kvm 是linux内核包含的东西,使用qemu作为上层管理(命令行),kvm面向的对象主要是服务器。
1).KVM是开源软件,全称是kernel-based virtual machine(基于内核的虚拟机)。
2).是x86架构且硬件支持虚拟化技术(如 intel VT 或 AMD-V)的Linux全虚拟化解决方案。
3).它包含一个为处理器提供底层虚拟化 可加载的核心模块kvm.ko(kvm-intel.ko或kvm-AMD.ko)。
4).KVM还需要一个经过修改的QEMU软件(qemu-kvm),作为虚拟机上层控制和界面。
5).KVM能在不改变linux或windows镜像的情况下同时运行多个虚拟机,(它的意思是多个虚拟机使用同一镜像)并为每一个虚拟机配置个性化硬件环境(网卡、磁盘、图形适配器……)。
6).在主流的Linux内核,如2.6.20以上的内核均已包含了KVM核心。
qemu 全称Quick Emulator。是独立虚拟软件,能独立运行虚拟机(根本不需要kvm)。kqemu是该软件的加速软件。kvm并不需要qemu进行虚拟处理,只是需要它的上层管理界面进行虚拟机控制。虚拟机依旧是由kvm驱动。
KVM内存管理
KVM继承了Linux系统管理内存的诸多特性,比如,分配给虚拟使用的内存可以被交换至交换空间、能够使用大内存页以实现更好的性能,以及对NUMA的支持能够让虚拟机高效访问更大的内存空间等。
KVM基于Intel的EPT(ExtendedPage Table)或AMD的RVI(Rapid Virtualization Indexing)技术可以支持更新的内存虚拟功能,这可以降低CPU的占用率,并提供较好的吞吐量。
此外,KVM还借助于KSM(Kernel Same-pageMerging)这个内核特性实现了内存页面共享。KSM通过扫描每个虚拟机的内存查找各虚拟机间相同的内存页,并将这些内存页合并为一个被各相关虚拟机共享的单独页面。在某虚拟机试图修改此页面中的数据时,KSM会重新为其提供一个新的页面副本。实践中,运行于同一台物理主机上的具有相同GuestOS的虚拟机之间出现相同内存页面的概率是很的,比如共享库、内核或其它内存对象等都有可能表现为相同的内存页,因此,KSM技术可以降低内存占用进而提高整体性能。
从本质上看,虚拟出的每个虚拟机对应 host 上的一个 Qemu 进程,而虚拟机的执行线程(如 CPU 线程、I/O 线程等)对应 Qemu 进程的一个线程。下面通过一个虚拟机启动过程看看 Qemu 是如何与 KVM 交互的。
// 第一步,获取到 KVM 句柄
kvmfd = open("/dev/kvm", O_RDWR);
// 第二步,创建虚拟机,获取到虚拟机句柄。
vmfd = ioctl(kvmfd, KVM_CREATE_VM, 0);
// 第三步,为虚拟机映射内存,还有其他的 PCI,信号处理的初始化。ioctl(kvmfd, KVM_SET_USER_MEMORY_REGION, &mem);
// 第四步,将虚拟机镜像映射到内存,相当于物理机的 boot 过程,把镜像映射到内存。
// 第五步,创建 vCPU,并为 vCPU 分配内存空间。
ioctl(kvmfd, KVM_CREATE_VCPU, vcpuid);
vcpu->kvm_run_mmap_size = ioctl(kvm->dev_fd, KVM_GET_VCPU_MMAP_SIZE, 0);
// 第五步,创建 vCPU 个数的线程并运行虚拟机。ioctl(kvm->vcpus->vcpu_fd, KVM_RUN, 0);
// 第六步,线程进入循环,并捕获虚拟机退出原因,做相应的处理。
for (;;) {
ioctl(KVM_RUN)
switch (exit_reason) {
case KVM_EXIT_IO: /* ... */
case KVM_EXIT_HLT: /* ... */
}
}
// 这里的退出并不一定是虚拟机关机,
// 虚拟机如果遇到 I/O 操作,访问硬件设备,缺页中断等都会退出执行,
// 退出执行可以理解为将 CPU 执行上下文返回到 Qemu。
Qemu 源码结构
Qemu 软件虚拟化实现的思路是采用二进制指令翻译技术,主要是提取 guest 代码,然后将其翻译成 TCG 中间代码,最后再将中间代码翻译成 host 指定架构的代码,如 x86 体系就翻译成其支持的代码形式,ARM 架构同理。
所以,从宏观上看,源码结构主要包含以下几个部分:
其中,涉及的主要几个函数如下:
知道了这个总体的代码结构,再去具体了解每一个模块可能会相对容易一点。
qemu-kvm虚拟化平台构建
准备工作
首先需要检查一下CPU是否支持虚拟化,执行一下命令来检查/proc/cpuinfo文件中是否有vmx或svm虚拟化相关的字,如果有的话表明CPU支持虚拟化技术。
egrep “(svm|vmx)” /proc/cpuinfo
有结果输出,如下图:
上面命令执行结果如果返回0,表示CPU不支持虚拟化技术。当然主板BIOS中的虚拟化技术也可能不是默认开启的,如果没有开启需要手动开启一下。
安装KVM及相关依赖包
sudo apt-get install qemu-kvm
sudo apt-get install qemu
sudo apt-get install virt-manager
sudo apt-get install virt-viewer
sudo apt-get install libvirt-bin
sudo apt-get install bridge-utils
其中:virt-manager为GUI管理窗口,bridge-utils:用于网络桥接
命令行输入kvm --version kvm-ok lsmod | grep kvm来验证安装是否成功
上面的方式为联网安装,也可以下载源码编译安装,具体如下:
源码下载
centos:sudo apt-get install qemu
ubuntu:sudo yum install qemu -y
安装包:
$wget http://wiki.qemu-project.org/download/qemu-2.0.0.tar.bz2
$tar xjvf qemu-2.0.0.tar.bz2
Git:
$git clone git://git.qemu-project.org/qemu.git
编译及安装
$cd qemu-2.0.0 //如果使用的是git下载的源码,执行cd qemu
$./configure --enable-kvm --enable-debug --enable-vnc --enable-werror --target-list="x86_64-softmmu"
$make -j8
$sudo make install
configure 脚本用于生成 Makefile,其选项可以用 ./configure --help 查看。
这里使用到的选项含义如下:
还是首先看一下其配置:
其中interface与NetworkManager(nm)之间具有某种关系,感兴趣的朋友可以自行百度,nm会与右上角的图标有关。
常用命令
virsh iface-bridge ens33 br0
提示找不到网卡为啥呢????
如果出现问题,也没关系
原先的配置
如果virsh iface-bridge ens33 br0出现问题,用下面的方法
brctl addbr br0 创建br0网桥
编辑/etc/network/interfaces,增加如下内容
auto br0
iface br0 inet dhcp # 网桥使用DHCP模式,从DHCP服务器获取IP
bridge_ports enp3s0 # 网卡名称,网桥创建前连接外部的网卡,可通过ifconfig命令查看,有IP地址的就是
bridge_stp on # 避免数据链路出现死循环
bridge_fd 0 # 将转发延迟设置为0
systemctl restart networking.service //重启网络
桥接之后的配置
如果宿主机ip已经成功变到网桥上,并且宿主机能正常上网而虚拟机获取不到ip,可能是ufw没有允许ip转发导致的,编辑/etc/default/ufw允许ip转发。
DEFAULT_FORWARD_POLICY="ACCEPT"
重启ufw服务让设置生效
systemctl restart ufw.service
创建虚拟机
qemu-img create ubuntu16.04-arm64.img 16G
镜像文件创建完成后,可使用 qemu-system-x86_64 来启动aarch64 (x86_64)架构的虚拟机:
qemu-system-aarch64 -m 2048 -cpu cortex-a57 -smp 2 -M virt -bios QEMU_EFI.fd -nographic -drive if=none,file=ubuntu-16.04.3-server-arm64.iso,id=cdrom,media=cdrom -device virtio-scsi-device -device scsi-cd,drive=cdrom -drive if=none,file=ubuntu16.04-arm64.img,id=hd0 -device virtio-blk-device,drive=hd0
-m 指定虚拟机内存大小,默认单位是 MB。可在弹出的窗口中操作虚拟机,安装操作系统,安装完成后重起虚拟机便会从硬盘 (ubuntu16.04-arm64.img ) 启动
各个选项的含义如下:
QEMU_EFI.fd、ubuntu-16.04.3-server-arm64.iso、ubuntu16.04-arm64.img
文件在当前目前下,否则需要修改成对应的文件路径。在上述参数中,指定安装光盘这里-drive if=none,file=ubuntu-16.04.3-server-arm64.iso,id=cdrom,media=cdrom -device virtio-scsi-device -device scsi-cd,drive=cdrom
我在有些网站上找到了不同的方式并尝试,但进入到光盘的安装界面后会报如下图所示错误,最后发现上述指定能正确的完成安装。qemu-system-aarch64 -m 2048 -cpu cortex-a57 -smp 2 -M virt -bios QEMU_EFI.fd -nographic -drive if=none,file=ubuntu16.04-arm64.img,id=hd0 -device virtio-blk-device,drive=hd0
如果出现下面的界面,不要慌。。。
上面是进入到了UEFI的交互shell里面,为什么没有执行grub并引导进入ubuntu系统?说明UEFI固件没有找到ESP分区(EFI system partition,安装过程中就会看见创建了一个ESP分区)或者没有找到ESP分区中的EFI文件,因为系统需要该EFI文件来引导。在该shell下执行exit
进入到UEFI的管理界面,并手动选择EFI文件启动系统,如下图所示。
这样就可以进入到系统中。
利用virt-manager启动虚拟机
下面介绍用带界面的virt-manager工具去直观地管理虚拟机(开关虚拟机、添加删除网络接口也很方便),于是进行了一番尝试,找到了一个可行的方法。启动virt-manager,这种情况下需要提供系统镜像外,还要提供vmlinuz内核文件和initrd文件。
安装完成后启动virt-manager,如下图。在选择Architecture为aarch64后,出现了图中所示的warning,表示找不到aarch64架构的UEFI固件,并且在安装方式上自动选择了Import existing disk image(导入已存在的磁盘映像)。一想也是,系统最开始执行的就是UEFI固件,而我们并没有指定UEFI固件的路径。
在ubantu系统下安装uefi固件,可以直接用以下命令:
sudo apt-get install qemu-efi
固件就会下载到/usr/share/qemu-efi/中,接着就可以用图行界面来安装,具体步骤省略。
参考链接
https://blog.csdn.net/chenxiangneu/article/details/78955462#6%E5%88%A9%E7%94%A8virt-manager%E5%90%AF%E5%8A%A8%E8%99%9A%E6%8B%9F%E6%9C%BA
http://makaidong.com/pengdonglin137/86753_291419.html
https://blog.csdn.net/wujianyongw4/article/details/80353892
https://www.cnblogs.com/wangaohui/p/5184476.html