---
url: /courses/virtualization-tech/04-ubuntu-desktop-spice/index.md
---
# 第 4 课 把桌面装进窗口

> 里程碑 `V3`｜Ubuntu Desktop、SPICE 显示协议与来宾代理｜理论 2 学时 + 实训 2 学时（180 分钟）

![一台 Ubuntu 宿主机中，Ubuntu Desktop 桌面来宾通过 SPICE 显示在宿主机窗口里，学生正在核对显示、剪贴板与来宾代理状态](./assets/03/ubuntu-desktop-illustration.png)

::: tip 项目目标
在前两课中，你已经能够熟练使用 virt-manager 创建命令行模式的 Ubuntu Server 虚拟机。本课你将为“星舟实训云”交付一台带 GUI 图形桌面的 Ubuntu Desktop 虚拟机 `desk01`。
通过本课的学习与实训，你将掌握：

1. **显示协议原理**：理解为什么虚拟机需要远程显示协议（VNC 与 SPICE 的核心区别），以及如何在图形界面与命令行中查看当前配置；
2. **虚拟硬件与代理分工**：掌握 Virtio GPU 虚拟显卡、SPICE 多通道传输与两类来宾代理（`spice-vdagent` 与 `qemu-guest-agent`）的作用边界；
3. **查看器与控制台体验**：学会安装并使用 `virt-viewer` 独立窗口连接桌面，实现动态分辨率自动跟随与双向剪贴板同步；
4. **宿主出界管理**：理解基于 Virtio 串口的 QEMU Guest Agent 管理机制，使用 `guest-ping` 在无网络/无 SSH 状态下探测来宾健康度。
   :::

{{assessment:lesson-04-precheck}}

## 4.1 显示协议：什么是 SPICE 与 VNC

### 1. 为什么虚拟机需要远程显示协议？

在日常使用物理台式机或笔记本电脑时，屏幕显示非常直观：显示器通过 HDMI、DisplayPort 或 VGA 线缆直接插入物理显卡的接口上，显卡将渲染好的帧缓冲（Framebuffer）实时输出到屏幕。

但是在 KVM 虚拟化环境中，虚拟机（Guest OS）只是宿主机内核管理下的一个进程。虚拟机内部并没有真实的物理显卡，也没有物理显示器插槽。如果我们要在一个运行在宿主机桌面上的“窗口”里看到虚拟机的 GUI 界面（如 Ubuntu 桌面、Windows 桌面），就必须通过**远程显示协议**（Remote Display Protocol）。

简而言之，远程显示协议的作用就是：**捕获虚拟机内部的图形输出，通过网络或本地 Socket 传输，最后交由宿主机侧的客户端窗口渲染展示。**

下面的动画直观演示了 VNC 像素快照与 SPICE 多通道图形指令模式的原理对比：

### 2. 常见显示协议对比：VNC vs SPICE

在 Linux/KVM 虚拟化生态中，最常见的两种远程显示协议是 **VNC**（Virtual Network Computing）与 **SPICE**（Simple Protocol for Independent Computing Environments）。对于零基础的初学者，可以通过以下底层机制来区分它们：

#### (1) VNC 协议：经典的“屏幕像素快照”模式

VNC 采用 RFB（Remote Framebuffer）协议。它的工作方式非常原始直接：

* **原理**：QEMU 服务端会定期抓取虚拟机显示缓冲区的**原始像素快照**，经过简单的切块与压缩后，直接将像素点发送给客户端。
* **优点**：极其简单，几乎所有操作系统和浏览器都有 VNC 客户端，兼容性极佳。
* **缺点**：
  * **网络带宽消耗大**：如果在虚拟机里播放视频或拖动窗口，VNC 需要不断传输大量的像素数据，容易产生明显的卡顿与延时；
  * **缺乏高级交互**：VNC 协议原生不支持动态分辨率自适应（拖动窗口窗口不会变大，只会产生黑边），对剪贴板双向复制粘贴、音频传输支持非常弱。

#### (2) SPICE 协议：专为虚拟化打造的“图形指令与多通道”模式

SPICE 是红帽（Red Hat）主导开源的专门面向虚拟桌面的高性能协议：

