0%

一篇文章讲解什么是虚拟化和 kvm 的使用方法

virtualization

注意:本篇篇幅较长,从计算机、虚拟化、网络的概念,到网络、虚拟化工具、LaaS 管理工具等,都逐一介绍,推荐使用左侧目录来快速定位阅览。

一、计算机的构成

计算机的五大部件:CPU(运算器、控制器),RAM,IO 设备(输入、输出设备)
什么是程序:指令 + 数据,也就是算法 + 数据结构

  • 以算法为核心,数据服务算法,是面向过程的编程
  • 以数据为核心,算法服务数据,是面向对象的编程

1. CPU

以 32 位 CPU 为例,对内存的前端标识有 32 位的线路标识内存的存储单元,32 根线有电和没电的排列组合共 2 的 32 次方,每个存储单位是 1 字节,所以 32 位 CPU 支持最大的内存数是 4G

2. 内存

  • 线性地址:4G
  • 物理地址:1G
    所有程序写数据到内存时,由内核将物理内存分配成页框后,以超供的方式,分配给进程。所有程序认为自己使用了物理机的全部 4G 内存,叫线性地址。写入线性内存数据时,由内核进行转换,再写到映射的物理地址上。
    转换过程需要有一定的消耗,会浪费 CPU 的能计算能力,所以使用 MMU 芯片来管理线性内存到物理内存的转换,加速转换过程,再根据数据有热区的效应,将映射关系缓存在 TLB 上。虚拟化时,为了防止内存映射混乱,将使用带标签的 TLB,TaggedTLB

二、虚拟化介绍

虚拟化就是将一组物理平台,虚拟化为多组不同的,彼此之间隔离的平台。
CPU 在 OS 安装以后就已经被虚拟化了,每个进程认为自己是独占 CPU,内存的。

实现方式

时间复用:

  • CPU 通过 时间复用,将时间分片,实现多任务

空间复用:

  • 内存通过虚拟内存,以 空间复用 的形式,实现多任务

虚拟化技术类型

  • 主机虚拟化:xen,kvm,vmware,virtualbox,…
  • 容器(用户名称空间隔离 NameSpace):
    • Net 网络
    • Mount 根文件系统
    • PID 模拟 PID
    • UTS 一个内核配置多个主机名
    • IPC 进程间通信机制
    • User 用户
      实现的管理管理工具:docker,lxc(LinuX Container),openvz, …
  • 系统库虚拟化:wine,…
  • 应用程序级虚拟化:jvm,pvm,…

主机虚拟化实现方式

CPU:

  • 模拟:emulation, 虚拟机的 arch 与物理平台的 arch 可以不相同
    • 实现:qemu
  • 虚拟:virtualization
    • 完全虚拟化(full-virt)
    • BT(vmware): 二进制转换 (软件)
    • HVM:硬件辅助的虚拟化(硬件): “Intel VT” & “AMD AMD-v”
  • 半(准)虚拟化 (para-virt):GuestOS 得明确知道自己运行于虚拟化技术

内存:

  • MMU virtualization:线性内存和物理内存转换器
    • Intel: EPT(Extended Page Table)
    • AMD: NPT(Nested Page Table)
  • TLB virtualization:缓存模块
    • tagged TLB

IO:

  • Emulation:模拟
    • Para-virtualization:半虚拟化
    • IO-through:IO 透传
      性能上: IO 透传>半虚拟化>完全虚拟化

虚拟化的两种两种模型

Type-I 型:

不需要在硬件安装操作系统,让虚拟化软件(hypervisor 你可以理解它是一个虚拟机监控程序 )直接运行在硬件上,它可以直接接管 CPU,内存等等,所有运行在当前物理硬件上的主机都是虚拟机。
典型代表有:xen,ESX/ESXi.

Type-II 型:

易于管理,方便借助 HOST 的管理工具)
需要在硬件上安装一个操作系统,在操作系统上安装一个虚拟化软件,通过虚拟化软件创建各个虚拟机。
典型代表:kvm,VMware Workstation,Virtualbox

xen 和 kvm 不能很准确定位:

  • xen 需要在操作系统上,安装 xen 软件后重启,但是重启后,xen 就顶替掉原来的内核,摇身一变成了 hypervisor,原来的内核和用户空间就变成了虚拟机叫 dom0。xen 负责管理 cpu 和内存的虚拟化,而 io 虚拟化为了能兼容大量 io 设备的驱动,则由运行着原来内核的 dom0 通过 qemu 来管理 io 设备,所以 dom0 也是个特权域

  • kvm 不是软件,是在原来的操作系统上,通过加载内核模块的方式来启动,启动后内核就直接变成了 hypervisor 来管理 cpu 和内存虚拟化,而原来的用户空间内则运行 qemu 来管理 io 虚拟化

三、网络虚拟化工具

虚机机的网络通过软件来模拟真实的物理环境,后文中还会介绍几种常见 网络模型,需要用到的工具如下:

1. 网络名称空间管理工具

1
2
3
4
ip netns
- ls 列出
- add NSNAME 创建
- exec NSNAME COMMAND 在指定的网络名称空间内执行命令

2. 管理虚拟网卡

1
2
3
4
ip link
- add IFNAME.1 type veth peer name IFNAME.2 添加一对 veth 网卡 IFNAME.1 和 IFNAME.2
- set IFNAME.2 netns NSNAME 把 IFNAME.2 放到 NSNAME 名称空间内
- set IFNAME.1 name NEWNAME 改名

3. 网桥管理工具

1
2
3
4
5
6
brctl
- show 显示桥
- addbr BRNAME 添加桥
- delbr BRNAME 删除桥
- addif BRNAME IFNAME 添加接口
- delif BRNAME IFNAME 删除接口

openvswitch 是个非常非常强大的虚拟网络管理工具,本文暂时不做说明,以后 OpenStack 中用到时会再详细说明

四、KVM 介绍

kvm:全称 Kernel-based Virtual Machine

Qumranet 公司 --> 后被 RedHat
特性:
(1) 只支持 X86_64
(2) 硬件虚拟化 HVM:Intel VT | AMD AMD-v

KVM 的组件

两类组件:

  • 1.(kvm.ko)/dev/kvm:工作为 hypervisor,在用户空间可通过系统调用 ioctl() 与内核中的 kvm 模块交互,从而完成虚拟机的创建、启动、停止、删除等各种管理功能;
  • 2.qemu-kvm 进程:工作于用户空间,用于实现 IO 设备模拟;用于实现一个虚拟机实例;

KVM 模块加载进内存之后,系统的运行模式:

  • 内核模式:GuestOS 执行 IO 类的操作时,或其它的特殊指令操作时的模式;它也被称为“Guest-Kernel”模式;
  • 用户模式:Host OS 的用户空间,用于代为 GuestOS 发出 IO 请求;
  • 来宾模式:GuestOS 的用户模式;所有的非 IO 类请求;

运行中的一个 kvm 虚拟机就是一个 qemu-kvm 进程,运行 qemu-kvm 程序并传递给它合适的选项及参数即能完成虚拟机启动,终止此进程即能关闭虚拟机;

QEMU 的组件

QEMU 主要有以下几个组成部分:

  • 处理器模拟器(x86、PowerPC、Sparc 等)
  • 仿真设备(显卡、网卡、硬盘等)
  • 关联仿真设备至真实设备的通用设备:仿真主机的描述(如 PC、Power Mac 等)
  • 调试器:与仿真器交互的用户接口

红帽团队从 QEMU 项目分支出一个项目,只支持 KVM,就叫 qemu-kvm

KVM 的管理工具

kvm 工具栈:

  • qemu:
    • qemu-kvm
    • qemu-img
  • libvirt:
    • GUI: virt-manager, virt-viewer
    • CLI: virsh, virt-install
    • C/S: libvirtd

五、KVM 管理工具

常用管理工具:

  • virt-manager 图形的工具
  • virsh 命令行的工具
  • qemu-kvm 底层命令行工具

使用难度上
qemu-kvm(纯手工) > virsh(半自动化) > virt-manager(图形)
但如果论可定制化和执行效率,却是要将排名颠倒一下的
下面从最简单的开始介绍

1. virt-manager

判断 CPU 是否支持硬件虚拟化

1
2
3
grep -i -E '(vmx|svm|lm)' /proc/cpuinfo
vmx:Intel VT-x
svm:AMD AMD-v

加载 kvm 模块

(1) 装载内核模块

  • kvm:核心模块
  • kvm-intel|kvm-amd
1
modprob kvm

安装图形界面

virt-manager 依赖图形
如果没有安装图形界面,先安装

1
yum groupinstall "GNOME Desktop"

安装并启动 virt-manager

1
2
3
4
~]# yum install qemu-kvm libvirt-daemon-kvm  virt-manager
~]# modprobe kvm
~]# systemctl start libvirtd.service
~]# virt-manager &

注意:如果是用远程工具,需要远程工具支持 GNOME 图形(或使用 vnc)

  • ubuntu 桌面版可以 ssh -X 直接在本地调用远程图形程序
  • 而 win 下就比较麻烦,我使用 xshell+xmanager 方案,也可以成功调用
1
2
~]# ssh root@192.168.50.11                      #先远程到 kvm 服务器 192.168.50.11
kvm_server ~]# ssh -X 127.0.0.1 virt-manager #执行 ssh -X 转发 X11 请求,本地打开图形界面

    打开控制台后,点新建虚拟机,选择一个已存在的 qcow2 格式的磁盘映像,就可以开机启动了,由于我下的的 cloud 版的磁盘镜像,开机会自动找 metadata 服务,但是我本地没有,所以会等很久,重试 20 次失败后,进入系统登录界面,过程都是图形化的操作,和 vmware 很相似,就不过多阐述了

