虚拟化

虚拟化原理

什么是虚拟化?
将一组物理平台虚拟/抽象为多组相互隔离的平台,每一个平台就仿佛就自己在使用硬件资源一样,每一个平台都应该有5大基本组件(CPU,MEM,I/O,KEYBORAD,MONITOR)

cpu虚拟化

对于cpu虚拟化也是通过分时技术实现
cpu一共有4个ring,从最外侧的ring3到ring0,ring3运行普通指令,ring2,ring1未使用的,ring0是特权环,比如操作硬件,等等指令,内核空间就在环0上执行,用户空间在ring3上执行,如果用户空间想用特权资源比如操作硬件就要发起系统调用,
在这里插入图片描述
当我们引入虚拟化环境后,虚拟机也分用户空间和内核空间,就拿我们常用的vmware(后简称为vw)来说明,首先我们的vw跑在我们的操作系统之上的,vw虚拟出来的虚拟机也在我们的操作系统之上,这时候我们称宿主机的操作系统为host,vw虚拟出来的操作系统称为guest,当我们的guest运行起来后他对于host来说也是一个进程,他也受我们的host管控,所以我们的虚拟机guest用户空间运行的进程要想到达硬件级别要经过2次内核,一次自己的内核空间,一次宿主机host的内核空间 ,直接运行在ring0上的内核是host的内核,而我们guest的内核运行在ring3上,一个内核开发的时候,一定会认为自己直接操作所有的硬件设别,也就是说内核的开发者在开发内核的时候假定内核可以运行所有硬件,也就是说假定他运行在ring0上,在这时候有一个矛盾,那就是如果让guest运行在ring0上反客为主把host踢掉怎么办?,如果我guest运行在ring3上他又跑不起来,因为内核要直接调用硬件,那怎么办?这时有一个解决办法,那就是用一个进程或者一个线程模拟出一个cpu,这个cpu也有ring3,ring2,ring1,ring0,供guest使用,大家都知道cpu就是由逻辑电路,数字电路,等组成,这些设备输出的接口就是运行指令的接口,任何一个硬件芯片提供给我们的接口都是微码编程的接口,我们把微码模拟的接口用软件模拟出一个假的,这个假的还是要在真的上运行,,这个软件中也有特权指令当然是假的,当你真正执行特权指令(系统调用)他是向host发送请求,host发现后要把你隔离开来或者把多个虚拟机发送的特权指令隔离开来,比如我们的一个guest要关机的时候,请求关机就是特权指令,他只是把虚拟机的模拟电源切断,我们的模拟cpu一般不超过你的物理核心数,但是理论上可以模拟几百几千个,因为一个模拟的cpu是一个进程或者线程,我们模拟N个cpu就会出现N个进程他们所发出的指令最终都会到正真的cpu上这样带来大量的切换,会导致性能非常的低,所以少于物理核心为好,
我们的这样的模式还有一种不好的地方,当guest用户进程发送指令(系统调用)到guest的内核,guest的内核不能直接执行,所以虚拟软件要解码封装,然后作为host的用户进程发送指令到host内核,host内核再调用,非常消耗资源,所以这时候vmware公司出现了BT技术(Binari Translation) 也就是在guest用户空间对特权指令的调用也就是向内核空间发送系统调用,(如果不是虚拟环境内核再向cpu发送指令)的那一刻就翻译成对host特权指令的调用,使得早期虚拟技术大幅度提升,在这时候,guest的用户空间运行在ring3上,而guest的内核空间运行在ring1上就是因为BT技术,让他实时翻译
在这里插入图片描述
如果我们底层的cpu是x86架构的也可以模拟初arm架构的cpu,但是我们arm的指令级要转化成x86的,这非常的慢
在没有虚拟化的环境当中,我们的用户空间的指令只要不是特权指令(只要不是调用硬件)就可以直接在cpu ring3 上跑,如果是特权指令需要内核在ring0上运行,所以如果我们的host的物理架构和guest的物理架构一致,那么guest的用户空间的非特权指令可以直接在cpu上运行,所以BT技术有一个缺陷那就是物理架构和虚拟机架构要保持一致
所以到此我们的虚拟化有2种一种是

  • 模拟(emulation)

    纯软件实现,不用在意底层cpu的架构和虚拟机的架构是否一致,不管是特权指令还是非特权指令都要由软件转换再由host发送 我们要给他模拟ring0,1,2,3
    Emulators emulate hardware without relying on the CPU being able to run code directly and redirect some operations to a hypervisor controlling the virtual container.

  • 虚拟(virtualization)

    底层的架构和上层的架构必须一致,只有 特权指令需要转换,我们只需要模拟ring0,
    Virtual machines make use of CPU self-virtualization, to whatever extent it exists, to provide a virtualized interface to the real hardware

完全虚拟化(full-virtualization)

我们的VMware workstation是一个完全虚拟化,guest完全意识不到自己运行在虚拟环境中大部分的功能还是靠软件的方式实现,并且各个guest运行在ring1上面的 比如BT

硬件辅助虚拟化(HVM)

让cpu具有5个ring分别是,ring3,ring2,ring1,ring0,ring-1,host内核运行在ring-1上(特权指令环),各个guest运行在ring0上但是没有特权指令了,各个虚拟机的用户空间运行在ring3上(这样虚拟机就认为自己运行在真正的cpu上而且看到自己可以调用特权指令,当然这个特权指令是cpu虚拟给他的),当guest调用特权指令的时候的时候调用ring0,此视ring0并没有真正的特权,此时真正交给的是host的ring-1,我们的host可以捕获对ring0上的特权指令的调用,进而自己可以用硬件转换成特权指令
BT和硬件辅助虚拟化都是完全虚拟化不过一个是软件模拟ring0转换特权指令,一个是硬件模拟出一个ring-1转换特权指令,完全虚拟化一定会有一个转换的过程

半虚拟化(para-virtualization)

刚才我们提到完全虚拟化就是让所有的guest意识不到自己运行在虚拟化环境中,所以在半虚拟化的环境中各个guest明确的意识到自己运行在虚拟化环境中,所以在guest的用户空间运行特权指令的时候不是去直接调用特权指令而是直接去和宿主机的内核发起请求,所以之间的调用直接简化成对宿主机内核某些特权指令请求,所以此时我们的宿主机叫做vritual machine monitor(也就是vmm),也可以叫做hypervisor,hypervisor直接管理硬件,服务器的内存和cpu(不包括IO设备)直接由我们的hypervisor管理,他直接把对cpu和内存的调用虚拟成为hyper call,我们用户空间对内核空间的调用叫做系统调用(system call),当我们的虚拟机发起系统调用,只要是不影响到其他虚拟机或者hypervisor的直接由我们的虚拟机内核发起调用然后转换到内核空间,如果影响到了就调用hypercall由我们的hypervisor执行,所以我们的半虚拟化必须要修改虚拟机的内核不然他不知道会像hypercall调用
在这里插入图片描述

内存虚拟化