* **原理**：SPICE 不仅能传输像素，还能传输 2D **图形绘制指令**（例如“在坐标(10,10)绘制一个矩形”、“渲染这段文本”）。宿主客户端收到指令后在本地硬件上渲染，从而大幅减少传输数据量。
* **多通道架构**：SPICE 内部拆分为多个独立的子通道（Channels）：
  * **Main Channel**：管理会话连接与鼠标键盘控制；
  * **Inputs Channel**：高精度的键盘与鼠标事件输入；
  * **Display Channel**：图形画面与视频流传输；
  * **Cursor Channel**：本地鼠标指针绘制（避免远程指针延迟）；
  * **Playback/Record Channel**：音频输入与输出；
  * **Spicevmc Channel**：来宾代理通信（剪贴板同步、分辨率跟随）。
* **优点**：画面流畅、占用带宽小，原生支持拖动窗口改变分辨率、双向剪贴板、USB 设备重定向与音频传输。
* **缺点**：需要在来宾操作系统中安装对应的驱动程序与代理服务（如 `spice-vdagent`）。

| 特性维度 | VNC 协议 | SPICE 协议（本课选择） |
| --- | --- | --- |
| **传输内容** | 屏幕像素快照 / 图像块 | 图形绘制指令 + 增量像素流 |
| **网络带宽占用** | 较高（频繁全屏刷像素） | 极低（仅传输绘制指令与变动区域） |
| **分辨率自适应** | 不支持（拖动窗口出现黑边） | **支持**（来宾分辨率平滑跟随窗口大小） |
| **剪贴板双向同步** | 原生无支持或极弱 | **支持**（经由 Spicevmc 代理通道） |
| **音频与 USB 重定向** | 不支持 | **支持**（内置声音通道与 USB 转发） |
| **来宾驱动依赖** | 无依赖（通用 VGA 即可） | 需要 Virtio 显示驱动与 `spice-vdagent` |

### 3. 如何在实际环境中查看当前使用的是哪种协议？

在管理虚拟机时，你不需要死记硬背。你可以通过图形界面或命令行两种方式核对 `desk01` combat 配置使用的是 SPICE 还是 VNC：

#### 方法 A：在 virt-manager 图形界面中查看

1. 打开 `virt-manager` 窗口，双击打开虚拟机；
2. 点击控制台窗口上方工具栏的 **`ⓘ` 按钮**（显示虚拟硬件详情）；
3. 在左侧侧边栏中找到 **“显示器 SPICE” (Display SPICE)** 或 **“视频 Virtio” (Video Virtio)**。如果看到类型为 SPICE，则说明当前配置的是 SPICE 协议。

#### 方法 B：使用 virsh 命令行查看

在宿主机终端中执行以下命令：

```bash
virsh dumpxml desk01 | grep '<graphics'
```

* **输出包含 `type='spice'`**：表示当前虚拟机配置走 SPICE 协议；
* **输出包含 `type='vnc'`**：表示当前虚拟机走 VNC 协议。

### 4. 画面传输完整路径

画面从来宾应用程序最终推送到你的宿主机屏幕，经过了主链路与旁路代理。下面的架构拓扑展示了这一完整的流动方向：

## 4.2 核心角色厘清：虚拟显卡、协议与代理

为了避免在后续操作中混淆概念，我们需要清晰厘清运行在**来宾内部**、**传输层**以及**宿主侧**的核心角色分工：

### 1. 虚拟显示设备（Virtio GPU / QXL / VGA）

* **它是什么**：这是运行在虚拟机内部的“虚拟显卡”。来宾操作系统（Ubuntu）启动时，内核会检测到一块 PCI 显示设备并加载驱动。
* **常见类型**：
  * **VGA**：标准传统显卡模拟，兼容性最好，但性能差，无硬件加速；
  * **QXL**：红帽早期的 SPICE 专用虚拟显卡，性能较好；
  * **Virtio GPU（本课推荐）**：现代 KVM 标准的半虚拟化显示设备，性能优异，Ubuntu 内核原生自带驱动。

### 2. 传输协议（SPICE 协议通道）

* **它是什么**：连接 QEMU 模拟器与宿主显示窗口的传输数据线。它把 Virtio GPU 渲染好的图像数据压缩打包后，传给宿主窗口展示。

### 3. 来宾代理（Guest Agents）

