KVM部署复盘
一、环境
操作系统:Ubuntu
CPU:支持硬件虚拟化;验证:egrep -c '(vmx|svm)' /proc/cpuinfo至少返回一行vmx或svm,没有就BIOS开启VT-x/AMD-V
内存:8GB
存储:256GB
网络:支持桥接或NAT的网卡
*碰到的问题:虚拟机启动失败,报错“错误:无法启动域:internal error: ……”之类的。是冲突服务问题,网上找了下,最好关闭冲突服务。
sudo setenforce 0 # 临时关闭 SELinux
sudo sed -i 's/SELINUX=enforcing/SELINUX=disabled/g' /etc/selinux/config # 永久关闭
sudo systemctl disable --now firewalld # 关闭防火墙
swapoff -a && sysctl -w vm.swappiness=0 # 禁用 swap 分区
二、安装
1.核心组件安装
更新软件包列表
sudo apt update
安装KVM libvirt qemu
sudo apt -y install qemu-kvm libvirt-daemon-system virtinst virt-manager bridge-utils
- qemu-kvm CPU虚拟化核心引擎
- libvirt 管理API守护进程
- virt-install 命令行创建虚拟机工具
- virt-manager 图形化管理
- bridge-utils 配置桥接
验证
sudo systemctl status libvirtd
显示active (running)就行
需要开机自启可以设置sudo systemctl enable --now libvirtd
2.配置权限
虚拟化相关默认root用户操作,不配置可能直接virt-manager或virsh的时候出现拒绝访问之类的。
sudo usermod -aG libvirt $(whoami)
- usermode 修改账户信息
- aG 追加(a)指定附加组(G)
- libvirt 目标用户组名
- $(whoami) 自动获取当前登录的用户名。你也可以直接替换成用户名
newgrp libvirt 创建一个新的登录Shell,并切换到指定的用户组
3.验证KVM
lsmod | grep kvm试下KVM有没有加载,输出kvm_intel或kvm_amd就行
三、创建管理虚拟机
1.两种创建方法
(1)命令行
virt-install 命令行快速创建虚拟机
- Ⅰ:纯文本界面,在当前终端里操作
点击查看代码
sudo virt-install \
--name=ubuntu-vm \ # 虚拟机名称
--memory=4096 \ # 分配内存(MB)
--vcpus=2 \ # 虚拟CPU核心数
--disk path=/var/lib/libvirt/images/ubuntu-vm.qcow2,size=20 \ # 磁盘路径与大小(GB)
--os-type=linux \ # 操作系统类型
--os-variant=ubuntu22.04 \ # 系统发行版版本
--location=/iso/镜像 \ # ISO 镜像路径
--network bridge=br0 \ # 桥接到主机网卡
--graphics none \ # 禁用图形控制台
--console pty,target_type=serial \ # 启用串行控制台
--extra-args="console=ttyS0" # 内核参数(文本安装)
- Ⅱ:安装时会开启VNC服务,需要用VNC客户端连过去看图形安装界面
点击查看代码
virt-install \
--name=ubuntu-vm \
--ram=4096 \
--vcpus=2 \
--disk path=/var/lib/libvirt/images/ubuntu-vm.qcow2,size=20 \
--os-type=linux \
--os-variant=ubuntu22.04 \
--network bridge=virbr0 \
--graphics vnc,listen=0.0.0.0 \ #用于开启VNC并允许远程连接
--cdrom /path/to/ubuntu-22.04-live-server-amd64.iso
(2)图形化
virt-manager
然后就是创建新虚拟机,选择本地iso镜像,分配CPU/内存资源(内存≥2GB,CPU≥1核心),设置虚拟磁盘(默认路径:/var/lib/libvirt/images/),配置网络为 Bridge模式(据说性能最优)或 NAT
2.虚拟机管理
启动:virsh start ubuntu-vm
关闭:virsh shutdown ubuntu-vm
查看虚拟机列表:virsh list --all
删除:
强制关闭virsh destroy ubuntu-vm
删除定义virsh undefine ubuntu-vm
删除磁盘文件rm /var/lib/libvirt/images/ubuntu-vm.qcow2
其他:
网络配置、优化及排障参考这两个
从零搭建KVM虚拟服务器:完整指南与实战技巧
KVM虚拟化
四、KVM存储
存储池默认位置:/var/lib/libvirt/images/
1.自定义存储池
可以自定义一个基于目录的存储池
创建个目录 mkdir -p /data/vmfs
定义个存储池名字为vmdisk,目录类型 virsh pool-define-as vmdisk --type dir --target /data/vmfs
创建已定义的存储池 virsh pool-build vmdisk
查看下 virsh pool-list --all
刚创建的可能是未启动,需要开一下
virsh pool-start vmdisk
virsh pool-autostart vmdisk
创建虚拟机存储卷
virsh vol-create-as vmdisk(指定池) test(自定义名字).qcow2 20G(指定空间) --format qcow2
2.存储池相关管理命令
(1)在存储池中删除虚拟机存储卷
virsh vol-delete --pool vmdisk test(之前定义的名字).qcow2
(2)取消激活存储池
virsh pool-destroy vmdisk
(3)删除存储池定义的目录/data/vmfs
virsh pool-delete vmdisk
(4)取消定义存储池
virsh pool-undefined vmdisk
3.磁盘格式
raw 原始格式,性能最好
qcow2 性能不如raw,但raw不支持快照,qcow2支持
现在默认安装好用的raw,做快照要改成qcow2
写时拷贝:raw立刻分配空间,不管是否有用到这么多。qcow2是承诺分配空间,需要用的时候再分配
4.创建磁盘文件
建立qcow2格式磁盘文件
qemu-img create -f qcow2 test.qcow2 20G
建立raw格式磁盘文件:
qemu-img create -f raw test.raw 20G
查看已经创建的虚拟磁盘文件
qemu-img info test.qcow2
5.挂载
碰到过虚拟机无法启动的情况,要对内部排查,网上搜了下一般是用Libguestfs Linux工具集
Libguestfs允许在虚拟机上挂载任何类型的文件系统,以便修复启动故障
使用Libguestfs,首先要用Libvirt(管理接口)
*如果是vmware的ESXI虚拟机,为将虚拟机迁移到Linux中,可以使用SSH连接到ESXI主机。这样首先要启用ESXI主机的ssh访问方式,完成后在Linux平台上scp一下
查看磁盘镜像分区
virt-df -h -d vm1(虚拟机名字)
vir-filesystems -d vm1
挂载磁盘镜像分区
gustmount -d vm1 -m /dev/ubuntu/root --rw /mnt
df -Th查看
查看挂出来的passwd文件cat /mnt/etc/passwd
拷贝到宿主机opt cp passwd /opt
取消挂载 guestunmount /mnt
这时候进mnt就是空目录了
六、KVM管理
1.基本管理
查看虚拟机 virsh list仅列出运行ing的,加--all看所有的
查看虚拟机配置文件 virsh dumpxml name
将node4虚拟机的配置文件保存至node6.xml(x) virsh dumpxml node4 > /etc/libvirt/qemu/node6.xml
修改node6配置文件(x) virsh edit node6
edit是直接修改,不用重启。如果用vim修改,要virsh start node6
暂停虚拟机 virsh suspend vm_name
恢复虚拟机 virsh resume vm_name
关闭 第一种 virsh shutdown vm1一般用这种
第二种 virsh destroy vm1
重启 virsh reboot vm1
重置 virsh reset vm1
删除虚拟机 virsh undefine vm1
虚拟机开机自启动 virsh autostart
域vm1标记为自动开始 ls /etc/libvirt/qemu/autostart目录默认不存在,有开机启动的虚拟机时自动创建
域取消vm1标记为自动开始 virsh autostart --sidable vm1
查看所有开机自启动的guest os ls /etc/libvirt/qemu/autostart/
virsh list --all --autostart
2.虚拟机克隆
(1)图形界面
Application-System Tools-Virtual Machine Manager
或者输入命令virtual-manager
确保机器关机状态,右键克隆
(2)终端命令克隆
virt-clone -o vm1(机器名) --auto-clone这样克隆出来名字是vm1-clone
加-n会指定名字,-f为新客户机使用新的磁盘镜像文件,如下
virt-clone -o vm1(机器名) -n vm2(自定义机器名) -f /var/lib/libvirt/images/vm2.img
3.增量镜像
……这个就不写了,没搞过
4.快照
创建快照
(1)图形界面方式
(2)命令行方式
创建 virsh snapshot-create-as vm2 vm2.snap
恢复 比如恢复到第四个快照,先关闭再操作这条 virsh snapshot-revert vm2(虚拟机名字) vm2.snap4(快照名)
这个快照得是qcow2,raw不行
qcow2可以写时复制,还支持zlib磁盘压缩、支持AES加密
raw格式转qcow2qemu-img convert -O qcow2 /var/lib/libvirt/images/vm2-1.raw /var/lib/libvirt/images/vm2-1.qcow2
可以看下格式
ll -h找到vm2-1.qcow2
查看qemu-img info vm2-1.qcow2看到file fomat是qcow2就行
虚拟机硬盘也要指向转换后的,这里要关掉机器,再配置
vim /etc/libvirt/qemu/vm2.xml
以下框住和划横线的地方改成qcow2