内存本来就是虚拟化的,他为了让所有的进程觉得自己独占所有内存(我们的内核空间才会真正这样)
我们的cpu上有一个叫做MMU(Memory Management Unit)的东西

如果处理器没有启用MMU,CPU执行单元发出的内存地址将直接传到芯片引脚上,被内存芯片(以下称为物理内存,以便与虚拟内存区分)接收,这称为物理地址,
如果处理器启用了MMU,CPU执行单元发出的内存地址将被MMU截获,从CPU到MMU的地址称为虚拟地址(Virtual Address,以下简称VA),而MMU将这个地址翻译成另一个地址发到CPU芯片的外部地址引脚上,也就是将VA映射成PA 早期我们的计算机cpu寻找就是直接寻找物理地址,而现在cpu寻找的都是虚拟地址,虚拟地址发送内存之前先被mmu转换成物理地址,而且程序在内存中存储的数据在物理地址上是离散的

当我们引入了虚拟化技术后
在物理内存上对内存进行管理的是hypervisor,hypervisor上有很多虚拟机,在hypervisor中内存任然被分成内存叶分配给各个虚拟机,虚拟机用户空间发起系统调用请求内存,然后hypervisor给他分配内存,然后在虚拟机内存看来地址是一个连续的,然后虚拟机要访问这个内存,发起系统调用,cpu收到后不会直接访问这个地址的而是转给MMU,然后由mmu转换成"物理地址",这个物理地址是虚拟机内核管理的地址,这个物理地址还是虚拟的,还要被hypervisor系统调用转换成真正的物理地址,第一次虚拟机的用户空间(某个进程)访问内存由MMU转换成虚拟机的内核管理的内存空间(还是虚拟的),然后再有hyperviosr由shadows page mmu转换成他所管理的物理地址空间,因为MMU是给进程用的,MMU不能把它抢过来,

这样每当我们的cpu进行虚拟机切换就会导致(TLB缓存重新刷新这样效率非常低)

TLB(Translation Lookaside Buffer)转换检测缓冲区是一个内存管理单元,用于改进虚拟地址到物理地址转换速度的缓存 TLB一共分成3部分一个是标识,一个是数据,一个是辅助信息,其中标识是虚拟地址的19~31位,数据是物理地址的13 ~31位,还有一个是辅助信息
首先我们的虚拟地址有32位由cpu生产,这个虚拟地址中间包含偏移量,这个偏移量就是由物理地址或者说是实际地址(段尾地址,这个段是一个数据的内存段),减去段地址(也就是段首地址)得到的,这个虚拟地址我们也可以叫成实际地址

所以此时,针对第二次地址转换以前是软件模拟,现在由intel和amd提供了一种硬件级别的MMU虚拟化
intel:EPT (Extended Page Table)
amd:NTP(Nested Page Table)

所以我们现在的工作流程是这样的
没有虚拟化的时候

cpu用到地址切换(比如进程去根据地址访问内存),就调用MMU,MMU将线性地址转换成物理地址空间,进程看到的是线性地址空间,线性地址我们一般叫做虚拟地址,让进程以为可以使用所以内存

虚拟化场景

首先虚拟机的进程,访问内存由MMU将虚拟机的进程的虚拟机的虚拟地址转换成虚拟机的虚拟机的物理地址,但是他还是虚拟的,所以需要我们的hypervisor进行转换这非常的麻烦,但是引入MMU虚拟化(intel,amd cpu硬件方面的虚拟化)后虚拟机的进程调用地址的某个数据,这个虚拟机的虚拟地址直接由intel的EPT或者amd的NTP直接转换成物理地址,

但是我们的TLB还是不能实现缓存命中,每当cpu切换虚拟机的时候TLB就会清空(因为TLB是进程调用的虚拟地址转换到物理地址的缓存,他的设计之初就是对于主机模式而非虚拟化模式)这时我们还有TLB虚拟化

TLB虚拟化
TLB虚拟化使用的是tagged TLB,以前的TLB就是3个字段,一个是标识(虚拟地址的19~31位),一个是数据(页物理地址的13 ~31位),一个是辅助信息,tagged TLB为他们加上一个字段,为guest的标识字段,而且后面的标识为guest的虚拟地址,数据就直接成为了内存物理地址,不需要转换成虚拟机的物理地址再由hypervisor 进行转换到内存物理地址,当然他要支持cpu的MMU虚拟化

I/O虚拟化

首先我们的IO设备有
外存

硬盘,光盘,U盘

网络设备

网卡

显示设备

VGA

键盘鼠标

ps/2,USB

I/O虚拟化的方式有3种

  • 模拟
  • 半虚拟化(模拟就是和全虚拟化一样)
  • I/O透传(I/O-through)

模拟

模拟就是完全通过软件的方式去模拟真实硬件,他的过程大致如下
首先由guest的用户空间调用网卡,然后发起系统调用,内核空间接受到后调用驱动再由驱动调用网卡,但是这个网卡是模拟的,他要转换成对hypervisor的调用,这时他会把包发往hypervisor,hypervios上也有对应的模拟软件,hypervisor接收到包后,需要将他发出去,所以hypervisor由一个队列,然后再调用驱动发送至网卡,kvm只能虚拟内存和cpu,cpu是通过硬件辅助进行虚拟,其他的io等虚拟化都要用到qemu进行模拟

半虚拟化

虚拟机明确知道我们的IO设备是被虚拟出来的,所以他不会去使用他的硬件驱动去调用网卡,而是采用前端驱动的方式,首先guest的确有一个网卡这个网卡只是让用户看到的,guest不需要驱动直接调用这个前端网卡然后向后端hypervisor转发,省去了调用驱动的 过程,在guest上的驱动叫做前端驱动(IO frontend),后端hypervisor上的驱动叫做后端驱动(backend),后端收到包后排入队列,再调用真实驱动发出网卡,存储设备和网络设备一般是这么虚拟的

我们的显示设备一般是通过frame buffer(帧缓冲机制)给每一个虚拟机一个窗口,显卡有硬件加速功能每当切换虚拟机,缓存就会被清除,显卡的硬件加速就失效了
而我们的键盘和鼠标是怎么虚拟化的了?他一般是通过焦点捕获方式来实现,首先会给所有的虚拟机模拟出键盘鼠标,当你在窗口操作时焦点属于那个虚拟机或者物理机焦点就由那个捕获

IO透传

让虚拟机直接使用物理设备(仍然需要hypervisor协调),他是由hypervisor去协调直接将设备分配给虚拟机,虚拟机直接调用驱动来调用物理设备,但是我们的硬件也要由透传功能的支持,比如intel VT-d

虚拟化的2种实现方式

1型虚拟化(type1)

在硬件上不安装操作系统而直接安装hypervisor,hypervisor可以直接管理硬件
代表xen,vmware ESXI/ESX
他是直接由hypervisor跑在操作系统上

二型虚拟化 (type2)