* **它是什么**：安装在虚拟机操作系统内部后台运行的小服务，用于将虚拟机内部的状态与宿主机进行双向沟通。
* **两类代理的区别**：
  * **`spice-vdagent`**：**桌面体验代理**。运行在来宾的图形会话中，通过 SPICE 专有通道通信。负责窗口缩放时自动通知来宾调整分辨率、以及宿主与来宾之间的双向剪贴板同步。
  * **`qemu-guest-agent`**：**运维管理代理**。运行在来宾的系统服务中，通过独立的 Virtio 串口（`org.qemu.guest_agent.0`）与宿主机的 `libvirt` 通信。负责响应宿主发起的 `guest-ping` 健康检查、报告网络 IP 地址、执行文件系统冻结等运维操作。

## 4.3 创建与配置 Ubuntu Desktop 虚拟机

在了解了基本原理后，我们开始在宿主机上创建 `desk01` 虚拟机。

### 1. 虚拟机配置参数表

在打开 `virt-manager` 之前，先明确本次创建的虚拟机参数：

| 参数名称 | 配置值 | 配置说明与选择理由 |
| --- | --- | --- |
| **虚拟机名称** | `desk01` | 保持课程统一命名规范（Server 为 `svr01`，Desktop 为 `desk01`） |
| **vCPU 核心数** | `2` vCPU | 桌面操作系统包含图形合成器，配置 2 核保证桌面流畅操作 |
| **内存容量** | `4096` MiB (4GB) | Ubuntu 24.04 Desktop 推荐内存为 4GB |
| **虚拟磁盘格式** | **QCOW2**，容量 `35` GB | QCOW2 格式支持动态按需增长，35GB 是上限，初始写入仅占几 GB |
| **虚拟网卡** | `default` NAT 网络（模型 **Virtio**） | 共享宿主机网络连接外网，Virtio 网卡提供最佳网络吞吐 |
| **图形协议** | **SPICE** | 提供低延迟桌面传输与代理集成通道 |
| **显示设备** | **Virtio**（3D 加速：关闭） | 稳定、标准的半虚拟化显示模型，本课实验无需开启 3D 加速 |

### 2. 关键概念深度解读

#### (1) QCOW2 格式 vs RAW 格式

* **RAW 格式**：原始镜像格式。你分配 35GB，系统在磁盘上立刻占用 35GB 空间。优点是 Read/Write 性能稍高，缺点是极其浪费空间且不支持快照。
* **QCOW2 格式**：QEMU 专门设计的写时复制格式（QEMU Copy-On-Write）。你分配 35GB，初始新建时文件可能只有几百 KB；随着系统安装写入了 7GB 数据，该文件才生长到 7GB。QCOW2 还原生支持虚拟机快照与写时复制模板（后文课程将详细讲解）。

#### (2) Virtio 半虚拟化 vs 全虚拟化模拟

* **全虚拟化模拟（如 e1000 网卡、IDE 硬盘）**：QEMU 需要完全用软件模拟真实物理芯片的每个寄存器动作。虚拟机每次读写数据，都会产生大量昂贵的 CPU 上下文切换（VM-Exit），性能较差。
* **Virtio 半虚拟化**：来宾操作系统知道自己运行在虚拟机中，直接使用 Virtio 共享内存环形缓冲区（`virtqueue`）与宿主机传输数据。数据传输不需要经过繁琐的寄存器模拟，性能接近物理硬件。

### 3. 准备工作：安装 virt-viewer 并获取 ISO

在开始创建前，先完成以下准备工作：

#### Step 1：在宿主机安装 virt-viewer

`virt-viewer` 是宿主机上用于显示虚拟机界面的独立客户端。如果你的宿主机尚未安装，请在 **宿主机终端** 中执行：

```bash
sudo apt update
sudo apt install -y virt-viewer
```

::: tip virt-manager 与 virt-viewer 的区别与联系
现在你已经成功安装了 `virt-viewer`，我们清晰区分这两个工具的作用：

1. **virt-manager（虚拟机管理器）**：
   * **定位**：全功能图形管理面板（基于 `libvirt` API）。
   * **能做什么**：创建/删除虚拟机、配置 CPU 内存、管理虚拟存储池与虚拟网络、查看所有虚拟机运行状态。
   * **何时使用**：当你需要对虚拟机进行**硬件管理与运维控制**时使用。