kvm_manager

创建桥接网络

默认 libvirt 安装好后只创建一个 NAT 网络,如果想要使用桥接,需要手动配置,配置方法:

1、更改默认网卡配置文件 ifcfg-ens33,将 IP 地址、MAC、UUID 等信息去掉,添加一项 BRIDGE=br-ex

1
BRIDGE=br-ex

2、新建桥配置文件 br-ex,并且把 ip 地址绑定在桥上

1
2
3
4
5
6
7
8
DEVICE=br-ex
TYPE=Bridge
ONBOOT=yes
NM_CONTROLLED=no
BOOTPROTO=none
IPADDR=192.168.50.11
PREFIX=24
GATEWAY=192.168.50.1

如果是 openstack 中使用 openvswitch 管理的话,配置文件有所变化,请参考
RedHat 官方文档

3、重启网络服务,查看网卡配置,可以看到 ip 地址已经配置在桥网卡 be-ex 上了,桥接就配置好了

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
kvm_server ~]# systemctl restart network

kvm_server ~]# ip addr
➜ network-scripts ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever
inet6 ::1/128 scope host
valid_lft forever preferred_lft forever
2: ens33: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast master br-ex state UP group default qlen 1000
link/ether 00:0c:29:cf:e7:f6 brd ff:ff:ff:ff:ff:ff
22: br-ex: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default qlen 1000
link/ether 00:0c:29:cf:e7:f6 brd ff:ff:ff:ff:ff:ff
inet 192.168.50.11/24 brd 192.168.50.255 scope global noprefixroute br-ex
valid_lft forever preferred_lft forever
inet6 fe80::20c:29ff:fecf:e7f6/64 scope link
valid_lft forever preferred_lft forever

2. virsh

virsh 是什么

virsh 属于 libvirt 系的 kvm 管理工具,它可以对虚拟机做全生命周期的命令行管理工具,从创建、启动、以及后续的虚拟机管理的操作都能实现
通过 virsh help 可以查看命令帮助信息,命令按类型分成不同的组,可以通过 virsh help [组名] 来查看单组信息

virsh 常用参数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
vitsh
- list # 列出虚拟机
--all # 列出所有虚拟机
--name # 只显示名字
--state-running # 列出运行的虚拟机
--state-shutoff # 列出关闭的虚拟机
- dumpxml # 显示虚机的 xml 信息
- create # FILE.xml 从一个 XML 文件创建虚拟机 检查语法错误加 --validate
- define # FILE.xml 从一个 XML 文件创建虚拟机,但不启动 检查语法错误加 --validate
- console ID|UUID|NAME # 连接控制台

- start # 启动一个非活跃的虚机
- autostart # 开机启动启动
- reboot # 热重启虚机
- reset # 冷重启虚机
- shutdown # 热关机,等于虚机内执行 shutdown
- destroy # 冷关机,直接把电源
- undefine # 删除虚机

- suspend # 挂起虚拟机(暂停)
- resume # 继续运行虚拟机
- save [insNAME] [PATH.bin] # 保存虚拟机(挂起) --running 恢复时直接运行 --paused 恢复成暂停状态
- restore [PATH.bin] # 恢复一个虚机 --running 恢复后直接运行 --paused 恢复后暂停 如果不指定以保存时的参数为准↑

- domrename # 修改虚拟机名字
- domhostname # 显示主机名
- domiflist # 列出虚机所有网络接口
- domifaddr # 列出虚机所有的 ip 地址
- domfistat [dev] # 查看网口接口状态
- domblklist # 列出所有块
- domblkstat # 查看块状态
- domblkinfo # 列出虚机块设备大小信息

- net-list # 显示网络
- iface-list # 显示接口
- net-dumpxml <netwok name> # 显示网络详细信息
- net-create # 从 xml 文件创建网络


