Ubuntu 22.04 安装 KVM 虚拟机
一、KVM 虚拟机安装部署
1. 基础环境验证
# 如果输出的数字大于 0,则表示CPU 支持虚拟化
root@ubuntu:~# egrep -c '(vmx|svm)' /proc/cpuinfo
8
root@ubuntu:~# hostnamectl set-hostname kvm-host
root@ubuntu:~# exec bash
root@kvm-host:~# 2. 安装 kvm 软件包
# 更新安装源
root@kvm-host:~# sudo apt update
# 安装KVM虚拟机及管理工具
root@kvm-host:~# sudo apt install qemu-kvm libvirt-daemon-system libvirt-clients bridge-utils libguestfs-tools virt-viewer virt-manager virtinst
# 安装python API
root@kvm-host:~# sudo apt install python3-libvirt说明:
qemu-kvm:即 qemu+kvm,kvm 负责 cpu 和内存的虚拟化,而 qemu 负责 IO 设备,如网卡和磁盘等的虚拟化。
libvirt-daemon-system:KVM 管理工具,为不同的虚拟机监视器提供了统一的接口。
libvirt-clients: 包含了一组用于与 libvirt 库交互的命令行工具,包括 virsh、virt-install,virt-clone
virsh: 用于虚拟机的创建,启动,停止,迁移,克隆,配置文件管理等操作。
virt-install:用于 GuestOS 安装
virt-clone:用于虚拟机克隆
bridge-utils:配置网桥
libguestfs-tools:虚拟机镜像管理工具,包括 virt-cat、virt-edit、virt-ls、virt-rescue
virt-viewer:用于虚拟机控制台
virt-manager:图形界面管理KVM虚拟化
virtinst: 命令行工具,包括 virt-install、virt-clone、virt-manager 等。
python3-libvirt:libvirt 库的 Python 绑定,在Python 中使用 libvirt 的功能,包括对虚拟机、存储池、网络等资源的管理,以及对
拟化宿主机的监控和控制。
# 查看服务是否启动
root@kvm-host:~# systemctl is-active libvirtd
inactive
# 启动并开机自启
root@kvm-host:~# systemctl enable libvirtd --now
root@kvm-host:~# systemctl status libvirtd
● libvirtd.service - Virtualization daemon
Loaded: loaded (/lib/systemd/system/libvirtd.service; enabled; vendor preset: enabled)
Active: active (running) since Wed 2025-08-20 06:32:08 UTC; 1s ago
TriggeredBy: ● libvirtd-admin.socket
● libvirtd.socket
● libvirtd-ro.socket
Docs: man:libvirtd(8)
https://libvirt.org
Main PID: 36659 (libvirtd)
Tasks: 21 (limit: 32768)
Memory: 10.0M
CPU: 394ms
CGroup: /system.slice/libvirtd.service
├─36659 /usr/sbin/libvirtd
├─36838 /usr/sbin/dnsmasq --conf-file=/var/lib/libvirt/dnsmasq/default.conf --leasefile-ro --dhcp-script=/usr/lib/libvirt/libvirt_leaseshelper
└─36839 /usr/sbin/dnsmasq --conf-file=/var/lib/libvirt/dnsmasq/default.conf --leasefile-ro --dhcp-script=/usr/lib/libvirt/libvirt_leaseshelper
Aug 20 06:32:08 kvm-host systemd[1]: Started Virtualization daemon.
Aug 20 06:32:08 kvm-host dnsmasq[36838]: started, version 2.90 cachesize 150
Aug 20 06:32:08 kvm-host dnsmasq[36838]: compile time options: IPv6 GNU-getopt DBus no-UBus i18n IDN2 DHCP DHCPv6 no-Lua TFTP conntrack ipset no-nftset auth cryptohash DNSSEC loop-detect inotify dumpfile
Aug 20 06:32:08 kvm-host dnsmasq-dhcp[36838]: DHCP, IP range 192.168.122.2 -- 192.168.122.254, lease time 1h
Aug 20 06:32:08 kvm-host dnsmasq-dhcp[36838]: DHCP, sockets bound exclusively to interface virbr0
Aug 20 06:32:08 kvm-host dnsmasq[36838]: reading /etc/resolv.conf
Aug 20 06:32:08 kvm-host dnsmasq[36838]: using nameserver 127.0.0.53#53
Aug 20 06:32:08 kvm-host dnsmasq[36838]: read /etc/hosts - 8 names
Aug 20 06:32:08 kvm-host dnsmasq[36838]: read /var/lib/libvirt/dnsmasq/default.addnhosts - 0 names
Aug 20 06:32:08 kvm-host dnsmasq-dhcp[36838]: read /var/lib/libvirt/dnsmasq/default.hostsfile3. 用户和组管理
用户添加到 KVM 和 Libvirt 组
想要创建和管理虚拟机,你需要添加你的用户到 libvirt和 kvm用户组。
root@kvm-host:~# sudo usermod -aG kvm $USER
root@kvm-host:~# sudo usermod -aG libvirt $USER4. 网络设置
1. 默认 NAT 网络
在libvirt 安装过程中,一个被称为 virbr0 的桥接设备默认被创建。这个设备使用 NAT 来连接客户机到外面的世界。
root@kvm-host:~# ifconfig
ens160: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 192.168.198.70 netmask 255.255.255.0 broadcast 192.168.198.255
inet6 fe80::250:56ff:fe89:ffa1 prefixlen 64 scopeid 0x20<link>
ether 00:50:56:89:ff:a1 txqueuelen 1000 (Ethernet)
RX packets 364005 bytes 388849387 (388.8 MB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 180983 bytes 16904439 (16.9 MB)
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 268 bytes 25922 (25.9 KB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 268 bytes 25922 (25.9 KB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
virbr0: flags=4099<UP,BROADCAST,MULTICAST> mtu 1500
inet 192.168.122.1 netmask 255.255.255.0 broadcast 192.168.122.255
ether 52:54:00:d3:94:16 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
默认不会修改本机的网卡配置,并且 192.168.122.0/24 地址段是由一个 default 配置文件提供

查看当前的网桥和它们连接的接口
root@kvm-host:~# brctl show
bridge name bridge id STP enabled interfaces
virbr0 8000.525400d39416 yes
root@kvm-host:~# virsh net-list --all
Name State Autostart Persistent
--------------------------------------------
default active yes yes默认网络设置适合大部分 Ubuntu 用户,但是有限制,由于虚拟机地址段为私有IP地址,你只能从虚拟机所在宿主机访问虚拟机地址,无法从外部网络访问虚拟机地址。

如果需要从外部连接虚拟机,需要创建一个新的网桥,将该网桥桥接到物理网卡,以便虚拟机配置物理网段的IP地址,进而实现通过外部网络直连虚拟机。
2. 网桥共享物理网卡
桥接网络与 KVM 客户虚拟机共享一个真实的以太网设备。使用桥接模式时,所有客户虚拟机都与主机物理机位于同一子网内。同一物理网络上的所有其他物理机都感知到这些虚拟机,并可以访问它们。桥接在 OSI 网络模型的第 2 层上运行。
每个客户虚拟机都可以像物理服务器一样直接绑定到 LAN 上任何可用的 IPv4 或 IPv6 地址。在所有 libvirt 网络类型中,桥接提供最佳性能且复杂性最低。只有当有足够的 IP 地址分配给每个客户虚拟机时,桥接才可用。这对于 IPv6 来说不是问题,因为托管服务提供商通常会提供许多免费的 IPv6 地址。但是,额外的 IPv4 地址很少有空闲的。

5. 创建NAT网络模式虚拟机
1.1 下载 cloud image 镜像
下面以默认NAT网络模式为例,介绍使用 ubuntu cloud image 快速启动虚拟机,以 jammy(Ubuntu Server 22.04 LTS)为例。
创建镜像模版目录
root@kvm-host:~# mkdir -pv /var/lib/libvirt/images/templates
mkdir: created directory '/var/lib/libvirt/images/templates'
root@kvm-host:~# cd /var/lib/libvirt/images/templates
root@kvm-host:/var/lib/libvirt/images/templates# wget https://mirrors.tuna.tsinghua.edu.cn/ubuntu-cloud-images/jammy/current/jammy-server-cloudimg-amd64.img
1.2 定制镜像参数
export image=/var/lib/libvirt/images/templates/jammy-server-cloudimg-amd64.img
virt-customize -a $image --run-command 'adduser ubuntu'
virt-customize -a $image --run-command 'echo "ubuntu:123456" | chpasswd'
virt-customize -a $image --run-command 'adduser ubuntu sudo'
virt-customize -a $image --run-command 'apt update -y'
virt-customize -a $image --run-command 'apt install -y qemu-guest-agent'创建
ubuntu用户,密码为123456,并赋予sudo权限更新系统软件索引(可选)
安装必要的软件包(可选)

1.3 创建虚拟机存储路径并复制镜像模板
root@kvm-host:/var/lib/libvirt/images/templates# mkdir -pv /var/lib/libvirt/images/ubuntu01
mkdir: created directory '/var/lib/libvirt/images/ubuntu01'
root@kvm-host:/var/lib/libvirt/images/templates# cp /var/lib/libvirt/images/templates/jammy-server-cloudimg-amd64.img /var/lib/libvirt/images/ubuntu01/1.4 使用virt-install命令创建虚拟机
root@kvm-host:/var/lib/libvirt/images/ubuntu01# virt-install \
--name ubuntu01 \
--vcpus 1 \
--memory 2048 \
--disk path=/var/lib/libvirt/images/ubuntu01/jammy-server-cloudimg-amd64.img \
--os-variant ubuntu22.04 \
--import \
--autostart \
--noautoconsole
参数说明:
--name:可选,指定虚拟机名称
--vcps:可选,指定虚拟机cpu大小
--memory:可选,指定虚拟机内存大小
--disk path:必选,指定虚拟机镜像位置
--os-variant:必选,指定虚拟机操作系统类型
--import :必选,指定虚拟机安装方式,安装方式不同该参数不同
--autostart:可选,默认虚拟机不会随主机重启后一起启动,可通过添加该参数配置
--noautoconsole:可选,不指定该参数virt-install命令将始终处于挂起状态,需要另开窗口登录虚拟机
说明:使用osinfo-query命令可以列出 --os-variant 选项支持的所有参数。
root@kvm-host:/var/lib/libvirt/images/ubuntu01# apt install -y libosinfo-bin
root@kvm-host:/var/lib/libvirt/images/ubuntu01# osinfo-query os
创建虚拟机后,查看网口及网桥变化,主机新增vnet0网卡,网桥新增vnet0接口,说明虚拟机连接到了网桥上。

1.5 查看虚拟机
# 查看启动状态
root@kvm-host:/var/lib/libvirt/images/ubuntu01# virsh list --all
Id Name State
--------------------------
1 ubuntu01 running
# 查看虚拟机网络信息
root@kvm-host:/var/lib/libvirt/images/ubuntu01# virsh domifaddr ubuntu01 --source agent
Name MAC address Protocol Address
-------------------------------------------------------------------------------
lo 00:00:00:00:00:00 ipv4 127.0.0.1/8
- - ipv6 ::1/128
enp1s0 52:54:00:40:dc:42 N/A N/A1.6 进入虚拟机
使用 virsh console 命令连接到虚拟机
root@kvm-host:/var/lib/libvirt/images/ubuntu01# virsh console ubuntu01
Connected to domain 'ubuntu01'
Escape character is ^] (Ctrl + ])
ubuntu login: ubuntu
Password: 123456
可以看到网卡未获取任何IP地址,通过主机上的网桥接口virbr0可以确认网桥地址段默认为192.168.122.0/24,网关地址为192.168.122.1/24,该地址段和网关就是虚拟机可用的地址段和网关。

启用网卡配置,确认虚拟机网卡名称为enp1s0,虚拟机中创建网卡配置文件
cat >/etc/netplan/00-installer-config.yaml<<EOF
network:
version: 2
ethernets:
enp1s0:
dhcp4: false
addresses:
- 192.168.122.10/24
nameservers:
addresses:
- 223.5.5.5
- 223.6.6.6
routes:
- to: default
via: 192.168.122.1
EOFroot@ubuntu:~# chmod 600 /etc/netplan/00-installer-config.yaml
root@ubuntu:~# netplan apply
WARNING:root:Cannot call Open vSwitch: ovsdb-server.service is not running.测试可以 ping 通外网

1.7 退出虚拟机
退出虚拟机执行exit命令,然后按键盘快捷键ctrl + ]。
在kvm主机上查看虚拟机网卡IP地址(依赖虚拟机中的 qemu-guest-agent)

