文章目录
基础知识
(一)KVM
KVM(Kernel-based Virtual Machine,基于内核的虚拟机)是一种 TYPE1 Hypervisor(裸金属类型)虚拟化技术,VMM 和 HostOS 一体化,直接运行 Host Hardware 之上,实现硬件和虚拟机完全管控。具有以下 3 个典型特点是:
依赖 CPU 硬件辅助的虚拟化技术(e.g. Intel VT-x / AMD-V);
VMM 和 HostOS 一体化;运行效率高。
KVM 的本质就是一个 Linux Kernel Module,命名为 kvm.ko(kvm-intel.ko / kvm-AMD.ko),在利用了 Kernel 所提供的部分操作系统能力(e.g. 内存管理、进程管理、硬件设备管理)的基础之上,再加入了 CPU 和 Memory 虚拟化的能力,使得 Linux Kernel 得以具备成为一个完备 VMM 的 3 个条件:
资源控制(Resource Control):VMM 必须能够管理所有的系统资源。
等价性(Equivalence):在 VMM 管理下运行的 HostOS 和 GuestOS,除了 CPU 时序和硬件资源可用性之外的行为应该完全保持一致。
效率性(Efficiency):绝大多数的 GuestOS 指令应该由 Host Hardware 直接执行而无需 VMM 的参与(二进制翻译)。
(二)QEMU
QEMU(Quick Emulator)最早于 2001 由天才程序员 Fabrice Bellard 发布,是一款开源的、采用了动态二进制翻译技术的 TYPE2 Hypervisor(寄居式类型)VMM 软件。
QEMU 4.0.0 发布并对外宣称支持模拟 x86、x86_64、ARM、MIPS、SPARC、PowerPC 等多种 CPU 架构,同时也几乎可以模拟所有的物理设备,这简直就是一个奇迹般的软件。
但由于原生的 QEMU 主要采用了软件 “捕获-模拟“ 的实现方式,所以也存在性能低下的问题。
QEMU 通过 open() / close() 来打开/ 关闭 /dev/kvm 设备接口文件,并通过设备 I/O 接口 ioctl() 来调用 kvm.ko 提供的接口函数,以此来应用 KVM 基于硬件辅助虚拟化技术实现的 CPU 虚拟化、Memory 虚拟化、I/O 虚拟化等功能。此外的,VM 配置管理、VM 生命周期管理、VM 虚拟外设管理、以及一些特定的虚拟机技术(e.g. 动态迁移)等,则都由 QEMU 自己来实现。
open("/dev/kvm", O_RDWR|O_LARGEFILE) = 3
ioctl(3, KVM_GET_API_VERSION, 0) = 12
ioctl(3, KVM_CHECK_EXTENSION, 0x19) = 0
ioctl(3, KVM_CREATE_VM, 0) = 4
ioctl(3, KVM_CHECK_EXTENSION, 0x4) = 1
ioctl(3, KVM_CHECK_EXTENSION, 0x4) = 1
ioctl(4, KVM_SET_TSS_ADDR, 0xfffbd000) = 0
ioctl(3, KVM_CHECK_EXTENSION, 0x25) = 0
ioctl(3, KVM_CHECK_EXTENSION, 0xb) = 1
ioctl(4, KVM_CREATE_PIT, 0xb) = 0
ioctl(3, KVM_CHECK_EXTENSION, 0xf) = 2
ioctl(3, KVM_CHECK_EXTENSION, 0x3) = 1
ioctl(3, KVM_CHECK_EXTENSION, 0) = 1
ioctl(4, KVM_CREATE_IRQCHIP, 0) = 0
ioctl(3, KVM_CHECK_EXTENSION, 0x1a) = 0
Kernel 在加载 kvm.ko 成为 VMM 之后,就具备了 3 种不同的运行模式,分别对应了 Intel VT-x 的 2 种特权模式:
User Mode(User space):运行 QEMU(User Process)代码。
Kernel Mode(Kernel space,CPU Root Mode):运行 kvm.ko 代码。
Guest Mode(Kernel space,CPU Non-root Mode):运行 GuestOS 代码。
Kernel Mode 作为 User Mode 和 Guest Mode 之间沟通的桥梁。在 User Mode 中,QEMU 通过 ioctl() 来操作 VM。然后 Kernel Mode 收到 ioctl() 请求,首先完成一些准备工作(e.g. 将 vCPU 上下文加载到 VMCS 等),然后 CPU 执行 VM Entry 指令,进入到 Non-Root Mode,CPU 开始执行 GuestOS 的代码。
(三)Linux容器技术
1.Linux Container容器是一种内核虚拟化技术,可以提供轻量级的虚拟化,以便隔离进程和资源。
LXC为Linux Container的简写。可以提供轻量级的虚拟化,以便隔离进程和资源,而且不需要提供指令解释机制以及全虚拟化的其他复杂性。相当于C++中的NameSpace。容器有效地将由单个操作系统管理的资源划分到孤立的组中,以更好地在孤立的组之间平衡有冲突的资源使用需求。与传统虚拟化技术相比,它的优势在于:
(1)与宿主机使用同一个内核,性能损耗小;
(2)不需要指令级模拟;
(3)不需要即时(Just-in-time)编译;
(4)容器可以在CPU核心的本地运行指令,不需要任何专门的解释机制;
(5)避免了准虚拟化和系统调用替换中的复杂性;
(6)轻量级隔离,在隔离的同时还提供共享机制,以实现容器与宿主机的资源共享。
总结:Linux Container是一种轻量级的虚拟化的手段。
Linux Container提供了在单一可控主机节点上支持多个相互隔离的server container同时执行的机制。Linux Container有点像chroot,提供了一个拥有自己进程和网络空间的虚拟环境,但又有别于虚拟机,因为lxc是一种操作系统层次上的资源的虚拟化。
2.LXC与docker的关系
(1)Docker并不是LXC的替代品,Docker的底层就是使用了LXC来实现的。LXC将Linux进程沙盒化,使得进程之间相互隔离,并且能够控制各
进程的资源分配。
(2)在LXC的基础之上,Docker提供了一系列更强的功能。
namespace 是 Linux 内核的一项特性,它可以对内核资源进行分区,使得一组进程可以看到一组资源;而另一组进程可以看到另一组不同的资源。该功能的原理是为一组资源和进程使用相同的 namespace,但是这些 namespace 实际上引用的是不同的资源。
这样的说法未免太绕了些,简单来说 namespace 是由 Linux 内核提供的,用于进程间资源隔离的一种技术。将全局的系统资源包装在一个抽象里,让进程(看起来)拥有独立的全局资源实例。同时 Linux 也默认提供了多种 namespace,用于对多种不同资源进行隔离。
实验过程
(一)虚拟机KVM/QEMU
虚拟机要提前做好准备工作,包括iso文件(提前下载好),硬盘文件linux.qcow2,虚拟机配置文件linux.xml
<domain type='kvm'>
<name>linux</name>
<memory unit='GiB'>8</memory>
<vcpu>4</vcpu>
<os>
<type arch='x86_64' machine='pc-i440fx-rhel7.6.0'>hvm</type>
</os>
<features>
<acpi/>
</features>
<cpu mode='host-passthrough'>
</cpu>
<clock offset='utc'/>
<on_poweroff>shutdown</on_poweroff>
<on_reboot>restart</on_reboot>
<on_crash>destroy</on_crash>
<devices>
<emulator>/usr/libexec/qemu-kvm</emulator>
<disk type='file' device='disk'>
<driver name='qemu' type='qcow2' cache='none'/>
<source file='/root/virbcl/linux.qcow2'/>
<target dev='sda' bus='ide'/>
<boot order='2'/>
</disk>
<disk type='file' device='cdrom'>
<driver name='qemu' type='raw'/>
<source file='/root/virbcl/Linux-xxxx.iso'/>
<target dev='sdb' bus='ide'/>
<readonly/>
<boot order='1'/>
</disk>
<interface type='network'>
<source network='default'/>
<model type='virtio'/>
</interface>
<serial type='pty'>
<target type='isa-serial' port='0'>
<model name='isa-serial'/>
</target>
</serial>
<console type='pty'>
<target type='serial' port='0'/>
</console>
<input type='mouse' bus='ps2'/>
<graphics type='vnc' listen='0.0.0.0'/>
</devices>
</domain>
若define有qemu❌107:107报错可参考,没有则跳过此步骤
# vim /etc/libvirt/qemu.conf
user="root"
group="root"
# systemctl restart libvirt
执行 virsh 命令启动一台虚机
# virsh start linux.xml
virt-install命令行安装虚拟机
如果你的linux服务器是桌面版本的,可以使用上述图形化安装kvm虚拟机。但是大部分linux虚拟机并不带可视化桌面,我们只能使用命令行的方式创建虚拟机,这里使用到的工具——virt-install。
用yum install安装工具:
//qemu-kvm virt-install libvirt vnc
这里需要多安装一个vnc服务,因为不是带桌面的版本,所以我们安装完成之后需要通过vnc连接安装好的虚拟机。
(二)安装docker等容器技术
安装docker
测试运行helloworld
停止 docker 服务。
sudo service docker stop
(三)测试isula与docker比较他们的并发性能和启动速度等性能指标
isula和Docker都是容器运行时(Container Runtime)工具,用于在操作系统层面创建和管理容器。它们在性能指标方面可能存在一些差异。以下是对它们的并发性能和启动速度等性能指标进行比较的一些常见考虑因素:
并发性能:
资源隔离:isula和Docker都使用Linux内核的命名空间和控制组(cgroups)来实现容器的资源隔离。在并发负载下,两者的性能可能相当,因为它们都依赖于相同的内核机制。
网络性能:对于网络密集型应用,isula和Docker的并发性能可能会受到网络驱动程序的影响。具体性能取决于所选择的驱动程序和网络配置。
存储性能:isula和Docker使用不同的存储驱动程序,如overlay2、aufs等。性能可能因驱动程序的不同而有所差异。
并发性能测试:
#安装 Apache Bench 工具
sudo apt-get install apache2-utils
#使用 Apache Bench 运行并发性能测试
ab -n 1000 -c 100 http://your-website.com/
启动速度:
# 创建一个简单的 Docker 镜像
# Dockerfile
FROM ubuntu:latest
CMD echo "Hello, World!"
# 构建 Docker 镜像
docker build -t my-image .
# 启动 Docker 容器并计时启动时间
time docker run --rm my-image
容器镜像:isula和Docker都使用容器镜像来创建容器。启动速度可能与镜像的大小和复杂性有关。较大和复杂的镜像可能需要更长的时间来启动。
存储驱动程序:启动速度也可能受到所选的存储驱动程序的影响。某些驱动程序可能在启动时需要更多时间来加载和准备容器的文件系统。
需要注意的是,性能测试结果可能会因环境配置、硬件规格、软件版本和测试方法等因素的不同而有所差异。因此,建议在特定的部署环境中进行自己的性能测试,以获得更准确和可靠的性能指标。
另外,isula最初是由华为开发的容器运行时工具,而Docker是业界使用最广泛的容器平台之一。虽然它们在某些方面可能存在一些差异,但在大多数常见的性能指标上,两者的性能表现应该是相当接近的。
遇到的问题
1.虚拟机管理器连接失败
这是因为libvirt负责虚拟机与宿主机的通信
如果网卡配置错误或者建立通信的环节出现错误的话。
libvit就会运行libvirtd
守护进程,这也是一种保护方式。
如果网卡都没有配置错误的话关闭防火墙试试。
一开始虚拟机不能ping通外网和本机,是因为ip地址和网关没有设置好。设置好之后,却发现在桥接模式下还是不能ping通。此处留有疑问。后面尝试用NAT模式,就能成功了。
第二个,虚拟机内创建虚拟机报错:Kvm internal error: process exited :cannot set up guest memory ‘pc.ram‘:Cannot allocate memory的问题。
问题解决详述:此问题是在用KVM软件创建虚拟机时提示存储不够,内存的问题。后来发现是在修改外虚拟机配置的过程中,忘了增加内存和处理器个数导致的。改正后就没有再报错了,创建虚拟机成功。
第三个,克隆虚拟机时存储空间不够的问题
问题解决详述:克隆虚拟机时提示外虚拟机的存储空间不足。一开始我的外虚拟机给了20G的存储,说不够。其实后来的扩容操作并不顺利。看报错是什么挂载问题。那台虚拟机之前遇到第二个问题的时候配置调出了毛病,直接导致扩容的连锁问题。于是我便重新开了个虚拟机,配了48G的存储空间。后面就没有遇到克隆空间不足的问题了。
第四个,克隆过程中,shutdown命令无法关闭虚拟机的问题
问题解决详述:在克隆之前,我通过shutdown命令明明将虚拟机关闭了,终端的提示说虚拟机已经关闭,但是在KVM里看,虚拟机还是开着的,克隆操作也无法进行,所以判断shutdown命令失效了,并没有将虚拟机关闭。后来我并没有找到适合的终端关闭虚拟机的命令,于是我在KVM中用图形界面把虚拟机给关闭了。后面的克隆操作就顺利了。
2.编译动态库时遇到relocation R_X86_64_32 against a local symbol
编译动态库时遇到例如以下错误:
…
… relocation R_X86_64_32 against `a local symbol’ can not be used when making a shared object; recompile with -fPIC
… could not read symbols: Bad value
解决的方法编译器已经提示了:recompile with -fPIC
可是我们应该又一次编译谁带上这个參数呢?经过我几番折腾,发现例如以下情况:
1、编译.o文件的时候,没有参数-fPIC,这问题个在gcc version 3.4.6版本号没有发生,可能那个编译器默认都给加上吧。
2、当前程序中实用到某个静态库,那个静态库编译.o文件的时候没有加上-fPIC(静态库事实上就是.o文件打包)。补充一点:我发现手写Makefile时即使不加-fPIC也没有这个问题,这一点非常郁闷,这个仅仅在用automake工具编译出.a文件时才出现过。
3.error while loading shared libraries: xxx.so.x" 错误的原因和解决的方法
一般我们在Linux下执行某些外部程序的时候可能会提示找不到共享库的错误, 比方:
tmux: error while loading shared libraries: libevent-1.4.so.2: cannot open shared object file: No such file or directory
原因一般有两个, 一个是操作系统里确实没有包括该共享库(lib*.so.*文件)或者共享库版本号不正确, 遇到这样的情况那就去网上下载并安装上就可以.
另外一个原因就是已经安装了该共享库, 但执行须要调用该共享库的程序的时候, 程序依照默认共享库路径找不到该共享库文件.
所以安装共享库后要注意共享库路径设置问题, 例如以下:
- 假设共享库文件安装到了/lib或/usr/lib文件夹下, 那么需执行一下ldconfig命令
ldconfig命令的用途, 主要是在默认搜寻文件夹(/lib和/usr/lib)以及动态库配置文件/etc/ld.so.conf内所列的文件夹下, 搜索出可共享的动态链接库(格式如lib*.so*), 进而创建出动态装入程序(ld.so)所需的连接和缓存文件. 缓存文件默觉得/etc/ld.so.cache, 此文件保存已排好序的动态链接库名字列表. - 假设共享库文件安装到了/usr/local/lib(非常多开源的共享库都会安装到该文件夹下)或其他"非/lib或/usr/lib"文件夹下, 那么在执行ldconfig命令前, 还要把新共享库文件夹加入到共享库配置文件/etc/ld.so.conf中, 例如以下:
# cat /etc/ld.so.conf
include ld.so.conf.d/*.conf
# echo "/usr/local/lib" >> /etc/ld.so.conf
# ldconfig
- 假设共享库文件安装到了其他"非/lib或/usr/lib" 文件夹下, 可是又不想在/etc/ld.so.conf中加路径(或者是没有权限加路径). 那能够export一个全局变量LD_LIBRARY_PATH, 然后执行程序的时候就会去这个文件夹中找共享库.
LD_LIBRARY_PATH的意思是告诉loader在哪些文件夹中能够找到共享库. 能够设置多个搜索文件夹, 这些文件夹之间用冒号分隔开. 比方安装了一个mysql到/usr/local/mysql文件夹下, 当中有一大堆库文件在/usr/local/mysql/lib下面, 则能够在.bashrc或.bash_profile或shell里加入下面语句就可以:
export LD_LIBRARY_PATH=/usr/local/mysql/lib:$LD_LIBRARY_PATH
一般来讲这仅仅是一种暂时的解决方式, 在没有权限或暂时须要的时候使用。
4.容器技术出现的问题
出现的问题:
1.列出镜像列表失败。
2.拉取镜像失败。
3.两个容器无法通过“容器名”通信。(bbox1与bbox2)
4.在web1容器中找不到ip a命令。(command not found)
解决方案:
1.要先启动docker。
2.新建daemon.json配置文件,设置国内镜像源加速地址。
3.修改daemon.json文件,配置全部容器的DNS,重启docker使之生效
4.进行资源更新和升级。(apt-get update/apt-get upgrade)
实验总结
容器技术和QEMU/KVM是两种不同的虚拟化技术,它们在应用场景、性能、资源利用和管理等方面存在差异。
容器技术适用于轻量级应用隔离和部署,通过共享操作系统内核,实现高效的资源利用和快速的启动时间。容器具有较低的开销和较高的性能,适合于部署大量相似的应用实例和微服务架构。
QEMU/KVM是一种基于硬件虚拟化的技术,可以在宿主机上运行多个独立的虚拟机。它提供了完全的虚拟化,每个虚拟机都有独立的操作系统和内核。QEMU/KVM适用于需要隔离和管理整个操作系统环境的场景,如运行不同操作系统的虚拟机提供完全隔离的开发/测试环境等。
在性能方面,容器技术通常比QEMU/KVM更轻量级且具有更低的虚拟化开销。容器直接运行在宿主机的内核上,因此几乎没有额外的性能损失。而QEMU/KVM需要模拟硬件设备,并运行完整的操作系统,因此会有更多的性能开销。
然而,QEMU/KVM提供了更高的隔离性和安全性,每个虚拟机都是独立的,可以实现更好的资源隔离和安全性。另外,QEMU/KVM支持运行不同操作系统的虚拟机,提供了更大的灵活性。