- attach-disk <insNAME> /PATH/*.img <devname> # 增加硬盘
- detached-disk <insNAME> <devname> # 分离硬盘 不能拆除正在使用和系统盘

网络配置文件

注意:网络配置文件可以从默认的 default.xml 复制然后修改,也可以使用 virt-manager 直接创建

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
~]# cp /etc/libvirt/qemu/networks/default.xml /etc/libvirt/qemu/networks/nat.xml

~]# vim /etc/libvirt/qemu/networks/nat.xml
<!--
WARNING: THIS IS AN AUTO-GENERATED FILE. CHANGES TO IT ARE LIKELY TO BE
OVERWRITTEN AND LOST. Changes to this xml configuration should be made using:
virsh net-edit default
or other application using the libvirt API.
-->
# 官方表示不建议直接修改,而是使用 virsh net-edit 来修改,实验时手动修改来加深对配置文件的理解
<network>
<name>default</name> # 需要修改名字
<!-- <uuid>47ce6b39-0d10-4c3a-b676-08dd5578824b</uuid> --> # 注释掉 UUID,会自动生成
<forward mode='nat'/> # 设置网络模型,nat、routed 等
<bridge name='virbr0' stp='on' delay='0'/>
<mac address='52:54:00:51:43:18'/> # mac 可以随机改一个
<ip address='192.168.122.1' netmask='255.255.255.0'> # 定义子网
<dhcp>
<range start='192.168.122.2' end='192.168.122.254'/> # 定义 DHCP
</dhcp>
</ip>
</network>
1. libvirt 网络基本概念

libvirt 默认使用了一个名为 default 的 nat 网络,这个网络默认使用 virbr0 作为桥接接口,使用 dnsmasq 来为使用 nat 网络的虚拟机提供 dns 及 dhcp 服务,dnsmasq 生效后的配置文件默认保存在以下路径:

1
2
3
- /var/lib/libvirt/dnsmasq/default.hostsfile   # mac&&ip 绑定的配置文件
- /var/lib/libvirt/dnsmasq/default.leases # dhcp 分配到虚拟机的 ip 地址列表
- /var/lib/libvirt/network/default.xml # default 网络的配置文件

dnsmasq 服务的启动脚本在 /etc/init.d/dnsmasq,但是我们如果手动使用此脚本来启动服务将会导致 dnsmasq 读取其自己的配置文件来启动此服务,因此这么做是不推荐的,因为这个服务完全由 libvirtd 在接管,当 libvirtd 服务启动的时候,它会将它管理的被标记为 autostart 的 network 一并启动起来,而启动 network 的时候就会自动调用 dnsmasq 并赋予其适宜的配置文件来运行服务。

使用 libvirt 管理的网络都会用到 dnsmasq 来产生相应的配置,比如定义了一个名为 route110 的 network,那么这个 route110 将使用一个新的桥接接口 virbr1 来接入网络,并使用 dnsmasq 产生名为 route110.hostsfile 和 route110.leases 的配置文件。其实这里提到的 virbr0 和 virbr1 都是 libvirt 产生的虚拟网卡,其作用就相当于一个虚拟交换机,为虚拟机提供网络转发服务。

2. libvirt 中网络的类型

首先分析一下 libvirt 所能提供的网络类型:isolated 和 forwarding,其中,isolated 意为绝对隔离的网络,也就是说处于此网络内的虚拟机对于外界是隔离的,这种模式可以用到一些特殊的场合,比如虚拟机只提供给内部使用,虚拟机只要求能相互通信而不需要与互联网通信。另外一类,forwarding,就是把虚拟机的数据 forward 到物理网络实现与外部网络进行通讯,其中 forwarding 又分为两种:nat 和 routed。

3. nat

就是把虚拟机的网络数据在经过物理机网络的时候进行 ip 伪装,这样所有虚拟机出去的网络数据都相当于是物理机出去的数据,也就是说,我们可以分配给使用 nat 网络的虚拟机一个内网 ip,而这个内网 ip 的虚拟机访问出去的时候外部网络看到的是物理机的公网 ip,这样做的用处就是实现多个虚拟机共享物理主机的公网 ip,节省公网 ip 地址;如前所述,默认情况下 libvirt 已经提供了一个名为 default 的 nat 网络,在不需要进行任何配置的情况下使用 default 网络的虚拟机即可访问互联网,但是互联网却无法访问虚拟机提供的服务,这是因为 default 网络只对虚拟机的数据包进行了伪装,而没有进行 dnat 和 snat。

需要注意的是 libvirt 所实现的这种 nat 网络是通过物理机的 iptables 规则来实现的,也即是在虚拟机数据经过 nat 表的 postrouting 链出去的时候对其进行了伪装。

4. routed

forwarding 模式的另外一种,routed,就是将虚拟机的数据直接通过物理机 route 出去,和 nat 一样,也是需要一个 virbr 虚拟网卡接口来与外面进行通信,这种模式的不同之处在于虚拟机的数据没有经过伪装便直接交给了外部网络,也就是说,使用 route 模式网络的虚拟机可以使用公网 ip 地址,而物理机却恰恰在这个时候完全可以使用一个内网 ip 而不对外提供访问,这样,虚拟机的网卡仅仅把物理机当作一个 route 数据的工具,此模式应用的场合很多,比如需要让虚拟机运行在一个 dmz 网络中。但是使用 route 模式有诸多限制,例如物理机的网络接口不够用的情况下。

这里需要注意的是,nat 模式和 route 模式的区别仅仅在于前者使用了 iptables 对虚拟机的数据包进行了伪装,而后者没有。

参考

磁盘映像

可以通过 qemu 来创建 qcow2 和管理磁盘映像文件

补充:
快照技术分为

  • 1.全量快照:
    • 镜像分离
  • 2.增量快照:
    • 写时复制:cow > copy on write
    • 写时重定向:row > Redirect on write
常用命令
1
2
3
4
qemu-create -f qcow2 -o preallocation=metadata(稀疏格式),size=10G /PATH/name.img  #创建磁盘映像
qemu-img info *.img #查看磁盘信息
convert 转换
snapshot 快照

创建虚机

virsh 创建虚机需要指定 xml 格式的文件,如果纯手敲很容易写错,可以先使用 virt-manager 图形界面创建一个虚机,然后在目录 /etc/libvirt/qemu 找到刚才创建的虚机的 xml 文件,复制一份作为模板使用,需要注意的是,要把虚机的标识信息删除,比如网卡配置文件等,不然会冲突。然后手动定义比如名字、磁盘文件目录等信息,UUID 的信息可以直接删除,系统会自动创建。

3. qemu-kvm

qemu-kvm 是 QEMU 项目的一个分支,只支持 KVM,由红帽团队维护

qemu 都负责什么

Qemu:

  1. 处理器模拟器,虽然对 cpu 的虚拟是由 kvm 负责调度,但是给每个虚拟机拿到一个假的 cpu 可以用,是 qemu 的工作
  2. 仿真各种 IO 设备
  3. 将仿真设备连接至主机的物理设备
  4. 提供用户接口

使用 qemu-kvm 管理 vms,命令放置在 /usr/libexec/qemu-kvm,他是 被 Red-Hat 有意放置在这个目录,如果不想用绝对路径来执行,可以创建一个软连接到 /usr/bin/ 下

1
ln -sv /usr/libexec/qemu-kvm /usr/bin/

qemu 常用参数

注意:qemu-kvm 复杂且繁琐,需要耐心查看和使用。

标准选项
1
2
3
4
5
6
7
8
qemu-kvm
- machine ? # 平台硬件,加问号可以显示出支持的 cpu 类型
- cpu ? # 指定 cpu 型号,使用 host 可以直接输出为物理机 cpu
- smp n[,maxcpus=cpus][,sockets=sockets] [,cores=cores][,threads=threads] # 指明虚拟机上 vcpu 数量及拓扑
- boot [order=drives][,once=drives][,menu=on|off] [,splash=sp_name][,splash-time=sp_time][,reboot-timeout=rb_time][,strict=on|off] # 执行引导设备和次序
- order:各设备的引导次序:c 表示第一块硬盘,d 表示第一个光驱设备;-boot order=dc,once=d
- m megs # 虚拟机的内存大小
- name NAME # 当前虚拟机的名称,要惟一
块设备相关选项
1
2
3
4
5
6
7
8
- cdrom file       # 指定要使用光盘映像文件
- drive [file=file][,if=type][,media=d][,index=i] [,cache=writethrough|writeback|none|directsync|unsafe][,format=f] # 指定加载的硬盘设备参数
file=/PATH/TO/SOME_IMAGE_FILE # 映像文件路径
if=TYPE # 块设备总线类型,建 virtio 议,ide, scsi, sd, floppy, ...
media=TYPE # 介质类型,cdrom 和 disk
index=i # 设定同一类型设备多个设备的编号
cache=writethrough|writeback|none|directsync|unsafe #缓存方式
format=f # 磁盘映像文件的格式,qcow2、vmdk,...
显示选项
1
2
3
4
5
6
7
8
9
10
11
12
13
14
- display type # 显示的类型,sdl, curses, none 和 vnc
- nographic # 不使用图形接口,也就是不适用显卡
- vga [std|cirrus|vmware|qxl|xenfb|none] # 模拟出的显卡的型号
- vnc display[,option[,option[,...]]]] # 启动一个 vnc server 来显示虚拟机接口; 让 qemu 进程监听一个 vnc 接口
- display:
(1) HOST:N # 在 HOST 主机的第 N 个桌面号输出 vnc
5900+N
(2) unix:/PATH/TO/SOCK_FILE
(3) none
- options:
password # 连接此服务所需要的密码
- monitor stdio # 在标准输出上显示 monitor 界面
Ctrl-a, c # 在 console 和 monitor 之间切换
Ctrl-a, h
网络选项
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
- net nic[,vlan=n][,macaddr=mac][,model=type][,name=str][,addr=str][,vectors=v] # 为虚拟机创建一个网络接口,并将其添加至指定的 VLAN;
macaddr=mac # 指明 mac 地址,mac 地址必须指定,默认 52:54:00:00:00,不然一定冲突
model=type # 指明模拟出的网卡的型号,建议使用 virtio。 ne2k_pci,i82551,i82557b,i82559er,rtl8139,e1000,pcnet;


- net tap[,vlan=n][,name=str][,fd=h][,fds=x:y:...:z][,ifname=name][,script=file][,downscript=dfile]:
tap # 模拟一个二层的设备,二层的接口,通过物理的 TAP 网络接口连接至 vlan n
script=file # 启动虚拟机时要执行的脚本,默认为 /etc/qemu-ifup
downscript=dfile # 关闭虚拟机时要执行的脚本,/etc/qemu-ifdown,可以不指定,能自动完成
ifname=NAME # 自定义接口名称
-----------------------------------------------------------------
/etc/qemu-ifup.sh # 网卡启动脚本

#!/bin/bash
#
bridge=br0 if [ -n "$1" ];then
ip link set $1 up
sleep 1
brctl addif $bridge $1
[ $? -eq 0 ] && exit 0 || exit 1
else
echo "Error: no interface specified."
exit 1
fi
-----------------------------------------------------------------
其它选项
1
- daemonize  # 以守护进程运行
示例,启动一个虚机
1
2
3
4
~]# qemu-kvm -cpu host -smp 8,ockets=2,cores=2,threads=2 \
-m 64 -name vm1 -boot order=dc \
-drive file=/vm/vm1/vm1.img,media=disk,if=virtio,cache=writeback,format=qcow2 \
-vnc :6 -net nic,macaddr=52:54:00:00:00:01,model=virtio -net tap,script=/etc/qemu-ifup

六、各种网络模型的实现

虚机机的网络通过软件来模拟真实的物理环境,使用的工具上文中也提到过,下面介绍怎么使用软件来创建各种网络模型

1. 隔离网络

创建一个网卡桥,把两个虚拟机的网卡加到桥上,只有连接到桥上的设备才能互相通信,是个隔离的二层网络
开启内核转发

1
2
kvm_server ~]# echo "net.ipv4.ip_forward = 1" >> /etc/sysctl.conf
kvm_server ~]# sysctl -p

创建 mybr0 并 up

1
2
kvm_server ~]# brctl addbr mybr0
kvm_server ~]# ip link set dev mybr0 up

创建两个虚拟机 vm1 和 vm2,网卡叫 vm1eth0 和 vm2eth0

1
2
3
4
5
6
7
8
9
10
11
kvm_server ~]# qemu-kvm -cpu host -smp 8,ockets=2,cores=2,threads=2 \
-m 64 -name vm1 -boot order=dc \
-drive file=/vm/vm1/vm1.img,media=disk,if=virtio,cache=writeback,format=qcow2 \
-vnc :1 -net nic,macaddr=52:54:00:00:00:01,model=virtio \
-net tap,script=/etc/qemu-ifup.sh,ifname=vm1eth0 -daemonize

kvm_server ~]# qemu-kvm -cpu host -smp 8,ockets=2,cores=2,threads=2 \
-m 64 -name vm1 -boot order=dc \
-drive file=/vm/vm2/vm2.img,media=disk,if=virtio,cache=writeback,format=qcow2 \
-vnc :2 -net nic,macaddr=52:54:00:00:00:02,model=virtio \
-net tap,script=/etc/qemu-ifup.sh,ifname=vm2eth0 -daemonize

可以看到两个虚拟机的网卡已经添加到 mybr0 上了

1
2
3
4
kvm_server ~]# vm1 brctl show
bridge name bridge id STP enabled interfaces
mybr0 8000.eab976f7c64c no vm1eth0
vm2eth0

使用 vncviewer 登录虚拟机

1
2
kvm_server ~]# vncviewer 127.0.0.1 :1 &   # 1 和 2 是创建虚机时指定的桌面号
kvm_server ~]# vncviewer 127.0.0.1 :2 &

配置 vm1 和 vm2 的 IP 地址

1
2
3
vm1 ~]# ip addr add 10.0.0.1/24 dev eth0  # vm1 上的 eth0

vm2 ~]# ip addr add 10.0.0.2/24 dev eth0 # vm2 上的 eth0

可以互相 ping 通了,隔离网络就做好了,但是 不能和其他任何网络通,连宿主机也 ping 不到

1
2
3
4
5
vm1 ~]# ping 10.0.0.2
PING 10.0.0.1 (10.0.0.1): 56 data bytes
64 bytes from 10.0.0.1: seq=0 ttl=64 time=0.669 ms
64 bytes from 10.0.0.1: seq=1 ttl=64 time=2.108 ms
64 bytes from 10.0.0.1: seq=2 ttl=64 time=2.201 ms

2. 仅主机网络 Host-Only

仅主机的网络是在隔离网络的基础上,给 mybr0 的桥上配置一个同网段的地址,宿主机就有 IP,可以与 vm1 和 vm2 连通了

1
2
3
4
5
6
7
kvm_server ~]# ip addr add 10.0.0.254/24 dev mybr0  # 给桥配上同网段 IP
kvm_server ~]# ping 10.0.0.1 # 宿主机可以通 vm1 了
PING 10.0.0.1 (10.0.0.1) 56(84) bytes of data.
64 bytes from 10.0.0.1: icmp_seq=1 ttl=64 time=0.481 ms
64 bytes from 10.0.0.1: icmp_seq=2 ttl=64 time=0.234 ms
64 bytes from 10.0.0.1: icmp_seq=3 ttl=64 time=0.233 ms

仅主机的网络目前只能在宿主机内通信,如果想和外边的网络通信,有两种方法可以实现

3. Route 网络和 NAT

第一种是 route,需要开启核心转发,然后把网关指向 mybr0 桥的 ip 就可以了,但是因为外部网络没有私有网络的路由,所以 ip 包是有出无回

另一种是 NAT,将地址转换成宿主机的 ip 发出,ip 包有出有回,下边说 NAT 网络构建方法:

在仅主机的网络上,添加一条 iptables 规则

1
2
kvm_server ~]# iptables -t nat -A POSTROUTING -s 10.0.0.0/24 ! -d 10.0.0.1/24 -j MASQUERADE
原地址是这个网络 ↑ 目的地不是这个网络的 ↑ 做 MASQUERADE 转换,是一种 SNAT

虚拟机把默认网关路由指向 mybr0 桥的地址 10.0.0.254

1
vm1 ~]# ip route add default via 10.0.0.254

虚机就可以通过 NAT 转发 ping 外网了

1
2
3
4
5
vm1 ~]# ping 8.8.8.8
PING 8.8.8.8 (8.8.8.8): 56 data bytes
64 bytes from 8.8.8.8: seq=0 ttl=50 time=47.073 ms
64 bytes from 8.8.8.8: seq=1 ttl=50 time=49.069 ms
64 bytes from 8.8.8.8: seq=2 ttl=50 time=50.580 ms

4. dnsmasq 服务

dnsmasq 是一个 轻量化的程序,可以实现简单的 dns_forword 和 dhcp 功能
使用 dnsmasq 实现在自己创建的 mybr0 网络中,增加 dhcp 功能,让虚机开机就能通过 dhcp 获取到 IP 地址

1
2
dnsmasq --listen-address=10.0.0.254 --dhcp-range=10.0.0.1,10.0.0.253,48h --dhcp-option=3,10.0.0.254
3 是指网关

在虚机内使用 cirros-dhcpc up eth0 就可以自动获得 ip 地址和网关了
以后在 mybr0 这个网络中的虚机,开机就能自动获得 ip 地址了!

七、镜像预生成器

这是啥?

镜像预生成器可以在不开启虚机的情况下,对磁盘镜像文件进行定制,并且剥离一些独有数据,比如 mac 地址、ssh 秘钥等等,还可以设置 root 密码,安装软件等等等…

两种使用场景:

  1. 目前流行的社区都提供了开机即用的磁盘镜像文件下载,但是不一定能符合自己的使用要求,这样就可以使用镜像预生成器来进行二次定制
  2. 克隆的虚机,mac 地址,bash 历史命令,私有文件等,需要去除

安装工具 virt-sysprep

1
yum install libguestfs-tools

virt-sysprep 语法格式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
virt-sysprep [--options] -d domname   # 可指定一个虚机
virt-sysprep [--options] -a disk.img [-a disk.img ...] # 可指定一个磁盘文件

--set-format # 要剥离的属性
--remove-user-account <users> # 删除后来创建的用户账号,只保留默认的
--root-password <SELECTOR> # 设置 root 的密码
--truncate <FILE> # 清空指定文件
--install <PKG> # 安装指定的程序包
--uninstall <PKG> # 卸载指定的程序包

--operation <operation> # 指定一些特殊的参数
--list-operations # 查看支持哪些特殊参数
bash-history # 清空 shell 命令
abrt-data # 清除 abrt 数据
net-hwaddr # 清除 MAC 地址
package-manager-cache # 清空 yum 缓存
ssh-hostkeys # 删除主机秘钥信息
ssh-userdir # 删除主机.ssh 目录

示例:事先设置好 root 密码,并且安装好 httpd,使用 --network 参数让虚拟机开启网络,默认是关闭的,会影响 yum 安装 httpd

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
[root@centos_1 templates]# virt-sysprep --root-password password:123qwe \
--install httpd --network -a vm1.qcow2
[ 0.0] Examining the guest ...
[ 5.9] Performing "abrt-data" ...
[ 5.9] Performing "backup-files" ...
[ 6.7] Performing "bash-history" ...
[ 6.7] Performing "blkid-tab" ...
[ 6.7] Performing "crash-data" ...
[ 6.7] Performing "cron-spool" ...
[ 6.7] Performing "dhcp-client-state" ...
[ 6.7] Performing "dhcp-server-state" ...
[ 6.7] Performing "dovecot-data" ...
[ 6.8] Performing "logfiles" ...
[ 6.8] Performing "machine-id" ...
[ 6.8] Performing "mail-spool" ...
[ 6.8] Performing "net-hostname" ...
[ 6.8] Performing "net-hwaddr" ...
[ 6.8] Performing "pacct-log" ...
[ 6.8] Performing "package-manager-cache" ...
[ 6.9] Performing "pam-data" ...
[ 6.9] Performing "passwd-backups" ...
[ 6.9] Performing "puppet-data-log" ...
[ 6.9] Performing "rh-subscription-manager" ...
[ 6.9] Performing "rhn-systemid" ...
[ 6.9] Performing "rpm-db" ...
[ 6.9] Performing "samba-db-log" ...
[ 6.9] Performing "script" ...
[ 6.9] Performing "smolt-uuid" ...
[ 6.9] Performing "ssh-hostkeys" ...
[ 6.9] Performing "ssh-userdir" ...
[ 6.9] Performing "sssd-db-log" ...
[ 6.9] Performing "tmp-files" ...
[ 6.9] Performing "udev-persistent-net" ...
[ 7.0] Performing "utmp" ...
[ 7.0] Performing "yum-uuid" ...
[ 7.0] Performing "customize" ...
[ 7.0] Setting a random seed
[ 7.0] Setting the machine ID in /etc/machine-id
[ 7.0] Installing packages: httpd
[ 30.3] Setting passwords
[ 33.7] Performing "lvm-uuids" ...

八、LaaS 管理平台

以上就是关于 kvm 的各种管理工具,但是生产环境中,这样的管理方式效率还是太低了,目前市面上有很多工具,可以更好的管理 LaaS 这一层的资源,可以参考官方手册
推荐几个各种环境下的开源解决方案:

  • kimchi   基础 h5 的管理工具,只能管理单机
  • Proxmox VE 可以在小规模企业使用,对节点多、环境复杂的架构管理欠缺
  • oVirt    可以管理近百个节点的管理软件
  • OpenStack  数百个以上的物理节点,只有 OpenStack 支持的比较好了

kimchi

这里主要介绍一下 kimchi:kimchi 通过 web 界面来管理 kvm,配置好模板后,可以根据模板快速创建虚拟机,适合自己做实验,或者公司节点比较少的情况下使用

安装 kimchi

1、打开官方项目首页
2、需要下载 wok 和 kimchi 两个软件包,根据自己的平台下载二进制安装程序,我是 centos7 64 位,所以下载
- kimchi-2.5.0-0.el7.centos.noarch.rpm
- wok-2.5.0-0.el7.centos.noarch.rpm

1
2
~]# wget https://github.com/kimchi-project/kimchi/releases/download/2.5.0/kimchi-2.5.0-0.el7.centos.noarch.rpm
~]# wget https://github.com/kimchi-project/kimchi/releases/download/2.5.0/wok-2.5.0-0.el7.centos.noarch.rpm

3、使用 yum 安装,来解决依赖问题,需要注意因为依赖 vnc,请同时安装 vnc 工具

1
2
3
~]# yum install kimchi-2.5.0-0.el7.centos.noarch.rpm \
wok-2.5.0-0.el7.centos.noarch.rpm \
tigervnc

4、启动 kimchi

1
2
~]# systemctl daemon-reload
~]# systemctl restart wokd

访问 web

在浏览器输入 https://[address]:8001,就可以访问了,注意是 https 的,用户名密码为 root 系统账号
web 界面一目了然,简单易懂,相信如果对以上知识都了解的话,配置起来不会有一点问题,这里说一下使用流程,就不放图片了

  1. 在 网络里 创建好自己需要的 网络模型
  2. 添加 存储器,就是虚机磁盘镜像文件要保存的地方,自己指定即可
  3. 创建 模板,配置好 文件路径,其实就是这个模板要用的磁盘镜像文件,创建好模板后可以查看并编辑默认的配置信息,如 cpu、内存,调整 磁盘大小,注意只能扩大,不能缩小
  4. 然后在 访客 就可以根据刚才做好的模板,创建虚拟机啦
  5. 创建好之后可以通过 web 访问虚拟机的 vnc,还可以通过控制来开机、关机、克隆、快照等操作

使用 qemu-img info 查看刚创建好的虚拟机的磁盘文件,可以看出是以快照的方式创建的,大小只有 1.1M,在有新的文件写入时才会增长。这与 ceph 的 rbd 中,使用 RAW 格式创建的磁盘镜像很相似,应该属于 row(写时重定向)机制的快照,所以依赖源镜像文件,也就是模板中指定的磁盘镜像文件,所以千万不要删除,不然虚拟机就出问题啦

1
2
3
4
5
6
7
8
9
10
~]# qemu-img info 045b56f8-4a94-420c-aa6e-3bd82deaf295-0.img
image: 045b56f8-4a94-420c-aa6e-3bd82deaf295-0.img
file format: qcow2
virtual size: 50G (53687091200 bytes)
disk size: 1.1M
cluster_size: 65536
backing file: /vms/templates/virt-cirros-0.3.4-x86_64-disk.img # 有依赖关系!!!
backing file format: qcow2
Format specific information:
compat: 0.10