KVM架构
KVM:提供 CPU / 内存硬件级虚拟化能力(内核层)
QEMU:模拟各种外设、磁盘、网络,配合 KVM 实现完整虚拟机(用户层)
Libvirt:封装 KVM+QEMU,提供统一 API / 命令行,方便管理、创建、控制虚拟机

KVM部署
操作系统:Ubuntu 20.04.1 LTS (Focal Fossa)
# 查看服务器是否支持KVM,返回值大于0即可
grep -E 'vmx|svm' /proc/cpuinfo|wc -l
# 安装基础包
apt-get install -y qemu-kvm libvirt-daemon-system libvirt-clients bridge-utils virtinst virt-manager osinfo-db-tools osinfo-db
# 启动libvirtd并加入开机自启动
systemctl enable libvirtd --now
# 设置内核参数
# br0 是 Linux 原生网桥 → 走二层转发 → 受 bridge-nf-call-iptables 参数控制
# 当这两个参数为1时:br0 转发的所有数据包(包括 KVM 和 Docker 的流量)都会强制经过 iptables 规则过滤,而你的 iptables 规则仅针对性放行 Docker 或 KVM 流量,极易因规则遗漏 / 顺序问题导致一方流量被拦截;
# 当设置为0时:br0 仅做纯二层网桥转发(类似物理交换机),不再触发 iptables 规则,KVM 虚拟机的流量直接通过 br0 转发,Docker 的流量则走 docker0 网桥 + iptables 端口映射,两者互不干扰。
cat >> /etc/sysctl.conf <<EOF
net.ipv4.ip_forward = 1
net.bridge.bridge-nf-call-iptables=0
net.bridge.bridge-nf-call-ip6tables=0
EOF
sysctl -p
# 验证kvm是否可以正常运行,返回KVM acceleration can be used说明正常
kvm-ok
自动设置网卡桥接:virsh iface-bridge eno1 br0命令执行后,会把eno1的网络信息迁移到br0网卡上,把eno1加入到br0的网桥中,建议使用该方式操作。
virsh iface-bridge eno1 br0
手动设置网卡桥接:操作前先备份网卡的配置文件,如果配置错误会断开连接,必须保证配置的br0网卡IP和你的网络可以连通。该步骤不需要执行,仅用于做记录。
# 备份配置文件
cp /etc/netplan/01-network-manager-all.yaml /etc/netplan/01-network-manager-all.yaml.bak
# 创建桥接网卡,并吧eno1网卡连接到br0网桥上
cat > /etc/netplan/01-network-manager-all.yaml <<EOF
network:
ethernets:
eno1:
addresses: []
dhcp4: no
dhcp6: no
bridges:
br0:
dhcp4: no
dhcp6: no
addresses: [192.168.6.136/22]
gateway4: 192.168.4.1
nameservers:
addresses: [114.114.114.114,223.5.5.5]
interfaces: [eno1]
version: 2
EOF
查看网桥,网卡信息
# 查看网桥信息,eno1网卡接入br0网桥中
> brctl show
bridge name bridge id STP enabled interfaces
br0 8000.3cecefab46bc yes eno1
# 查看网卡信息,eno1没有IP地址,且MAC地址和br0MAC地址相同
> ifconfig
br0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 192.168.6.136 netmask 255.255.252.0 broadcast 192.168.7.255
ether 3c:ec:ef:ab:46:bc txqueuelen 1000 (Ethernet)
RX packets 8226194 bytes 3700218410 (3.7 GB)
RX errors 0 dropped 368575 overruns 0 frame 0
TX packets 1603790 bytes 1084981132 (1.0 GB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
eno1: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
ether 3c:ec:ef:ab:46:bc txqueuelen 1000 (Ethernet)
RX packets 326368717 bytes 248360725787 (248.3 GB)
RX errors 2940 dropped 218927 overruns 0 frame 2940
TX packets 271161440 bytes 275610392685 (275.6 GB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
定制镜像
生产环境一般使用定制的qcow2(cow是copy on write)硬盘类型镜像, 支持快照、压缩、加密、动态扩容等,稀疏分配空间,占多少用多少,而raw类型硬盘是预分配空间,无高级功能,读写速度快,性能好。
定制qcow2的步骤:
- 新建一个空白 qcow2 格式的磁盘
- 用 ISO 镜像正常安装系统,提前准备镜像
- 进入系统做模板化优化,如执行初始化脚本
- 关机、压缩、得到最终定制 qcow2 模板
# 创建目录,images存储qcow2镜像,disk存储虚拟机磁盘,iso存储操作系统镜像
mkdir -p /opt/ops-kvm/{images,disk,iso}
cd /opt/ops-kvm/images
# 创建200G空白qcow2
qemu-img create -f qcow2 rocky9-custom-template.qcow2 200G
# 安装虚拟机
virt-install \
--name rocky9-install-temp \
--ram 16384 \
--vcpus 8 \
--disk path=/opt/ops-kvm/disk/rocky9-custom-template.qcow2,format=qcow2,bus=virtio \
--cdrom /opt/ops-kvm/iso/Rocky-9.6-x86_64-minimal.iso \
--network bridge=br0,model=virtio \
--graphics vnc,listen=0.0.0.0,port=5920 \
--noautoconsole \
--extra-args="console=ttyS0,115200n8"
# 使用VNC连接虚拟机,设置网卡为eth0
# VNC连接后,按TAB,添加net.ifnames=0 biosdevname=0参数,设置网卡为eth0
# 执行初始化脚本,该步骤略
# 配置虚拟机eth0网卡信息,建议DHCP获取IP地址,并删除UUID,设置开机自启动
cat > /etc/NetworkManager/system-connections/eth0.nmconnection <<EOF
[connection]
id=eth0
type=ethernet
interface-name=eth0
autoconnect=yes
[ethernet]
[ipv4]
method=auto
#method=manual
#address1=192.168.6.12/22
#gateway=192.168.4.1
#dns=114.114.114.114;8.8.8.8;
[ipv6]
addr-gen-mode=eui64
method=disabled
[proxy]
EOF
# 清空machine-id
echo "" > /etc/machine-id
# 关闭虚拟机
virsh destroy rocky9-install-temp
# 删除虚拟机
virsh undefine rocky9-install-temp
# 对定制的qcow2镜像进行压缩,后面在安装新的虚拟机就可以基于此镜像进行操作
qemu-img convert -c -f qcow2 -O qcow2 rocky9-custom-template.qcow2 rocky9-custom-template-final.qcow2
运行虚机
# 安装名为ops-kvm-01的虚拟机
# 参数说明:
# --name ops-kvm-01 \ 虚拟机名称
# --memory 16384,maxmemory=32768 \ 单位M,当前内存16G,最大支持内存32G
# --vcpus 8,,maxvcpus=16 \ CPU个数,当前cpu8个,最大支持16个
# --virt-type kvm \ 虚拟化类型
# --os-type linux \ 操作系统类型
# --os-variant rocky9 \ 操作系统版本
# --import \ 将disk导入为操作系统
# --disk path=/opt/ops-kvm/disk/ops-kvm-01_rocky9.6.qcow2,format=qcow2,bus=virtio \ 指定虚拟机的disk
# --network bridge=br0,model=virtio \ 指定桥接网络
# --graphics vnc,listen=0.0.0.0,port=59181 \ 开启VNC
# --noautoconsole 不自动连接console
# 运行虚拟机
virt-install \
--name ops-kvm-01 \
--memory 16384,maxmemory=32768 \
--vcpus 8,maxvcpus=16 \
--virt-type kvm \
--os-type linux \
--os-variant rocky9 \
--import \
--disk path=/opt/ops-kvm/disk/ops-kvm-01_rocky9.6.qcow2,format=qcow2,bus=virtio \
--network bridge=br0,model=virtio \
--graphics vnc,listen=0.0.0.0,port=59181 \
--noautoconsole
# 如果运行报os-variant错误,说明操作系统中没有要指定的os-variant
# 下载最新版的osinfo-db,并进行导入,然后重新运行虚拟机
wget https://releases.pagure.org/libosinfo/osinfo-db-20251212.tar.xz
osinfo-db-import --system osinfo-db-20251212.tar.xz
osinfo-query os
# 加入开启自启动
virsh autostart ops-kvm-01
常用命令
基础管理
|
命令 |
功能说明 |
实操示例 |
|
|
查看虚拟机状态 |
|
|
|
启动虚拟机 |
|
|
|
正常关机(优雅关闭) |
|
|
|
强制断电(粗暴关闭) |
|
|
|
重启虚拟机 |
|
|
|
挂起虚拟机(暂停运行) |
|
|
|
恢复挂起的虚拟机 |
|
|
|
重命名虚拟机 |
|
|
|
删除虚拟机定义(配置) |
|
|
|
获取网络接口信息 |
|
配置管理
|
命令 |
功能说明 |
实操示例 |
|
|
导出 / 备份虚拟机配置 |
|
|
|
导入配置文件创建虚拟机 |
|
|
|
编辑虚拟机配置,自带语法检查(推荐) |
|
连接管理
|
命令 |
功能说明 |
实操示例 |
|
|
查询虚拟机 VNC 端口号 |
输出示例: (对应端口 5901,VNC 端口规则: → 5900+N) |
|
|
宿主机直连虚拟机终端 |
|
补充:配置 console 终端(解决无法进入的问题),若 virsh console 连接后无响应,需在虚拟机内添加内核参数或者在创建虚拟机的时候指定参数:
# 如果在使用iso镜像前,指定了--extra-args="console=ttyS0,115200n8",该步骤就不需要操作了
1. 进入虚拟机(VNC/SSH),添加console内核参数(适配ttyS0串口)
grubby --update-kernel=ALL --args="console=ttyS0,115200n8"
# 2. 如需删除该参数,执行:
grubby --update-kernel=ALL --remove-args="console=ttyS0,115200n8"
# 3. 重启虚拟机生效
reboot
自启管理
配置虚拟机开机自启动
|
命令 |
功能说明 |
实操示例 |
|
|
开启虚拟机开机自启 |
|
|
|
取消开机自启 |
|
磁盘管理
|
命令 |
功能说明 |
实操示例 |
|
|
查看虚拟磁盘的格式、实际占用空间、总容量、快照信息等核心属性 |
|
|
|
1. 不指定 2. |
1. 2. |
|
|
1. 2. |
1. 2. |
|
|
1. 2. |
|
快照管理
kvm的快照是给当前磁盘做一个"只读备份点",后续新数据写在新的增量文件里,不改动原始磁盘,从而实现快速备份 / 回滚。
|
命令 |
核心说明 |
实操示例 |
|
|
列出虚拟机所有快照,显示名称、创建时间、状态 |
|
|
|
查看指定快照的详细信息(是否当前快照、存储位置、父子关系等) |
|
|
|
仅创建磁盘快照,虚拟机可运行 / 关机,数据存在镜像文件内(内置快照) |
|
|
|
恢复到指定快照状态,建议先关机;加 可直接恢复运行状态 |
|
|
|
删除内置快照(含数据);外部快照加 仅删元数据(保留文件) |
|
|
|
查看虚拟机当前使用的快照(确认是否在目标快照状态) |
|
网络管理
生产环境中使用桥接网络,可通过如下方式创建桥接网络
|
命令 |
核心说明 |
基础语法 |
实操示例 |
|
|
创建网桥并将物理网卡桥接到网桥 |
|
|
|
|
解绑网桥,恢复物理网卡独立工作 |
|
|
桥接网络原理:
- 所有流量先到 br0,再转发
- 虚拟机访问外部网络:走 br0 → eno1
- 外部网络访问虚拟机:eno1 → br0 → 对应 vnet
- 物理机自身访问网络:br0 → eth0
物理机的网卡eno1相当于是一根连接到外部网络的网线。

维护操作
热更新硬盘
常见维护操作:添加新硬盘,现有硬盘扩容
热添加新硬盘
# 创建硬盘
qemu-img create -f qcow2 /opt/ops-kvm/disk/web01-vdb.qcow2 5G
# 查看当前的target
virsh domblklist web01
# 临时添加,vda默认是系统盘,从vdb开始添加,使用virsh domblklist查看target,指定磁盘类型是qcow2
virsh attach-disk web01 /opt/ops-kvm/disk/web01-vdb.qcow2 vdb --subdriver qcow2
# 永久添加,写到配置文件中
virsh attach-disk web01 /opt/ops-kvm/disk/web01-vdb.qcow2 vdb --subdriver qcow2 --config --live
# 添加磁盘后进入虚拟机格式化,挂载
mkfs.ext4 /dev/vdb
mount /dev/vdb /data
# 卸载硬盘
virsh detach-disk web01 vdb --live --config
硬盘扩容,包含在线扩容或离线扩容
# 关机扩容,停止虚拟机,给磁盘文件增加空间,对根分区扩容
virsh destroy test-kvm
qemu-img resize test.qcow2 +5G
# 进入虚拟机
dnf install -y cloud-utils-growpart
growpart /dev/vda 2
pvresize /dev/vda2
lvextend -l +100%FREE /dev/mapper/rl-root
xfs_growfs /
# 在线扩容,扩容到220G
virsh blockresize ops-kvm-01 /opt/ops-kvm/disk/ops-kvm-01_rocky9.6.qcow2 220G
growpart /dev/vda 2
pvresize /dev/vda2
lvextend -l +100%FREE /dev/mapper/rl-root
xfs_growfs /
热添加内存
需要设置最大内存,建议一开始就规划好,虚拟机的内存不能超过最大内存设置
# 设置最大内存为8G,--live临时调整,--config永久调整
virsh setmaxmem web04 8192M --live
virsh setmaxmem web04 8192M --config
# 假设虚拟机内存是500M,增加内容到1G,最大不能超过最大内存设置,--live --config可以同时使用
virsh setmem web04 1024M --live
virsh setmem web04 1024M --config
热更新CPU
需要设置最大vcpus数量,虚拟机的vcpus不能超过最大vcpus设置
# 调整vcpu个数为10,临时调整
virsh setvcpus web05 10 --live
# 调整vcpu个数为10,永久调整
virsh setvcpus web05 10 --config
热更新网卡
# 添加网卡,不加--config是临时生效
virsh attach-interface web04 --type bridge --source br0 --mode virtio --config
# 删除网卡
virsh detach-interface web04 --type bridge --mac mac地址
虚拟机克隆
完整克隆:互相独立,磁盘之间无依赖关系
# 完整克隆方式1,操作前关机/挂起
virsh shutdown web03
virt-clone -o web02 -n web03 --auto-clone
virt-clone -o web02 -n web03 -f /opt/ops-kvm/disk/web03.qcow2
# 完整克隆方式2
--> 拷贝磁盘镜像
--> 拷贝并修改配置,修改虚拟机名称,删除uuid和mac地址,磁盘文件,vnc端口
--> virsh define导入
# 链接克隆方式1,操作前关机/挂起
virsh shutdown web03
virt-clone \
-o centos7-vm \
-n centos7-vm-linked \
-f /var/lib/libvirt/images/centos7-vm-linked.qcow2 \
--force-copy=off # 关键:禁用完整复制,使用链接模式
# 链接克隆方式2,操作前关机/挂起
virsh shutdown web03
qemu-img create -f qcow2 -b 源磁盘文件 新磁盘文件
# 用新的磁盘文件创建虚拟机即可
virt-install --disk path=新磁盘文件,format=qcow2,bus=virtio \
虚拟机快照
# 对centos7-vm虚拟机创建快照,名称为20260320-snap-init,备注为"系统初始化完成"
virsh snapshot-create-as centos7-vm 20260320-snap-init "系统初始化完成"
# 查看快照描述
virsh snapshot-dumpxml ops-kvm-01 snap-init |grep desc
常用脚本
创建虚拟机脚本,使用示例: sh vm_create.sh ops-agent-sts-02:5915
#!/bin/bash
ARGS="$1"
if [ "$#" = "0" ];then
echo "Usage: sh $0 主机名:VNC端口号"
echo "Example: sh $0 ops-agent-sts-02:5915"
exit 1
fi
VIRTUAL_NAME=$(echo ${ARGS}|awk -F ':' '{print $1}')
VNC_PORT=$(echo ${ARGS}|awk -F ':' '{print $2}')
# 这里的目录需要替换,已经提前做好了qcow2模板,拷贝模板到新目录直接运行virt-install创建虚拟机
cp /opt/ops-kvm/images/rocky9-custom-template-final.qcow2 /opt/ops-kvm/disk/${VIRTUAL_NAME}_rocky9.6.qcow2
virt-install \
--name ${VIRTUAL_NAME} \
--memory 16384,maxmemory=32768 \
--vcpus 8,maxvcpus=16 \
--virt-type kvm \
--os-type linux \
--os-variant rocky9 \
--import \
--disk path=/opt/ops-kvm/disk/${VIRTUAL_NAME}_rocky9.6.qcow2,format=qcow2,bus=virtio \
--network bridge=br0,model=virtio \
--graphics vnc,listen=0.0.0.0,port=${VNC_PORT} \
--noautoconsole
查看虚拟机信息脚本,脚本的IP和MAC地址基于arp协议,创建虚拟机后需要手动ping一下IP地址
#!/bin/bash
# 脚本名称:vm_info.sh
# 功能:批量获取KVM中名称包含"ops"的虚拟机的信息
# 定义颜色(可选,增强输出可读性)
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[0;33m'
NC='\033[0m' # 重置颜色
# 标题输出
echo "-------------------------------------------------------------------------"
printf "%-20s %-20s %-20s %-20s\n" "HOSTNAME" "MAC ADDRESS" "VPC PORT" "IP ADDRESS"
echo "-------------------------------------------------------------------------"
# 遍历名称包含"ops"的虚拟机
# 优化:用virsh list --name过滤,避免grep/awk处理表头
for vm_name in $(virsh list --name | grep "ops"); do
# 跳过空值(避免无匹配时循环异常)
if [ -z "$vm_name" ]; then
continue
fi
vnc_port=$(virsh vncdisplay $vm_name|grep ':'|awk -F ':' '{print "59"$2}'|tr -d '\n')
mac_addr=$(virsh domiflist "$vm_name" 2>/dev/null | grep -i "bridge" | awk '{print $NF}')
ip=$(arp -an|grep $mac_addr|awk '{print $2}'|tr -d '()'|xargs)
# 异常处理:未找到桥接网卡
if [ -z "$mac_addr" ]; then
echo -e "${RED} 错误:未找到该虚拟机的桥接网卡MAC地址${NC}"
continue
fi
# 格式化MAC地址(将:替换为-,兼容你的原始需求)
mac_formatted=$(echo "$mac_addr" | sed 's/:/-/g')
printf "%-20s %-20s %-20s %-0s\n" "$vm_name" "$mac_formatted" "$vnc_port" "$ip"
done
执行脚本的结果如下
-------------------------------------------------------------------------
HOSTNAME MAC ADDRESS VPC PORT IP ADDRESS
-------------------------------------------------------------------------
ops-agent-dep-01 52-54-00-3b-5f-13 5914 192.168.6.14
ops-agent-dep-02 52-54-00-4c-5a-11 5915 192.168.6.15
ops-agent-dep-03 52-54-00-d8-b1-ca 5916 192.168.6.16
ops-agent-sts-01 52-54-00-c8-c6-e8 5917 192.168.6.17
ops-agent-sts-02 52-54-00-22-eb-ba 5918 192.168.6.18
ops-agent-sts-03 52-54-00-55-31-21 5919 192.168.6.19
ops-master-01 52-54-00-1e-3e-4b 5911 192.168.6.11
ops-master-02 52-54-00-98-89-cf 5912 192.168.6.12
ops-master-03 52-54-00-38-a7-74 5913 192.168.6.13
ops-storage-01 52-54-00-5b-27-17 5920 192.168.6.20
ops-storage-02 52-54-00-74-1d-8a 5921 192.168.6.21
ops-storage-03 52-54-00-b5-ad-1c 5922 192.168.6.22
ops-lb-01 52-54-00-97-fa-7b 5923 192.168.6.23
ops-observe-01 52-54-00-20-1f-f0 5924 192.168.6.24

1572

被折叠的 条评论
为什么被折叠?



