Featured image of post KVM安装记录

KVM安装记录

前言

最近想搭一个linux虚拟机来玩ai工具,主要是codex cli和gemini cli这些东西。结果整个安装过程磕磕绊绊,最后总算在ai的帮助初步成功了。期间踩了不少坑。写个流水账记录一下吧。

虚拟机安装

本人的宿主机是debian12。由于之前在windows下安装过VMWare workstation。想着这玩意比较有名,而且现在还免费了,所以准备也采用VMWare workstation。下载后安装,结果直接给我来个需要编译内核文件。网上找了一通,发现有人在linux安装也会遇见,主要还是debian的更新策略太保守(这是一个很频繁的坑)。但是研究了下发现解决起来太麻烦,遂放弃。改为让AI给我推荐一下在debian12下安装哪种虚拟机最合适。结果AI大力推荐KVM + virt-manager,这个作为Linux原生方案,最稳定、性能最好(顺便把VMWare给贬低了一通)。所以我最终选择的方案是:Debian 12 安装 KVM + virt-manager。最终方案如下:

1
2
3
4
5
6
7
8
9
Debian 12 (host)
 └── KVM
      └── Ubuntu VM
            ├── Docker
            ├── Codex CLI
            ├── Python
            ├── Node.js
            ├── MCP
            └── AI tools

确认 CPU 支持虚拟化

执行如下命令。如果输出:0。说明:BIOS没开启虚拟化或 CPU 不支持,那就不用往下进行了。如果大于0就没问题。

1
egrep -c '(vmx|svm)' /proc/cpuinfo

安装KVM全家桶

  1. 执行如下命令:
1
2
sudo apt update
sudo apt install qemu-kvm libvirt-daemon-system virt-manager ovmf dnsmasq-base bridge-utils

这里面几个包的作用如下:

作用
qemu-kvm 虚拟机核心
libvirt-daemon-system 后台虚拟化服务
virt-manager 图形化管理器
ovmf UEFI 固件
dnsmasq-base NAT 网络
bridge-utils 网桥支持
  1. 启动 libvirt 服务 安装完成后执行如下命令确认服务开启:
1
2
3
sudo systemctl enable --now libvirtd
systemctl status libvirtd
active (running) //看到这个证明服务已正常启动。

执行:

1
virsh list --all

如果输出如下,说明:libvirt 正常。

1
2
|Id  | Name |  State  |
|----|------|---------|
  1. 把当前用户加入 libvirt 组(否则每次都要sudo)
1
2
sudo usermod -aG libvirt $USER
reboot

下载Ubuntu ISO

目前最新的是26.04版本。建议下载24.04版本的。因为版本太新对后续安装ai cli工具可能会有点影响。另外建议安装Ubuntu Server版本(没有gui)。另外建议把下载后的iso文件放入/var/lib/libvirt/images/文件夹并修正权限:

1
2
sudo cp ~/Downloads/ubuntu-24.04*.iso /var/lib/libvirt/images/
sudo chmod 644 /var/lib/libvirt/images/*.iso

启动 virt-manager

virt-manager 你会看见GUI界面,这就是以后主要操作入口。注意你此刻应该看见的是qemu:///system,而不应该是qemu:///session。建议通过virt-manager –connect qemu:///system来打开virt manager。

创建第一个 Ubuntu VM

  1. 在virt-manager中点击:File->New Virtual Machine。
  2. 选择Local install media。
  3. 选择镜像文件。直接选择刚刚放入/var/lib/libvirt/images/下面的iso文件。这里注意,取消下方Automatically detect from installation media的勾选。然后在choose operation system you are install下方输入ubuntu22.10或者任意显示的版本。这个不会影响你当前版本的安装。其实直接选Generic Linux也没问题。
  4. CPU和内存:3c8g。硬盘60G qcow2。
  5. 勾选Customize configuration before install,然后点击finish。
  6. 现在会进入虚拟机硬件设置:
    • 在overview中把BIOS改成UEFI x86_64(也就是OVMF)
    • 在CPUs中选择host-passthrough(虚拟机直接使用宿主 CPU 特性)
    • 磁盘改成VirtIO(默认可能是SATA)
    • 网卡改成virtio
  7. 点击Begin Installation开始安装。

安装ubuntun 安装ubuntun 安装ubuntun 安装ubuntun 安装ubuntun 安装ubuntun 安装ubuntun 安装ubuntun 安装ubuntun 安装ubuntun

  1. 安装完成后执行如下命令:
1
2
3
4
sudo apt update
sudo apt upgrade -y
sudo apt install openssh-server(安装ssh,如果刚才安装镜像时已经选择了,这里可以略过)
ip a(查看vm ip)
  1. 从宿主机SSH登录虚拟机。如果成功登陆,那恭喜你,VM安装就成功了。
1
ssh user@192.168.x.x

推荐安装开发环境

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
sudo apt install -y \
  git \
  curl \
  wget \
  unzip \
  zip \
  vim \
  tmux \
  htop \
  jq \
  build-essential

配置Git

1
2
git config --global user.name "你的名字"
git config --global user.email "你的邮箱"

安装Node.js

AI Cli本质上都是Node.js。但是这里不建议直接apt install来安装,因为版本可能会比较老。推荐使用 NVM。

1
2
3
4
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/master/install.sh | bash
nvm install --lts
node -v  //应该是Node 22.x
npm -v  //应该是npm 10.x+

安装Python:

1
2
3
sudo apt install python3 python3-pip python3-venv -y
python3 --version
pip3 --version

安装AI Cli:

1
2
npm install -g @openai/codex //codex cli
npm install -g @google/gemini-cli //Gemini Cli

安装完成后一些注意事项:

重启宿主机后再启动KVM报错。

安装好ubuntun并且也能ssh进去。但是重启宿主机之后,打开virt-manager后点击run,系统提升如下错误信息: Error starting domain: Requested operation is not valid: network ‘default’ is not active。这个时候运行如下命令:virsh uri。如果显示qemu:///session,那么大概率是重启后virt-manager自动回退到session模式了。这时候只要执行如下指令就能切换会system模式:

1
2
3
4
sudo virsh -c qemu:///system net-list --all(表面上查network,实际它隐式激活了system libvirt环境)
 Name      State    Autostart
--------------------------------
 default   active   yes

这个操作过一次后后面应该就不会再切换回session模式了。如果要稳妥一点的话,建议每次通过virt-manager –connect qemu:///system来启动virt-manager。再确认 libvirtd 自动启动

1
2
3
systemctl is-enabled libvirtd
应该输出:enabled。否则:
sudo systemctl enable --now libvirtd

另外执行如下命令开机默认开始虚拟网卡:

1
2
sudo virsh net-start default(立即启动 default NAT 网络)
sudo virsh net-autostart default(让它以后开机自动启动)

推荐专门建一个共享宿主机目录。以方便在宿主及机和VM之间传递文件。KVM官方推荐共享文件系统virtiofs。

1
2
3
4
5
6
7
8
9
Debian(宿主机):/home/john/workspace
        │ virtiofs
Ubuntu(虚拟机):/mnt/workspace

qemu-system-x86_64 --version //7.x或者8.x都支持virtiofs。
which virtiofsd //确认virtiofsd已安装
sudo apt install virtiofsd //virtiofsd

在virt-manager中配置:

  • 关闭虚拟机
  • 打开:virt-manager,选择你的Ubuntu虚拟机。右键点击:Open -> Show virtual hardware details(那个灯泡图标)。点击:Add Hardware。
  • 选择:Filesystem。配置:Driver:virtiofs,Source Path:宿主机目录,Target Path:例如workspace(这里不是路径,只是一个标签名)。如果出现“You may need to ‘Enable shared memory’ on the ‘Memory’ screen.”的提升,需先在Memory里面开启"Enable shared memory"选项。
  • 点击:Finish

创建共享目录 创建共享目录 创建共享目录

  • 启动虚拟机。Ubuntu启动后安装工具:
1
sudo apt install -y virtiofsd  //实际上客户端内核已经支持。主要确保工具齐全。
  • 创建挂载点,例如:
1
sudo mkdir -p /mnt/workspace
  • 挂载目录。假设刚才Target写的是workspace:
1
sudo mount -t virtiofs workspace /mnt/workspace
  • 查看结果。最好放一个文件进行测试。
1
df -h //应该能看到:workspace或者virtiofs设备。
  • 设置开机自动挂载(/etc/fstab中增加一行):
1
2
3
4
sudo vim /etc/fstab
workspace  /mnt/workspace  virtiofs  defaults  0 0
sudo systemctl daemon-reload
sudo mount -a
  • 在宿主机和虚拟机两边都执行“id”命令,确保两边的id相同,后续不会有访问权限的问题。

三、创建KVM快照(折腾之前先做一个快照,以后搞坏了可以直接回滚,比重装 Ubuntu 快得多)

  1. 创建快照
    • 先确认虚拟机名称
    1
    
      virsh list --all
    
    • 查看磁盘格式(重要)
    1
    2
    3
    4
    5
    6
    
      virsh domblklist ubuntu22.10
    
      Target   Source
      -----------------------------------------
      vda      /var/lib/libvirt/images/ubuntu22.qcow2
      如果是:*.qcow2,那快照体验最好。
    
    • 创建kvm快照
     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    
    打开 virt-manager
        
    选中 ubuntu22.10
        
    Open
        
    Snapshots
        
    Take Snapshot
    
    或者同等功能的命令行:
      virsh shutdown ubuntu22.10
      virsh snapshot-create-as ubuntu22.10 before-ai-tools "Before installing Gemini CLI and Codex CLI"
      virsh snapshot-list ubuntu22.10
      Name                Creation Time
      --------------------------------------------
      before-ai-tools     2026-06-05 16:30
    
    • 恢复快照。如果以后搞坏了:
    1
    2
    3
    
      virsh shutdown ubuntu22.10
      virsh snapshot-revert ubuntu22.10 before-ai-tools
      virsh start ubuntu22.10
    
  2. 备份整个镜像文件(推荐)
    上面创建快照的方法其实就是在KVM中打了个tag。未来可以回滚回这个tag。他并没有真正备份整个KVM镜像文件。如果要备份整个KVM镜像文件:
    1
    2
    3
    4
    
      virsh shutdown ubuntu22.10
      sudo cp /var/lib/libvirt/images/ubuntu22.10.qcow2  /var/lib/libvirt/images/ubuntu22.10-before-ai-tools.qcow2
    或者:
      sudo qemu-img convert -O qcow2 /var/lib/libvirt/images/ubuntu22.10.qcow2 /var/lib/libvirt/images/ubuntu22.10-before-ai-tools.qcow2
    
    这样你得到一个真正独立的磁盘镜像:
    1
    2
    
      ubuntu22.qcow2
      ubuntu22-before-ai-tools.qcow2
    
    以后需要恢复时:
    1
    
      sudo cp /var/lib/libvirt/images/ubuntu22.10-before-ai-tools.qcow2 /var/lib/libvirt/images/ubuntu22.10.qcow2
    

注意:当KVM使用pflash固(OVMF/UEFI),libvirt不支持对KVM创建内部快照,只能使用镜像文件备份的方式。

关于KVM的网络(NAT模式下):

  • virbr0 可以理解成一个“虚拟交换机 + 虚拟路由器 + NAT网关”的组合体。libvirt默认会创建一个网络。这个default网络对应virbr0。更准确的说法virbr0是libvirt自动创建的一个虚拟NAT网络,其中virbr0本身是虚拟交换机(bridge),而 libvirt + dnsmasq + NAT 规则共同组成了一个“小型虚拟路由器”。
1
2
3
4
5
6
7
virsh net-list

Name      State
----------------
default   active

ip addr show virbr0  //通常显示192.168.122.1/24
  • 整个KVM的网络大致如下:
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
Internet
家用路由器:192.168.1.1
Debian:192.168.1.100
virbr0:192.168.122.1 (KVM的默认网关)
Ubuntu VM:192.168.122.100
  • libvirt自动启动了dnsmasq,专门服务于virbr0网络,用来做dhcp服务。
1
ps aux | grep dnsmasq
  • libvirt 自动创建了NAT规则:
1
2
3
4
sudo iptables -t nat -L
192.168.122.0/24
192.168.1.100
  • 一个更准确的结构图:
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
               Internet
          家用路由器:192.168.1.1
     ┌────────────────────────┐
     │ Debian宿主机            │
     │ 192.168.1.100          │
     │                        │
     │     virbr0             │
     │ 192.168.122.1          │
     └──────────┬─────────────┘
      ┌─────────┴─────────┐
      │                   │
      ▼                   ▼
 Ubuntu VM1         Ubuntu VM2
192.168.122.100    192.168.122.101
  • KVM会创建一对虚拟网卡。其中一个是KVM中的虚拟网卡,另一个则是虚拟机网卡在宿主机侧的接口(vnet0)。如果把virbr0比作一个交换机,那么vnet0就相当于交换机上的一个网口(另一头连着KVM的虚拟网卡)。
 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
virbr0  ← 虚拟交换机(Bridge)
   └── vnet0 ← 虚拟机网卡在宿主机侧的接口

virbr0
   ├── vnet0 → Ubuntu
   ├── vnet1 → Debian测试机
   └── vnet2 → Windows VM

Ubuntu VM:192.168.122.100
      │ (虚拟网卡 ens3)
====================
vnet0
====================
virbr0:192.168.122.1
NAT
Debian宿主机:192.168.1.x
家庭路由器
Internet

KVM配置科学上网

由于搭建KVM的主要目的是要使用AI Cli。所以科学上网这块是必须要配置的。各个AI Cli理论上都是HTTP API/HTTPS请求,所以推荐最简单的方式就是用宿主机科学工具(比如V2rayN)+KVM环境变量代理”。

  • 宿主机V2rayN在设置中打开允许局域网连接选项,并且最好打开TUN模式(处理全局不确定流量)。KVM只做环境变量代理(SOCKS/HTTP)。设置成KVM的网关IP,也就是virbr0的IP。
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
VM (192.168.122.10)
virbr0 (192.168.122.1)  ← VM 的“默认网关”
宿主机 NAT
Internet
virbr0 = 虚拟局域网的“路由器”
192.168.122.1 = 路由器 LAN 口 IP
VM = 连接在这个 LAN 上的电脑
  • KVM设置如下环境变量(写入~/.bashrc)并验证。这里有个坑要注意下:每次在KVM创建新用户后,不要忘了把下面的环境变量加入~/.bashrc中。不然AI Cli会连接不上。
1
2
3
export ALL_PROXY=socks5h://192.168.122.1:10808
export all_proxy=socks5h://192.168.122.1:10808
curl --proxy socks5h://192.168.122.1:10808 https://ipinfo.io

Codex Cli登录

  • Codex登录失败错误
    首先检查:

    1
    
      curl -i https://auth.openai.com/api/accounts/deviceauth/usercode
    

    如果看到:

    1
    2
    3
    4
    5
    
      {
    	  "error": {
      	    "code": "unsupported_country_region_territory"
    	   }
      }
    

    基本就可以直接判断是网络出口问题。一般是~/.bashrc中没有设置代理环境变量。

  • 登录成功后出现bubblewrap警告
    如果Codex登录后出现“Codex could not find bubblewrap on PATH. Install bubblewrap with your OS package manager.”,说明bubblewrap没有安装。bubblewrap(简称 bwrap)是 Linux 上的轻量级沙箱工具。Codex 在执行代码时会用它创建隔离环境,例如:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    
    Agent
    Codex Sandbox
    Shell
    Python
    Git
    

    安装bubblewrap:

    1
    2
    3
    4
    
      sudo apt update
      sudo apt install uidmap bubblewrap
      echo "kernel.apparmor_restrict_unprivileged_userns=0" | sudo tee /etc/sysctl.d/99-codex-userns.conf
      sudo sysctl --system
    

KVM常用命令

  • 查看虚拟机
1
virsh list --all
  • 启动虚拟机
1
virsh start <虚拟机名称>
  • 关闭虚拟机
1
virsh shutdown <虚拟机名称>
  • 查看网络
1
virsh net-list
Built with Hugo
Theme Stack designed by Jimmy