硬件上装操作系统,在操作系统上安装虚拟化软件,通过各种工具对虚拟机进行管理
代表:KVM,vmware-workstation,virtual box
type2的管理虚拟机的是Vitual Machine Monitor

虚拟化网络

桥接 (bridge)

桥接我们可以看成一个交换机,我们原先 物理机上的网卡(物理网卡) 连接到桥后一切物理网卡与网络协协议栈的交互都会先发给bridge再由bridge发往网络协议栈或者自己根据mac地址表转发,这个bridge也有交换功能,他也可以配置ip(所以可以不用再eth0上配置IP,直接在bridge上配置ip即可),每个guest都有一个虚拟网卡,这个虚拟网卡可以看成我们每个交换机的网口,当有数据包进来后(如果通过eth0并且eth0连接在bridge上就会直接发给bridge),拆封装发现目标mac是guest的MAC就发往特定的guest,如果目标mac就是本地的host了?其实在桥接的时候物理网卡被做成交换机,他会再虚拟出一个网卡,这个网卡专门用来接收发往host本地的数据,这个虚拟设备叫做桥设备,

仅主机(hosts-only)

仅主机会让各个虚拟机之间通讯,虚拟机和物理机之间通讯,但是不会去向外部通讯,首先我们在host上创建一个虚拟交换机(纯软件实现),各个虚拟机都有一个网卡并且连接在这之上,并且物理机上也会虚拟一个网卡连接在这个交换机之上,这样实现了虚拟机和物理机之间的通讯,这时我们的网卡转发功能并没有开启(网卡转发功能就是一个网卡可以转发到另一个网卡上面可以看成路由的下一跳),如果开启了网卡转发功能就成了路由模型就可以和外部通讯了,但是guest需要把网关指向主机上的虚拟网卡地址,当guest有包发到未知地址的时候就会交给网关(虚拟网卡),然后网关再发往主机上的物理网卡(因为开启了网卡转发功能),再由物理网卡发往外面,但是外面的主机想返回到虚拟机上,我们必须要再外部主机上配置静态路由指向本地的物理网卡
在这里插入图片描述

NAT

nat的模型和上面的仅主机一样但是host虚拟出的网卡为另外一个网卡,当我们的guest要发生包出去的时候经过虚拟交换机传到host虚拟出的网卡上的时候(这个网卡用来连接别的host和虚拟交换机)再通过nat吧原ip地址转换成host虚拟网卡的ip再发出去

tun设备

TUN 设备是一种虚拟网络设备,通过此设备,程序可以方便地模拟网络行为。TUN 模拟的是一个三层设备,也就是说,通过它可以处理来自网络层的数据,更通俗一点的说,通过它,我们可以处理 IP 数据包。

先来看看物理设备是如何工作的:
在这里插入图片描述
上图中的 eth0 表示我们主机已有的真实的网卡接口 (interface)。

网卡接口 eth0 所代表的真实网卡通过网线(wire)和外部网络相连,该物理网卡收到的数据包会经由接口 eth0 传递给内核的网络协议栈(Network Stack)。然后协议栈对这些数据包进行进一步的处理。

对于一些错误的数据包,协议栈可以选择丢弃;对于不属于本机的数据包,协议栈可以选择转发;而对于确实是传递给本机的数据包,而且该数据包确实被上层的应用所需要,协议栈会通过 Socket API 告知上层正在等待的应用程序。
下面看看 TUN 的工作方式:
在这里插入图片描述
在这里插入图片描述
我们知道,普通的网卡是通过网线来收发数据包的话,而 TUN 设备比较特殊,它通过一个文件收发数据包。

如上图所示,tunX 和上面的 eth0 在逻辑上面是等价的, tunX 也代表了一个网络接口,虽然这个接口是系统通过软件所模拟出来的.

网卡接口 tunX 所代表的虚拟网卡通过文件 /dev/tunX 与我们的应用程序(App) 相连,应用程序每次使用 write 之类的系统调用将数据写入该文件,这些数据会以网络层数据包的形式,通过该虚拟网卡,经由网络接口 tunX 传递给网络协议栈,同时该应用程序也可以通过 read 之类的系统调用,经由文件 /dev/tunX 读取到协议栈向 tunX 传递的所有数据包。

此外,协议栈可以像操纵普通网卡一样来操纵 tunX 所代表的虚拟网卡。比如说,给 tunX 设定 IP 地址,设置路由,总之,在协议栈看来,tunX 所代表的网卡和其他普通的网卡区别不大,当然,硬要说区别,那还是有的,那就是 tunX 设备不存在 MAC 地址,这个很好理解,tunX 只模拟到了网络层,要 MAC地址没有任何意义。当然,如果是 tapX 的话,在协议栈的眼中,tapX 和真是网卡没有任何区别。

tap设备

TAP 设备与 TUN 设备工作方式完全相同,区别在于:

TUN 设备是一个三层设备,它只模拟到了 IP 层,即网络层 我们可以通过 /dev/tunX 文件收发 IP 层数据包,它无法与物理网卡做 bridge,但是可以通过三层交换(如 ip_forward)与物理网卡连通。可以使用ifconfig之类的命令给该设备设定 IP 地址。
TAP 设备是一个二层设备,它比 TUN 更加深入,通过 /dev/tapX 文件可以收发 MAC 层数据包,即数据链路层,拥有 MAC 层功能,可以与物理网卡做 bridge,支持 MAC 层广播。同样的,我们也可以通过ifconfig之类的命令给该设备设定 IP 地址,你如果愿意,我们可以给它设定 MAC 地址。

tun/tap转自与https://blog.csdn.net/lishuhuakai/article/details/73136442

创建桥设备

首先桥设备不支持networkmanager服务,而且我们的kvm,xen都不会自己去创建桥,他默认是host-only或者nat,这个需要我们自己创建,我们先关闭NetworkManager服务

[root@zhr ~]# systemctl stop NetworkManager   
[root@zhr ~]# systemctl disable NetworkManager
[root@zhr ~]# 

我们管理桥要使用brctl工具来管理它属于bridge-utils包
说一千道一万brctl是通过linux内核模块tun和tap实现的