2. **virt-viewer（控制台查看器）**：
   * **定位**：独立的轻量级桌面显示客户端（基于 `spice-gtk` / `libvirt-glib`）。
   * **能做什么**：只专注一件事——连接到指定的虚拟机，把控制台桌面拉出一个独立窗口显示出来，并处理鼠标键盘输入与剪贴板。
   * **何时使用**：当你不需要看管理界面，只想**像操作普通软件一样直接使用虚拟机桌面**时使用。例如直接执行 `virt-viewer desk01`。
     :::

#### Step 2：获取 Ubuntu Desktop 24.04 LTS 镜像

请确认宿主机上已准备好 Ubuntu Desktop 24.04 LTS 的官方 ISO 镜像文件。若尚未下载，可通过以下官方镜像源获取：

* [Ubuntu 官方下载站](https://ubuntu.com/download/desktop)
* [清华大学开源软件镜像站 Ubuntu 镜像](https://mirrors.tuna.tsinghua.edu.cn/ubuntu-releases/24.04/)

### 4. 在 virt-manager 中创建 desk01

按以下步骤在图形界面中完成新建：

::: steps

1. **启动向导**：打开 `virt-manager`，点击菜单栏左上角的“新建虚拟机”图标。
2. **选择安装介质**：选择“本地安装介质 (ISO 镜像或光盘)”，点击“前进”。
3. **选择 ISO 文件**：点击“浏览”，选择下载好的 Ubuntu Desktop 24.04 ISO 镜像。如果系统未能自动识别 OS 版本，请在搜索框中手动选择 `Ubuntu 24.04 LTS`。
4. **配置 CPU 与内存**：将内存（RAM）设置为 `4096` MiB，CPUs 设置为 `2`。
5. **创建虚拟磁盘**：选择“为虚拟机创建磁盘镜像”，容量输入 `35` GB。
6. **名称与自定义**：
   * 名称输入：`desk01`；
   * 勾选 **“安装前自定义配置” (Customize configuration before install)**；
   * 网络选择 `default`（NAT 网络）。
7. **核对硬件配置**：
   * 在弹出的配置详情窗口中，点击左侧 **“图形” (Graphics SPICE)**，确认类型为 `SPICE`；
   * 点击左侧 **“视频” (Video Virtio)**，确认模型为 `Virtio`，且“开启 3D 加速”**未勾选**；
   * 点击左上方“开始安装”。
8. **完成图形化安装**：根据 Ubuntu 官方安装向导完成系统安装，设置好用户名与密码。安装完成后点击“立即重启”。

:::

## 4.4 安装来宾增强工具 (spice-vdagent 与 qemu-guest-agent)

系统安装完成并重启进入桌面后，你需要打开 **`desk01` 虚拟机内部的终端**，安装两个增强工具服务。

```bash
# 1. 更新软件包列表并安装 spice-vdagent 与 qemu-guest-agent
sudo apt update
sudo apt install -y spice-vdagent qemu-guest-agent

# 2. 启动并设置 qemu-guest-agent 服务开机自启
sudo systemctl enable --now qemu-guest-agent
```

### 工具原理与运行通道

1. **`spice-vdagent`**：
   * **运行位置**：运行在 `desk01` 的用户图形会话后台；
   * **通信通道**：通过 `/dev/virtio-ports/com.redhat.spice.0` 虚拟串口与 SPICE 服务端通信；
   * **核心功能**：监听 virt-viewer 窗口的大小改变事件，实时通过 DRM/RANDR 接口修改 Linux 的屏幕分辨率；同时监听系统剪贴板（CLIPBOARD/PRIMARY），实现宿主与来宾间的文本搬运。

2. **`qemu-guest-agent`**：
   * **运行位置**：作为系统级 systemd 服务 (`qemu-guest-agent.service`) 在后台常驻；
   * **通信通道**：通过 `/dev/virtio-ports/org.qemu.guest_agent.0` 专用 Virtio 串口与宿主机的 libvirt 进程通信；
   * **核心功能**：提供出界（Out-of-band）管理功能。宿主机不需要知道虚拟机的 SSH 密码或 IP 地址，即可通过串口向该代理发送命令，查询虚拟机内存状态、网卡 IP 地址、执行文件系统 Freeze 等。

## 4.5 桌面控制台与双向剪贴板体验

安装完工具后，我们使用 `virt-viewer` 独立窗口体验 SPICE 的桌面集成能力。

### 1. 使用 virt-viewer 打开独立控制台

在 **宿主机终端** 中执行以下命令，直接拉出 `desk01` 的控制台窗口：

```bash
virt-viewer desk01
```

::: tip virt-viewer 常用快捷键

* **全屏 / 退出全屏**：`Shift + F11`
* **释放鼠标/键盘独占捕获**：`Ctrl + Alt`
  :::

### 2. 测试分辨率自适应跟随

用鼠标点击并拖动 `virt-viewer` 窗口的边框，任意改变窗口的大小。

* **预期现象**：`desk01` 的 Ubuntu 桌面分辨率会在 0.5 秒内自动调整，适应新的窗口宽高比。画面始终保持清晰填充，不会出现传统 VNC 的黑边、拉伸或滚动条。
* **背后的工作机制**：
  1. 宿主侧 `virt-viewer` 窗口尺寸发生变化；
  2. SPICE 客户端将新的分辨率参数发送给 SPICE Server；
  3. SPICE Server 经由 Spicevmc 串口通道送达 `desk01` 内部的 `spice-vdagent` 进程；
  4. `spice-vdagent` 调用来宾系统的 X11/Wayland 图形接口修改显示分辨率。

### 3. 测试双向剪贴板同步

我们来进行宿主机与 `desk01` 虚拟机之间的双向复制粘贴测试：

::: steps

1. **宿主机 ➔ 虚拟机**：
   在宿主机上打开任意文本编辑器或网页，复制一段文字（例如：`Hello KVM Desk01`）；切换到 `virt-viewer` 窗口中，在 `desk01` 的文本编辑器（Text Editor）中按 `Ctrl + V`，确认文本能够成功粘贴。

2. **虚拟机 ➔ 宿主机**：
   在 `desk01` 内部的终端或文本编辑器中输入一段文本（例如：`Output from Guest`）并复制；切换回宿主机的文本编辑器按 `Ctrl + V`，确认文本能够成功粘贴回宿主机。

:::

## 4.6 宿主机管理通道与 guest-ping 深度验证

除了桌面交互，宿主机运维还需要能够在不依赖网络和 SSH 的情况下，探测来宾系统的健康状况。

### 1. 什么是 QEMU Guest Agent 与 guest-ping？

在第 2 课中，我们通过 SSH 登录到 `svr01` 进行管理。但 SSH 存在一个前提：虚拟机必须配置好 IP 地址、网络正常通畅，且 SSH 服务（`sshd`）正在运行。

而 `qemu-guest-agent` 走的是**出界管理通道（Out-of-band Management）**：

* 宿主机的 `virsh` 命令行通过 libvirt 向 QEMU 发送 JSON 格式的 QMP（QEMU Monitor Protocol）指令；
* QEMU 将指令塞入 `/dev/virtio-ports/org.qemu.guest_agent.0` 虚拟串口；
* 虚拟机内部的 `qemu-guest-agent` 收到指令后处理并回传结果。

`guest-ping` 就是在该通道上运行的最基础健康检测指令。**哪怕虚拟机的网卡未分配 IP 地址，或者防火墙禁用了所有网络端口，只要虚拟机没有死机、QGA 服务正常，`guest-ping` 就能成功回应。**

### 2. 执行 guest-ping 与 IP 地址查询

在 **宿主机终端** 中执行以下管理命令：

#### (1) 发起 guest-ping 健康检查

```bash
virsh qemu-agent-command desk01 '{"execute":"guest-ping"}'
```

* **预期输出**：`{"return":{}}`
* **解析**：返回空的 `return` JSON 对象表示 `qemu-guest-agent` 响应正常，虚拟机系统运行健康。

#### (2) 通过 Agent 途径查询来宾网卡 IP 地址

```bash
virsh domifaddr desk01 --source agent
```

* **预期输出**：展示 `desk01` 内部所有网卡名称、MAC 地址及 IPv4/IPv6 地址信息。
* **与 `--source lease` 的区别**：
  * `--source lease`：宿主机读取 `dnsmasq` 的 DHCP 租约文件获取地址（静态 IP 或自定义网络下查不到）；
  * `--source agent`：直接由来宾代理在虚拟机内部执行网络查询后汇报，结果最权威真实。

下面的动态拓扑展示了 SPICE 桌面通道与 QGA 管理通道双路运行及故障隔离原理：

## 4.7 常见问题排错矩阵

在实际搭建和使用过程中，如果遇到问题，请参照下表进行分层排查：

| 故障现象 | 可能的原因分析 | 最小排查命令 / 检查方法 | 解决办法 |
| --- | --- | --- | --- |
| **virt-manager 显示运行，但打开控制台黑屏** | 1. 图形协议配置错误2. 视频模型选择了不兼容驱动 | 打开虚拟机硬件详情，检查 Display 与 Video 节点 | 确认图形协议为 SPICE，视频显示模型为 Virtio，且关闭 3D 加速 |
| **拖动 virt-viewer 窗口，分辨率不跟随** | 1. 来宾内未安装 `spice-vdagent`2. 图形会话未重启 | 在来宾终端执行：`pgrep -a spice-vdagent` | 安装 `spice-vdagent` 软件包，在桌面注销并重新登录 |
| **宿主与来宾之间无法复制粘贴文本** | 1. `spice-vdagent` 进程未启动2. SPICE 代理通道被占用 | 在来宾终端检查 `systemctl status spice-vdagent` | 启动代理服务或重启来宾图形会话 |
| **`guest-ping` 报错 "Guest agent is not responding"** | 1. 来宾内 `qemu-guest-agent` 服务未启动2. XML 缺少 Virtio 串口通道 | 在来宾终端执行：`systemctl status qemu-guest-agent` | 执行 `sudo systemctl enable --now qemu-guest-agent` 启动服务 |
| **`domifaddr --source agent` 无 IP 输出，但虚拟机能上网** | 来宾内部代理未正确获取网络层接口状态 | 在来宾终端直接执行 `ip -br addr` 对照 | 检查 `qemu-guest-agent` 服务日志：`journalctl -u qemu-guest-agent` |

## 4.8 提交内容

完成本课实训后，请提交以下 **4 张包含命令与清晰结果的截图** 作为验收证据：

| 截图文件名 | 内容要求 | 核心验收点 |
| --- | --- | --- |
| `01-virt-manager-desk01.png` | `virt-manager` 管理主界面截图 | 能够看到 `desk01` 处于 Running 状态，配置为 2 vCPU / 4GB RAM |
| `02-virt-viewer-desktop.png` | `virt-viewer` 独立运行窗口截图 | 展示 `desk01` 成功进入 Ubuntu 桌面，拖动调整窗口后无黑边 |
| `03-clipboard-test.png` | 宿主机与虚拟机剪贴板测试截图 | 展示在宿主机复制文本后成功粘贴至 `desk01` 内部的编辑器画面 |
| `04-guest-ping-result.png` | 宿主机终端执行结果截图 | 包含 `guest-ping` 返回 `{"return":{}}` 及 `domifaddr --source agent` 输出 |

{{assessment:lesson-04-check}}

## 本章小结

* **远程显示协议**：SPICE 协议通过传输图形绘制指令与多通道架构，相比传统的 VNC 提供了更低延时、更低带宽、支持动态分辨率自适应与剪贴板集成的高清桌面体验。
* **角色分工**：Virtio GPU 提供虚拟显卡接口，SPICE 负责传输数据，`virt-viewer` 是宿主侧独立的桌面显示窗口；`spice-vdagent` 与 `qemu-guest-agent` 分别服务于桌面体验与出界运维管理。
* **独立管理通道**：QEMU Guest Agent 运行在虚拟机内部，通过 Virtio 串口与宿主通信。`guest-ping` 与 `domifaddr --source agent` 提供了不依赖 IP 地址和 SSH 的可靠健康监测途径。

在下一课中，我们将创建 Windows 虚拟机 `win01`，学习如何在 Windows 环境下安装 VirtIO 驱动与 SPICE 增强工具，并解决 UEFI 与虚拟 TPM 等平台问题。