1.8 管理虚拟机基本操作
配置随宿主机自动启动,或在创建虚拟机时指定--autostart参数
root@kvm-host:~# virsh autostart ubuntu01如果需要删除虚拟机,需要先将虚拟机关机
root@kvm-host:~# virsh shutdown ubuntu01确认虚拟机已关机
root@kvm-host:~# virsh list --all
Id Name State
---------------------------
- ubuntu01 shut off然后执行以下命令删除虚拟机
root@kvm-host:~# virsh undefine ubuntu01如果需要彻底删除虚拟机,则进一步删除虚拟机磁盘文件
root@kvm-host:~# rm -rf /var/lib/libvirt/images/ubuntu01/6. 创建 Bridged 网络模式虚拟机
桥接网络与其他虚拟机共享主机的真实网络接口,以连接到外部网络。因此,每个 VM 都可以直接绑定到任何可用的 IPv4 或 IPv6 地址,就像一台物理计算机一样。
默认情况下,KVM 设置了一个专用虚拟网桥,以便所有 VM 都可以在主机内相互通信。它提供自己的子网和 DHCP 来配置虚拟机的网络,并使用 NAT 访问主机网络。
查看 KVM 默认虚拟接口的 IP 地址:

可以看到,KVM默认网络virbr0使用192.168.122.1/24 IP地址。所有虚拟机都将使用192.168.122.0/24 IP 范围内的 IP 地址,主机操作系统可通过192.168.122.1访问。应该能够从虚拟机操作系统内部通过 ssh 进入主机操作系统(位于 192.168.122.1)并使用 scp 来回复制文件。
如果您只从主机本身访问内部的 VM 就可以了。但是,无法从网络中的其他远程系统访问虚拟机。
为了从其他远程主机访问虚拟机,必须设置一个在主机网络上运行的公共网桥,并使用主机网络上的任何外部 DHCP 服务器。通俗地说,我们将使所有虚拟机使用主机系统使用的相同 IP 系列。
如果你打算从本机(Ubuntu 22.04)之外访问 KVM 虚拟机,你必须将虚拟机的网卡映射至网桥。virbr0 网桥是 KVM 安装完成后自动创建的,仅做测试用途。
1.1 禁用 KVM 默认 NAT 网络
# 查看正处于激活状态
root@kvm-host:~# virsh net-list --all
Name State Autostart Persistent
--------------------------------------------
default active yes yes
# 停止
root@kvm-host:~# virsh net-destroy default
Network default destroyed
# 查看已停止
root@kvm-host:~# virsh net-list --all
Name State Autostart Persistent
----------------------------------------------
default inactive yes yes
# 删除
root@kvm-host:~# virsh net-undefine default
Network default has been undefined
# 再次查看
root@kvm-host:~# virsh net-list --all
Name State Autostart Persistent
----------------------------------------1.2 设置 KVM 公共网桥
现在,让我们设置 KVM 公共网桥以在创建新 VM 时使用。查找网络接口 ens160 的MAC地址
root@kvm-host:~# ifconfig ens160
ens160: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 192.168.198.70 netmask 255.255.255.0 broadcast 192.168.198.255
inet6 fe80::250:56ff:fe89:ffa1 prefixlen 64 scopeid 0x20<link>
ether 00:50:56:89:ff:a1 txqueuelen 1000 (Ethernet)
RX packets 1170396 bytes 1164729436 (1.1 GB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 573186 bytes 59367339 (59.3 MB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0MAC 地址为:00:50:56:89:ff:a1
为 VM(虚拟机)创建桥接网络。首先查看主机网卡默认配置
root@kvm-host:~# cat /etc/netplan/00-installer-config.yaml
# This is the network config written by 'subiquity'
network:
ethernets:
ens160:
addresses:
- 192.168.198.70/24
nameservers:
addresses:
- 223.5.5.5
search: []
routes:
- to: default
via: 192.168.198.1
version: 2修改如下:
root@kvm-host:~# cat /etc/netplan/00-installer-config.yaml
# This is the network config written by 'subiquity'
network:
ethernets:
ens160:
dhcp4: false
dhcp6: false
bridges:
br0:
interfaces: [ ens160 ]
dhcp4: false
dhcp6: false
addresses: [192.168.198.70/24]
macaddress: 00:50:56:89:ff:a1
routes:
- to: default
via: 192.168.198.1
nameservers:
addresses: ["223.5.5.5","223.6.6.6"]
parameters:
stp: false
forward-delay: 4
version: 2请注意:需要将 br0 的 macaddress 设置为在上面找到的 ens163的 MAC 地址。
测试网卡配置是否正确
root@kvm-host:~# netplan generate
root@kvm-host:~# echo $?
0更新网卡配置
root@kvm-host:~# netplan apply
WARNING:root:Cannot call Open vSwitch: ovsdb-server.service is not running.查看网卡 IP 信息

1.3 添加网桥到 KVM 中
当前 kvm 网络设置为空
root@kvm-host:~# virsh net-list
Name State Autostart Persistent
---------------------------------------使用以下内容创建文件 br0.xml
root@kvm-host:~# cat >/etc/kvm/host-bridge.xml<<EOF
<network>
<name>host-bridge</name>
<forward mode="bridge"/>
<bridge name="br0"/>
</network>
EOFname– 虚拟网络的简称。它可以是任何字母数字字符串forward– 表示虚拟网络必须连接到物理网络。 mode=“bridge” 在我们的例子中意味着正在连接到在 libvirt 之外创建的网桥。bridge– 确定要连接的网桥的名称。
查看新增的网络
root@kvm-host:~# virsh net-list
Name State Autostart Persistent
------------------------------------------------
host-bridge active yes yes
现在,安装 KVM 后,您可以继续在 KVM 上创建 Ubuntu 22.04 虚拟机。
1.4 创建虚拟机
新建虚拟机ubuntu02,创建存储路径并复制镜像模板
root@kvm-host:~# mkdir -pv /var/lib/libvirt/images/ubuntu02
mkdir: created directory '/var/lib/libvirt/images/ubuntu02'
root@kvm-host:~# cp /var/lib/libvirt/images/templates/jammy-server-cloudimg-amd64.img /var/lib/libvirt/images/ubuntu02/运行同样命令创建虚拟机
root@kvm-host:~# virt-install \
--name ubuntu02 \
--vcpus 1 \
--memory 2048 \
--disk path=/var/lib/libvirt/images/ubuntu02/jammy-server-cloudimg-amd64.img \
--os-variant ubuntu22.04 \
--import \
--autostart \
--noautoconsole查看启动情况
root@kvm-host:~# virsh list --all
Id Name State
---------------------------
2 ubuntu02 running
- ubuntu01 shut off
root@kvm-host:~# virsh domifaddr ubuntu02 --source agent
Name MAC address Protocol Address
-------------------------------------------------------------------------------
lo 00:00:00:00:00:00 ipv4 127.0.0.1/8
- - ipv6 ::1/128
enp1s0 52:54:00:77:b8:ac N/A N/A
1.5 进入虚拟机

确认虚拟机网卡名称为enp1s0,虚拟机中创建网卡配置文件,注意这次配置的虚拟机IP与主机同一个网段。
cat >/etc/netplan/00-installer-config.yaml<<EOF
network:
version: 2
ethernets:
enp1s0:
dhcp4: false
addresses:
- 192.168.198.71/24
nameservers:
addresses:
- 223.5.5.5
- 223.6.6.6
routes:
- to: default
via: 192.168.198.1
EOF测试发现无法 ping 通路由器网关

宿主机开启 bridge 和 ipv4 转发
root@kvm-host:~# vim /etc/sysctl.conf
net.ipv4.ip_forward = 1
net.bridge.bridge-nf-call-ip6tables = 0
net.bridge.bridge-nf-call-iptables = 0
net.bridge.bridge-nf-call-arptables = 0
root@kvm-host:~# modprobe br_netfilter
root@kvm-host:~# ls /proc/sys/net/bridge
bridge-nf-call-arptables bridge-nf-call-ip6tables bridge-nf-call-iptables bridge-nf-filter-pppoe-tagged bridge-nf-filter-vlan-tagged bridge-nf-pass-vlan-input-dev
root@kvm-host:~# sysctl -p
net.ipv4.ip_forward = 1
net.bridge.bridge-nf-call-ip6tables = 0
net.bridge.bridge-nf-call-iptables = 0
net.bridge.bridge-nf-call-arptables = 0再次进入虚拟机测试没问题
但是!如果还是不通的话,假如此刻你的这个 KVM 宿主机也是运行在 ESXI 中的虚拟机,那么!
VMware vSwitch 默认的安全策略会拦截桥接出来的虚拟机流量
1.6 调整 ESXI vSwitch 安全策略
宿主机本身 是运行在 ESXi 上的虚拟机,再在里面跑 KVM(嵌套虚拟化)。这种情况下,VMware vSwitch 默认的安全策略会拦截桥接出来的虚拟机流量,表现就是:
VM ↔ 宿主机 通(因为都在 br0 内部交换)。
VM → 网关 不通(因为报文要通过 ESXi vSwitch 发出去,vSwitch 默认会丢掉“不是宿主机自身 MAC”的流量)。
原因
ESXi vSwitch 出于安全考虑,默认配置是:
Promiscuous Mode: Reject
MAC Address Changes: Reject
Forged Transmits: Reject
而 KVM 虚拟机在发包时用的是它自己的 MAC,不是宿主机的 MAC,所以 vSwitch 直接把这些包丢了 → 你就看到 VM 能 ping 宿主机,但 ping 不通网关。
解决办法就是把策略给允许通过,如下截图




此时解决了虚拟机无法 ping 通网关了。
7. 常用 virsh 管理命令
8. virt-manager 管理界面
windows 的话可以直接使用 xshell 连接 ssh,然后执行 virt-manager 打开可视化页面
而,Mac OS 的话可以下载安装 XQuartz 地址 https://www.xquartz.org/