[root@zhr ~]# modinfo tun      
filename:       /lib/modules/4.16.3-301.fc28.x86_64/kernel/drivers/net/tun.ko.xz
alias:          devname:net/tun
alias:          char-major-10-200
license:        GPL
author:         (C) 1999-2004 Max Krasnyansky <maxk@qualcomm.com>
description:    Universal TUN/TAP device driver
depends:        
retpoline:      Y
intree:         Y
name:           tun
vermagic:       4.16.3-301.fc28.x86_64 SMP mod_unload 
sig_id:         PKCS#7
signer:         
sig_key:        
sig_hashalgo:   md4
signature:      30:82:02:CF:06:09:2A:86:48:86:F7:0D:01:07:02:A0:82:02:C0:30:
                82:02:BC:02:01:01:31:0D:30:0B:06:09:60:86:48:01:65:03:04:02:
                01:30:0B:06:09:2A:86:48:86:F7:0D:01:07:01:31:82:02:99:30:82:
                02:95:02:01:01:30:70:30:63:31:0F:30:0D:06:03:55:04:0A:0C:06:
                46:65:64:6F:72:61:31:22:30:20:06:03:55:04:03:0C:19:46:65:64:
                6F:72:61:20:6B:65:72:6E:65:6C:20:73:69:67:6E:69:6E:67:20:6B:
                65:79:31:2C:30:2A:06:09:2A:86:48:86:F7:0D:01:09:01:16:1D:6B:
                65:72:6E:65:6C:2D:74:65:61:6D:40:66:65:64:6F:72:61:70:72:6F:
                6A:65:63:74:2E:6F:72:67:02:09:00:F1:03:40:DC:73:31:5F:0E:30:
                0B:06:09:60:86:48:01:65:03:04:02:01:30:0D:06:09:2A:86:48:86:
                F7:0D:01:01:01:05:00:04:82:02:00:89:E8:0F:F1:74:01:7C:26:17:
                56:C4:1D:1A:88:0A:69:39:60:99:7C:DC:CA:D6:73:B3:70:2D:0F:B2:
                21:61:9E:17:80:E0:CC:D1:E4:F6:56:BF:86:0F:4A:EE:9B:9D:8F:6B:
                3B:B4:A3:45:99:B1:76:9D:D9:CD:00:0A:90:96:A6:08:6A:DC:D0:74:
                5E:57:48:ED:C7:8C:35:75:13:64:0F:6E:CC:BD:A7:58:AA:AD:41:80:
                FF:12:E7:D9:5D:CB:D7:E2:4D:5D:E0:58:15:C8:3E:5E:68:A4:C0:9D:
                55:F4:31:19:2C:6A:2F:40:C3:3E:2B:13:29:67:46:12:10:5F:05:03:
                8B:DD:9F:76:4A:2D:31:A6:B7:47:36:00:67:29:04:AC:F4:DB:6F:A7:
                E3:B2:31:29:E9:2B:D9:FC:F1:79:C5:52:8A:FC:94:6C:C7:5C:78:08:
                1A:BC:73:D5:A3:53:23:4C:85:48:41:E4:70:12:21:AB:85:8F:42:36:
                5F:DF:0A:F0:5C:05:05:91:13:96:2D:57:18:AA:11:DA:6D:B5:8D:34:
                C4:2B:30:F0:ED:2E:61:7A:AA:C8:83:00:9F:7C:33:8B:69:E1:93:3A:
                F7:3E:30:CA:82:06:D0:A5:33:BE:BE:C2:E3:1E:4F:8C:78:18:3B:D4:
                48:2E:B0:A2:99:30:D1:D3:D1:E5:8C:BF:03:04:CD:6D:66:ED:46:42:
                FB:08:1F:E5:FD:12:13:F7:18:FA:AB:DA:E6:0D:A8:D0:BA:09:DA:D9:
                32:DE:DF:BE:03:BE:DE:F7:6E:C4:D6:DF:4E:A1:F2:BE:D5:F5:1F:28:
                24:81:EC:1C:B8:05:40:38:8C:13:B7:89:EF:8C:89:2B:0A:C1:C4:92:
                7A:93:06:49:99:21:6D:AF:21:2A:3D:2D:CA:81:81:DC:46:87:EA:2C:
                AA:A7:CD:7B:0B:C5:23:5A:4B:BB:8A:24:65:6F:36:FC:F5:9D:44:B3:
                27:02:2C:76:9D:72:B6:DC:AD:CD:1C:41:36:C9:9B:BC:75:79:9A:24:
                C8:55:58:63:B5:61:54:AC:35:2B:3D:77:76:31:39:9C:B2:76:52:F7:
                B3:7E:0B:B2:E3:D9:EC:29:A2:61:76:61:07:D4:D3:B6:F8:6A:E2:BC:
                53:DA:7C:6D:33:C3:BD:D0:6F:D2:A7:98:02:D7:87:15:35:6E:36:F7:
                BA:91:F6:39:48:78:43:E9:64:82:11:58:37:3D:36:A1:79:A7:F9:33:
                0E:BB:85:E1:CA:ED:78:BA:87:43:68:57:9D:27:7C:29:64:E1:D8:08:
                54:AE:CB:07:88:17:68:96:D2:6B:B6:95:85:F8:15:A5:1F:86:04:B4:
                A1:E4:DE