可以进入图形化查看信息,可以找到快照
七、网络管理
网络:nat、isolated
接口:bridge
虚拟交换机:linux-bridge(Linux自带)、ovs(open-Vswitch)
用ip a命令查看虚拟接口之类的
用brctl show查看有多少虚拟机
1.配置文件方式配置桥接
点击查看代码
在宿主机上
1.修改配置文件
cat ifcfg-bro
TYPE=BridgeNAME=br0
DEVICE=br0
ONBOOT="yes"
BOOTPROTO=static
IPADDR=宿主机IP地址
GATEWAY=宿主机网关(route查网关)
NETMASK=255.255.255.0
DNS1=114.114.114.114
DNS2=8.8.8.8
备份
cp ifcfg-enp3s0 ifcfg-enp3s0.bak
打开文件
vim ifcfg-enp3s0
编辑以下内容
DEVICE="enp3s0"
ONBOOT="yes"
BRIDGE=br0
重启libvirtd服务
重启network服务
2.配置文件方式创建nat网络
点击查看代码
cp /etc/libvirt/qemu/networks/default.xml
/etc/libvirt/qemu/networks/nat1.xml
vim /etc/libvirt/qemu/networks/nat1.xml
<network>
<name>nat1(不能有冲突,随便改一个)</name>
<uuid>4d8b9b5c-748f-4e16-a509-848202b9c83b(不能有冲突,随便改一个)</uuid>
<forward mode='nat'/>
#和隔离模式的区别
<bridge name='virbr4(不能有冲突,随便改一个)' stp='on' delay='0'/>
<mac address='52:57:00:62:0c:d4'(不能有冲突,修改后三段)/>
<domain name='natl'/>
<dhcp></dhcp></ip></network>
<ip address='192.168.104.1(可以自定义)' netmask='255.255.255.0'>
<range start='192.168.104.128' end='192.168.104.254'/>
重启服务:
systemctl
restart libvirtd
3、配置isolated隔离网络模式
点击查看代码
cp default.xml isolated200.xml
vim isolated200.xml
<network>
<name>isolated200(要修改)</name>
<uuid>6341d3a6-7330-4e45-a8fe-164a6a68929a(要修改)</uuid>
<bridge name='virbr2'(要修改) stp='on' delay='0'/>
<mac address='52:54:00:6b:39:0c'(要修改)/>
<domain name='isolatel'/>
<ip address='192.168.101.1'(自定义) netmask='255.255.255.0'>
<dhcp>
<range start='192.168.101.128' end='192.168.101.254'/>
</dhcp>
</ip>
</network>
systemctl restart libvirtd
查看所有的网络:
virsh net-list
启动网络:
virsh net-start isolated200
开机自启动:
virsh net-autostart
isolated200
网络相关基本命令
查看一个guest主机的网络接口信息:
virsh domiflist vm2
4.Virbro的DHCP
Virbr0是KVM默认创建的一个Bridge,其作用是为连接其上的虚机网卡提供NAT访问外网的功能。
Virbr0默认分配了一个P192.168.122.1,并为连接其上的其他虚拟网卡提供DHCP服务。
点击查看代码
Virbr0使用 dnsmasq提供 DHCP服务,可以在宿主机中查看该进程信息
ps -elf | grep dnsmasq
会显示/usr/sbin/dnsmasq --conf-file=/var/lib/libvirt/dnsmasq/default.conf
在/var/lib/libvirt/dnsmasq/目录下有一个virbr0.status 文件,当 VM1 成功获得
DHCP的IP后,可以在该文件中查看到相应的信息
cat virbr0.status
[
{
"ip-address":"192.168.122.28",
"mac-address": "52:54:00:94:a7:a1",
"hostname":"vm1",
"expiry-time": 1511626337
}
]
八、脚本管理
批量创建虚拟机
1.准备:模板镜像和配置文件模板
# 下载官方云镜像(以 Rocky Linux 9 为例) wget https://download.rockylinux.org/pub/rocky/9/images/x86_64/Rocky-9-GenericCloud.latest.x86_64.qcow2 -O /var/lib/libvirt/images/rocky9-template.qcow2
给模板做一个快照(后续基于此快照创建,不破坏原文件) qemu-img create -f qcow2 -b /var/lib/libvirt/images/rocky9-template.qcow2 /var/lib/libvirt/images/rocky9-base.qcow2
自己创建下目录
~/kvm-ansible/
├── ansible.cfg # Ansible 配置文件
├── inventory.ini # 主机清单
├── create-vms.yml # 主 Playbook
├── files/
│ └── cloud-init/
│ ├── user-data.template # cloud-init 模板(配置用户和密码)
│ └── network-config # 网络配置模板
└── vars/
└── main.yml # 变量定义(虚拟机参数)
2.ansible配置文件
ansible.cfg
点击查看代码
[defaults]
host_key_checking = False
inventory = inventory.ini
remote_user = root
timeout = 30
log_path = /var/log/ansible-kvm.log
inventory.ini
点击查看代码
[kvm_hosts]
kvm-host-1 ansible_host=192.168.1.10
kvm-host-2 ansible_host=192.168.1.11
vars/main.yml
点击查看代码
# 虚拟机通用配置
vm_defaults:
memory: 4096 # 内存 MB
vcpus: 2 # vCPU 核心数
disk_size: 40G # 磁盘大小
network: default # libvirt 网络名称
os_variant: rocky9 # 系统类型 (用 osinfo-query os 查看)
# 要创建的虚拟机列表
vms:
- name: web-01
memory: 4096
vcpus: 2
disk_size: 50G
ip: 192.168.122.101
hostname: web-01.example.com
- name: web-02
memory: 4096
vcpus: 2
disk_size: 50G
ip: 192.168.122.102
hostname: web-02.example.com
- name: db-01
memory: 8192
vcpus: 4
disk_size: 100G
ip: 192.168.122.201
hostname: db-01.example.com
- name: cache-01
memory: 2048
vcpus: 1
disk_size: 20G
ip: 192.168.122.251
hostname: cache-01.example.com
files/cloud-init/user-data.template
点击查看代码
#cloud-config
hostname: {{ hostname }}
manage_etc_hosts: true
users:
- name: admin
sudo: ALL=(ALL) NOPASSWD:ALL
ssh_authorized_keys:
- {{ ssh_pub_key | default('') }}
shell: /bin/bash
password: {{ password | default('Welcome123!') }}
chpasswd:
expire: false
package_update: true
package_upgrade: false
runcmd:
- systemctl enable --now sshd
files/cloud-init/network-config
点击查看代码
version: 2
ethernets:
eth0:
dhcp4: false
addresses:
- {{ ip }}/24
gateway4: {{ gateway | default('192.168.122.1') }}
nameservers:
addresses:
- {{ dns | default('223.5.5.5') }}
- {{ dns2 | default('223.6.6.6') }}
3.编写主 Playbook
create-vms.yml
点击查看代码
- name: 批量创建 KVM 虚拟机
hosts: kvm_hosts
gather_facts: yes
vars_files:
- vars/main.yml
tasks:
- name: 1. 确保基础镜像存在
stat:
path: /var/lib/libvirt/images/rocky9-base.qcow2
register: base_image
- name: 1.1 如果基础镜像不存在则报错
fail:
msg: "基础镜像 /var/lib/libvirt/images/rocky9-base.qcow2 不存在,请先准备"
when: not base_image.stat.exists
- name: 2. 确保 cloud-init 目录存在
file:
path: /var/lib/libvirt/cloud-init/{{ item.name }}
state: directory
recurse: yes
loop: "{{ vms }}"
- name: 3. 生成 cloud-init 配置文件(user-data)
template:
src: files/cloud-init/user-data.template
dest: /var/lib/libvirt/cloud-init/{{ item.name }}/user-data
loop: "{{ vms }}"
- name: 4. 生成 cloud-init 配置文件(network-config)
template:
src: files/cloud-init/network-config
dest: /var/lib/libvirt/cloud-init/{{ item.name }}/network-config
loop: "{{ vms }}"
- name: 5. 创建虚拟机磁盘(基于基础镜像)
command:
cmd: qemu-img create -f qcow2 -b /var/lib/libvirt/images/rocky9-base.qcow2 /var/lib/libvirt/images/{{ item.name }}.qcow2 {{ item.disk_size | default(vm_defaults.disk_size) }}
creates: /var/lib/libvirt/images/{{ item.name }}.qcow2
loop: "{{ vms }}"
- name: 6. 创建虚拟机(使用 virt-install)
command:
cmd: >
virt-install
--name {{ item.name }}
--memory {{ item.memory | default(vm_defaults.memory) }}
--vcpus {{ item.vcpus | default(vm_defaults.vcpus) }}
--disk path=/var/lib/libvirt/images/{{ item.name }}.qcow2,format=qcow2
--disk path=/var/lib/libvirt/cloud-init/{{ item.name }}/user-data,device=cdrom,format=raw
--disk path=/var/lib/libvirt/cloud-init/{{ item.name }}/network-config,device=cdrom,format=raw
--network network={{ item.network | default(vm_defaults.network) }}
--os-variant {{ item.os_variant | default(vm_defaults.os_variant) }}
--import
--noautoconsole
--wait=-1
args:
creates: /etc/libvirt/qemu/{{ item.name }}.xml
loop: "{{ vms }}"
register: vm_create
- name: 7. 等待虚拟机获得 IP 地址
shell: |
virsh domifaddr {{ item.name }} --source lease | grep -Eo '([0-9]{1,3}\.){3}[0-9]{1,3}' | head -1
register: vm_ip
until: vm_ip.stdout != ""
retries: 30
delay: 10
loop: "{{ vms }}"
- name: 8. 输出创建结果
debug:
msg: |
虚拟机: {{ item.item.name }}
IP地址: {{ item.stdout }}
SSH登录: ssh admin@{{ item.stdout }}
loop: "{{ vm_ip.results }}"
4.执行部署
点击查看代码
cd ~/kvm-ansible
# 1. 先测试 SSH 连通性
ansible kvm_hosts -i inventory.ini -m ping
# 2. 执行 Playbook(创建虚拟机)
ansible-playbook create-vms.yml
容易碰到的问题
virt-install 命令不存在:yum install -y virt-install
基础镜像不存在:提前下载并放置到 /var/lib/libvirt/images/
cloud-init 未生效:确保 user-data 和 network-config 正确挂载为 cdrom
虚拟机无法联网:检查 libvirt 默认网络:virsh net-start default
SSH 无法登录:检查 cloud-init 是否成功设置密码/密钥
虚拟机名字已存在:先 virsh undefine 删除旧虚拟机
磁盘空间不足检查 /var/lib/libvirt/images 可用空间

浙公网安备 33010602011771号