[root@zhr ~]# 
[root@zhr ~]# modinfo tap
filename:       /lib/modules/4.16.3-301.fc28.x86_64/kernel/drivers/net/tap.ko.xz
license:        GPL
author:         Sainath Grandhi <sainath.grandhi@intel.com>
author:         Arnd Bergmann <arnd@arndb.de>
depends:        
retpoline:      Y
intree:         Y
name:           tap
vermagic:       4.16.3-301.fc28.x86_64 SMP mod_unload 
sig_id:         PKCS#7
signer:         
sig_key:        
sig_hashalgo:   md4
signature:      30:82:02:CF:06:09:2A:86:48:86:F7:0D:01:07:02:A0:82:02:C0:30:
                82:02:BC:02:01:01:31:0D:30:0B:06:09:60:86:48:01:65:03:04:02:
                01:30:0B:06:09:2A:86:48:86:F7:0D:01:07:01:31:82:02:99:30:82:
                02:95:02:01:01:30:70:30:63:31:0F:30:0D:06:03:55:04:0A:0C:06:
                46:65:64:6F:72:61:31:22:30:20:06:03:55:04:03:0C:19:46:65:64:
                6F:72:61:20:6B:65:72:6E:65:6C:20:73:69:67:6E:69:6E:67:20:6B:
                65:79:31:2C:30:2A:06:09:2A:86:48:86:F7:0D:01:09:01:16:1D:6B:
                65:72:6E:65:6C:2D:74:65:61:6D:40:66:65:64:6F:72:61:70:72:6F:
                6A:65:63:74:2E:6F:72:67:02:09:00:F1:03:40:DC:73:31:5F:0E:30:
                0B:06:09:60:86:48:01:65:03:04:02:01:30:0D:06:09:2A:86:48:86:
                F7:0D:01:01:01:05:00:04:82:02:00:18:45:98:98:CF:E5:32:DE:96:
                C6:0A:9B:E7:C8:36:37:99:93:1A:B4:08:84:AF:DA:58:E4:95:70:7C:
                9A:43:49:4C:20:7D:46:8E:F3:F3:4D:F3:4D:EF:BC:1B:0F:05:AE:58:
                07:3C:C3:21:A4:DD:27:72:18:48:B4:4F:05:2F:D8:D2:5C:1D:9A:38:
                62:8F:97:C9:E2:F6:10:D6:31:7F:0C:13:DF:D2:65:71:9A:9D:77:30:
                58:61:C9:E6:1C:D4:50:12:B1:DD:3B:85:7D:CE:35:C6:EC:56:1B:08:
                E2:4E:3B:FC:63:3C:29:48:83:0A:CC:76:FE:E0:2B:ED:C9:56:6A:EA:
                C7:5B:45:E5:68:84:69:3D:33:C8:F7:D8:6E:D0:D5:1E:7E:50:C4:87:
                63:9C:63:BB:C2:33:48:8A:1E:4C:40:88:DE:2B:38:0D:D0:6B:67:5A:
                93:B8:15:C9:FA:F2:E9:53:FB:2C:B9:7A:FF:31:24:83:79:FF:70:FF:
                65:72:17:C7:36:AB:03:58:1D:18:6D:66:18:F5:33:A8:32:91:47:A6:
                4D:8F:08:39:17:75:84:E7:74:4B:4D:12:BC:EF:48:F1:03:41:2E:3B:
                E8:C7:DE:2D:43:8E:06:CC:C0:75:93:F1:FB:8B:93:69:93:D3:61:84:
                11:C0:AE:28:E5:D6:60:E4:D9:1F:F0:75:4C:A6:BA:25:07:25:4C:3A:
                94:37:7A:C5:14:2D:3E:12:4D:3D:2F:C1:E1:F6:63:85:CA:BB:19:BF:
                12:08:FA:2E:B7:8C:87:BD:E6:40:A6:46:F2:38:07:76:BD:97:84:3E:
                17:4A:A3:D7:DA:00:03:A0:36:6A:7C:93:5D:E3:0B:9F:74:16:22:05:
                0A:63:04:89:70:06:F7:50:A7:14:3C:40:34:B5:C8:C2:1A:7A:EC:32:
                70:31:76:18:9E:A2:71:4D:20:8B:44:D6:4C:9A:27:89:C4:28:E2:DD:
                7E:C9:48:B1:6A:E0:20:88:2B:C9:64:32:FC:C8:00:A1:B2:4F:25:F9:
                75:75:54:28:19:2F:59:C5:E0:B3:79:7C:CD:28:C3:BD:40:26:0A:73:
                66:AB:51:63:E8:BB:99:E8:13:E2:E8:4E:A5:15:36:26:7F:3E:18:06:
                2B:C6:9C:F0:C1:C1:60:1F:C4:6D:1D:93:CE:0A:53:13:2A:CC:4D:3C:
                40:9B:20:B8:77:2D:F7:3F:EE:8D:6F:D3:2D:4C:89:11:B7:D2:64:41:
                DE:8B:FD:02:5E:7A:D0:EF:FF:DC:79:42:93:C7:E4:5F:77:36:E4:1E:
                74:2F:C4:96:46:DD:A1:3B:F5:4B:45:23:C2:DC:05:DF:DB:CE:BE:3F:
                48:2D:B3
[root@zhr ~]# 

我们可以使用最原始的配置文件实现配置

[root@zhr network-scripts]# cp ifcfg-ens33  ifcfg-br0    #创建br文件然后进去更改   
[root@zhr network-scripts]#vim ifcfg-br0
TYPE=Bridge		#类型是桥注意B大写后面小写
BOOTPROTO=none
NM_CONTROLLED=no	#是否使用network_manager管理此网卡
ONBOOT=yes
DEVICE=br0
IPADDR=192.168.2.88
NETMASK=255.255.252.0
GATEWAY=192.168.0.1
DNS1=8.8.8.8
IPV6INIT=no
:wq  
#更改被桥接网卡  
[root@zhr network-scripts]# vim ifcfg-ens33 
TYPE=Ethernet
BOOTPROTO=none
ONBOOT=yes
DEVICE=ens33
BRIDGE=br0		#添加这一项将此网卡桥接到桥br0上
:wq
#重启网络服务  
[root@zhr network-scripts]# systemctl restart network  
#查看桥
[root@zhr network-scripts]# ifconfig
br0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
        inet 192.168.2.88  netmask 255.255.252.0  broadcast 192.168.3.255
        inet6 fe80::20c:29ff:fea5:b13  prefixlen 64  scopeid 0x20<link>
        ether 00:0c:29:a5:0b:13  txqueuelen 1000  (Ethernet)
        RX packets 31153  bytes 141750352 (135.1 MiB)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 29830  bytes 2211256 (2.1 MiB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0
ens33: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
        ether 00:0c:29:a5:0b:13  txqueuelen 1000  (Ethernet)
        RX packets 142707  bytes 149931425 (142.9 MiB)
        RX errors 0  dropped 187  overruns 0  frame 0
        TX packets 31525  bytes 2520495 (2.4 MiB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0
lo: flags=73<UP,LOOPBACK,RUNNING>  mtu 65536
        inet 127.0.0.1  netmask 255.0.0.0
        inet6 ::1  prefixlen 128  scopeid 0x10<host>
        loop  txqueuelen 1000  (Local Loopback)
        RX packets 0  bytes 0 (0.0 B)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 0  bytes 0 (0.0 B)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0  
#通过观察发现上面ens33和br0的mac一模一样,我们也可以这样理解所有发往ens33的帧都转到br0了 ,但是此时br0看起来看着像网卡而ens33像桥设备 
# 我们可以通过brctl show查看桥设备   
[root@zhr network-scripts]# brctl show 
bridge name     bridge id               STP enabled     interfaces
br0             8000.000c29a50b13       no              ens33 
#我们可以通过命令开启此br0的生成树   
[root@zhr network-scripts]# brctl stp br0 on 	#开启生产树
[root@zhr network-scripts]# brctl show       
bridge name     bridge id               STP enabled     interfaces
br0             8000.000c29a50b13       yes             ens33
#以上的命令都可以通过命令实现


命令实现bridge

#我们要将eth0加入到bridge中,并且如果加入后eth0不在向内核协议栈发送包而是直接将包发往bridge中我们就不用再再eth0上配置ip地址,我们直接在bridge上配置ip地址即可  
root@zhr ~]# ifconfig  ens33 0 up 	#去掉ens33的ip
[root@zhr ~]# ifconfig ens33
ens33: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
        inet6 fe80::847a:a0f7:fe4b:f44d  prefixlen 64  scopeid 0x20<link>
        ether 00:0c:29:a5:0b:13  txqueuelen 1000  (Ethernet)
        RX packets 12736  bytes 1106115 (1.0 MiB)
        RX errors 0  dropped 34  overruns 0  frame 0
        TX packets 335  bytes 36195 (35.3 KiB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0
[root@zhr ~]# brctl addbr br0  	#添加br0
[root@zhr ~]# ifconfig br0 
br0: flags=4098<BROADCAST,MULTICAST>  mtu 1500
        ether ea:e5:37:80:41:b5  txqueuelen 1000  (Ethernet)
        RX packets 0  bytes 0 (0.0 B)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 0  bytes 0 (0.0 B)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

[root@zhr ~]# ifconfig br0 192.168.2.88/22 up 	#为br0添加ip并且启动  
[root@zhr ~]# brctl addif br0 ens33 	#将我们的物理网口ens33加入到br0中
[root@zhr ~]# route add default gw 192.168.0.1	#在主机上添加一个默认的路由192.168.0.1  
#完成配置

[root@zhr ~]# ifconfig
br0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
        inet 192.168.2.88  netmask 255.255.252.0  broadcast 192.168.3.255
        inet6 fe80::e8e5:37ff:fe80:41b5  prefixlen 64  scopeid 0x20<link>
        ether 00:0c:29:a5:0b:13  txqueuelen 1000  (Ethernet)
        RX packets 55946  bytes 4423934 (4.2 MiB)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 240  bytes 25626 (25.0 KiB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

ens33: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
        inet6 fe80::847a:a0f7:fe4b:f44d  prefixlen 64  scopeid 0x20<link>
        ether 00:0c:29:a5:0b:13  txqueuelen 1000  (Ethernet)
        RX packets 102382  bytes 23227131 (22.1 MiB)
        RX errors 0  dropped 36  overruns 0  frame 0
        TX packets 530  bytes 56868 (55.5 KiB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

lo: flags=73<UP,LOOPBACK,RUNNING>  mtu 65536
        inet 127.0.0.1  netmask 255.0.0.0
        inet6 ::1  prefixlen 128  scopeid 0x10<host>
        loop  txqueuelen 1000  (Local Loopback)
        RX packets 0  bytes 0 (0.0 B)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 0  bytes 0 (0.0 B)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0


kvm

kvm全称(kernel-based virtual machine)
他最开始是由以色列Qumranet公司开发,2008年后被redhat收购,此前xen就被抛弃了,因为xen要抢占对硬件掌控
kvm其实是是一个linux内核模块,,众所周知linux有内核空间和用户空间,如果这个kvm内核模块一装在内核中,这个内核直接摇身一变就成为hypervisor,用户空间变成hypervisor的控制台管理接口的运行位置,只要我们使用kvm模块提供的功能就可以创建虚拟机了,我们在用户空间使用管理工具就可以创建虚拟机了,每一个虚拟机事实上就是运行在linux上的进程
我们的KVM离不开HVM(硬件辅助虚拟化)技术也就是说你的cpu要支持intel的 VT-x或者AMD的AMD-v,
KVM模块载入后系统就有了三种运行模式

  • 内核模式

guestos执行io类操作或者其他的特殊指令的操作都是由内核模式实现

  • 用户模式

代表guestos请求IO类操作

  • 来宾模式

当我们的guest非IO操作,就直接在此用户空间实现,事实上他被成为虚拟机的用户模式

kvm运行过程
首先guest上面运行一个虚拟机,这个guest上运行一个应用,这个应用的非特权直接交给cpu运行(因为每个虚拟机都有虚拟cpu这个虚拟cpu在linux就是一个线程或者进程,并且映射到真正的cpu上),当真正的用到了特权指令首先进guest os kernel,然后再转换成对vmm的调用(vmm一定在cpu上运行的),vmm运行后返回给虚拟机一个假的状态已经运行成功

KVM组件

/dev/kvm

工作在hypervisor上,可以通过ioctl()系统调用来完成对vm的创建,启动登管理功能。
他是一个字符设备,其实现的主要功能是创建vm,为vm分配内存,读写vcpu寄存器,向vcpu注入中断,和运行vcpu也就是调度到核心上运行

qemu组建

qemu工作与用户空间主要用于实现模拟pc机的io设备,比如显示器,键盘等等

KVM特性

内存管理

支持将分配给vm的内存交换至swap,支持huge page,支持使用intel EPT,或者amd的RVI技术完成内存地址映射,她直接从虚拟机的虚拟内存空间到host的物理地址空间的映射
它还支持KSM(kernel same-page merging ):ksm扫描所有虚拟机的内存查找相同内容的内存叶,让后把相同的内存叶合并成各相关vm可以共享的内存叶,如果虚拟机要写的话可以使用cow机制,来改副本

硬件支持

取决于linux内核,因为他的hypervisor就是linux内核

存储

KVM可以使用linux支持的所有存储设备
他支持网络附加存储 NAS
他支持存储区域网络 SAN
他也支持分布式存储,他吃吃Glust FS

实时迁移

要实现实时迁移必须要用共享存储,实时迁移就是在一台主机上的虚拟机在虚拟机开机的状态下迁移到另一个虚拟机上

支持guest os

linux,windows,openbsd,freebsd,opensolaris,

设备驱动

kvm可以通过模拟的方式实现完全虚拟化,也可以在guest安装前端驱动后完成半虚拟化,在kvm上的半虚拟化驱动是virtio由redhat和IBM联合研发,
virtio-blk支持硬盘的半虚拟化,virtio-net支持对网络设备的半虚拟化,virtio-pci支持对pci设备的半虚拟化,virtio-console支持对console设备的半虚拟化,要知道如果io使用qemu去进行模拟性能只能有源性能的一半不到,而使用virtio进行的半虚拟化新能可以达到85%左右,当然透传更高可以达到百分之95

kvm的局限性

1,如果我们的物理cpu有4个我们可以创建8个cpu这个是没有问题的,但是他的性能不会提升还会下降,一般不建议所有的虚拟机,所有的cpu核心数加起来不超过物理cpu核心量,
2,任何虚拟机的时钟都不会精确,大部分的guest都需要外部来完成精确计时的,因为linux系统有2套时钟,一套是硬件时钟,一个是系统启动后从硬件读取的时钟,一启动系统后开始自己计时,
假如我们的cpu有2G赫兹,我们认为他在一秒钟振荡2G赫兹,也可以认为当震荡2G赫兹后代表1秒钟,但是虚拟化后第一个虚拟机运行1G赫兹,那个虚拟机运行1G赫兹,时钟不会精确,我们的vmware有一个叫做vm-tool的东西它可以不断的向物理硬件同步时钟,我们的linux最好通过ntp服务器精确时间,
3,MAC地址
kvm的mac地址是随机的当我们的虚拟机非常的的时候有可能冲突
4,实时迁移

  • guest os的镜像文件要放在共享存储上
  • 目标hypervior要兼容原kvm
  • 2台主机共享存储要挂在同一位子
  • 2台主机最好cpu都是一至的
  • 2台物理机的时间最好一致
  • 2台物理主机最好有一样的物理网络配置,比如都有eth0,ens33
  • 并且性能也会有损失

KVM工具栈

1,第一组由qemu提供的(提供虚拟机的创建启动等功能),这一类叫做qemu-kvm,通过qemu-img对磁盘映像文件的管理,qemu-io完成对IO性能的监控
2,第二类组建是vitual machine manager他的组建由virsh来管理包(libvirt)括虚拟机的安装删除等虚拟机生命周期的管理,其中virt-manager是用图形化管理安装vm,virt-viewer只是用来查看的还有一个virt-install,通过命令行来实现安装,virsh是一个纯命令行工具可以创建管理虚拟机我们一般用他来管理,virt其实还是调用qemu来进行虚拟机创建管理,但是他支持远程管理他有一个守护进程libvirtd ,他是由红帽等厂商开发
libvirt可以看成一个对容器虚拟化,kvm,zen等等虚拟化的一个抽象层,可以用这个工具管理LXC,zen,kvm等等虚拟化工具

所以我们使用kvm可以选择qemu+kvm,和libvirt+kvm两种方式

qemu是一个仿真模拟器功能非常强大,他也是一个虚拟化软件,我们主要用到一下几点(因为kvm只模拟cpu和内存,qemu本身可以模拟cpu但是新能比较低,qemu-kvm相较于qemu只更改了模拟cpu和内存的部分,其他都是沿用qemu本身的功能)

  • 仿真io设备
  • 关联模拟的设备至真实设备
  • 调试器
  • 与模拟器交互的用户接口

我们主要用到仿真io设备和与模拟器交互的用户接口

KVM使用

使用qemu-kvm管理虚拟机

首先我们先看此cpu是否支持HVM硬件辅助虚拟化

[root@zhr ~]# grep -E  "(vmx|svm)" /proc/cpuinfo
flags           : fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush dts mmx fxsr sse sse2 ss syscall nx pdpe1gb rdtscp lm constant_tsc arch_perfmon pebs bts nopl xtopology tsc_reliable nonstop_tsc cpuid aperfmperf 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 epb invpcid_single pti tpr_shadow vnmi ept vpid fsgsbase tsc_adjust bmi1 avx2 smep bmi2 invpcid rdseed adx smap xsaveopt dtherm ida arat pln pts hwp hwp_notify hwp_act_window hwp_epp
flags           : fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush dts mmx fxsr sse sse2 ss syscall nx pdpe1gb rdtscp lm constant_tsc arch_perfmon pebs bts nopl xtopology tsc_reliable nonstop_tsc cpuid aperfmperf 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 epb invpcid_single pti tpr_shadow vnmi ept vpid fsgsbase tsc_adjust bmi1 avx2 smep bmi2 invpcid rdseed adx smap xsaveopt dtherm ida arat pln pts hwp hwp_notify hwp_act_window hwp_epp
#发现支持,vmx是intel的硬件虚拟化,svm是amd的硬件虚拟化  

然后我们装在kvm模块让我们的内核变成hypervisor

[root@zhr ~]# modprobe kvm 
[root@zhr ~]# modprobe kvm-intel 	#专用Intel cpu的

我们查看/dev下是否由kvm文件

[root@zhr ~]# ls /dev/kvm
/dev/kvm  
#装在成功

然后我们安装管理工具栈 如果我们只使用qemu-kvm来管理虚拟机的化就只安装qemu-kvm即可

[root@zhr ~]# yum install qemu-kvm -y     

如果时debain系列的系统可以用以下命令

root@workstastion:~# apt-get install qemu-kvm

qemu-kvm的使用格式是

qemu-kvm [options] [disk_image]	#选项加上虚拟机的磁盘映像文件,所以说我们创建虚拟机之前先创建磁盘映像文件 

qemu-kvm的选项分几大类
1,标准选项(standerd option)

标准选项从本质上来讲是用来管理虚拟机自身的,名字,cpu,内存等

2,磁盘选项 (block option)

专门管理硬盘的

3,usb 选项(usb option)

专门管理usb选项,定义当前主机是否支持usb接口虚拟化,还可以指定去顶接口等

4,display option

专门管理虚拟机控制台,也是窗口

5,network option

网络选项

6,character device option

指定字符设备选项比如键盘等

7,device url syntax

可以指定iSCSI选项

8, bluetooth option

可以提供蓝牙虚拟化

9,debug/expert option

专家选项,用来debug

创建磁盘映像文件
我们现在的kvm支持多个格式的虚拟机映像文件,比如qemu-img专门用来实现这多种磁盘映像文件管理的
现在kvm支持

blkdebug blkreplay blkverify bochs cloop dmg file ftp ftps gluster host_cdrom host_device http https iscsi iser luks nbd nfs null-aio null-co parallels qcow qcow2 qed quorum raw rbd replication sheepdog ssh throttle vdi vhdx vmdk vpc vvfat

这么多的磁盘映像文件,其中包括vmware的文件iscsi,qcow2等

qcow2支持磁盘镜像文件的压缩加密,磁盘稀疏格式,快照等高级功能,是kvm现行最新的磁盘映像文件
稀疏格式可以看成黑洞文件,也就是lssek的时候偏移量大于文件的大小,中间形成的空洞,这个空洞是不计入block的

qemu-img还支持磁盘映像文件格式转换

所以我们可以先创建一个磁盘镜像文件,使用qcow2格式(kvm最好都使用这个格式,如果兼容virtualbox可以选择vmdk)
首先我们创建一个目录专门用来存储磁盘文件

root@workstastion:/home/zhr# mkdir /vm/images -pv
mkdir: created directory '/vm'
mkdir: created directory '/vm/images'

创建一个稀疏格式的磁盘,磁盘大小100G,预分配存储元数据,格式为qcow2

root@workstastion:/home/zhr# qemu-img create -f qcow2 -o size=100G,preallocation=metadata /vm/images/test1.qcow2

注意-o选线是option的意思,可以指定预分配和size大小,如果preallocation后面是full说明不使用稀疏存储,而是直接分配120G,我们看我们创建的磁盘文件

root@workstastion:/vm/images# ls -lh test1.qcow2
-rw-r--r-- 1 root root 101G  2月 17 01:00 test1.qcow2
#101G大小文件。其中1G是元数据

再看看这个文件的实际大小,只有16M,因为里面充斥着黑洞,也就是非常多0,这个0不计入总大小

root@workstastion:/vm/images# du -h test1.qcow2
16M     test1.qcow2

这样的磁盘什么也没有,不过我们装载这个后可以使用pxe或者http/https等方式在线安装,这里我们不做演示,在virt-manager上可以图形画操作,下面我们使用一个已经安装好的磁盘映像,cirrors,这个非常小的镜像进行安装

root@workstastion:/vm/images# qemu-img info cirros1.img
image: cirros1.img
file format: qcow2
virtual size: 39.2 MiB (41126400 bytes)
disk size: 9.31 MiB
cluster_size: 65536
Format specific information:
    compat: 0.10
    refcount bits: 16

我们使用virt-manager进行安装的时候选用导入磁盘镜像的方式即可
安装完成后登陆这个cirrors虚拟机默认账号cirros密码cubswin:)
每当我们使用virt-manager创建一个虚拟机后我们会在/etc/libvirt/qemu/VM_NAME.xml里面看到我们创建虚拟机的信息

使用libvirt管理虚拟机

libvirtd管理架构
在这里插入图片描述

安装 libvirtd

root@workstastion:~# apt-get install libvirt-daemon-system
#安装libvirt的守护进程,这个守护进程在一定意义上使我们的libvirt管理工具实现了远程管理的功能

安装libvirt-client

root@workstastion:~# apt-get install libvirt-clients
#安装后可以用这个客户端程序连接服务端程序libvirtd进行各种虚拟化工具管理 

安装virt-manager图形化管理工具,通过libvirt管理kvm虚拟机

root@workstastion:~# apt-get install virt-manager

然后我们直接输入virt-manager开启图形化管理界面(如果是root用户请使用su登陆root,而非su -登陆root)

root@workstastion:~# virt-manager

我们在创建虚拟机的时候可以使用virtinst命令行创建,或者用图形画工具virt-manager进行创建,创建完成后我们可以在/etc/libvirt/qemu/VM_NAME.xml中看到相关虚拟机的配置信息,每次启动我们都根据这个配置信息进行虚拟机加载,如果我们想用命令行管理虚拟机使用virtsh,创建虚拟机还是用图形画的比较方便 ,我们这里主要讲解virsh命令管理虚拟机
输入virsh进入交互模式

root@workstastion:~# virsh
Welcome to virsh, the virtualization interactive terminal.

Type:  'help' for help with commands
       'quit' to quit

virsh #  

查看当前运行的虚拟机

root@workstastion:/home/zhr# virsh list
 Id   Name   State
----------------------
 2    c1     running

关闭虚拟机 (相当于输入poweroff)

root@workstastion:/home/zhr# virsh shutdown c1
Domain c1 is being shutdown

强制关闭虚拟机(拔电源的那种)

root@workstastion:/home/zhr# virsh destroy c1
Domain c1 destroyed

关闭后再看一下虚拟机

root@workstastion:/home/zhr# virsh list --all
 Id   Name   State
-----------------------
 -    c1     shut off

开启c1虚拟机

root@workstastion:/home/zhr# virsh start c1
Domain c1 started

连接c1虚拟机的控制台(如果虚拟机没有ssh的时候非常好用)

root@workstastion:/home/zhr# virsh console c1
Connected to domain c1
Escape character is ^] (Ctrl + ])

login as 'cirros' user. default password: 'cubswin:)'. use 'sudo' for root.
cirros login: cirros
Password:
//ctrl+]退出控制台

virsh也可以创建虚拟机但是他这个创建只是按照xml文件进行创建(我们用virt-manager创建虚拟机的时候用鼠标选择的选项都会保存到一个xml文件中),所以我们要先创建xml文件再用virsh create进行创建,创建完成后自动启动虚拟机
1,将c1虚拟机的xml文件做成模板

root@workstastion:/home/zhr# cp /etc/libvirt/qemu/c1.xml /etc/libvirt/qemu/tempory.xml

2,更改模板

root@workstastion:/home/zhr# vim /etc/libvirt/qemu/tempory.xml
//更改4个地方,一个是name,一个是uuid,一个是device的磁盘镜像,一个是mac地址

3,通过模板启动虚拟机

root@workstastion:/home/zhr# virsh create /etc/libvirt/qemu/tempory.xml --console    //--console可以在创建的时候直接连接console       

define和create大致一样,但是define不启动虚拟机只创建,这里不演示

挂起虚拟机,我们知道挂起虚拟机后虚拟机的内存都会被保存下来(保存在属主机的内存中,而不是文件,文件有另一个命令)

root@workstastion:/vm/images# virsh suspend c1
Domain c1 suspended
//再恢复c1
root@workstastion:/vm/images# virsh resume c1
Domain c1 resumed

我们也可以将其保存在文件中(和快照不一样,快照保存后系统照样运行,但是这个保存后虚拟机就处于pause状态)

root@workstastion:/vm/images# virsh save c1 /root/c1.dump --running

Domain c1 saved to /root/c1.dump
//--running代表恢复后虚拟机处于什么状态
root@workstastion:~# virsh list --all
 Id   Name   State
-----------------------
 4    c2     running
 -    c1     shut off

根据文件恢复虚拟机

root@workstastion:~# virsh restore /root/c1.dump



Domain restored from /root/c1.dump

root@workstastion:~#
root@workstastion:~#
root@workstastion:~#
root@workstastion:~# virsh list --all
 Id   Name   State
----------------------
 4    c2     running
 6    c1     running

我们查看以下虚拟机的硬件信息

root@workstastion:~# virsh dominfo c1
Id:             6
Name:           c1
UUID:           74773125-088e-4121-b768-b7ebb6debc15
OS Type:        hvm
State:          running
CPU(s):         2
CPU time:       2.5s
Max memory:     1048576 KiB
Used memory:    1048576 KiB
Persistent:     yes
Autostart:      disable
Managed save:   no
Security model: apparmor
Security DOI:   0
Security label: libvirt-74773125-088e-4121-b768-b7ebb6debc15 (enforcing)

我们更改其cpu的数量 ,这个cpu不能减,只能加,而且加的时候如果我们创建cpu的时候没有指定最大几个,然后默认就是设定的个数,加的时候就加不成。。。

root@workstastion:~# virsh setvcpus c2 2     

调整内存

root@workstastion:~# virsh setmem c2 --size 1024M

我们可以为虚拟机上一块硬盘
首先创建一个磁盘映像文件

root@workstastion:~# qemu-img  create  -f qcow2 -o size=20G,preallocation=metadata ./test.img
Formatting './test.img', fmt=qcow2 size=21474836480 cluster_size=65536 preallocation=metadata lazy_refcounts=off refcount_bits=16

然后我们看一下虚拟机c1的磁盘信息

root@workstastion:~# virsh domblklist c1
 Target   Source
----------------------------------
 vda      /vm/images/cirros1.img

再看一下这个vda的详细信息

root@workstastion:~# virsh domblkinfo c1 vda
Capacity:       41126400
Allocation:     9768960
Physical:       9761280

将磁盘加上去

root@workstastion:/vm/images# virsh attach-disk c1 /vm/images/test.img vdb
Disk attached successfully
root@workstastion:/vm/images# virsh domblklist c1
 Target   Source
----------------------------------
 vda      /vm/images/cirros1.img
 vdb      /vm/images/test.img

我们也可以拆除这个磁盘

root@workstastion:/vm/images# virsh    detach-disk c1 vdb
Disk detached successfully
root@workstastion:/vm/images# virsh domblklist c1
 Target   Source
----------------------------------
 vda      /vm/images/cirros1.img

我们也可以热插拔一个网卡上去
首先创建一个新的桥

root@workstastion:/vm/images# brctl addbr br6
root@workstastion:/vm/images# brctl show
bridge name     bridge id               STP enabled     interfaces
br6             8000.000000000000       no

然后将网卡插上去

root@workstastion:/vm/images# virsh attach-interface c1 bridge br6

查看一下

root@workstastion:/vm/images# virsh domiflist c1

拔掉网卡

root@workstastion:/vm/images# virsh detach-interface c1 bridge br6

说了这么多的命令,我们其实有非常多跨平台,管理多个主机虚拟机的软件
opentack
kimchi
ovirt

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值