Xen-之书-全-
Xen 之书(全)
原文:The Book of Xen
译者:飞龙
引言
这是一段关于我们的英雄在追求性能的过程中所遇到的挣扎和艰辛的描述:其中有一段短暂的混乱和开始。

从前,在阴影之地阿蒙克,一群邪恶的程序员正在编织他们的邪恶计划。似乎地球终于迎来了黑暗的日子,而且永远如此,因为程序员们似乎非常聪明,没有人能够抵挡他们。即使某个英雄,通过极大的幸运或难以想象的英雄主义,将他们中的一个击败,那么仍然会剩下无数的人,每个人都比前一个更加邪恶和狡猾。
等等。这完全不对。事实上,这是另一本完全不同的书的开始。让我们再试一次。
这本书是关于 Xen 的。它不是关于禅。它不会向你展示一条通往觉悟的道路,即从浮世解脱出来。我们不会给你关于八正道的建议,也不会列举四圣谛。这些都超出了我们的范围。但如果一切顺利,这本书将让你感到快乐。
虚拟化:简史
在这种情况下,幸福的载体将是虚拟化。这听起来很奇怪,但自从时间的开始,人们就试图通过虚拟化来获得幸福。(在计算机术语中,那就是 20 世纪 70 年代。)IBM 在阿蒙克的一支程序员团队推出了我们知道的第一个虚拟机(VM)解决方案,即 VM/370,以确保他们的新机器能够运行为旧型号开发的程序。顾客在 1979 年非常喜欢它,Xen 开发者将其视为一个重要的灵感来源。一个类似但更现代的例子可能是 Xbox 360 对原始 Xbox 的软件模拟。
一段时间里,并没有什么成果。虚拟化在计算机领域继续发挥作用,主要在市场的高端,但人们仍然固执地要求大多数任务需要一个完整的机器,直到大约 2001 年。
2001 年,每个人都必须承认,与 1979 年大不相同。计算机变得小巧而无处不在。大型分时机器让位于个人电脑。批量处理变得罕见,完全交互式的桌面应用已成为计算机的存在理由。最重要的是,从我们的角度来看,单台计算机已被网络所取代:大多数值得拥有的计算机都连接到互联网,并且每个都需要各种服务。
这些服务反过来被设计成可以由甚至最便宜、最小的服务器轻松提供,通常要多得多.^([2]) 突然间,运营这些服务的人们有了大量的计算能力过剩,消耗的电力远远超出他们实际提供的服务。必须采取某种措施。虚拟化重新出现的舞台已经搭建,这次作为服务器 整合 的手段。
剑桥的一些聪明人士决定,这个想法可以进一步扩展——如果虚拟化允许个人或公司合并他们的机器,他们推理,那么它是否也应该允许 多个 组织合并他们的机器并获取更大的利益?这就是 Xen 的目标。它将虚拟化视为一种技术,允许人们完全忽略硬件。在这个模型中,计算成为一种服务或商品,“创造一个 XenoServer 执行平台遍布全球,任何公众成员都可以使用的世界。”^([3])
这就是我们今天所在的位置。尽管 XenoServer 平台从未发布,但其愿景今天仍然以“云计算”的形式存在,这是由 Xen(以及诚然其他虚拟化系统)实现的。Xen 通过允许站点创建“节点”,这些节点可以通过其他计算服务机制无法实现的方式进行管理、转移和计费,从而融入这个庞大的云计算方案。
^([1]) 然而,令我们非常沮丧的是,它与电影中的描述也非常不同。
^([2]) 我们知道,有许多应用情况并非如此——但仍然有许多小型网络服务器(例如)存在。
^([3]) Hand 等人,“控制 XenoServer 开放平台”,(英国剑桥大学,2003 年)。摘要。
那么,Xen 又是什么呢?(我为什么要使用它?)
即使你对这种网格计算类型不感兴趣,Xen 也为系统管理员和家用用户提供了某些优势。
Xen 是一种软件,它使一台机器表现得就像多个 虚拟 机器。这些机器中的每一个都可以运行自己的操作系统,并且几乎独立于同一硬件上运行的其它虚拟机器。每个虚拟机器(在 Xen 术语中称为 实例 或 域)都有自己的明显网络接口、磁盘和内存。
最初,这使 Xen 看起来与 模拟器 没有什么不同,例如 VMware、微软的 Virtual PC 或开源的 QEMU.^([4]) 然而,这些传统的模拟器通过在模拟处理器上运行软件来实现,而这个模拟处理器本身也是软件——这是一个相当慢的过程。Xen 实际上以全速直接在处理器上运行所有软件,只为一些资源管理任务产生非常小的开销。
这导致了 Xen 的第一个,也可能是最重要的优势:与传统的模拟器相比,Xen 运行得非常快。"Xen 和虚拟化的艺术"——Xen 的开创性论文之一——的初步结果表明,在标准负载下性能下降不到 2%,在最坏的情况下为 10% 到 20%。从那时起,Xen 已经得到了改进。我们通常只认为 Xen 的性能是"足够的",就到此为止。(想要更精确答案的读者可能想阅读第十章,该章节讨论了使用特定应用程序对 Xen 的性能进行基准测试。)
Xen 的优势在与独立机器的对比中也显现出来,甚至超出了之前提到的整合论点。就像传统的模拟器一样,Xen 提供了强大的故障隔离——也就是说,任何影响一个虚拟机的软件问题不太可能影响真实机器或同一硬件上运行的其它虚拟机。这使得它在用户意图或技能水平无法确定的环境中特别有用。
同样,像传统的模拟器一样,Xen 在机器和用户之间提供了一个额外的抽象层,这增加了管理员的灵活性——突然之间,应用程序可以几乎完全与硬件解耦;可以停止、启动、移动;可以变成真正的服务。
但从某种意义上说,Xen 的主要优势是心理上的:它使得将计算机时间视为比它已经更像是商品成为可能。^(5) 使用 Xen,你可以根据自己的需要运行自己的虚拟计算机,所需资源根据所需的应用程序进行定制。
此外,Xen 还允许你在任何给定时间运行所需的任何配置。例如,想要测试新网页与不同版本的微软 Internet Explorer 的网页开发者不需要维护一个包含不同 Windows 版本、不同补丁级别和不同 Internet Explorer 版本的 Windows 箱子农场。相反,只需在硬盘上保留不同的操作系统镜像,并在需要时启动它们。
Xen 的局限性
好吧,我们有点走远了。Xen 并非完美,也不是任何形式的计算万能药。它既有缺点也有局限性。
Xen 的主要缺点是它只能与专门修改以支持它的操作系统一起工作。(但请注意,在足够先进的硬件上,未修改的客户端操作系统也是可能的。我们将在第十二章中稍后讨论这一点。)
与纯软件模拟器相比,设置 Xen 需要用户完全在客户端域(尽管是一个特殊、受保护的客户端域)中工作,而不是简单地启动一个外部的模拟程序。
此外,Xen 文档的状态相当糟糕。(你可能会说,这正是我们在这里的原因。)当然,人们正在努力改进它,但众所周知,编写代码比编写文档更有趣。此外,Xen 正在如此积极地开发中,以至于现有的许多文档已经过时。
这些是重大的缺点,但它们并不糟糕到让你放弃运行 Xen。
最后,尽管也有一些情况下 Xen——以及虚拟化本身——根本不起作用。例如,对于具有持续、CPU 限制的工作负载的人来说,Xen 并不是特别有用。在大型服务器农场中,单个节点已经根据其工作进行了扩展,Xen 也不是很好。在这些情况下,Xen 可能不是你想要的,尽管开发人员(以及开源社区)正在为这些环境开发吸引人的功能。
但是,最终,真正有趣的不是 Xen 本身,而是你可以用它做什么。
那么,为什么我应该使用 Xen 呢?
简短的回答是,因为它会使你的生活更轻松。不相信某个软件?创建一个虚拟机,看看你喜不喜欢。需要测试一个网络应用程序?启动几台机器,看看它们如何相互通信。有一个你想要在上面测试新软件的集群,但负担不起第二个“测试”集群?Xen 提供了一个解决方案。想要良好的快照备份?Xen 可以是你的答案,它能够在几秒钟内暂停并备份正在运行的机器。需要为数十个用户提供托管服务,每个用户都希望完全控制他们的配置?这正是我们所做的,而 Xen 是我们这样做的方式。(敏锐的读者可能会注意到我们的写作中存在某种偏向于最后一个应用。这就是原因。)
在更基本的层面上,Xen 允许你停止一台机器,将其发送到其他地方,并随意恢复其运行。这减少了一件事要考虑——突然间硬件不再重要。这对用户和管理员来说都是一件好事!
最后,还有一个很好的理由来运行 Xen,这个理由既大又平凡,常常被忽视:Xen 简直比运行多个盒子便宜。数据中心中的 CPU 使用率在 5% 到 40% 之间——这个数字相当不引人注目。⁶ Xen 允许你利用那些未使用的周期,而不会牺牲可靠性、性能或可扩展性。
与几十年前的虚拟化技术不同,Xen 虚拟化了廉价的通用硬件;一开始这可能没有意义,直到你意识到市场的大部分内容对价格非常敏感,而电力正变得越来越昂贵。运行一个大型双四核系统比运行八个单核系统便宜得多,而使用 Xen,你可以轻松地将那个四核系统分割成单独的系统。
^([4]) 事实上,Xen 广泛使用了 QEMU,正如我们将看到的。
^([5]) 这有点像手机。人们使用它们,不是作为固定电话的替代品,而是作为传统计划的替代品。
^([6]) 这是一个普遍存在的信念,但经常引用的一个来源是托马斯·比特曼的演示文稿“虚拟化:掌握您的服务器”。
本书概述
好了,不要过多吹嘘。现在让我们进入正题。
我们将本书(主要是)理论与实践讨论交替进行。根据我们的经验,管理员需要实际经验和坚实的理论基础才能有效地解决问题,这正是我们旨在提供的。
第一章是 Xen 和虚拟化技术的一般概述。我们试图概述 Xen 的工作原理,它与其他虚拟化软件包的区别,以及你为什么可能(或可能不)想使用它。这一章理论性较强。
第二章是一个基于经验的快速入门步骤,其理由是没有替代品。我们在 CentOS 系统上从基本原理安装 Xen。
第三章介绍了如何手动创建虚拟机镜像以供 Xen 使用。
第四章涵盖了存储。听起来可能有点平凡,但存储实际上是虚拟化的一个关键部分——如果存储与特定的机器或硬件配置相关联,那么 Xen 的一些最酷的功能将无法工作。我们涵盖了各种存储选项,为后续关于迁移和快照的讨论奠定了基础。
我们在第五章第五章. 网络连接中讨论了网络连接——如何设置以及这样做时有哪些选项。这一章和上一章都更多地侧重于理论。
第六章介绍了几种流行的前端包装,这些前端可以与开源 Xen 虚拟机管理程序一起使用来自动化虚拟机管理的日常繁琐工作。我们还讨论了 Xen 的脚本编写,如果你更愿意构建自己的前端。
第七章回到实际案例研究,讨论 Xen 在共享托管中的应用。这是推动 Xen 早期采用的主要应用之一,我们在这一领域有很多经验。
从共享托管迁移过来,在第八章第八章. 超越 LINUX:在其他类 UNIX 开源系统中使用 Xen 中,我们讨论了 Linux 作为“主机”和“客户机”操作系统的可能替代方案。
在第九章中,我们描述了迁移的理论和实践。
第十章是关于使用 Xen 进行性能分析的内容。我们讨论了 Xen 在这一领域的强大支持,这似乎没有得到应有的关注。
在第十一章中,我们稍微偏离一下,来介绍 XenSource(现在是 CITRIX 的一个部门)围绕 Xen 构建的商业产品。
第十二章是关于 Xen 的 HVM 支持——也就是说,由 Intel 和 AMD 最新处理器支持的硬件虚拟化。
第十三章涵盖了 Windows。我们讨论了如何与 Xen 一起使用它,使其表现良好,你可以期望如何访问它,以及一旦它运行正常后你可能期望用它做什么。
第十四章是针对 Xen 管理员的一组非常实用的技巧。
第十五章是故障排除章节——收集了我们遇到的问题以及我们是如何解决它们的。
我们还包含了关于 Xen 的域配置文件和xm语法的附录。
但我很急躁!
如果你真的迫不及待地想开始使用 Xen,跳到第二章并按照我们的分步指导进行。然后根据你的兴趣浏览书的其余部分。
如果你计划将 Xen 作为服务提供商部署,我们建议按照第二章中的步骤进行,然后阅读第三章、第四章、第五章、第六章、第七章、第八章,可能还有第十一章,最后再通读整本书。
对于那些正在考虑大规模部署 Xen 的读者,你们可能最感兴趣的是第第三章、第四章、第五章、第六章和第七章,以及第十三章来考虑商业 XenSource 产品。但再次强调,我们认为我们在整本书中都提供了有用的信息。
注意
我们尽量使这本书尽可能独立于发行版和版本,除了在教程部分,我们试图非常具体和详细,以及在特定发行版的笔记中,这些笔记必然是,嗯,特定发行版的。
我们经常会陷入一些荒谬的广泛概括,比如“只有白痴才会用 Linux 作为 NFS 服务器。”^([7]) 在合理的情况下,我们尽量添加脚注来限定和缓和偶尔过于尖锐的声明。
^([7]) 实际上,我们也见过笨蛋和白痴也这样做。
第一章。XEN:高级概述

我们将首先解释 Xen 与其他虚拟化技术不同的地方,然后提供一些关于 Xen 如何工作以及其组件如何组合的底层细节。
虚拟化原理
首先,我们可能需要提到,即使是配备现代多任务操作系统的最新、最快的计算机,一次也只能执行一条指令.^([8]) 现在,你说,“但是我的计算机正在同时执行许多任务。甚至现在,我可以看到时钟在运行,听到音乐在播放,下载文件,和朋友们聊天,所有这些都在同一时间进行。”这是真的。然而,实际上发生的情况是,计算机在这些不同任务之间切换得如此之快,以至于延迟变得难以察觉。就像电影是由一系列静态图像组成,给人以运动错觉一样,计算机执行的任务交织得如此紧密,以至于看起来是同时进行的。
虚拟化只是将这个比喻扩展了一点点。通常,这种多路复用是在操作系统的指导下进行的,操作系统的作用是监督任务并确保每个任务都能获得其公平的 CPU 时间。因为操作系统必须因此对任务进行调度以在 CPU 上运行,所以操作系统的这个方面被称为调度器。在 Xen 虚拟化中,发生的过程相同,整个操作系统取代了任务的位置。调度方面由 Xen 内核处理,该内核在“监督”客户操作系统之上运行,因此我们称之为管理程序。
当然,事情并不那么简单——操作系统,即使是经过修改以适应 Xen 的操作系统,也比应用程序使用更不同、更全面的假设集,并且在这些假设之间切换几乎必然涉及更多的复杂性。
因此,让我们看看传统上是如何进行虚拟化的,以及 Xen 的设计是如何新颖和不同的。传统的虚拟机旨在以任何方式模仿真实机器,以至于在虚拟机内部无法判断它不是真实的。为了保持这种错觉,完全虚拟化的机器会拦截尝试访问硬件的尝试,并在软件中模拟该硬件的功能——从而与虚拟机内的应用程序保持完美的兼容性。这一层间接性使得虚拟机非常慢。
Xen 通过一种称为Para 虚拟化的方法绕过这种减速——Para作为前缀意味着类似或并行。正如其名所示,它不是传统意义上的“真实”虚拟化,因为它不试图提供一个无缝的机器幻觉。Xen 仅向托管操作系统呈现底层硬件的部分抽象,将机器的一些方面作为限制暴露给客户操作系统,客户操作系统需要知道它在 Xen 上运行,并相应地处理某些硬件交互。
注意
较新的处理器集成了对硬件虚拟化的支持,允许未经修改的操作系统在 Xen 下运行。有关详细信息,请参阅第十二章。
这些限制中的大多数——出于设计考虑——对系统用户来说并不明显。为了在 Xen 下运行,客户操作系统内核需要修改,以便例如,它向 Xen 请求内存而不是直接分配。Xen 的设计目标之一是在客户操作系统的硬件相关部分进行这些更改,而不改变内核与用户级软件之间的接口。
这个设计目标通过确保现有的二进制文件在 Xen 客户操作系统上无需修改即可运行,并且虚拟机在大多数方面将表现得与真实机器完全一样,至少从系统最终用户的角度来看是这样。
因此,Xen 以高性能的 Para 虚拟化环境为代价,换取了无缝虚拟化。原始 Xen 开发者最初提出这个项目的论文,“Xen 与虚拟化艺术”,^([9]) 强调了这一点,说“Para 虚拟化对于在 x86 等不合作的机器架构上实现高性能和强资源隔离是必要的。”这并不像“Para 虚拟化使计算机变快”那么简单——例如,I/O 可能会导致昂贵的上下文切换,但它通常比其他方法快。我们通常假设 Xen 客户在物理硬件上的运行速度大约是其原生速度的 95%,假设机器上的其他客户空闲。
然而,虚拟化并非仅通过 Para 虚拟化一种方式来运行虚拟机。存在两种竞争性的方法:全虚拟化和操作系统级别的虚拟化。
^([8]) 当然,SMP 和多核 CPU 使得这一点并不完全成立,我们在流水线、超标量执行等方面做了极大的简化,但原则仍然适用——在任何时刻,每个核心只做一件事。
^([9]) 请参阅www.cl.cam.ac.uk/research/srg/netos/papers/2003-xensosp.pdf。
虚拟化技术:全虚拟化
并非所有虚拟化方法都使用 Xen 的方法。虚拟化软件有三种类型。在一种极端情况下,你有完全虚拟化,或仿真,其中虚拟机是硬件的软件模拟,无论是真实的还是虚构的——只要存在驱动程序,这并不重要。这类产品包括 VMware 和 QEMU。
注意
你可能会问,这种虚构的硬件是什么?除了明显的“不真实”答案之外,一个很好的例子是 VTPM 驱动程序。TPM(可信平台模块)硬件相对不常见,但它有一些潜在的代码签名应用——例如,确保正在运行的内核是正确的,而不是由 rootkit 或病毒放置的假内核。因此,Xen 为 domUs 提供了一个虚拟 TPM。
在完全虚拟化的情况下,未经修改的^([10]) 操作系统“托管”一个用户空间程序,该程序模拟一个“客户”操作系统运行的机器。这是一种流行的方法,因为它不需要以任何方式修改客户操作系统。它还有这样的优势,即虚拟化架构可以与主机架构完全不同——例如,QEMU 可以在 IA-32 主机上模拟 MIPS 处理器以及一系列其他芯片。
然而,这种程度的硬件独立性是以巨大的速度惩罚为代价的。未经加速的 QEMU 比本地执行慢一个数量级,而加速的 QEMU 或 VMware ESX 服务器只能在模拟机器与底层硬件相同架构的情况下加速。在这种情况下,对于正常使用来说,全仿真器的硬件多功能性增加并不比 Xen 有显著优势。
VMware 是目前最知名的完全虚拟化产品供应商,拥有强大的工具集、广泛的支持和强大的品牌。VMware 的最近版本通过尽可能在原地运行指令并在必要时动态转换代码来解决速度问题。尽管这种方法很优雅,并且不需要修改客户操作系统,但它不如 Xen 快,因此在生产环境或全职工作环境中不太受欢迎。
^([10]) 或者稍微修改过的操作系统——例如,QEMU 具有 KQEMU 内核模块,它通过允许在可能的情况下直接在处理器上运行来加速模拟代码。
虚拟化技术:操作系统虚拟化
在另一种极端情况下是操作系统级别的虚拟化,其中被虚拟化的是操作系统环境,而不是完整的机器。FreeBSD 监狱和 Solaris 容器采用这种方法。
操作系统虚拟化认为操作系统已经提供,或者至少可以被配置为提供足够的隔离来执行正常虚拟机用户期望的一切——在全局范围内安装软件、在客户机中升级系统库而不影响主机中的库,等等。因此,操作系统虚拟化不是模拟物理硬件,而是使用操作系统功能模拟一个完整的操作系统用户空间。
FreeBSD 监狱和 Solaris 容器(或区域)是两种流行的操作系统级别虚拟化实现。两者都源自经典的 Unix chroot监狱。其想法是,被监禁的进程只能访问位于某个目录下的文件系统的一部分——对于这个进程来说,文件系统的其余部分,简单地讲,是不存在的。如果我们把操作系统安装到那个目录中,它就可以被认为是一个完整的虚拟环境。监狱和区域通过限制某些系统调用并提供虚拟网络接口来扩展这个概念,以增强虚拟机之间的隔离。尽管这非常有用,但它既不如完整的虚拟机有用,也不如灵活。例如,由于监狱共享内核,因此内核恐慌将导致硬件上的所有虚拟机崩溃。
然而,由于它们绕过了虚拟化硬件的开销,虚拟化机器可以与本地执行一样快——事实上,它们就是本地的。
操作系统虚拟化和 Xen 相互补充,在不同的情境下都很有用,甚至可能同时使用。例如,可以想象给用户分配一个单独的 Xen 虚拟机(VM),然后他可以将它分区成多个区域(Zones)供自己使用。
虚拟化:Xen 的方法
最后,在两者之间,有一种叫做半虚拟化的技术,它依赖于操作系统被修改以与一种“超级操作系统”协同工作,我们称之为虚拟管理程序。这正是 Xen 所采用的方法。
半虚拟化的工作原理
Xen 通过引入一个非常小、非常紧凑且专注于硬件的软件片段来工作,该软件直接在硬件上运行并为虚拟化操作系统提供服务。¹¹
Xen 对虚拟化的方法消除了主机操作系统和客户操作系统之间的大部分分裂。全虚拟化和操作系统级别的虚拟化有一个明显的区别——主机操作系统是拥有完全权限的那个。在 Xen 中,只有虚拟管理程序(hypervisor)拥有完全权限,并且它被设计得尽可能小和有限。
与这种“主机/客人”的划分不同,虚拟机管理程序依赖于一个受信任的客人操作系统(domain 0,驱动域,或者更非正式地,dom0)来提供硬件驱动程序、内核和用户空间。这个特权域被独特地区分开来,是虚拟机管理程序允许访问设备并执行控制功能的域。通过这样做,Xen 的开发者确保虚拟机管理程序保持小巧且易于维护,并且尽可能占用最少的内存。图 1-1 展示了这种关系。

Figure 1-1. 这里展示了带有域的虚拟机管理程序。注意虚拟机管理程序直接在硬件上运行,但它本身并不中介对磁盘和网络设备的访问。相反,dom0 直接与磁盘和网络设备交互,为其他域提供服务。在这个图中,domU 1 还充当一个未命名的 PCI 设备的驱动域。
注意
另请参阅“使用 Xen 虚拟机监控器安全访问硬件”,Fraser 等人.^([12]) 此外,还可以存在非-dom0 的驱动域——然而,在没有 IOMMU(I/O 内存管理单元)的情况下,它们在当前硬件上不被推荐,因此这里不会涉及。有关 IOMMU 开发的更多信息,请参阅第十二章。
Domain 0 的特权操作大致分为两类。首先,dom0 作为一个区域,用于管理 Xen。从 dom0 出发,管理员可以控制机器上运行的其它域——创建、销毁、保存、恢复等。网络和存储设备也可以被操作——创建、呈现给内核、分配给 domUs 等。
第二,dom0 对硬件具有独特的特权访问权限。domain 0 的内核拥有通常的硬件驱动程序,并使用它们将硬件设备的抽象导出给虚拟机管理程序,然后传递给虚拟机。想象一下这台机器就像一辆车,dom0 就像是司机。他也是一个乘客,但拥有其他乘客没有的特权和责任。
^([11]) 有些人可能会称 Xen 虚拟机管理程序为微内核,而有些人则不会。
^([12]) 查看 www.cl.cam.ac.uk/research/srg/netos/papers/2004-oasis-ngio.pdf。
Xen 的底层:详细情况
因此,牢记这个虚拟设备的概念,问题变成了:计算机在最低级别需要提供什么?Xen 的开发者深入考虑了这个问题,并得出结论,Xen 必须管理CPU 时间、中断、内存、块设备和网络。
虚拟机管理程序的工作方式与传统操作系统的核心非常相似,将 CPU 时间和资源分发给在其下运行的操作系统,这些操作系统再将其分配给各自的进程。正如现代操作系统可以透明地暂停一个进程一样,Xen 虚拟机管理程序可以暂停一个操作系统,暂时将控制权交给另一个操作系统,然后无缝地重新启动暂停的系统。
由于 Xen 被设计成小巧简单,虚拟机管理程序与其下运行的操作系统使用非常少数量定义良好的接口进行交互,Xen 团队将这些接口称为超调用。
这些超调用取代了标准操作系统的系统调用,具有类似的接口。实际上,它们具有相同的功能——允许用户代码以受信任代码可以控制和管理的的方式进行特权操作。
超调用有几个设计目标和要求。首先,它们是异步的,这样超调用就不会阻塞其他进程或其他操作系统——当一个域等待超调用完成时,另一个域可以获取一些 CPU 时间。其次,它们很小、简单且定义明确——与 Linux 的 300 多个系统调用相比,Xen 只有大约 50 个超调用。最后,超调用使用一个通用的通知系统与 Xen 虚拟机管理程序进行交互。
调度
无论是否进行 Xen 虚拟化,CPU 仍然是一个物理对象,受所有混乱和难以处理的物理现实法则的约束。它一次只能执行一条指令,因此对它注意力的各种需求必须进行调度。Xen 根据客户操作系统发出的指令在 CPU 上调度进程运行,同时根据其自己的计算,确定在任何给定时间哪个客户机应该有权访问 CPU。
每个客户机维护自己的内部队列,指定下一个要运行的指令——本质上就是哪个进程获得 CPU 时间片。在一个普通机器上,操作系统会在物理 CPU 上运行队列头部的进程。(在 Linux 中,是运行队列。)在虚拟机上,它反而会通知 Xen 运行该进程一定时间,以域虚拟术语表示。
客户机还可以与 Xen“预约”时间,根据域虚拟定时器或系统定时器,在稍后请求中断和 CPU 时间。
域虚拟定时器主要用于进程之间的内部调度——domU 内核可以请求虚拟机管理程序在经过一定量的虚拟时间后抢占一个任务并运行另一个任务。请注意,域实际上并不直接在 CPU 上调度进程——这种硬件交互必须由虚拟机管理程序处理。
系统定时器用于对现实世界时间敏感的事件,例如网络。使用系统定时器,域可以暂时放弃 CPU 并请求在适当的时间醒来以填充网络缓冲区或发送下一个 ping。
管理员还可以调整 Xen 用于向域分配资源的调度参数。有几种不同的算法,其有用程度各不相同。有关调度的更多详细信息,请参阅第七章。
中断
在计算机术语中,中断是请求注意的信号。中断通常发生在某些硬件需要与其控制软件(即驱动程序)交互时(即,驱动程序)。传统上,中断必须立即处理,并且所有其他进程都必须等待直到中断处理程序完成。在虚拟化的上下文中,这是明显不可接受的。
因此,Xen 会拦截中断,而不是直接将它们传递给客户域。这允许 Xen 保持对硬件的控制,调度中断服务,而不是仅仅做出反应。域可以提前向虚拟机管理程序注册中断处理程序。然后,当中断到来时,Xen 通知适当的客户域并为其安排执行。在域等待执行时发生的中断会被合并成一个漂亮的包,避免不必要的通知。这也为 Xen 的性能做出了贡献,因为域之间的上下文切换是昂贵的。
内存
虚拟机管理程序对本地化和绝对化的内存都拥有权限。它必须为所有域分配内存,但它只处理物理内存和页表——客户操作系统处理所有其他内存管理功能。
结果证明,这几乎满足了任何明智的实现者的需求。在 x86 架构下,内存管理既困难又晦涩。Xen 的作者以一种经典的低调方式指出,“x86 处理器使用了一种复杂的混合内存管理方案。”图 1-2
图 1-2. 让我们以翻译应用程序给出的地址为例。首先,在左侧,我们有给出的地址。这由段选择器和偏移量组成。MMU 在 GDT(全局描述符表)中查找段选择器,以找到该段在线性地址空间中的位置,这是进程可访问的完整地址空间(通常是 4GB)。然后,偏移量在该段内充当地址。这给处理器提供了一个相对于进程地址空间的线性地址。然后 MMU 将该地址分解为两个索引和一个偏移量——首先它通过页目录找到正确的页表,然后它在页表中找到正确的页,最后它使用偏移量返回一个机器地址——实际的物理内存。
与物理内存一样,虚拟内存是逐字访问的,通过编号的地址。物理地址和虚拟地址之间的映射由 页表 处理,它们将物理内存块与虚拟内存页关联起来。
这种抽象级别甚至适用于机器上只运行一个操作系统的情况。它是虚拟化的基本形式之一,如此普遍以至于大多数非程序员都未注意到。
Xen 在这一点上介入,作为页表的唯一守护者。因为应用程序必须通过 Xen 来更新它们在虚拟内存和物理内存之间的映射,因此虚拟机管理程序可以确保域只能访问其预留的内存——域无法访问的内存不会被映射到任何页面上,因此从域的角度来看,这些内存不存在。图 1-3 展示了虚拟机管理程序、物理内存和伪物理映射之间的关系。
到目前为止一切顺利。x86 通过硬件部分处理这个问题,使用处理器中的一个区域,称为MMU,或内存管理单元。
虽然这种映射应该足以提供内存保护和连续虚拟内存的错觉,但 x86 架构也使用分段来保护内存并增加可寻址内存的数量.^([13]) 应用级地址是逻辑地址,每个地址包括一个 16 位的段选择器和 32 位的段偏移量,处理器然后将这些地址映射到虚拟(或线性)地址,这些地址最终被转换为物理地址。

图 1-3. 虚拟机管理程序的主要作用是验证 domU 对页表的更新,确保 domU 只映射分配给它的内存。domU 直接使用物理页来处理内存,在必要时生成伪物理地址。
然而,在实践中,现代软件通常尽可能避免使用段寄存器——段被简单地等同于整个地址空间,这在实际效果上允许进程忽略它们的实际存在。然而,未使用的分段模型为 Xen 提供了保护其内存预留的完美方式。Xen 虚拟机管理程序在每个域的分配开始处预留一小块内存,并安排域的段,使它们不包含虚拟机管理程序的内存区域。
注意
这导致了常见的 /lib/tls 问题。更多信息请见第十五章。
但等等!还有更多。每个内存段也可以通过环系统来保护,该系统指定了允许按进程访问内存的特权级别。Xen 通过允许虚拟机管理程序在特权环 0 中运行来保护虚拟机管理程序,而客户操作系统使用特权环 1 到 3。这样,处理器可以捕获对保护段开始的访问尝试。
最后,Xen 给这个内存管理塔又增加了一层。因为分配给域的物理内存很可能会碎片化,而且大多数客户操作系统都不期望必须处理这类事情,因此它们必须修改以在硬件和虚拟机之间建立映射,即真实物理和伪物理地址之间的映射。这个映射用于客户操作系统的所有其他组件,以便它们有在连续地址空间中操作的错觉。
因此,客户操作系统页表仍然包含真实机器地址,客户本身将其转换为伪物理地址以供应用程序使用。这有助于 Xen 保持快速,但这也意味着客户不能被信任直接操作页表。
内部更新机制被两个超调用所取代,这些超调用请求 Xen 代表域操作页表。
I/O 设备
显然,domUs 不能被信任独立处理设备。Xen 模型的一部分是,即使是积极恶意的主机域也不应该能够干扰硬件或其他域。所有设备访问都通过虚拟机管理程序进行,dom0 提供辅助。
Xen 通过使用设备通道和虚拟设备来处理域 I/O。这些是在 domU 的前端设备与 dom0 的后端设备之间建立的点对点链接,实现为环形缓冲区,如图图 1-4 所示。(注意,这些与 x86 特权环不同。)

图 1-4。环形缓冲区是一种简单的数据结构,由预分配的内存区域组成,每个区域都带有描述符。当一个实体向环形缓冲区写入时,另一个实体从其中读取,每个实体在过程中更新描述符。如果写入者达到“已写入”块,环形缓冲区已满,它需要等待读取者标记一些块为空。
这些环形缓冲区的重要特性是它们具有固定大小和轻量级——域直接在物理内存上操作,无需虚拟机管理程序的不断干预。在适当的时机,虚拟机会通知虚拟机管理程序它已更新了环形缓冲区,然后虚拟机管理程序采取适当的行动(发送数据包,用数据回复等)。
由于性能原因,环形缓冲区通常包含 I/O 描述符而不是实际数据。数据保存在通过 DMA 访问的单独缓冲区中,Xen 使用类似于内存分配的原则来维护对这些缓冲区的控制。虚拟机管理程序还锁定相关页面,确保应用程序不会尝试将它们赠送或错误使用。
当读取环形缓冲区的内容时,它们会被空描述符替换,这表明缓冲区有空间存储更多数据。同时,读取过程继续到下一个缓冲区条目。在缓冲区末尾,它简单地循环回来。
当环形缓冲区填满时,后端设备会静默地丢弃分配给它的数据。这类似于网络卡或磁盘填满其缓冲区,通常会导致在更方便的时间重新请求数据。
网络
Xen 的网络架构(如图 1-5)设计得尽可能重用代码。Xen 通过设备通道为域和功能提供虚拟网络接口,作为数据包可以从虚拟机域的虚拟接口移动到驱动程序域的虚拟接口的媒介。其他功能留给标准网络工具处理。

图 1-5。domU 使用 netfront 或网络前端驱动程序作为其网络设备,该设备然后将数据包透明地转发到 dom0 中的 netback 驱动程序。数据包随后通过 Linux 软件桥,穿越 Linux 的网络堆栈(包括与 iptables 和其他工具的交互),并最终通过 Linux 的网络驱动程序进入网络。
虚拟机管理程序仅作为数据通道,通过该通道数据包可以从物理网络接口移动到 domU 的虚拟接口。它调解域之间的访问,但不验证数据包或执行会计——这些由 dom0 中的 iptables 规则处理。
因此,虚拟网络接口相对简单——一个用于接收数据包的缓冲区,一个用于发送数据包的缓冲区,以及一个超调用来通知虚拟机管理程序有变化。
另一方面,Xen 的网络配置有很多可定制性,因为你可以使用所有标准的 Linux 工具对虚拟接口进行操作。有关网络信息和如何使用这种几乎无限的力量的建议,请参阅第五章。
块设备
在实际应用中,块设备是指磁盘或类似磁盘的设备。MD 数组、文件系统镜像和物理磁盘都属于块设备的总类别。
Xen 处理块设备的方式与网络设备非常相似。虚拟机管理程序导出虚拟块设备(通常称为 VBDs)到 domUs,并依赖于 dom0 提供后端驱动程序,将真实块设备的函数映射到 VBD。环系统和有限的超调用系统也类似,如图 1-6 所示图 1-6。

图 1-6。domU 请求块设备从 blkfront 或块前端驱动程序开始,该驱动程序在虚拟机管理程序中使用缓冲区与域 0 中的块后端驱动程序交互。然后 Blkback 通过 dom0 的块设备驱动程序(可以是 SCSI 驱动程序、IDE、光纤通道等)读取或写入请求的块。
Xen 依赖于 dom0 创建块设备并提供将物理设备映射到 Xen 虚拟设备的设备驱动程序。
更多关于这方面的信息,请参阅第四章。
^([13]) 对于 AMD64 来说,这是不真实的,因为它完全取消了分段。相反,Xen 在 x86_64 上使用页级保护来保护其内存区域。天地间还有更奇怪的事情,哈罗特。
组合起来
通常,所有这些实现细节都表明 Xen 关注简单性和代码重用。在可能的情况下,Xen 开发者选择专注于提供和管理物理设备与虚拟设备之间的通道,让 Linux 用户空间工具和内核机制处理仲裁和设备访问。此外,实际工作尽可能多地卸载到 dom0,以减少虚拟机管理程序的复杂性并最大化设备支持。
对于管理员来说,这意味着 Xen 可以通过标准工具进行管理和监控,大多数与 Xen 的交互都发生在 dom0 级别。当 Xen 安装并运行域时,Xen 域就像正常的物理机器一样运行,运行未经修改的用户空间程序,但有一些注意事项。让我们继续下一章,看看如何在实践中设置它。
第二章。开始使用

尽管 Xen 的理论基础和实现细节非常吸引人,但我们可能应该转向直接使用 Xen 进行一些实践。毕竟,经验是无法替代的。
所以!欢迎来到 Xen。本章是一个简单的快速入门指南,旨在温和地将 Xen 介绍到你的机器之一。我们将牵着你的手,不会让你放手。
因为这是一个详细的操作指南,我们将给出专注、具体的指令,偏离我们通常的模糊和发行版无关的政策。为了本章的目的,我们假设你正在安装带有 服务器 默认设置和内置 Xen 支持的 CentOS 5.x。
如果你使用的是其他东西,本章可能仍然有用,但你可能需要即兴发挥——目标将是相同的,但步骤可能不同。
红帽 VS. CentOS VS. Fedora
那么,什么是 CentOS,我们为什么要使用它?简短的答案是,CentOS,即 Community ENTerprise OS,是一个基于 RPM 的发行版,源自 Red Hat Enterprise Linux,去除了所有红帽的商标。我们在这里关注它,因为它得到了 Xen 的良好支持,结构上相当通用,并且相当受欢迎。此外,它比 Fedora 更稳定,比红帽的官方产品 Red Hat Enterprise Linux(简称 RHEL)便宜得多。
我们很难推荐 Fedora 用于生产使用,仅仅是因为其发布周期过于快速。虽然红帽精选更新以保证稳定性,但 Fedora 作为红帽的压力锅,更新频率更高。Fedora 在选择内核补丁等方面采用与红帽相同的哲学,但它们发布得更为频繁。(如果你曾经运行过标准的 2.6 内核,你就知道有人需要精选更新,无论是你自己还是你的发行版管理者,才能获得类似企业级的表现。14)Fedora 的发布可以被视为下一个 RHEL 的 alpha 版本,因此,像任何 alpha 软件,我们犹豫是否依赖它。
我们建议使用 CentOS 而不是 Red Hat Enterprise Linux 的原因很简单,那就是 RHEL 非常昂贵。(特别是在 Linux 标准)如果你需要支持,它可能确实值得——但我们坚持使用 CentOS。这是一个好产品,受益于红帽多年来在 Linux 方面的工作,它稳定且易于管理。
红帽公司在整合 Xen 方面的努力显示出特别的优势。红帽已经将 Xen 纳入产品,并做了大量工作。幸运的是,由于 Xen 是开源的,每个人都能从中受益。
通常,本指南的目标如下:
-
确保你的硬件能够运行 Xen。
-
安装一个基本的操作系统。
-
安装 Xen。
-
熟悉 Xen 环境。
-
安装一个 domU。
-
登录到你的 domU 并配置它以确保一切正常工作。
-
休息。
硬件兼容性
首先,确保您的硬件能够运行 Xen。 (几乎肯定可以。)
您只需要一个奔腾 Pro 或更好的处理器,512MiB 的内存,^([15]) 以及几百 MiB 的硬盘空间。如果您做不到这一点,就从沙发垫子里掏出一些零钱,买一台机器。PPro 是在 1996 年推出的,对吧?你没听说吗?这是未来。
目前,Xen 只能在 x86(即英特尔和 AMD)处理器以及 IBM 的 PowerPC 上运行。X86_64 是 x86 指令集的 64 位扩展,在 AMD 和英特尔处理器上得到支持。Xen 还支持英特尔 Itanium。为了这次演练,我们假设您正在使用 x86 或 x86_64 机器。
例如,我们的测试机——选择尽可能普通——是一台三年前的戴尔电脑,配备奔腾 4 处理器、1GB 内存和超出我最大想象的硬盘空间。我个人认为,这一切都太快了,让我感到恶心。
无论如何,你已经拥有了一台能够运行 Xen 的机器。恭喜你。首先,它需要一个基本的操作系统,这样 Xen 才能在其之上运行。
注意
在 之上运行可能不是描述 Xen 与 dom0 操作系统交互的最佳方式,考虑到 dom0 内核是在虚拟机管理程序上运行的,但这是一个方便且常用的短语。我们请求您耐心等待,忠实读者。
^([14]) 我们认识到有些人可能不同意这种观点。
^([15]) 最基本的可能需要 128MiB,但 CentOS 本身需要 256MiB,每个 domU 也需要相当数量的内存。
安装 CentOS
首先,我们将以完全普通的方式安装 CentOS。将安装介质放入驱动器中,从它启动,并根据您的偏好进行安装。我们选择了接受默认分区,这会创建一个小的 /boot 分区,并将驱动器的其余部分分配给 LVM 组,包括用于交换的逻辑卷和根卷。我们还接受了 GRUB 引导加载程序和默认网络配置的默认配置。
注意
现在也是确保您有某种互联网接入的好时机。
设置您的时区并输入 root 密码。目前我们只是在进行标准的 CentOS 安装过程——这可能是您熟悉的领域。按照提示操作。
接下来是包选择。我们选择了 虚拟化服务器 包组,因为它包括了 Xen 虚拟机管理程序和支持工具,其余的保持空白。如果您愿意,您也可以选择安装其他包组,如 GNOME 桌面或服务器-gui 包组,而无需修改本节中的任何步骤。
选择下一步。现在机器将安装您选择的软件包。这可能需要一段时间,具体取决于软件包的选择和安装介质。我们使用 DVD 安装大约花了 15 分钟。安装完成后,机器将重新启动,并给您进行安装后配置的机会——防火墙、服务、SELinux 等等。
在这一点上,您可能希望进行其他与系统配置相关的事情,但不直接与 Xen 相关。请随意。
现在,我们已经准备好创建一个虚拟机。但在开始之前,让我们先看看 Xen 的启动信息,并熟悉 Xen 环境。
THE LIVECD
所以,您下载了 LiveCD?不妨试试。它相当不错,但启动后,它只是另一个操作系统。这捕捉到了 Xen 如此迷人的地方——它的纯粹平凡。毕竟,经过所有这些工作,你最终会坐在一个 Linux 机器前。是的,它会根据需求假装成多个 Linux 机器,但事实上并没有多少“内容”,借用 Gertrude Stein 的一句名言。
尽管 LiveCD 展示了某些有用的功能。例如,它使用写时复制文件系统,以便在虚拟机重启后为每个 Xen 域提供持久的可写存储。LiveCD 还有一些巧妙的脚本,它们使用 XenBus 在 domU 启动时自动弹出 VNC 控制台。(有关更多信息,请参阅第十四章
图 2-1. 成功!Xen 内核想要与我们交谈。
在 GRUB 加载后,它会加载 Xen 虚拟机管理程序,然后接管硬件并输出其初始化行(以(XEN)开头)。然后它加载 dom0 内核,接管并输出我们熟悉且可以容忍的 Linux 启动信息。(请注意,如果您使用的是 VGA 控制台,您可能看不到这些信息,因为它们很快就会过去。您可以通过输入xm dmesg在任何时候查看它们。)
系统启动后,您应该看到正常的登录提示符,几乎没有迹象表明您正在 Xen 虚拟机中运行。(尽管是一个特别授权的虚拟机。)如果您还没有登录,现在是个好时机。
熟悉您的 Xen 系统
在我们开始创建虚拟机之前,让我们简要地看一下 dom0 中的 Xen 配置文件。我们将在未来的章节中经常引用这些文件,所以现在可能是快速浏览的好时机。
首先,是 Xen 配置目录,/etc/xen。大多数(尽管不是全部)的 Xen 配置都是通过文件在这里或 scripts 子目录中完成的。
主要的 Xen 配置文件是 xend-config.sxp。在这里,你会执行诸如启用迁移或指定网络后端等任务。现在,我们将满足于默认设置。
注意
如果你打算将此 Xen 安装用于除了本指南以外的任何目的,现在是一个好时机来设置 xend-config.sxp 中的 (dom-min-mem) 选项为一个合理的值。我们使用 (dom-min-mem 1024)。* 更多详情请见 第十四章。
/etc/xen/scripts 目录包含处理设置虚拟设备等任务的脚本。
最后,域配置文件位于 /etc/xen 中。例如,你可以查看 xmexample1 来查看一个注释丰富的示例配置。
/etc/init.d 目录包含启动和停止 Xen 相关服务的脚本。Xen 控制守护进程 xend 通过 /etc/init.d/xend 脚本作为标准服务运行。虽然你可能不需要修改它,但这可以是一个方便的地方来更改 xend 的参数。这也是重启 xend 的最简单方法,通过运行 /etc/init.d/xend restart。xendomains 脚本也可能引起你的兴趣——它在系统关闭时自动保存域,并在启动时恢复它们。
此外,还有 /boot/grub/menu.lst 文件。这个文件告诉引导加载程序 GRUB 引导 Xen 内核,将 dom0 Linux 内核降级为“模块”行。在这里,你可以更改 Xen 和 Linux 的引导参数。例如,你可能想使用 dom0_mem 虚拟机选项指定 dom0 的固定内存分配,或者通过 Linux 的 nloopbacks 选项增加网络环回设备的数量。
如果你在 CentOS 下使用基于文件的虚拟磁盘,并遵循 virt-install 的默认提示,domU 数据本身位于 /var/lib/xen/images。其他发行版和前端可能有不同的默认设置。
使用 xm 进行管理
你将与 Xen 交互的主要命令是 xm。这个工具有许多子命令。首先,因为我们还在环境中四处查看,所以尝试 xm list:
# xm list
Name ID Mem(MiB) VCPUs State Time(s)
Domain-0 0 934 2 r----- 37.6
xm list 的输出显示了正在运行的域及其属性。在这里,我们看到只有一个域正在运行,即 Domain-0(本书中缩写为 dom0),ID 为 0,内存为 934MiB,两个 VCPUS。它处于“运行”状态,自引导以来已使用了 37.6 秒的 CPU 时间。
注意
Red Hat 官方不支持 xm,尽管他们非官方地期望它将继续在 RHEL 5.x 上工作。因此,xm 的文档可能会宣传一些在 RHEL 或 CentOS 上不工作的功能。RHEL 及其朋友支持的管理工具是* virsh,用于*虚拟化 shell。
你也可以尝试 xm info 来获取更多关于虚拟机管理程序的信息。我们将在后面的章节中介绍更多的 xm 子命令,并在附录 A 中提供完整的列表。
创建 DomU
目前,由于我们想要创建一个 domU,我们最感兴趣的 xm 子命令是 create。然而,在我们能够创建一个域之前,我们需要为它创建一个可以从中引导并用作存储的操作系统镜像。
因为这是一个初步的演练,我们将使用 Red Hat 的 virt-install 工具安装我们的 Xen 镜像。有关构建自己的 domU 镜像的信息,请参阅第三章。
首先,启动 virt-install。它将以交互模式启动,并会与你进行一些对话,如下所示。我们的输入以粗体显示。(如果你决定安装 GUI,也可以使用图形化的 virt-manager 工具。提示信息看起来非常相似。)
# `virt-install`
What is the name of your virtual machine? `prospero`
How much RAM should be allocated (in megabytes)? `256`
What would you like to use as the disk (file path)? `/var/lib/xen/images/prospero.img`
How large would you like the disk (/var/lib/xen/images/prospero.img) to be (in gigabytes)? `4`
Would you like to enable graphics support? (yes or no) `no`
What is the install location? `http://mirrors.kernel.org/centos/5/os/i386`
然后,机器开始交互式地安装 CentOS 网络。现在我们不会深入其操作细节——只需说,已经付出了巨大的努力来保留在物理机上安装操作系统的外观。因此,安装过程应该会令人毛骨悚然地类似于我们在本章开头执行的过程。遵循其提示。(对于好奇者,我们将在第第三章和第第六章中更详细地讨论 virt-install 及其相关工具。)
一旦你完成了选择并完成了安装,机器将重新启动。登录后,通过 shutdown -h now 关闭机器(记住,它是一个普通的 Linux 盒子),这样我们就可以从 dom0 端更详细地查看一些内容。
域配置文件的结构
让我们花一点时间来检查 virt-install 为我们生成的配置文件。正如我们之前提到的,按照惯例,配置文件是 /etc/xen/
# cat /etc/xen/prospero
name = "prospero"
uuid = "9f5b38cd-143d-77ce-6dd9-28541d89c02f"
maxmem = 256
memory = 256
vcpus = 1
bootloader = "/usr/bin/pygrub"
on_poweroff = "destroy"
on_reboot = "restart"
on_crash = "restart"
vfb = [ ]
disk = [ "tap:aio:/opt/xen/images/prospero.img,xvda,w" ]
vif = [ "mac=00:16:3e:63:b7:a0,bridge=xenbr0" ]
如你所见,该文件由简单的 name=value 对组成,其中包含 Python 风格的方括号列表。注意我们在 virt-install 会话中指定的值,插入到适当的位置——名称、内存量和磁盘镜像。virt-install 还填写了一些网络配置,指定了 MAC 地址和 dom0 级别的桥接设备。
我们将在后续章节中更深入地检查许多配置文件参数。现在,让我们继续看看这些值对我们域的影响。
配置 DomU
最后,启动镜像!我们将使用 xm 和 create 子命令,它期望一个配置文件名作为参数。我们可以省略路径,因为它默认在 /etc/xen 中查找。
# `xm create -c prospero`
由于我们向 xm create 传递了 -c 选项,它将立即将我们连接到域的控制台,这样我们就可以与引导加载程序交互。按回车键使用默认选项启动,并观察其运行情况。
启动后,您应该会看到一个新的 Xen domU 的控制台,如图 2-2 所示。Figure 2-2 所示。以 root 身份登录并尽情享受。
首先,查看 domU 内部的 dmesg 命令的输出。请注意,磁盘和网络设备是 Xen 的特殊半虚拟化设备。

图 2-2. 我们向您保证这是 domU 控制台。
您还可以查看 domU 的网络设置,它与普通 Linux 系统的网络设置基本无法区分:
# ifconfig eth0
eth0 Link encap:Ethernet HWaddr 00:16:3E:63:B7:A0
inet addr:216.218.223.74 Bcast:216.218.223.127 Mask:255.255.255.192
inet6 addr: 2001:470:1:41:a800:ff:fe53:314a/64 Scope:Global
inet6 addr: fe80::a800:ff:fe53:314a/64 Scope:Link
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
RX packets:73650errors:0 dropped:0 overruns:0 frame:0
TX packets:49731 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
TX bytes:106033983 (101.1 MiB) RX bytes:2847950 (2.7 MiB)
注意,我们正在使用标准命令——Xen 的一个主要特性是大多数管理操作都通过熟悉的 Linux 命令进行。这使得自定义 Xen 环境变得容易,通常是通过修改支持脚本来实现。此外,标准命令通常以预期的方式运行——例如,您可以通过 ifconfig 给自己分配一个新的 IP 地址,它将像在物理机上一样工作.^([16])
让我们暂时回到 dom0,从外部看一下正在运行的域。要退出 domU 的控制台,请输入 CTRL-]。您可以在任何时候通过在 dom0 中运行 xm console <domU 名称或 ID> 来重新连接。
现在我们回到了 dom0,我们可以注意到我们的新域在 xm list 中显示,消耗内存和 CPU 时间:
# xm list
Name ID Mem(MiB) VCPUs State Time(s)
Domain-0 0 739 2 r----- 136.7
prospero 1 255 1 -b---- 116.1
并且它有一个可见的网络设备:
# ifconfig vif1.0
vif1.0 Link encap:Ethernet HWaddr FE:FF:FF:FF:FF:FF
inet6 addr: fe80::fcff:ffff:feff:ffff/64 Scope:Link
UP BROADCAST RUNNING NOARP MTU:1500 Metric:1
RX packets:49731 errors:0 dropped:0 overruns:0 frame:0
TX packets:73650 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:32
RX bytes:2847950 (2.7 MiB) TX bytes:106033983 (101.1 MiB)
关于网络设备的一些要点:首先,它有一个虚拟的 MAC 地址。您可以在 domU 内部看到虚拟以太网设备的实际 MAC 地址。其次,计数器是相反的——域实际上下载了 100MiB,并传输了 2.7。第三,IPv4 和 IPv6 在默认设置下“正常工作”。我们将在第五章中进一步详细介绍。
从这里您可以将域当作任何其他 Linux 服务器来处理。您可以在其上设置用户,通过 SSH 连接到它,或通过 xm console 访问其控制台。您可以通过 xm reboot 命令重新启动它,并使用 xm shutdown 命令关闭它。
^([16]) 管理员可以禁用此功能。您仍然可以从 domU 更改 IP 地址,但 dom0 将阻止来自新 IP 的流量。有关详细信息,请参阅第五章。
您已完成。请享用饼干。
现在您已经有一个域了,请阅读下一章。
如果它不起作用……那将是一个检查第十五章的绝佳机会。我们很抱歉。请给我们发邮件并说明我们的指示需要改进。
第三章。配置 DOMU
你可以通过下载正确的文件并将它们放在正确的位置,就像是从空气中吸取 Linux 一样,但可能世界上只有几百人能够以这种方式创建一个功能齐全的 Linux 系统。
——尼尔·斯蒂芬森,《命令行起源》
到目前为止,我们一直专注于管理 dom0,将 domU 创建的具体细节留给virt-install工具。然而,你有时可能需要从头开始构建 domU 镜像。这样做有很多原因——也许你想要一个绝对最小的 Linux 环境,用作虚拟专用服务器(VPS)托管设置的基准。也许你正在使用 Xen 部署一些自定义应用程序——一个服务器设备。这可能只是保持系统更新的好方法。可能你需要在没有网络连接的情况下创建 Xen 实例。
正如有许多原因想要定制的文件系统镜像一样,也有许多方法可以制作这些镜像。我们将详细说明我们经常使用的某些方法,并简要提及一些其他方法,但提供详尽的列表是不可能的(而且会很无聊)。本章的目标是给你一个关于配置 domU 文件系统选项的范围、对原理的熟练掌握,以及足够的逐步指导,以便熟悉这些流程。
基本 DomU 配置
我们在这里展示的所有示例都应该与一个基本的——实际上,可以说是骨架般的——domU 配置文件兼容。以下这样的配置应该可以工作:
kernel = /boot/vmlinuz-2.6-xen.gz
vif = ['']
disk = ['phy:/dev/targetvg/lv,sda,w']
这指定了一个内核、一个网络接口和一个磁盘,并允许 Xen 使用默认值来处理其他所有事情。根据你的站点调整变量,例如卷组和内核名称。正如我们在其他地方提到的,我们建议包括其他变量,例如 MAC 地址和 IP 地址,但为了清晰起见,我们将在本章中省略它们,以便我们能够专注于创建 domU 镜像。
注意
这不包括 ramdisk。你可以添加一个 ramdisk= 行,或者包括 xenblk (如果你计划在模块可用之前访问网络)和 xennet 。当我们编译自己的内核时,我们通常直接在内核中包含 xenblk 和 xennet 驱动程序。我们只使用 ramdisk 来满足发行版内核的要求。
如果你使用的是模块化内核,这非常可能,你还需要确保内核有一个与之匹配的模块集,可以从 domU 文件系统中加载。如果你使用与 dom0 相同的内核引导 domU,你可以像这样复制模块(如果 domU 镜像挂载在/mnt):
# mkdir -p /mnt/lib/modules
# cp -a /lib/modules/`uname -r` /mnt
注意,此命令仅在 domU 内核与 dom0 内核相同的情况下才有效!某些安装程序会自动安装正确的模块;而其他则不会。无论你如何创建 domU,都要记住,模块需要从 domU 中可访问,即使内核位于 dom0 中。如果你遇到麻烦,请确保内核和模块版本匹配,可以通过从不同的内核引导或复制不同的模块来实现。
选择内核
传统上,人们使用存储在 dom0 文件系统中的内核引导 domU 镜像,就像上一节中的示例配置文件一样。在这种情况下,通常使用与 domUs 和 dom0 相同的内核。然而,这可能会导致问题——一个发行版的内核可能过于专业化,无法与另一个发行版正确工作。我们建议使用适当的发行版内核,将其复制到 dom0 文件系统中,以便域构建者可以找到它,或者编译自己的通用内核。
另一个可能的选择是下载 Xen 的二进制发行版,其中包含预编译的 domU 内核,并从中提取适当的 domU 内核。
或者(当我们处理带有 Xen 感知内核的发行版时,我们通常使用这个选项),你可以绕过整个内核选择的问题,并使用 PyGRUB 在 domU 文件系统中引导发行版的自身内核。有关 PyGRUB 的更多详细信息,请参阅第七章。PyGRUB 还通过在 domU 中保留 domU 内核及其相应模块,使得将模块与内核匹配更加直观。
通过 tar 快速安装
让我们先考虑最基本可能的安装方法,以便了解涉及的原则。我们将通过从 dom0(或一个完全独立的物理机器)复制文件到 domU 来生成一个根文件系统。这种方法复制了一个已知可以工作的文件系统,不需要特殊工具,并且易于调试。然而,这也可能导致 domU 被来自源系统的大量不必要的东西污染,而且工作量也相当大。
对于这种“牛仔”方法,可能有一组好的命令:
# xm block-attach 0 duncan.img /dev/xvda1 w 0
# mke2fs -j /dev/xvda1
# mount /dev/xvda1 /mnt
# cd /
# tar -c -f - --exclude /home --exclude /mnt --exclude /tmp --exclude \
/proc --exclude /sys --exclude /var | ( cd /mnt/ ; tar xf - )
# mkdir /mnt/sys
# mkdir /mnt/proc
注意
所有这些操作都需要以 root 身份执行。
按顺序,这些命令将后端文件映射到 dom0 中的虚拟设备,在该设备上创建一个文件系统,挂载该文件系统,并使用 tar 将 dom0 根目录打包,同时排除/home、/mnt、/tmp、/proc、/sys和/var。然后,此tar命令的输出将用于辅助tar,用于在/mnt中提取文件。最后,我们创建一些 domU 启动后需要的目录。在此过程结束时,我们在duncan.img中有一个自包含的 domU。
为什么这不是最佳方案
除了其基本的不优雅之外,牛仔式方法的最大问题是它复制了大量的不必要的东西,而且没有简单的方法来清除它们。当 domU 启动时,您可以使用包管理器来删除东西,或者手动删除文件。但这是一项工作,而我们都在避免工作。
需要留意的事项
有几点需要注意:
-
您必须创建
mkdir /sys和/proc,否则事情将无法正常工作。这里的问题是 Linux 启动过程使用/sys和/proc来发现和配置硬件——如果,比如说,/proc/mounts不存在,引导脚本将变得非常烦恼。
-
您可能需要
mknod /dev/xvda b 220 0。/dev/xvd是 Xen 虚拟磁盘的标准名称,类似于hd和sd设备节点。第一个虚拟磁盘是/dev/xvda,它可以分区为/dev/xvda1,依此类推。命令
# /mknod /dev/xvda b 220 0创建节点/dev/xvda作为主设备号为 220(为 Xen VBDs 保留的数字)和次设备号为 0(因为它叫做xvda——系统中的第一个此类设备)的块设备(b)。
注意
在大多数现代 Linux 系统中,udev 使得这一点变得不再必要。
-
您可能需要编辑/etc/inittab和/etc/securettys,以便/dev/xvc0作为控制台工作,并具有适当的
getty。我们仅在 Red Hat 的内核中发现了这个问题:对于常规的 XenSource 内核(至少到 3.1 版本),tty0 上的默认
getty应该无需您进一步操作即可正常工作。如果它不起作用,请继续阅读!术语控制台是从大型分时机器时代遗留下来的,当时系统操作员坐在一个称为系统控制台的专用终端上。如今,控制台是一个接收系统管理消息的设备——通常是图形设备,有时是串行控制台。
在 Xen 的情况下,所有输出都发送到 Xen 虚拟控制台
xvc0。xm console命令通过xenconsoled的帮助连接到这个设备。要登录,Xen 的虚拟控制台必须添加到/etc/inittab中,以便init知道连接一个getty。^([17]) 通过添加如下类似的行来完成此操作:xvc:2345:respawn:/sbin/agetty -L xvc0(与书中所有示例一样,不要过于字面地理解这个结构!例如,如果您有一个不同名称的
getty二进制文件,您肯定希望使用那个而不是这个。)根据您对 root 登录策略的规定,您可能还需要将/dev/xvc0添加到/etc/securetty中,以便 root 能够通过它登录。只需在文件中添加一行包含设备名称xvc0的行即可。
^([17]) getty为您提供一个登录提示。你以为它们是凭空出现的吗,不是吗?
使用带有备用根的包管理系统
获取 domU 镜像的另一种方法是通过运行您选择的发行版的设置程序,并指示它安装到挂载的 domU 根目录。这里的缺点是,大多数设置程序都期望在真实机器上安装,并且当被迫处理虚拟化时,它们会变得固执和不可合作。
尽管如此,这对于大多数安装程序来说都是一个可行的过程,包括基于 RPM 和 Debian 的发行版。我们将描述使用 Red Hat 和 Debian 的工具进行安装。
红帽、CentOS 和其他基于 RPM 的发行版
在基于 Red Hat 的系统上,我们将此视为包安装,而不是系统安装。因此,我们不是使用系统安装程序anaconda,而是使用yum,它具有适合此类操作的安装模式。
首先,最简单的方法是确保 SELinux 被禁用或非强制执行,因为它的扩展权限和策略与安装程序不兼容。最快的方法是执行echo 0 >/selinux/enforce。一个更永久的方法是在内核命令行上使用selinux=0来引导。
注意
在加载 Linux 内核的“模块”行上指定内核参数作为空格分隔的列表——无论是在 /boot/grub/menu.lst 中还是在 GRUB 菜单中按 e 键。
完成后,将目标 domU 镜像挂载到适当的位置。在这里,我们在卷组*scotland*中创建逻辑卷*malcom*,并将其挂载到*/mnt*:
# lvcreate -L 4096 -n malcom scotland
# mount /dev/scotland/malcom /mnt/
创建一些重要的目录,就像在tar示例中一样:
# cd /mnt
# mkdir proc sys etc
创建基本的fstab(您可以直接从 dom0 复制并适当编辑根设备——使用前面提到的示例配置文件,您将使用/dev/sda):
# cp /etc/fstab /mnt/etc
# vi /mnt/etc/fstab
修复modprobe.conf,以便内核知道其设备驱动程序的位置。(这一步在技术上不是必需的,但它使得在内核更改时yum upgrade能够正确构建新的 initrd——如果您使用 PyGRUB,这将很有用。)
# echo "alias scsi_hostadapter xenblk\nalias eth0 xennet" > /mnt/etc/modprobe.conf
在这一点上,你需要一个描述软件发布版本并创建yum配置文件的 RPM 包——我们安装了 CentOS 5,所以我们使用了centos-release-5.el5.centos.i386.rpm。
# wget http://mirrors.prgmr.com/os/centos/5/os/i386/CentOS/centos-release-5.el5.centos.i386.rpm
# rpm -ivh --nodeps --root /mnt centos-release-5.el5.centos.i386.rpm
通常,CentOS 发布 RPM 包括次要版本号,但很难找到旧版本。请参阅同一目录下的*README.prgmr*文件以获取完整说明。
接下来,我们在新的安装树中安装yum。如果我们在此安装其他包之前不这样做,yum将抱怨事务错误:
# yum --installroot=/mnt -y install yum
现在目录已经适当填充后,我们可以使用yum来完成安装。
# yum --installroot=/mnt -y groupinstall Base
那就是全部内容。像往常一样创建一个 domU 配置文件。
使用 Debian 和 Ubuntu 的 Debootstrap
Debootstrap 要容易得多。为安装创建一个目标(使用 LVM 或平面文件),挂载它,然后使用 debootstrap 在该目录中安装基本系统。例如,在 x68_64 机器上安装 Debian Etch:
# mount /dev/scotland/banquo /mnt
# debootstrap --include=ssh,udev,linux-image-xen-amd64 etch /mnt http://mirrors.easynews.com/
linux/debian
注意 --include= 选项。因为 Xen 的网络需要热插拔系统,domU 必须包含一个带有支持脚本的 udev 的工作安装。(我们还包括了 SSH,只是为了方便并演示多个项目的语法。)如果你在 i386 平台上,请将 libc6-xen 添加到包含列表中。最后,为了确保我们有兼容的内核和模块集,我们向 include= 列表中添加一个合适的内核。我们使用 linux-image-xen-amd64。为你的硬件选择一个合适的内核。
如果你想使用 PyGRUB,在运行 debootstrap 之前,创建 /mnt/etc/modules 文件,并将以下内容放入该文件中:
xennet
xenblk
此外,创建一个 /mnt/boot/grub/menu.lst 文件,就像在物理机器上做的那样。
如果你没有计划使用 PyGRUB,请确保从 dom0 可以访问适当的 Debian 内核和 ramdisk,或者确保在 domU 中有与你的计划内核匹配的模块。在这种情况下,我们将把 sdom0 内核模块复制到 domU。
# cp -a /lib/modules/<domU kernel version> /mnt/lib/modules
当这一切都完成后,将 /etc/fstab 复制到新系统,如有必要进行编辑:
# cp /etc/fstab /mnt/etc
重命名网络设备
Debian,像许多系统一样,使用 udev 将 eth0 和 eth1 绑定到一致的物理设备。它是通过根据以太网设备的 MAC 地址分配设备名称(ethX)来实现的。这将在 debootstrap 过程中完成——这意味着它会将 eth0 绑定到你运行 debootstrap 的机器的 MAC 地址。反过来,domU 的以太网接口,假设有一个不同的 MAC 地址,将变成 eth1。^([19]) 你可以通过删除 /mnt/etc/udev/rules.d/z25_persistent-net.rules 文件来避免这种情况,该文件包含 MAC 地址和设备名称之间的存储映射。下次重启时,该文件将被重新创建。如果你只有一个接口,可能需要删除生成该文件的文件,即 /mnt/etc/udev/rules.d/z45_persistent-net-generator.rules。
# rm /mnt/etc/udev/rules.d/z25_persistent-net.rules
最后,卸载安装根。此时,你的系统应该基本上可以工作了。你可能想要更改主机名并编辑 domU 文件系统中的 /etc/inittab,但这些步骤完全是可选的。
# umount /mnt
通过创建一个配置文件来测试新的安装,如之前所述(例如,/etc/xen/banquo)并执行以下命令:
# xm create -c /etc/xen/banquo
^([18]) 虽然我们并不赞同在遇到麻烦的第一时间就禁用 SELinux 的趋势,但我们决定走阻力最小的路线。
^([19]) 或者另一个设备,具体取决于原始机器有多少个以太网设备。
QEMU 安装
我们最喜欢的创建 domU 镜像的方法——最接近真实机器的方法——可能是使用 QEMU 安装,然后使用已安装的文件系统作为你的 domU 根文件系统。这允许你,安装者,利用你多年安装 Linux 的经验。因为它是安装在像 Xen 一样强分区的虚拟机中,所以安装程序不太可能做任何令人惊讶的事情,更不可能与现有系统发生不良交互。QEMU 也与所有发行版以及非 Linux 操作系统一样工作得很好。
QEMU 的确存在速度慢的缺点。因为 KQEMU(内核加速模块)与 Xen 不兼容,你将不得不退回到仅软件的全仿真。当然,你可以仅为此初始镜像创建步骤使用它,然后根据需要复制原始磁盘镜像,在这种情况下,速度惩罚变得不那么重要。
QEMU 与 Xen 的关系
你可能已经注意到 QEMU 在与 Xen 相关的内容中经常被提及。这有一个很好的原因:这两个项目是互补的。尽管 QEMU 是一个 纯 或 经典 的全仿真器,但 QEMU 和 Xen 的需求有一些重叠。例如,Xen 可以使用 QCOW 图像进行磁盘仿真,并在硬件虚拟化模式下运行时使用 QEMU 的完全虚拟化驱动程序。QEMU 还为 Linux 内核中内置的硬件虚拟化(KVM,即内核虚拟机)和 win4lin 提供了一些代码,基于没有必要重新发明轮子的理论。
Xen 和 QEMU 并不相同,但普遍认为它们很好地互补,Xen 更适合高性能的生产环境,而 QEMU 则更专注于精确仿真。Xen 和 QEMU 的开发者已经开始共享补丁并共同工作。它们是不同的项目,但 Xen 开发者承认 QEMU “在 Xen 的成功中发挥了关键作用。”^([21])
这种技术通过在安装期间将 QEMU 作为纯仿真器运行,使用仿真设备来实现。首先获取并安装 QEMU。然后运行:
# qemu -hda /dev/scotland/macbeth -cdrom slackware-11.0-install-dvd.iso -boot d
此命令以目标设备(在这种情况下为逻辑卷)作为其硬盘驱动器,以安装介质作为其虚拟 CD 驱动器的方式运行 QEMU。(这里的 Slackware ISO 只是一个例子——安装你喜欢的任何东西。)-boot d 选项告诉 QEMU 从仿真 CD 驱动器启动。
现在像往常一样将安装到虚拟机中。最后,你应该有一个完全功能的 domU 镜像。当然,你仍然需要创建适当的 domU 配置文件,并从 dom0 端处理其他必要的配置,但所有这些都相对容易自动化。
最后一个需要注意的警告需要重复提及,因为它适用于许多这些安装方法:如果 domU 内核不是 Xen 兼容的,那么你将不得不使用 dom0 的内核,或者挂载 domU 并替换其内核。
^([20]) 尽管我们没有广泛介绍 KVM,但它也是一种有趣的虚拟化技术。更多信息可以在 KVM 网页上找到,kvm.sf.net/.
^([21]) Liguori, Anthony, "Merging QEMU-DM upstream," www.xen.org/files/xensummit_4/Liguori_XenSummit_Spring_2007.pdf.
virt-install—Red Hat 的单步 DomU 安装程序
Red Hat 选择支持通用的虚拟化 概念 而不是特定的 技术。他们的方法是将虚拟化封装在一个抽象层,libvirt。然后 Red Hat 提供支持软件,该软件使用这个库来替代虚拟化包特定的控制软件.^([22])(有关 libvirt 管理端的信息,virt-manager,请参阅第六章。)
例如,Red Hat 包括 virsh,这是一个控制虚拟机的命令行界面。xm 和 virsh 做的事情几乎相同,使用非常相似的命令。然而,virsh 和 libvirt 的优势在于,如果你决定切换到另一种虚拟化技术,virsh 接口将保持一致。目前,例如,它可以使用一组一致的命令控制 QEMU 和 KVM,以及 Xen。
该系统的安装组件是 virt-install。像 virsh 一样,它建立在 libvirt 之上,libvirt 为不同的虚拟化包提供了一个平台无关的包装。无论你使用哪种虚拟化后端,virt-install 都是通过提供一个标准网络安装方法的环境来工作的:首先它会询问用户配置信息,然后它会写入适当的配置文件,创建一个虚拟机,从安装介质加载内核,并最终使用标准的 Red Hat 安装程序 anaconda 引导网络安装。此时 anaconda 接管,安装按正常流程进行。
不幸的是,这意味着 virt-install 只能与可网络访问的 Red Hat 风格目录树一起工作。(其他发行版没有安装布局符合安装程序期望。)如果你计划将 Red Hat、CentOS 或 Fedora 标准化,这没问题。否则,这可能会成为一个严重问题。
虽然 virt-install 通常在 Red Hat 的 virt-manager 图形用户界面中调用,但它也是一个独立的可执行文件,你可以手动以交互式或脚本模式使用它。以下是一个 virt-install 会话示例,其中我们的输入以粗体显示。
# /usr/sbin/virt-install
Would you like a fully virtualized guest (yes or no)? This will allow you to
run unmodified operating systems. `no`
What is the name of your virtual machine? `donalbain`
How much RAM should be allocated (in megabytes)? `512`
What would you like to use as the disk (path)? `/mnt/donalbain.img`
How large would you like the disk (/mnt/donalbain.img) to be (in gigabytes)? `4`
Would you like to enable graphics support? (yes or no) `no`
What is the install location?
`ftp://mirrors.easynews.com/linux/centos/4/os/i386/`
大多数这些输入都是不言自明的。请注意,安装位置可以是ftp://、http://、nfs:或 SSH 风格的路径(user@host:/path)。所有这些在必要时都可以是本地的——例如,本地的 FTP 或本地 HTTP 服务器是一个完全有效的来源。图形支持表示是否使用虚拟帧缓冲区——它调整配置文件中的vfb=行。
这是根据输入生成的配置文件:
name = "donalbain"
memory = "512"
disk = ['tap:aio:/mnt/donalbain.img,xvda,w', ]
vif = [ 'mac=00:16:3e:4b:af:c2, bridge=xenbr0', ]
uuid = "162910c8-2a0c-0333-2349-049e8e32ba90"
bootloader = "/usr/bin/pygrub"
vcpus = 1
on_reboot = 'restart'
on_crash = 'restart'
关于virt-install的配置文件,有一些优点我们想提及。首先,请注意virt-install使用 tap 驱动程序访问磁盘镜像,以提高性能。(有关 tap 驱动程序的更多详细信息,请参阅第四章。)
它还将磁盘作为xvda导出到客户操作系统,而不是作为 SCSI 或 IDE 设备。生成的配置文件还包括为每个vif随机生成的 MAC 地址,使用分配给 Xen 的00:16:3e前缀。最后,该镜像使用 PyGRUB 启动,而不是在配置文件中指定内核。
^([22]) libvirt 本身并没有什么固有的Red Hat 特定之处,但 Red Hat 目前正在推动其采用。更多信息请参见libvirt.org/。
转换 VMware 磁盘镜像
虚拟化的一大优点是它允许人们分发虚拟设备——完整的、准备好运行、预先配置好的操作系统镜像。VMware 在这方面一直推动得最为积极,但只要稍加努力,就可以使用 VMware 预构建的虚拟机与 Xen 兼容。
PYGRUB、PYPXEBOOT 和朋友们
PyGRUB、pypxeboot 和类似程序背后的原理是,它们允许 Xen 的域构建器加载一个无法直接从 dom0 文件系统中访问的内核。这反过来又提高了 Xen 对真实机器的模拟。例如,使用 PXE 的自动化配置工具可以在不修改的情况下配置 Xen 域。这在 domU 镜像的上下文中尤为重要,因为它允许镜像成为一个自包含的包——在顶层放置一个通用的配置文件,就可以立即使用。
PyGRUB 和 pypxeboot 分别取代了物理机的类似实用程序:GRUB 和 PXEboot。两者都是用 Python 编写的仿真程序,专门用于与 Xen 一起工作。两者都能从普通加载器无法找到的地方获取内核。而且两者都可以帮助你在日常工作中,作为不幸的 Xen 管理员。
关于设置 PyGRUB 的更多说明,请参阅第七章。有关 pypxeboot 的更多信息,请参阅安装 pypxeboot。安装 pypxeboot。
其他虚拟化提供商基本上使用比 Xen 更复杂的磁盘格式——例如,它们包括配置或提供快照。Xen 的方法是将这类功能留给 dom0 中的标准工具。因为 Xen 尽可能使用开放格式和标准工具,所以其磁盘镜像仅仅是……文件系统。^([23)]
因此,将虚拟设备转换为与 Xen 兼容的最大部分在于转换磁盘镜像。幸运的是,qemu-img支持您可能遇到的大多数镜像格式,包括 VMware 的.vmdk或虚拟机磁盘格式。
转换过程相当简单。首先,获取一个 VMware 镜像进行测试。在www.vmware.com/appliances/directory/有一些不错的选择。
接下来,获取镜像并使用qemu-img将其转换为 QCOW 或原始镜像:
# qemu-img convert foo.vmdk -o qcow hecate.qcow
此命令将foo.vmdk的内容复制到名为hecate.qcow的 QCOW 镜像中(因此有-o qcow,表示输出格式)。(QCOW,顺便说一下,是由 QEMU 仿真器起源的磁盘镜像格式。它支持 AES 加密和透明解压缩。它也由 Xen 支持。有关使用 QCOW 镜像与 Xen 的更多详细信息,请参阅第四章。)在此阶段,您可以像通常一样引导它,如果它是 Xen 感知的或您正在使用 HVM,则通过 PyGRUB 加载内核;否则,在 dom0 中使用标准 domU 内核。
不幸的是,这不会生成适合用 Xen 引导镜像的基本配置文件。但是,应该很容易创建一个基本的配置文件,使用 QCOW 镜像作为其根设备。例如,这里有一个相当简化的通用配置,尽可能依赖默认值:
name = "hecate"
memory = 128
disk = ['tap:qcow:/mnt/hecate.img,xvda,w' ]
vif = [ '' ]
kernel = "/boot/vmlinuz-2.6-xenU"
注意,我们正在使用 dom0 文件系统中的内核,而不是像通常建议的那样通过 PyGRUB 从 VMware 磁盘镜像中加载内核。这样做是为了我们不必担心该内核是否与 Xen 兼容。
RPATH'S RBUILDER: 一种新的方法
RPath 相当有趣。它可能不值得进行深入讨论,但他们在构建虚拟机的方法上很酷。整洁。优雅。
RPath 首先关注机器打算运行的应用程序,然后使用软件来确定机器需要哪些软件来运行它,通过检查库依赖关系、注意哪些配置文件被读取等。这种方法的承诺是提供紧凑、调优、精细的虚拟机镜像,具有已知特性——同时保持管理大型系统所需的高度自动化。
他们的网站是rpath.org/。他们提供了一系列预配置的虚拟机,旨在测试和部署。(注意,尽管我们认为他们的方法值得提及,但我们与 rPath 没有任何关联。不过,您可能想尝试一下。)
^([23]) 除了它们是 QCOW 图像时。现在我们先忽略这一点。
大规模部署
当然,所有这些都与更广泛的 配置基础设施 问题以及更高层次的工具(如 Kickstart、SystemImager 等)有关。Xen 通过指数级增加您拥有的服务器数量并使上线另一台服务器变得容易和快速来放大这个问题。这意味着您现在需要能够自动部署大量主机。
手动部署
最基本的方法(类似于tarring up a filesystem)可能是使用我们讨论过的任何方法构建一个单一的 tarball,然后编写一个脚本,该脚本分区、格式化和挂载每个 domU 文件,然后提取 tarball。
例如:
#!/bin/bash
LVNAME=$1
lvcreate -C y -L 1024 -n ${LVNAME} lvmdisk
parted /dev/lvmdisk/${LVNAME} mklabel msdos
parted /dev/lvmdisk/${LVNAME} mkpartfs primary ext2 0 1024
kpartx -p "" -av /dev/lvmdisk/${LVNAME}
tune2fs -j /dev/mapper/${LVNAME}1
mount /dev/mapper/${LVNAME}1 /mountpoint
tar -C /mountpoint -zxf /opt/xen/images/base.tar.gz
umount /mountpoint
kpartx -d /dev/lvmdisk/${LVNAME}
cat >/etc/xen/${LVNAME} <<EOF
name = "$LVNAME"
memory = 128
disk = ['phy:/dev/lvmdisk/${LVNAME},xvda,w']
vif = ['']
kernel = "/boot/vmlinuz-2.6-xenU"
EOF
exit 0
此脚本接受一个域名作为参数,从 /opt/xen/images/base.tar.gz 的 tarball 中配置存储,并为基本域写入一个配置文件,包含 1GB 的磁盘空间和 128MB 的内存。对此脚本进行进一步扩展,如往常一样,很容易想象。我们在这里放置此脚本主要是为了展示如何使用 Xen 快速创建大量 domU 图像。接下来,我们将转向更复杂的配置系统。
QEMU 和您的现有基础设施
另一种进行大规模配置的方法是使用 QEMU,扩展我们之前概述的 QEMU 安装。因为 QEMU 模拟物理机器,您可以使用 QEMU 上的现有配置工具——实际上是将虚拟机完全当作物理机来对待。例如,我们已经使用 SystemImager 在模拟机器上执行自动安装。
这种方法可能是最灵活的(并且最有可能与您当前的配置系统集成),但它很慢。记住,KQEMU 和 Xen 不兼容,所以您正在运行老式的、仅软件的 QEMU。慢!而且没有必要这么慢,因为一旦创建了一个虚拟机,就没有什么可以阻止您复制它而不是再次通过整个流程。但是它有效,并且与您之前的配置系统完全一样有效.^([24])
我们将描述一个使用 SystemImager 和 QEMU 的基本设置,这应该足以推广到您现有的任何配置系统。
设置 SystemImager
首先,使用您选择的方法安装 SystemImager——yum、apt-get、从 wiki.systemimager.org/ 下载——随便哪种。我们使用 sis-install 脚本从 SystemImager 下载了 RPM:
# wget http://download.systemimager.org/pub/sis-install/install
# sh install -v --download-only --tag=stable --directory. systemconfigurator
\ systemimager-client systemimager-common systemimager-i386boot-standard \
systemimager-i386initrd_template systemimager-server
SystemImager 通过获取一个“金光客户”的系统镜像,在服务器上托管该镜像,然后将镜像自动分发到目标。在 Xen 的情况下,这些组件——金光客户、服务器和目标——都可以存在于同一台机器上。我们假设服务器是 dom0,客户端是通过其他方法安装的 domU,目标是新的 domU。
首先在服务器上安装依赖项systemconfigurator:
# rpm -ivh systemconfigurator-*
然后安装服务器包:
# rpm -ivh systemimager-common-* systemimager-server-* \
systemimager-i386boot-standard-*
使用xm create引导黄金客户端并安装软件包(注意我们是在 domU 而不是 dom0 中执行以下步骤):
# scp user@server:/path/to/systemimager/* .
# rpm -ivh systemconfigurator-*
# rpm -ivh systemimager-common-* systemimager-client-* \
systemimager-i386boot-initrd_template-*
SystemImager 从黄金客户端生成镜像的过程相当自动化。它使用rsync从客户端复制文件到镜像服务器。确保两个主机可以通过网络通信。完成这些后,在客户端运行:
# si_prepareclient --server <server address>
然后在服务器上运行:
# si_getimage --golden_client <client address> --image porter --exclude /mnt
服务器将连接到客户端并构建镜像,使用名称porter。
现在,您准备好配置服务器以实际提供镜像了。首先运行si_mkbootserver脚本并回答它的问题。它将为您配置 DHCP 和 TFTP。
# si_mkbootserver
然后回答有关客户端的更多问题:
# si_mkclients
最后,使用提供的脚本为所需的客户端启用网络引导:
# si_mkclientnetboot --netboot --clients lennox rosse angus
现在您已经准备好出发了。从模拟的网络适配器(我们在命令行上未指定,因为它默认是激活的)启动 QEMU 机器:
# qemu --hda /xen/lennox/root.img --boot n
当然,在客户端安装后,您需要创建 domU 配置。一种方法可能是使用一个简单的脚本(这次使用 Perl,以增加多样性):
#!/usr/bin/perl
$name = $ARGV[0];
open(XEN, '>', "/etc/xen/$name");
print XEN <<CONFIG;
kernel = "/boot/vmlinuz-2.6.xenU"
memory = 128
name = "$name"
disk = ['tap:aio:/xen/$name/root.img,hda1,w']
vif = ['']
root = "/dev/hda1 ro"
CONFIG
close(XEN);
(例如,根据名称生成 IP 等进一步优化当然容易想象。)无论如何,只需用名称作为参数运行此脚本即可:
# makeconf.pl lennox
然后启动您的新 Xen 机器:
# xm create -c /etc/xen/lennox
安装 pypxeboot
与 PyGRUB 类似,pypxeboot 是一个充当 domU 引导加载程序的 Python 脚本。正如 PyGRUB 从域的虚拟磁盘加载内核一样,pypxeboot 从网络加载内核,类似于独立计算机上 PXEboot(预引导执行环境)的方式。它通过调用udhcpc(微 DHCP 客户端)来获取网络配置,然后基于域配置文件中指定的 MAC 地址使用 TFTP 下载内核来实现这一点。
pypxeboot 开始使用并不困难。您需要 pypxeboot 包本身、udhcp 和 tftp。您可以从book.xen.prgmr.com/mediawiki/index.php/pypxeboot获取 pypxeboot,从book.xen.prgmr.com/mediawiki/index.php/udhcp获取 udhcp。您的发行版可能已经包含了 tftp 客户端。
pypxeboot 包包含一个 udhcp 的补丁,允许 udhcp 从命令行获取 MAC 地址。应用它。
# patch -p0 < pypxeboot-0.0.2/udhcp_usermac.patch
patching file udhcp-0.9.8/dhcpc.c
patching file udhcp-0.9.8/dhcpc.h
patching file udhcp-0.9.8/README.udhcpc
构建 udhcp。简单的make后跟make install对我们来说就足够了。
将 pypxeboot 和outputpy.udhcp.sh复制到适当的位置:
# cp pypxeboot-0.0.2/pypxeboot /usr/bin
# cp pypxeboot-0.0.2/outputpy.udhcp.sh /usr/share/udhcpc
接下来设置 TFTP 服务器以进行网络引导。引导服务器可以基本上与物理机的引导服务器相同,但需要注意的是内核和 initrd 需要支持 Xen 硬件虚拟化。我们使用了 Cobbler 生成的设置,但任何 PXE 环境都应该可以工作。
现在您应该能够使用与以下类似的 domU 配置使用 pypxeboot:
bootloader="/usr/bin/pypxeboot"
vif=['mac=00:16:3E:11:11:11']
bootargs=vif[0]
注意
在 pypxeboot 中找到 MAC 地址的正则表达式很容易混淆。如果您指定其他参数,请将空格放在mac=参数及其周围的逗号之间,例如,vif = ['vifname=lady , mac=00:16:3E:11:11:11 , bridge=xenbr0']*。
创建域:
# xm create lady
Using config file "/etc/xen/lady".
pypxeboot: requesting info for MAC address 00:16:3E:11:11:11
pypxeboot: getting cfg for IP 192.l68.4.114 (C0A80427) from server 192.168.4.102
pypxeboot: downloading initrd using cmd: tftp 192.168.4.102 -c
get /images/scotland-xen-i386/initrd.img /var/lib/xen/initrd.BEUTCy
pypxeboot: downloading kernel using cmd: tftp 192.168.4.102 -c
get /images/scotland-xen-i386/vmlinuz /var/lib/xen/kernel.8HJDNE
Started domain lady
红帽式的自动化安装
Red Hat 使用 Kickstart 来配置独立系统。关于 Kickstart 的全面讨论可能最好留给 Red Hat 的文档——简单地说,Kickstart 已被设计成,通过一些辅助工具,您可以使用它安装 Xen domUs。
您最可能想要用于安装虚拟机的工具是 Cobbler 和koan。Cobbler 是服务器软件,而koan(通过网络传输 Kickstart)^([25])是客户端。使用--virt选项,koan支持安装到虚拟机。
由于这是一个 Red Hat 工具,您可以使用yum进行安装。
不,对不起,我们之前撒谎了。首先,您需要将企业 Linux 额外包仓库添加到您的yum配置中。安装描述额外仓库的包:
rpm -ivh http://download.fedora.redhat.com/pub/epel/5/i386/epel-release-5-3.noarch.rpm
现在您可以使用yum安装 Cobbler:
# yum install cobbler
然后您需要对其进行配置。运行cobbler check,这将列出可能干扰 Cobbler 的问题。例如,开箱即用,Cobbler 为我们报告了以下问题:
The following potential problems were detected:
#0: The 'server' field in /var/lib/cobbler/settings must be set to something
other than localhost, or kickstarting features will not work. This should be
a resolvable hostname or IP for the boot server as reachable by all machines
that will use it.
#1: For PXE to be functional, the 'next_server' field in /var/lib/cobbler/
settings must be set to something other than 127.0.0.1, and should match the
IP of the boot server on the PXE network.
#2: change 'disable' to 'no' in /etc/xinetd.d/tftp
#3: service httpd is not running
#4: since iptables may be running, ensure 69, 80, 25150, and 25151 are
unblocked
#5: reposync is not installed, need for cobbler reposync, install/upgrade yum-
utils?
#6: yumdownloader is not installed, needed for cobbler repo add with --rpm-
list parameter, install/upgrade yum-utils?
在修复这些问题后,您就可以使用 Cobbler 了。这包括设置安装介质和添加配置文件。
首先,找到一些安装介质。Kickstart 是 Red Hat 特定的包,因此 Cobbler 仅与类似 Red Hat 的发行版(SUSE 也受支持,但为实验性)一起工作。Cobbler 支持通过rsync、挂载的 DVD 或 NFS 导入 Red Hat 风格的安装树。这里我们将使用 DVD——有关其他选项,请参阅 Cobbler 的手册页。
# cobbler import --path/mnt/dvd --name=scotland
如果您使用的是网络安装源,这可能需要一段时间。一个架构的完整镜像大约是 5GB 的软件。下载完成后,您可以通过运行cobbler report来查看镜像状态。当您有一个目录树时,您可以通过为计划安装的每种类型的虚拟机添加一个配置文件来将其用作安装源。我们建议通过 Cobbler 而不是裸机的 pypxeboot 和 Kickstart 进行安装,因为它具有专门针对设置虚拟机的功能。例如,您可以在机器配置文件中指定 domU 镜像大小和 RAM 数量(分别以 GB 和 MB 为单位):
# cobbler profile add -name=bar -distro=foo -virt-file-size=4 -virt-ram=128
当您添加了配置文件后,下一步是告诉 Cobbler 重新生成一些数据,包括 PXEboot 菜单:
# cobbler sync
最后,您可以使用客户端koan来构建虚拟机。指定 Cobbler 服务器、一个配置文件,以及可选的虚拟机名称。我们还使用了--nogfx选项来禁用 VNC 帧缓冲区。如果您启用帧缓冲区,您将无法通过xm console与 domU 交互:
# koan --virt --server=localhost --profile=scotland --virt-name=lady --nogfx
koan将创建一个虚拟机,安装,并自动创建一个 domU 配置,这样你就可以使用xm启动 domU:
# xm create -c lady
^([24]) 使用 HVM domU 进行 SystemImager 安装,而不是 QEMU 实例,可以使这个过程更快。虽然不是飞速,但有所改进。
^([25]) 这引发了一个问题,即是否存在非网络化的 Kickstart 安装,但我们暂时忽略这个问题。
然后...
在本章中,我们介绍了一系列安装方法,从通用的暴力安装到专门的和特定发行版的安装。尽管我们没有详尽地介绍任何内容,但我们尽力概述了程序,以强调你可能想要使用yum的时候,以及你可能想要使用 QEMU 的时候。我们还对每种方法的潜在陷阱进行了示意。
许多高级 domU 管理工具还包括一种快速简便的方法来安装 domU,如果这些更通用的方法中没有一种符合你的口味。(有关详细信息,请参阅第六章。)例如,你很可能会在 Red Hat 的virt-manager环境中遇到virt-install。
然而,重要的是要根据你的需求调整安装方法。考虑你将要安装多少系统,它们之间有多相似,以及 domU 的预期角色,然后选择最合理的方法。
第四章。使用 XEN 的存储

在这本书中,到目前为止,我们主要将 Xen 视为一个整体,一个完整的虚拟化解决方案,用市场营销的话来说。实际上,情况要复杂得多。Xen 本身只是旨在让用户摆脱与真实硬件打交道的一个平台的一部分。Xen 虚拟机管理程序虚拟化了一个处理器(以及第二章中概述的几个其他基本组件),但它依赖于几种底层技术来提供计算机所需的资源无缝抽象。这种区别在存储领域最为明显,在那里 Xen 必须与虚拟化存储层紧密合作,以提供我们期望的虚拟机的功能。
这意味着 Xen 结合适当的存储机制,几乎提供了完全的硬件独立性。用户可以在任何地方运行 Xen 机器,几乎可以随意移动实例,自由添加存储,干净地保存文件系统状态,并在完成后轻松删除。
听起来不错?让我们开始吧。
存储:基础知识
在我们深入 dom0 侧的配置之前,首先要知道的是如何将存储的存在通知给域。DomUs 通过检查 domU 配置文件中的disk=行来找到它们的存储。通常它看起来像这样:
disk = [
'phy:/dev/cleopatra/menas,sda,w',
'phy:/dev/cleopatra/menas_swap,sdb,w'
]
这一行定义了两个设备,它们在 domU 中表现为sda和sdb。两者都是物理的,如phy:前缀所示——其他存储后端有自己的前缀,例如file:和tap:用于文件支持的设备。您可以按需混合和匹配后端设备类型——我们曾经提供了一对phy:卷和一个文件支持的只读“救援”镜像。
我们称之为一行,但实际上它更像是一节——如果您认为这样更易读,可以将字符串放在单独的行上,用制表符缩进,并在逗号后留空格。在这种情况下,我们使用 LVM,有一个名为cleopatra的卷组,以及两个名为menas和menas_swap的逻辑卷。
注意
按照惯例,我们倾向于使用与域、其设备和其配置文件相同的名称。因此,在这里,逻辑卷 menas 和 menas_swap 属于域 menas,它具有配置文件 /etc/xen/menas 和具有类似名称的网络接口。这有助于保持一切井井有条。
您可以使用xm block-list命令来检查连接到域的存储——例如:
# xm block-list menas
Vdev BE handle state evt-ch ring-ref BE-path
2049 0 0 4 6 8 /local/domain/0/backend/vbd/1/2049
2050 0 0 4 7 9 /local/domain/0/backend/vbd/1/2050
现在,拥有了这些知识,我们可以继续在 dom0 中创建后备存储。
^([26]) 如您所料,物理 设备是通过块设备语义访问的设备,而不是必然是一块独立的硬件。前缀指示 Xen 将设备视为基本块设备,而不是为基于文件的镜像提供额外的转换。
存储类型的不同
在开源的世界里,Xen 支持许多不同的存储选项,每个选项都有其自身的优点、缺点和设计理念。这些选项大致可以分为 基于文件 和 基于设备 的类别。
Xen 可以使用 文件 作为块设备。这有一个优点,就是简单、易于移动、易于从主机操作系统上挂载,并且易于管理。它曾经非常慢,但随着 blktap 驱动程序的出现,这个问题已经基本消失。基于文件的块设备在 Xen 访问它们的方式(基本循环回环与 blktap)和内部格式(AIO、QCOW 等)上有所不同。
Xen 也可以对 物理 设备进行 I/O 操作。这显然有一个缺点,就是很难扩展到超出你能够添加物理设备到机器的能力。然而,物理设备可以是内核有驱动程序的任何东西,包括硬件 RAID、光纤通道、MD、网络块设备或 LVM。因为 Xen 通过设备驱动程序和 Xen 实例之间的 DMA(直接内存访问)访问这些设备,直接将 I/O 映射到客户操作系统的内存区域,所以 domU 可以以接近原生速度访问物理设备。
然而,无论什么情况,所有存储后端在 Xen 虚拟域内部看起来都一样。虚拟机管理程序将 Xen VBD(虚拟块设备)导出到 domU,然后将其以管理员定义的映射方式呈现给客户操作系统,通常是 hdx 或 sdx 形式的设备。虽然许多发行版现在使用 xvdx 作为 xen 虚拟磁盘。(hd 和 sd 设备通常也可以工作。)
我们推荐使用 blktap(一种特殊的文件后端)和 LVM 作为存储后端。这两个都工作良好,具有良好的可管理性,可以自由调整大小和移动,并支持一些我们现在期望的文件系统机制。blktap 设置简单,适合测试,而 LVM 可扩展性好,适合生产。
这一切并没有特别针对 Xen。实际上,LVM 在许多发行版(如 Red Hat)的根设备上默认使用(在 Xen 之外),因为抽象存储层带来的管理优势。blktap 简单来说就是 Xen 特定的机制,用于将文件用作块设备,就像传统的块循环驱动程序一样。它比循环机制更优越,因为它允许大幅提高性能和更灵活的文件系统格式,如 QCOW,但从管理员的角度来看,它并没有本质上的不同。
让我们开始吧。
基本设置:文件
对于不想处理 LVM 的麻烦和开销的人来说,Xen 通过 blktap 驱动和库支持快速高效的文件支持块设备。
blktap(由于“block”这个词被输入了数百次,所以“blk”是磨损的占位符)包括一个内核驱动和一个用户空间守护进程。内核驱动直接映射由后端文件包含的块,避免了通过循环回环挂载文件时涉及的大部分间接操作。它支持许多用于虚拟块设备的文件格式,包括通过 dd 命令从块设备获取的基本“raw”镜像格式。
你可以使用 dd 命令创建一个文件:
# dd if=/dev/zero of=/opt/xen/anthony.img bs=1M count=1024
注意
你的 dd 版本可能需要稍微不同的语法——例如,它可能需要你指定字节的块大小。
现在 dd 命令会持续一段时间,将零复制到文件中。最终它会完成:
1024+0 records in
1024+0 records out
1073741824 bytes (1.1 GB) copied, 15.1442 seconds, 70.9 MB/s
因此,有了文件系统镜像,你可以使用 tap 驱动程序将其附加,创建一个文件系统,并像通常一样使用 mount 命令挂载它。
# xm block-attach 0 tap:aio:/opt/xen/anthony.img /dev/xvda1 w 0
# mkfs /dev/xvda1
# mount /dev/xvda1 /mnt/
首先,我们使用 xm(8) 命令将块设备附加到域 0。在这种情况下,xm 命令后面跟着块附加子命令,带有参数 <要附加设备的域 ID> <后端设备> <前端设备> <模式> 以及可选的 [后端域 ID]。为了分解我们的示例,我们将使用 tap:aio 驱动将 anthony.img 以读写方式附加到域 0 中的 /dev/xvda1,使用域 0 来调解访问(因为我们倾向于避免使用非 dom0 驱动程序域)。当文件作为 /dev/xvda1 附加时,我们可以在它上面创建一个文件系统,就像任何块设备一样挂载它。
现在它已经挂载,你可以在里面放些东西。(有关详细信息,请参阅第三章)]
QCOW
到目前为止,我们一直在专门讨论“原始”文件格式——但这并非唯一的选择。一个可能的替代方案是 QEMU 项目使用的 QCOW 格式。它有很多值得推荐的地方——一个快速、健壮的格式,支持稀疏分配、加密、压缩和写时复制。我们喜欢它,但支持还不够成熟,所以我们不推荐它作为您的首选存储选项。
尽管如此,尝试一下可能很有趣。要开始使用 QCOW,拥有 QEMU 会很方便。(虽然 Xen 包含一些 QEMU 工具,但完整包包含更多功能。)从www.nongnu.org/qemu/download.html下载它。像往常一样,我们推荐源安装,特别是因为 QEMU 团队放弃了标准包管理来提供二进制发行版。
通过标准过程安装 QEMU:
# tar zxvf <qemu source package>
# cd <qemu source directory>
# ./configure
# make
# su
# make install
QEMU 包括qemu-img实用程序,用于创建和操作 QEMU 支持的多种图像文件,包括 QCOW、vmdk、raw 和其他格式。
# qemu-img create -f qcow enobarbus.qcow 1024M
此命令创建一个大小为 1,024MB 的 QCOW 格式(-f qcow)的镜像。当然,您会想用您应用程序的适当值替换文件名和大小。
您还可以使用img2qcow实用程序将原始镜像转换为 QCOW 镜像,该实用程序包含在 Xen 发行版中:
# img2qcow enobarbus.qcow enobarbus.img
您可以直接使用 QCOW 镜像作为具有 tap 驱动器的域的根磁盘。配置客户域使用 QCOW 镜像作为其根文件系统。在/etc/xen下的域配置文件中添加一个类似于的disk=行:
disk = [ 'tap:qcow:/opt/xen/enobarbus/enobarbus.qcow,sda1,w' ]
您可以使用另一个磁盘扩展这一行,如下所示:
disk = [ 'tap:qcow:/opt/xen/enobarbus/enobarbus.qcow,sda1,w' ,
'tap:qcow:/opt/xen/enobarbus/enobarbus_disk2.qcow,sdb1,w']
基本设置:LVM
LVM 操作的高级单元是卷组或VG。每个组将物理扩展(可配置大小的磁盘区域)映射到逻辑扩展。物理扩展托管在 LVM 所说的物理卷或PV上。每个 VG 可以包含一个或多个这样的物理卷,而物理卷本身可以是内核支持的任何类型的块设备。合理地讲,逻辑扩展位于逻辑卷上,简称LV。这些是 LVM 实际向系统呈现为可用块设备的设备。
正如我们常说的那样,经验确实无可替代。这里有一个五分钟的图文教程,介绍如何设置逻辑卷(见图 4-1)。

图 4-1. 此图显示了一个包含两个 PV 的单个 VG。从这个 VG 中,我们划分出了三个逻辑卷,lv1、lv2 和 lv3。lv1 和 lv3 被 domUs 使用,其中一个将整个卷视为单个分区,另一个将 LV 划分为用于/和/var 的子分区。
从一些硬盘开始。在这个例子中,我们将使用两个 SATA 硬盘。
注意
鉴于 Xen 基本上是一种服务器技术,可能最明智的做法是使用 RAID 支持的冗余存储,而不是实际的硬盘驱动器。它们也可以是硬盘上的分区、网络块设备、UFS 格式的光盘媒体……无论您想提及的任何类型的块设备。不过,我们将使用两个硬盘上的分区来提供指令。如果您只使用一个硬盘,这些指令同样适用。
警告
请注意,我们将重新分区和格式化这些驱动器,这将破坏它们上的所有数据。
首先,我们分区驱动器并将类型设置为 Linux LVM。尽管这不是严格必要的——如果您愿意,可以使用整个驱动器作为 PV——但通常被认为是良好的 Unix 卫生习惯。此外,如果您只想将磁盘的一部分用于 LVM,您将需要分区,这是一个相当常见的场景。(例如,如果您想从您用于 LVM 的物理磁盘之一启动,您将需要一个单独的 /boot 分区。)
因此,在这个例子中,我们有两个磁盘,sda 和 sdb。我们希望每个驱动器的第一个 4GB 被用作 LVM 物理卷,所以我们将使用 fdisk 对它们进行分区,并将类型设置为 8e(Linux LVM)。
如果磁盘上的任何分区正在使用中,您将需要重新启动以使内核重新读取分区表。(顺便说一句,我们认为这是荒谬的。这不是应该属于未来吗?)
接下来,确保您有 LVM,并且它是 LVM2,因为 LVM1 已被弃用。28
# vgscan --version
LVM version: 2.02.23 (2007-03-08)
Library version: 1.02.18 (2007-02-13)
Driver version: 4.5.0
您可能需要加载驱动程序。如果 vgscan 抱怨驱动程序缺失,请运行:
# modprobe dm_mod
在这个例子中,dm 代表 device mapper,它是一个低级卷管理器,作为 LVM 的后端。
在确认这三个组件都正常工作后,根据 图 4-2 中的说明创建物理卷。
# pvcreate /dev/sda1
# pvcreate /dev/sdb1

图 4-2。此图显示了在它上面运行了 pvcreate 的单个块设备。它大部分是空的,除了前面有一个小的标识符。
通过运行 vgcreate 将这些组件组合成一个卷组。在这里,我们将在设备 sda1 和 sdb1 上创建一个名为 cleopatra 的卷组:
# vgcreate cleopatra /dev/sda1 /dev/sdb1
最后,使用 lvcreate 从卷组创建卷,如图 4-3 所示。图 4-3。将其视为一种更强大、更通用的分区形式。
# lvcreate -L <length> -m1 --corelog -n menas cleopatra
我们已经创建了一个镜像逻辑卷,其日志保存在核心(而不是在单独的物理设备上)。请注意,这一步需要一个组名而不是设备节点。此外,镜像纯粹是为了说明目的——如果你使用某种冗余设备,如硬件 RAID 或 MD,则不是必需的。最后,使用 -n 选项给 LVs 赋予人类可读的名称是一种管理上的便利。这不是必需的,但非常推荐。

图 4-3。lvcreate 通过从 LV 中切割一些空间来创建一个逻辑卷,/dev/vg/lvol,这些空间透明地映射到 PV 上的可能不连续的物理扩展。
使用您喜欢的文件系统创建工具创建一个文件系统:
# mkfs /dev/cleopatra/menas
到目前为止,LV 已经准备好挂载和访问,就像它是一个普通磁盘一样。
# mount /dev/cleopatra/menas /mnt/hd
为了使新设备成为 Xen 域的合适根目录,将文件系统复制到其中。我们使用了一个来自 stacklet.com/ 的文件系统——我们只是挂载了他们的根文件系统并将其复制到我们新的卷中。
# mount -o loop gentoo.img /mnt/tmp/
# cp -a /mnt/tmp/* /mnt/hd
最后,为了与 Xen 一起使用,我们可以将逻辑卷指定给客户域,就像我们指定任何物理设备一样。(注意,在这里我们回到了本章开始时的同一个示例。)
disk = ['phy:/dev/cleopatra/menas,sda1,w']
到目前为止,开始启动机器。交叉手指,挥舞一只死鸡,进行习惯的仪式。在这种情况下,我们的神通过 xm create 来平息。在过去几千年中,标准已经降低。
# xm create menas
^([27]) 此示例并非纯粹学术。
^([28]) 除非您使用 Slackware,否则这不太可能成为问题。
扩大磁盘
文件系统图像和 LVM 磁盘都可以从 dom0 中透明地扩展。我们假设磁盘空间非常充足,您永远不会需要缩小图像。
在尝试调整其底层文件系统大小之前,请确保停止域。一方面,我们知道的所有的用户空间调整工具都不会尝试调整挂载的文件系统的大小。另一方面,Xen 虚拟机管理程序不会在没有重启域的情况下将更改传递给底层块设备的大小。最重要的是,即使您能够在域运行时调整后端存储,数据损坏几乎肯定会发生。
文件系统图像
增强文件系统图像背后的原理很简单:我们在文件中追加更多位,然后扩展文件系统。
首先,确保没有任何东西在使用该文件。停止任何挂载了该文件的 domUs。将其从 dom0 中分离。不这样做可能会导致文件系统损坏。
接下来,使用 dd 在末尾添加一些位。在这种情况下,我们将 1GB 从我们的 /dev/zero 位管路中引导到 anthony.img。 (注意,如果不指定输出文件,dd 将写入 stdout。)
# dd if=/dev/zero bs=1M count=1024 >> /opt/xen/anthony.img
使用 resize2fs 来扩展文件系统(或您选择的文件系统的等效工具)。
# e2fsck -f /opt/xen/anthony.img
# resize2fs /opt/xen/anthony.img
如果没有分区表,resize2fs 将默认将文件系统的大小设置为底层设备的大小。
如果图像包含分区,您需要在调整文件系统大小之前重新排列这些分区。使用 fdisk 删除您希望调整大小的分区,并重新创建它,确保起始柱面保持不变。
LVM
使用 LVM 扩展存储同样简单,或许甚至更简单。LVM 从一开始就是为了提高存储设备的灵活性而设计的,因此它包括一个简单的机制来扩展卷(以及缩小和移动)。
如果卷组中有空闲空间,只需简单地发出以下命令:
# lvextend -L +1G /dev/cleopatra/charmian
如果卷组已满,你需要扩展它。只需向机器添加一个磁盘并扩展 vg:
# vgextend /dev/cleopatra /dev/sdc1
最后,就像之前的例子一样,处理文件系统级别的扩展——我们将使用 ReiserFS 来展示这个过程。
# resize_reiserfs -s +1G /dev/cleopatra/charmian
Copy-on-Write 和快照
真实存储选项为你提供的另一个优点是写时复制,这意味着当 domU 更改文件时,后端而不是覆盖文件,而是在其他地方透明地写入一个副本。29] 作为推论,原始文件系统仍然作为一个快照存在,所有修改都指向写时复制的克隆。
这个快照提供了保存文件系统状态的能力,在给定时间或设定间隔内对其进行快照。关于快照有两个有用的方面:一方面,它们允许从用户错误中轻松恢复。30] 另一方面,它们提供了一个已知是一致的检查点——你可以方便地将其备份并移动到其他地方。这消除了需要关闭服务器进行备份的需求,就像我们在黑暗时代所做的那样。
CoW 同样有很多用途。其中,对 Xen 最基本的影响是它可以显著减少每个虚拟机在磁盘上的开销——而不是使用一个简单的文件作为块设备或逻辑卷,许多机器可以共享一个单独的基文件系统镜像,只需在文件系统中写入它们的更改即可。
CoW 也有自己的缺点。首先,存在速度惩罚。与直接写入设备相比,CoW 基础设施会显著减慢磁盘访问速度,无论是读取还是写入。
如果你为 CoW 卷使用稀疏分配,由于分配和重新映射块的开销,速度惩罚会更大。这会导致碎片化,并带来自己的一套性能惩罚。CoW 也可能导致过度订阅的管理问题;通过使过度订阅磁盘空间成为可能,如果你不小心用完,这会使生活变得更加困难。你可以通过预先分配空间来避免所有这些问题。
就像大多数有趣的功能一样,在管理复杂性方面也存在权衡。最终,作为 Xen 管理员,你必须决定多少复杂性是值得拥有的。
我们将讨论 LVM 所使用的设备映射器快照,因为我们最熟悉这种实现。对于共享存储,我们将关注 NFS,并在第九章(第九章)中更详细地介绍共享存储系统。我们还在第七章(第七章)中概述了一个使用 UnionFS 的 CoW 解决方案。最后,你可能想尝试 QCOW 块设备——尽管我们在这方面没有太多运气,但你的体验可能会有所不同。
^([29]) 这通常被缩写为 CoW,部分原因是因为它更短,但主要是因为 "cow" 这个词本身就很幽默。问问维基百科就知道了。
^([30]) 删除你的家目录并不像你想象的那么困难。
LVM 和快照
LVM 快照设计得更多的是为了 备份 和 检查点 文件系统,而不是作为长期存储的手段。保持 LVM 快照相对较新很重要——换句话说,确保在备份完成后删除它们。^([[31)]]
快照卷也可以用作域的读写后端存储,尤其是在你只想基于某个现有的磁盘镜像快速生成一个用于测试的 domU 的情况下。LVM 文档指出,你可以创建一个基本镜像,多次快照它,并对每个快照进行轻微修改以用于另一个域。在这种情况下,LVM 快照会像块级 UnionFS 一样工作。然而,请注意,当快照填满时,内核会立即丢弃它。这可能会导致数据丢失。添加 LVM 快照的基本步骤很简单:确保你的卷组中有一些未使用的空间,并为它创建一个快照卷。
Xen LiveCD 重新审视:COPY-ON-WRITE 实际操作
Xen LiveCD 实际上是一个相当不错的发布。它最酷的功能之一是能够在 Xen 域启动时自动创建基于 CD 上只读镜像的 copy-on-write 块设备。
实现使用设备映射器根据平面文件设置块设备和快照,并且出奇地简单。
首先,在域配置文件中,基本存储是通过这样一行定义的:
disk=['cow:/mnt/cdrom/rootfs.img 30,sda1,w']
注意使用 cow: 前缀,我们之前还没有提到过。这实际上是一个自定义前缀,而不是正常 Xen 软件包的一部分。
我们可以添加自定义前缀,如 cow:,因为 /etc/xen/scripts/create_block_device 如果遇到未知设备类型(在这种情况下是 cow),会跳转到以 block-[type] 形式命名的脚本。block-cow 脚本期望一个参数,即 create 或 destroy,这是在调用脚本时域构建器提供的。block-cow 然后根据需要调用 create_cow 或 destroy_cow 脚本。
实际的设置发生在脚本中,/usr/sbin/create_cow。此脚本本质上使用设备映射器根据 LVM 快照创建一个基于写时复制的设备,^([32]) 并将其呈现给域。我们在此不重复它,但它是一个很好的例子,说明了标准 Linux 功能如何成为复杂、抽象功能的基础。换句话说,这是一个很好的技巧。
首先,检查您是否有dm_snapshot驱动程序。大多数现代发行版都将其作为可加载模块构建。如果未构建,请转到您的 Linux 内核源树并编译它。
# locate dm_snapshot.ko
如有必要,手动加载它。
# modprobe dm_snapshot
使用带有-s选项的lvcreate命令创建快照,以指示“快照”。其他参数指定长度和名称,就像普通逻辑卷一样。最后一个参数指定源,或被快照的卷。
# lvcreate -s -L 100M -n pompei.snap /dev/cleopatra/pompei
此快照看起来像是文件系统的冻结图像——原始卷上的写入将按正常进行,但快照将保留在快照创建时更改的文件,直到达到快照的最大容量。
在创建快照时,长度表示快照能够存储的最大更改数据量。如果快照满了,内核驱动程序会自动将其丢弃,使其变得不可用。
有关使用 LVM 快照备份 Xen 实例的示例脚本,请参阅第七章。
^([31]) 即使您没有向快照本身添加任何数据,它也可能因为跟上主 LV 的变化而耗尽空间(并损坏自身)。
^([32]) 更确切地说,是一个设备映射器快照,LVM 快照就是基于这个的。LVM 快照是设备映射器快照,但设备映射器快照可以基于任何一对块设备,无论是 LVM 还是其他设备。LVM 工具提供了一个方便的前端,用于dmsetup使用的晦涩命令。
存储 和 迁移
这两种存储技术——平面文件和 LVM——非常适合于简单和自动化的冷迁移,在这种迁移中,管理员会停止域,将域的配置文件和备份存储复制到另一台物理机器上,然后重新启动域。
在基于文件的后端上复制就像在网络中复制任何文件一样简单。只需将其放入文件系统中的相应位置,然后启动机器。
复制 LVM 稍微复杂一些,但仍然简单明了:创建目标设备,挂载它,然后以您关心的任何方式移动文件。
查阅第九章以获取此类迁移的更多详细信息。
网络存储
这两种存储方法仅适用于本地可访问的存储。实时迁移,即在不停机的情况下将域从一个机器移动到另一个机器,需要这个谜题的另一部分:文件系统必须通过网络对多台机器可访问。这是一个活跃的开发领域,有几种竞争性解决方案。在这里,我们将讨论基于 NFS 的存储。我们将在第九章中讨论其他解决方案,包括以太网上的 ATA 和 iSCSI。
NFS
NFS 比我们还要古老,它被各种规模的组织所使用。它易于设置,相对容易管理。大多数操作系统都可以与之交互。因此,它可能是设置具有实时迁移功能的 Xen 域最简单、最便宜、最快的方式。
策略是利用 Xen 的网络隐喻:域(在默认设置中)连接到一个虚拟网络交换机。因为 dom0 也连接到这个交换机,所以它可以作为 domUs 的 NFS 服务器。
在这种情况下,我们导出的是一个目录树——既不是物理设备也不是文件。NFS 服务器设置相当简单,并且它是跨平台的,因此您可以使用您喜欢的任何 NFS 设备。(我们更喜欢基于 FreeBSD 的 NFS 服务器,但 NetApp 和其他几家公司也生产出色的 NFS 设备。正如我们可能提到的,我们使用 Linux 作为 NFS 服务器时运气不佳。)只需导出您的操作系统镜像。在我们的示例中,在 192.0.2.7 的 FreeBSD NFS 服务器上,我们有一个完整的 Slackware 镜像在*/usr/xen/images/slack*。我们的*/etc/exports*看起来有点像这样:
/usr/xen/images/slack -maproot=0 192.0.2.222
我们将服务器端的进一步设置留给您无疑丰富的 NFS 经验。一个简单的改进是使/为只读和共享,然后导出只读的 VM 特定*/var*和*/home*分区——但在最简单的情况下,只需导出一个完整镜像。
注意
尽管 NFS 确实会带来性能损失,但重要的是要记住,Xen 的网络缓冲区和磁盘缓冲区由相同的半虚拟化设备基础设施提供,因此实际的网络硬件并未参与。在穿越网络堆栈时会有增加的开销,但性能通常比千兆以太网要好,所以并没有您想象的那么糟糕。
现在配置客户端(CONFIG_IP_PNP=y)。首先,您需要对 domU 的内核进行一些修改,以启用 NFS 上的 root 访问:
networking->
networking options->
ip: kernel level autoconfiguration
如果您想通过 DHCP 完成所有操作(尽管您可能仍然需要在您的域配置文件中指定 MAC 地址),在该树中添加 DHCP 支持:CONFIG_IP_PNP_DHCP:或者如果您是老派用户,可以使用CONFIG_IP_PNP_BOOTP。如果您可以在 domU 配置文件中指定 IP,则可以跳过该步骤。
现在您需要启用 NFS 对 root 的支持。确保 NFS 支持设置为 Y 而不是 M;即,CONFIG_NFS_FS=Y。接下来,启用通过 NFS 的 root 访问:CONFIG_ROOT_NFS=Y。在menuconfig中,您可以在以下位置找到该选项:
File systems ->
Network File Systems ->
NFS file system support ->
Root over NFS
注意,menuconfig 不会给你选择通过 NFS 选择根目录的选项,直到你选择了内核级别的 IP 自动配置。
按正常方式构建内核并将其安装到 Xen 可以加载的地方。很可能是你不想为 dom0 内核这样做,所以请确保不要覆盖启动内核。
现在配置你将要通过 NFS 启动的域。编辑域的配置文件:
# Root device for nfs.
root = "/dev/nfs"
# The nfs server.
nfs_server = '38.99.2.7'
# Root directory on the nfs server.
nfs_root = '/usr/xen/images/slack'
netmask="255.255.255.0"
gateway="38.99.2.1"
ip="38.99.2.222"
注意,我们只是在域配置中添加了额外的 Linux 内核配置——Xen 未使用的值将被传递到内核命令行。你还可以明确地将此配置放在“extra”参数中。如果你想通过 DHCP 设置 IP 地址,可以将上面的最后三行替换为:
dhcp="dhcp"
然后,你可以像往常一样使用 DHCP 来指定 NFS 服务器和 NFS 根。启动域并完成。因为存储对网络上的任何机器都是可访问的,所以 Xen 的实时迁移应该也能正常工作。
结束建议
这可能看起来像是一个令人困惑的,甚至过度的存储选项多样性,但所有这些都有其位置——无论是在托管环境中,还是在桌面上,还是在用于效用计算的存储池中。我们在本章中提出的建议是一个起点,但最终我们能给出的最好建议是尝试所有这些,看看哪种最适合。在管理便捷性和可扩展性之间找到合适的平衡。
最后,你可以结合和扩展这些选项中的许多。例如,Xen LiveCD 使用带有 LVM 快照的平面镜像。根据你的应用,最佳解决方案可能是简单的文件系统镜像或软件 RAID 和 LVM 的组合。继续实验,看看哪种最适合。这些都是 Xen 基于标准的架构灵活性的例子,该架构依赖于用户可扩展的脚本来定义易于理解的语义来使用可用存储。在第五章中,我们将探讨这些相同的原则如何应用于 Xen 的网络设置。
第五章 网络

因此,您已经拥有了一个漂亮、闪亮的 Xen 盒子,并且现在您希望它能够与外界通信。这似乎是理所当然的。毕竟,Xen 的主要用途是服务器整合——一个没有网络的服务器在术语上就是矛盾的。好吧,您很幸运。Xen 有一个强大且经过充分测试的网络基础,它既灵活又易于设置。
就像 Xen 的许多其他部分一样,网络基础设施尽可能地重用标准工具。在这种情况下,Xen 使用标准的桥接工具和ip命令^([33]),所有这些都被一些巧妙的 bash 和 Python 脚本粘合在一起,以处理 dom0 和 domU 网络接口之间的流量。
作为管理员,您与 Xen 虚拟网络设备的主要交互是通过各种配置文件。正如您所预期的,全局参数和初始设置主要由xend-config.sxp中的指令处理。特定域的配置是在域的配置文件中完成的。
可以通过修改存储在/etc/xen/scripts中的 Xen 网络脚本来进行更高级的配置。
如果您是那种不惜一切代价避免重启的人,您可以在 VM 运行时通过brctl, iptables和xm命令直接操作 Xen 的网络基础设施,但这些更改并不总是成功传播到 domU。我们将重点关注“操作配置文件并重启 domU”的方法,因为它在所有情况下都有效。
Xen 的网络设置过程
Xen 在其网络脚本的两个点上运行:在xend启动时和在域启动时。(有对应于域关闭和xend停止的脚本。)
在xend启动时运行的脚本(通常是network-bridge或network-route)的作用是将标准、非 Xen 网络切换到基于 Xen 的网络。例如,在network-bridge的情况下,此脚本创建一个桥接并分配物理以太网设备给它。然后它初始化 dom0 的网络,创建一个虚拟接口,将其添加到桥接中,并将配置复制到桥接网络设备上。
当 Xen 启动一个域时,它会执行适当的vif-*脚本——例如,在network-bridge的情况下,执行vif-bridge。以下显示了默认设置下将运行的各个脚本。
(xend startup)
|
|- network-bridge
|
|-xen-script-common.sh
|-xen-network-common.sh
(xm create)
|
|-vif-bridge
|
|-vif-common.sh
|
|-xen-hotplug-common.sh
| |
| |-logging.sh
| |-xen-script-common.sh
| |-locking.sh
|
|-xen-network-common.sh
这些脚本中的大多数对我们目前的目的并不是非常重要。例如,logging.sh只是被源引用以提供log()函数。我们感兴趣的主要点是标记为
的地方。这些是编辑的好脚本或引入包装脚本的好地方。
这些脚本都是 bash shell 脚本(而不是像许多其他 Xen 配置文件那样是 Python)。它们默认都位于 /etc/xen/scripts 目录中,与支持其他类 Xen 虚拟设备的脚本放在一起。
^([33]) IP 命令 /sbin/ip 是现代(不幸地命名)的 ifconfig 替代品。它是 iproute2 工具集的一部分,提供了与 net-tools 类似的功能,但增加了额外的功能。
定义虚拟接口
所有的 Xen 网络选项都是通过在 dom0 中创建虚拟接口来实现的,这些虚拟接口作为网桥、iptables 规则等的目标。每个虚拟接口都由配置文件中 vif= 行的一个部分定义,由一对单引号分隔。
Xen 3 支持每个域最多八个虚拟接口(3.1 之前是三个)。例如,
vif=['','','']
定义了三个虚拟接口,并告诉 Xen 使用合理的默认值来配置它们。请注意,它们是逗号分隔的,并且与 Python 数组语法一致。
你可以通过在 dom0 中输入以下命令来检查这些虚拟接口
# ifconfig -a
这将输出一系列设备的详细信息
vif*`x`*.*`y`*
其中 x 和 y 是数字。(如果你在使用 HVM,你可能会看到 tap 设备。现在先将其视为 vifs 处理。)
注意
在最近的基于 Red Hat 的发行版(包括 CentOS 5.1 和 Fedora 8)中,libvirt 将创建另一个名为 virbr0 的网桥。这个网桥默认设置为 NAT,应被视为 libvirt 的一部分,而不是 Xen。它的工作方式与 Xen 的 network-nat 实现非常相似:dom0 在 virbr0 上运行 dnsmasq 服务器并为 domUs NAT 数据包。这对于桌面系统来说是一个合理的默认设置,但可能不适合服务器。要使用 Xen 的网桥而不是 libvirt 的,请指定 bridge=xenbr0。对于好奇者,virbr* 是通过 /etc/libvirt/qemu/networks/default.xml 配置的。你可以通过删除 /etc/libvirt/qemu/networks/autostart 中的符号链接来禁用 virbr 设备。
Xen 的默认行为是为每个虚拟接口分配一个基于域编号的名称,其中 x 是域编号,y 是 domU 中接口的顺序编号。例如,vif2.0 是域 2 中的 eth0;vif2.1 是域 2 中的 eth1。此外,机器中的每个物理网卡都会显示为一个 peth 设备(代表 物理以太网)。xend 在域启动时代表域创建这些虚拟接口。因此,你会看到不同数量的它们,这取决于运行了多少个域以及它们有多少个网络设备。
正如我们之前所述,dom0 是一个与其它一样的主域,只是它具有执行控制平面功能的能力以及访问 PCI 设备的能力。因此,vif0.0 是 dom0 的虚拟 eth0 接口,而 vif0.1 是 dom0 中的 eth1。(Xen 便利地通过将 ethX 映射到 vif0.x 来创建别名。)
注意
veth 设备也会出现在 dom0 中。不用担心它们。它们只是作为 xend 复制信息时的草稿纸。
通常在与 dom0 交互时可以忽略 vifs。然而,有几个需要注意的事项:因为 dom0 中的 eth0 实际上是虚拟接口的别名,它只能看到指向 dom0 的流量——domU 流量永远不会到达这个别名。如果你想在 dom0 中使用 tcpdump 或类似工具查看发送到 domUs 的流量,你必须查看物理以太网卡——即适当的 peth 接口。
此外,peth 可能有一个奇怪的 MAC 地址,通常是 FF:FF:FF:FF:FF:FF。因为没有任何数据包实际上在 peth 设备上起源或终止,所以它不需要实际的 MAC 地址。
最后,虚拟设备由 netloop 驱动程序提供,默认情况下一次只允许八个虚拟设备。可以通过增加 nloopbacks 参数的值来提高这个值:
# modprobe netloop nloopbacks=128
如果它是内置于内核中的,你可以使用更高的 loopback.nloopbacks 值来引导 dom0 内核。只需将 netloop.nloopbacks=128(或类似的大值)追加到 /boot/grub/menu.lst 中的加载 Linux 内核的 module 行即可。
虚拟接口命名
使用这种复杂的虚拟接口方案来计算带宽使用情况可能很棘手。因为接口名称基于域编号,而域编号每次域重新启动时都会改变,所以简单地使用 dom0 的内部计数器来监控带宽是不切实际的——你最终会得到类似这样的东西:
vif58.0 RX bytes:12075895 (11.5 MiB) TX bytes:14584409 (13.9 MiB)
重新索引名称
如果你决定使用 vifnames,你可能需要注意,尽管符号名称保持不变,但接口的 mib 数字在 domU 的每次重新启动时可能会改变。
一些 SNMP 监控软件期望 mib 数字保持不变。当它们改变时,软件将其解释为具有相同名称的新接口,这使得收集累积统计信息……变得困难。你通常可以通过配置你的 SNMP 软件以积极重新索引名称到数字,而不是依赖其缓存来解决这个问题。这只是需要注意的一点——不是无法修复,但很烦人。请查看您特定的监控软件的详细信息。
一种解决方法是命名虚拟接口,使得名称与域编号无关。你可以在 domU 配置文件中通过指定 vifname 参数作为 vif= 配置指令的一部分来命名虚拟接口。例如,
vif=['vifname=http']
这将导致 dom0 中的 vif 变为 http 而不是 vifx.y。(当然,在域内部,它只显示为 eth0。)如果域有多个接口,可以按照以下方式指定它们:
vif=['vifname=http1', 'vifname=http2']
到目前为止,你需要停止和启动域以强制它重新读取配置文件;简单的重启不起作用。
指定了 vifname 后,我们可以停止和启动域。这里我们关闭一个域:
# xm list http.xen
Name ID Mem(MiB) VCPUs State Time(s)
http.xen 6 96 1 -b---- 11358.0
# xm shutdown http.xen
xenbr0: port 8(vif6.0) entering disabled state
device vif6.0 left promiscuous mode
xenbr0: port 8(vif6.0) entering disabled state
注意,设备只是vif6.0。现在启动它。
# xm create http.xen
Using config file "http.xen".
device http entered promiscuous mode
xenbr0: port 8(http) entering learning state
xenbr0: topology change detected, propagating
xenbr0: port 8(http) entering forwarding state
Started domain http.xen.prgmr.com
# cat http.xen.prgmr.com | grep vifname
vif = [ 'vifname=http, bridge=xenbr0' ]
截断的 VIF 名称
Linux 会静默地将vifname截断为 15 个字符——它将忽略任何超出该长度的输入而不会引发错误。因此,对于一个名为wiki.xen.prgmr.com的vif,
# ifconfig wiki.xen.prgmr.
前面的 15 个字符(包括点)或
# ifconfig wiki.xen.prgmr.com
或
# ifconfig wiki.xen.prgmr.foo.bar.baz
将会工作,但
# ifconfig wiki.xen
将会失败,并返回一个ENODEV(一个“没有这样的设备”或“设备未找到”错误)。
注意,15 个字符的 vifnames 会导致某些 iptables 版本出现问题。为了安全起见,请将 vifnames 限制为 8 个字符。
自动配置
你可以只留下vif=行为空,并让xm自动生成整个配置,如下所示:
vif = ['']
这种场景的优点是允许 domU 管理员在 domU 内部完全自由地配置网络,使用最方便的工具。这是模拟物理机器最准确的方法。如果需要,Xen 可以自己生成 IP 和 MAC 地址,并配置它们以无需管理员干预的方式工作。
然而,我们不推荐这样做,因为它将网络接口的配置留给了用户。至少,你应该指定 IP 地址,以便 Xen 可以设置反欺骗规则来防止 Xen 实例的攻击者伪造其 IP 头中的源或目标地址,并指定 MAC 地址以避免冲突的可能性。IP 或 MAC 地址冲突可能会使你的网络崩溃!尽可能避免。
神秘递增的接口编号
通过指定 MAC 地址可以避免的一个其他问题是,在每次启动时地址改变时 domU 会变得困惑——在某些系统上,它会认为每个新的地址是一张新卡,因此在第二次启动时使用 eth1,第三次启动时使用 eth2,依此类推。当看到新的 MAC 地址时,udev 认为它找到了一张新卡。
简单的解决方案是在域配置文件中指定 MAC 地址,并清除 udev 的缓存,在/etc/udev/rules.d/z25_persistent-net.rules中。这应该会导致设备在下次启动时以 eth0 出现,并保持 eth0,因为它不再获得随机地址了。
指定 MAC 地址
通常情况下,在没有虚拟化的情况下,硬件制造商会确保每个以太网设备都有一个唯一的 MAC 地址。然而,在使用 Xen 的情况下,确保每个虚拟接口都有一个唯一的硬件地址就变成了管理员的责任。
首先,回想一下 7 层 OSI 网络模型。Xen 在 2 层和 3 层与该模型交互;也就是说,它提供了一个带有network-bridge的虚拟层 2 交换机,并作为带有network-route的 IP 路由器。这两个层次都需要 Xen 域有一个唯一的地址。反欺骗规则和ip指令可以处理第 3 层;然而,你也可能想要指定一个 MAC 地址。
Xen 可以简单地创建一个,但这会导致相对较高的冲突概率。当 Xen 为您选择 MAC 地址时,它从 IEEE 注册机构分配给 Xen 的 00:16:3e 前缀开始,并随机选择剩余的三个字节;这意味着您有 3 个字节的熵。在一个网络上的 1,000 个主机(大多数是 /22 的部分)中,这给您大约 3% 的冲突概率。(您可以使用生日悖论来计算这一点——这是您那些不为人知的数学趣闻的绝佳用途。)考虑到 MAC 地址冲突的巨大问题,我们建议始终手动指定 MAC 地址。这样做是通过更改您的 vif= 行以包含一个 mac= 部分,如下所示:
vif= ['ip="10.0.0.1",mac="ae:00:01:02:03:04"']
在 prgmr.com,我们选择一个 2 字节前缀,并以十六进制形式附加 IP 地址,因为 IP 地址已经唯一。尽管如此,在进行此操作时还有一些重要的规则:首先,最高有效位应该是零;其次,地址应该是“本地分配”块的一部分,以避免与真实以太网硬件可能发生的冲突。幸运的是,这些规则可以简化为一个基本公式:将第一个八位字节(如上例中的 e)的第二十六进制位设置为 2、6、A 或 E。(当然,您可以通过使用上面提到的 Xen 前缀来避免担心这一点。)
使用 xm 操作 vif
尽管我们通常通过配置文件间接修改网络设置,但也可以直接使用 xm 进行更改。
相关的命令是 network-attach 和 network-detach。使用 network-attach,您可以通过命令行指定选项来创建一个新的虚拟网卡,就像它在配置文件中指定过一样。例如,
xm network-attach wiki.xen.prgmr.com script=network-bridge mac=00:16:3e:02:ac:7d bridge=xenbr0
如果您没有指定各种参数,Xen 将提供默认值,就像它们在配置文件的 vif= 行中未指定一样。
类似地,network-detach 将从 domU 中断开一个 vif 并将其销毁。
xm network-detach wiki.xen.prgmr.com 0
上述命令将从域 wiki.xen.prgmr.com 中移除 eth0。
保护 Xen 的虚拟网络
从安全角度来看,Xen 网络有两个方面值得注意。首先,我们想确保用户不能假装成他们不是的人。这通过指定 IP 地址和启用反欺骗规则来解决。其次,我们想保护 dom0 同时允许流量通过到 domUs。这可以通过适当的 iptables 规则轻松处理。
指定 IP 地址
防欺骗规则使用iptables确保 Xen 盒子会丢弃不匹配来自vif的预期地址的数据包,从而保护您的网络免受恶意 domU 的侵害。网络脚本使用iptables添加规则到 FORWARD 链,允许匹配该 IP 地址的数据包通过到 domU 的网络设备。(执行此操作的功能在vif-common.sh中,供好奇者参考。)为了使其工作,您的 FORWARD 链应该有一个 DROP 策略——network-bridge应该自动处理这一点。
我们使用防欺骗功能,network-route通过添加类似规则来实现。已知它不与network-nat一起工作。
将以下内容添加到/etc/xen/xend-config.sxp:
(network-script 'network-bridge antispoof=yes')
并在域配置文件中设置以下内容:
vif=['ip=10.0.0.1',bridge=xenbr0]
(显然,为您的站点使用合适的 IP 和网桥。)
您还可以指定 CIDR 格式的 IP 地址范围(CIDR代表无类别域间路由);即,使用斜杠和设置在子网掩码中的位数,以十进制表示。例如,要允许 10. anything,上一行可以重写为
vif=['ip=10.0.0.1/8']
这并不能阻止 domU 管理员更改 domU 的 IP 地址,但它确实阻止了来自该更改 IP 地址的任何数据包。
防火墙 Dom0
在 Xen 的网络中,INPUT 和 OUTPUT 链不会影响针对 domUs 的数据包。因此,标准防火墙的 INPUT 链,如 Red Hat 的,不会影响 domU 数据包。(当然,domUs 本身可以根据需要防火墙自己的虚拟网络设备。)
注意
许多系统默认情况下不会像预期的那样将桥接流量发送到 FORWARD 链——RHEL/CentOS 5.1 就是这个问题的一个例子。这导致防欺骗规则无法工作。简单的 echo 1 > /proc/sys/net/bridge/bridge-nf-call-iptables 可以解决这个问题。将该行添加到 /etc/xen/scripts/network-bridge 以使其在 Xen 设置其网络时自动运行。
我们在通过 FORWARD 链发送 domU 数据包时遇到的问题仅在于,默认情况下,dom0 会将它们包含在其连接跟踪中。在负载很重的机器上,连接表会填满,机器会丢弃数据包。我们的解决方案是编辑vif-bridge中的frob_iptable()函数,添加如下规则:
iptables -t raw "$c" PREROUTING -m physdev --physdev-in "$vif" "$@" -j NOTRACK
这使得防欺骗功能可以正常工作,同时阻止 domU 流量干扰 dom0,同时允许 domUs 无障碍地访问其数据包。
使用 network-route 进行网络连接
network-route是 Xen 团队最初选择的原选项(并且自那时以来很少有人使用)。它通过创建一个内部 IP 路由器来实现,该路由器将流量转发到和从客户域。请注意,它不执行地址转换——为此您需要network-nat或virbr。它已被network-bridge取代,这提供了更多的灵活性。
然而,network-route确实有其用武之地。一方面,它与上游网络硬件相比是透明的,与network-bridge不同。另一方面,它要简单得多。network-route只是启用 IP 转发,然后在 dom0 中创建iptables规则以将流量转发到正确的虚拟接口。
要使用network-route,只需取消注释相应的行
(network-script network-route)
(vif-script vif-route)
并取消注释相应的network-bridge和vif-bridge行。这就是全部内容。重新启动xend,iptables将显示一个新的规则来处理转发到vif:
# iptables -L FORWARD
Chain FORWARD (policy ACCEPT)
target prot opt source destination
ACCEPT 0 -- 192.168.42.190 anywhere PHYSDEV match --physdev-in n1
ACCEPT udp -- anywhere anywhere PHYSDEV match --physdev-in n1 udp spt:bootpc dpt:bootps
network-route的一个常见“陷阱”是它只有在vif=行中指定了 IP 地址时才起作用——否则脚本不知道要添加哪些规则。因此,至少,上述示例的接口定义应该如下所示:
vif = ['ip="192.168.42.190",vifname="n1"']
使用network-bridge进行网络连接
network-bridge是处理 Xen 中虚拟域网络的标准方式。它使用 Linux 中的桥接工具创建一个虚拟的第二层交换机,并将 Xen 虚拟接口“插入”其中,如图图 5-1 所示。它具有与期望未受污染的以太网帧的协议一起工作的优势。这包括 AoE、TCP/IP 之前的 AppleTalk 版本、NetBEUI、IPX 以及许多来自黑暗时代的其他协议。它还将无缝地与 DHCP 一起工作,DHCP 依赖于广播数据包。它简单、逻辑性强且稳健。
network-bridge(除了其复杂性之外)的最大缺点是当xend启动时,它会拆解并重建真实的网络接口。在某些场景下(例如,当 dom0 有 NFS 根时),这可能是不被接受的。这并不是桥接本身的限制,而是使用 Xen 脚本将桥接附加到 dom0 网络设备时的限制——如果为桥接使用专用物理设备,问题就会消失。
network-bridge的另一个问题是它将物理以太网设备置于混杂模式。在繁忙的网络中,这可能会极大地消耗资源,因为 CPU 必须拦截所有数据包,而不仅仅是那些针对其地址的数据包。最后,出站数据包将具有与物理卡上不同的 MAC 地址,这可能导致与某些无线网络硬件的问题。这也使许多第二层 HTTP 负载均衡器陷入循环——任何只期望每个以太网端口只有一个 MAC 地址的东西都会感到非常困惑。

图 5-1. network-bridge的一些功能
即使有这些注意事项,我们仍然推荐在大多数 Xen 服务器上使用network-bridge。
如果你喜欢,可以手动启动network-bridge脚本。例如,要手动创建一个名为xenbr0的桥接器,并将其附加到eth0,请输入以下内容:
/etc/xen/scripts/network-bridge {start|stop} vifnum=0
注意
如果你将 vifnum 设置在 nloopbacks 之上 ,即使你只有一个桥接,Linux 也会抱怨好像你有比回环更多的桥接。这是因为 Xen 使用 vifnum 来确定它用于前端虚拟设备的数量,这假设了前面虚拟设备的存在。增加 nloopbacks,这样每个人都会满意*。
network-bridge 是默认的网络选项,因此 xend 不需要任何配置即可使用。然而,为了完整性——要配置 Xen 使用 network-bridge,修改 xend-config.sxp 以包含以下行
(network-script network-bridge)
注意
OpenSUSE 用户可能会发现 NetworkManager 会干扰 Xen 的桥接。要解决这个问题,请前往 YaST ► 网络设备 ► 网络卡 并选择 使用 ifup 的传统方法 选项。
此脚本导致 Xen 使用类似于以下设置的桥接:
# brctl show
bridge name bridge id STP enabled interfaces
xenbr0 8000.feffffffffff no vif0.0
peth0
vif9.0
xenbr0 显然是桥的名字。它连接了 dom0 的虚拟以太网接口 (vif0.0)、物理以太网卡和一个 domU 的虚拟接口。我们还可以看到 STP(生成树协议)已被禁用。在默认配置中,进一步的 domUs 将简单地将其接口添加到该桥上。
STP 的目的是防止网络中的环路。如果你在使用虚拟桥接进行任何复杂操作,你可能需要开启 STP。如果你有多个桥接和多个你与 Xen 一起使用的网络端口,这可能是个好主意。
要重命名桥,你可以在 network-bridge 脚本中指定桥名作为选项:
(network-script 'network-bridge bridge=foo')
还要注意,network-bridge 默认将 eth0 绑定到桥接。要更改物理网络卡,请使用
(network-script 'network-bridge bridge=foo netdev=eth1')
然后桥接设置变为
# brctl show
bridge name bridge id STP enabled interfaces
foo 8000.feffffffffff no vif0.01
peth01
vif9.0
使用 network-nat 进行网络连接
network-nat 是 network-route 的扩展,它包含了网络地址转换(简称 NAT,或在某些情况下称为 IP 伪装)。
Xen 伴随提供的 network-nat 脚本以两种方式绕过 network-route 的 DHCP 问题。首先,它可以启动一个本地 DHCP 服务器(因此虚拟域可以获得地址,因为它们现在位于路由器后面)。如果这不可取,它可以使用域 ID 创建本地唯一的 IP 地址。然后它设置一个标准的 iptables 规则用于 IP masq:
Dom0 # iptables -t nat -n -L
Chain POSTROUTING (policy ACCEPT)
target prot opt source destination
MASQUERADE 0 -- 0.0.0.0/0 0.0.0.0/0
Dom0 # iptables -L FORWARD
Chain FORWARD (policy ACCEPT)
target prot opt source destination
ACCEPT 0 -- 10.0.0.0/16 anywhere PHYSDEV
match --physdev-in n1
ACCEPT udp -- anywhere anywhere PHYSDEV
match --physdev-in n1 udp spt:bootpc dpt:bootps
当域启动时,它会获得一个 IP 地址并为自身添加适当的 iptables 规则。Xen 在引导时使用内核级 IP 自动配置机制将地址传递给内核(这不是很复杂吗)。network-nat 也可以与你的 DHCP 服务器集成。
DomU # ifconfig eth0 10.0.2.1/16
DomU # route add default gw 10.0.2.1
DomU # ping 192.168.42.60
PING 192.168.42.60 (192.168.42.60) 56(84) bytes of data.
64 bytes from 192.168.42.60: icmp_seq=1 ttl=63 time=1.94 ms
这显示了域 2 中 eth0 的默认配置 IP 地址。实际数字当然会根据你的设置而变化。
配置变量
正如我们提到的,管理员与 Xen 网络交互的两个基本地方是在 /etc/xen/xend-config.sxp 和域配置文件中。在这些文件中,你关注的是一行:前者的 (network-script) 行和后者的 vif= 行。
这些都会因为语法上的微小错误而严重失败,没有任何解释。(毕竟,这是 Python。如果你喜欢,你可以在配置文件中直接放置任意 Python 代码。配置文件应该始终使用一种 Turing 完整的语言编写。问问埃里克·奥勒曼就知道了。)
network-script行被括号包围,参数用引号括起来,并用空格分隔。例如,以下是一个有效的示例:
(network-script 'network-bridge bridge=xenbr1')
我们已经讨论了vif=行。请注意,vif配置使用与网络脚本设置完全不同的语法,即参数之间用逗号分隔的括号。
vif = ['','bridge=xenbr1','bridge=xenbr2,ip="10.1.2.6"']
这行配置了三个接口,第一个使用默认参数,第二个使用桥接参数,第三个使用桥接和 IP。注意两个单独接口和单独参数之间的逗号。
最后,在一些示例中,你会看到一个dhcp=yes行。除非内核在启动时需要获取其地址(例如,如果它正在通过 NFS 挂载其根文件系统),否则dhcp=行不是必需的。
自定义网络脚本
你可能此时会想,在 Xen 配置文件中指定配置脚本而不是简单地选择内置选项是过度杀鸡用牛刀。但请相信我们:指定自己的网络脚本的能力非常实用。因为 Xen 的网络建立在标准工具之上,所以脚本易于理解并可以根据你的特定需求进行定制。
做这件事最简单的方法,也是大多数配置的足够方法,是创建一个小的包装脚本,该脚本使用适当的参数调用标准 Xen 脚本。你也可以修改标准脚本以源额外的函数并在需要时调用它们——例如,修改防火墙规则或附加监控脚本。
多桥配置
考虑一个场景,你希望在纯虚拟网络上进行跨域 U 通信,每个域都有一个单独的接口与外界通信。
在那种情况下,你需要创建一对桥梁,一个使用默认的 Xen 设置,将物理接口与虚拟接口桥接,另一个只桥接虚拟接口。然后你需要在域配置文件中指定这两个接口,并在域内或配置文件中正常配置它们。
包装器可能看起来像这样:
#!/bin/sh
dir=$(dirname "$0")
"$dir/network-bridge" "$@" vifnum=0
"$dir/network-bridge" "$@" vifnum=1 netdev=dummy0
这会调用network-bridge两次,第一次是正常调用,第二次带有netdev参数,导致network-bridge使用虚拟网络设备而不是真实设备。
要让xend在启动时运行此脚本,请按照以下方式更改xend-config.sxp中的network-script行:
(network-script my-wrapper)
确保my-wrapper脚本可执行,否则将无法正常工作。
要从 domUs 使用这些桥梁,请在vif=行中指定正确的桥梁:
vif= ['mac="aa:0:1:2:3:4",bridge="xenbr1"']
桥接和路由
对这个场景进行轻微修改,将 domU 通信放在自己的桥接器上,然后通过 dom0 中的iptables规则进行路由,如图图 5-2 所示。(编写了执行此操作的脚本的 Arjen Runsink 称这为brouter——桥接和路由的组合。)

图 5-2. 结合桥接和路由
这创建了一个标准桥接器,但它并没有将物理设备附加到它上。相反,桥接器获得了一个 IP 地址和路由。当 domU 启动时,它的vif通过普通的vif-bridge脚本附加到桥接器上。
忽略标准函数等,脚本看起来大致如下:
#!/bin/sh
dir=$(dirname "$0")
. "$dir/xen-script-common.sh"
. "$dir/xen-network-common.sh"
findCommand "$@"
evalVariables "$@"
op_start () {
if [ ""${bridge}" = "null" ] ; then
return
fi
create_bridge ${bridge}
if link_exists "${bridge}" ; then
ip address add dev $bridge $bridgeip
ip link set ${bridge} up arp on
ip route add to $brnet dev $bridge
fi
if [ ${antispoof} = 'yes' ] ; then
antispoofing
fi
}
op_stop () {
ip route del to $brnet dev $bridge
ip link set ${bridge} down arp off
ip address del dev $bridge $bridgeip
brctl delbr ${bridge}
}
case "$command" in
start)
op_start
;;
stop)
op_stop
;;
*)
echo "Unknown command: $command" >&2
echo 'Valid commands are: start, stop' >&2
exit 1
esac
我们删除了show_status函数以节省空间;此脚本的完整版本可在en.opensuse.org/Xen3_and_a_Virtual_Network找到。我们还删除了像$bridgeip这样的参数的默认值,因为那是特定于站点的,并且我们删除了create_bridge和add_to_bridge的声明,因为这些由xen-network-common提供。
在/etc/xen/xend-config.sxp中使用以下两行调用此脚本:
(network-script 'network-virtual bridgeip="10.0.0.1/24" brnet="10.0.0.1/24"')
(vif-script vif-bridge)
进一步思考
这种技术的变体可以用于在特定域的基础上提供日志记录和会计功能,或者只需编辑网络脚本即可设置特定域的防火墙规则。最终,Xen 的网络基础设施非常灵活,你能够对 domU 做任何你能在 dom0(或者,就事论事,在非 Xen 系统)上做的事情,而且有足够的脚本钩子来实现自动化操作。
第六章。DOMU 管理:工具和前端

本书的大部分内容都集中在相对低级的行政任务上。我们关注这个方向有几个原因:首先,因为我们觉得在信任 GUI 工具处理数据之前,先了解它们在做什么会更好,^([34]) 其次,因为附加工具尚未完全开发。
然而,Xen 的真正好处是它允许你做一些事情,这些事情你用简单的物理机集合是无法做到的,或者很难做到。更先进的管理工具的主要优势是它们利用 Xen 虚拟化来提高灵活性。
此外,总是从基础原理开始做所有事情会变得有点单调乏味。在本章中,我们将从我们通常对尽可能繁琐的方式做事的执着中抽身出来,看看 Xen 可用的节省劳动的创新。
广义上,我们可以根据目标受众对各种前端软件包进行分类;一些工具是为 dom0 管理员设计的,而另一些是为 domU 管理员设计的(即在 Xen 的计算服务模型中的客户)。第一组通常专注于提供和销毁虚拟机,而第二组允许用户在没有访问 dom0 的情况下以更高的级别控制自己的虚拟机,例如,给域进行硬重启或在 domU 完全无法启动时恢复。
尽管这种 neat 和理论上有用的劳动分工,我们几乎会完全忽略第二类。有两个原因:首先,大多数最终用户不会想要对他们的 Xen 实例进行任何特别复杂的操作。在我们看来,大多数 Xen 控制面板都是寻找问题的解决方案。其次,截至本文撰写时,我们尝试过的这个类别的几乎所有工具似乎都没有稳定下来.^([35]) 相反,我们将专注于第一类:简化服务提供商生活的软件,从简单到复杂不等。我们将以简要讨论 Xen-shell 结束,这是一个有用的最小客户界面工具。
虚拟机提供商的工具
当寻找管理工具时,就像任何软件一样,首先要问自己的问题是,我需要哪些功能?Xen 管理工具的范围从简单的配置脚本,如 Xen-tools,到面向数据中心的数据包,如 OpenQRM。
假设多个前端都提供了必要的功能,影响您选择前端的最大因素可能是 dom0 操作系统。一些前端,如 Xen-tools,是针对 Debian 设计和构建的。一些与 Red Hat 配合得最好。Slackware 用户,您仍然需要自己动手。尽管您可以在 Debian 上安装virt-manager,但这将是一个困难的过程,与自然法则相悖.^([36]) 在本章中,我们将重点关注每个工具在其原生环境中,从 Debian 的 Xen-tools 开始。
Xen-tools
Xen-tools 在本质上是一个跨平台的 Perl 脚本集合,用于自动化安装,因此它对发行版的选择并不敏感。尽管作者在 Debian 上开发,分发*.deb 包,并有一个 Apt 仓库,但 Xen-tools 在其他系统上安装相对容易,所以我们鼓励您尝试它,无论您运行的是哪个发行版。请从xen-tools.org/下载 tar 包。
安装 Xen-tools
为了保持一切顺利进行,我们在 Debian 机器上使用 Debian 的 Apt 系统安装了 Xen-tools。因为,就像所有与 Xen 相关的东西一样,Xen-tools 正在经历快速的开发,我们选择从作者的仓库中获取包,以避免得到一个旧版本。
要做到这一点,请将他的仓库添加到您的/etc/apt/sources.list中。对于 Etch,我们附加了:
#
# Steve Kemp's repository: Etch
#
deb http://apt.steve.org.uk/etch etch main non-free contrib
deb-src http://apt.steve.org.uk/etch etch main non-free contrib
注意
有时 Apt 中的版本也不如网站上的版本新。如果所有其他方法都失败了,请下载 tar 包,解压它,然后运行 make install 来安装它。
然后像往常一样运行:
# apt-get update
# apt-get install xen-tools
然后,Apt 将执行其习惯性的魔法,安装 Xen-tools 脚本并创建一个配置目录,/etc/xen-tools。
对于使用信息,如果您有perldoc,您可以通过运行带有--manual选项的程序来访问任何程序的嵌入式手册页面。例如:
# xen-create-image --manual
将会打印出一个长而令人畏惧的 man 页面。不要气馁;这只是暴露了 Xen 本身提供的令人眼花缭乱的选项集。您可以通过在 Xen-tools 配置文件中提前指定这些选项中的大多数,而不是通过命令行选项来简化事情。
配置 Xen-tools
因此,让我们创建一个配置文件。请相信我们,花点时间设置一些默认值比每次使用命令时指定全局选项要愉快得多.^([37]) 将您首选的选项放入/etc/xen-tools/xen-tools.conf。我们会使用类似以下的内容:
lvm = verona
size = 2Gb
image = full
memory = 128Mb
swap = 128Mb
fs = ext3
dist = sarge
initrd = /boot/initrd.img-2.6.16-2-xen-686
kernel = /boot/vmlinuz-2.6.16-2-xen-686
install-method = debootstrap
填写适当的值,就像往常一样,并随意从注释丰富的示例配置中添加任何您喜欢的选项。其中一些选项,如initrd和kernel,指定了最终 domU 配置文件中的直接指令。其余的选项大多数都是不言自明的;size指定了文件系统大小,swap是域将拥有的交换空间量,等等。
由于我们指定了 LVM 组,域将使用 LVM 卷作为后端存储。您也可以通过指定dir = /path/而不是 LVM 组来使用文件系统镜像。如果您这样做,请确保该目录存在,否则镜像创建步骤将静默失败,xen-create-image将填充文件系统应该挂载的目录。这几乎肯定不是您想要的。
还请注意dist=行;这指定了xen-create-image将运行哪个集合的后安装钩子脚本以配置新域。如果没有在/usr/lib/xen-tools下对应于dist值的目录,xen-create-image将带有一个指导性的错误信息退出。如果您不想在创建时配置域,您可以创建一个空目录——比如/usr/lib/xen-tools/plan9——并将发行版的名称(在这种情况下为plan9)作为 dist 值传递。
当您已经填充了配置文件后,实际上创建域变得非常简单,几乎可以说是平淡无奇的。只需在命令行上指定一个主机名,最好是完全限定名称,以便安装后脚本可以正确配置镜像,然后工具会完成剩余的工作。例如:
# xen-create-image mercutio.prgmr.com
注意
尽管设置完全限定域名允许安装后脚本处理域名配置,但在某些 Red Hat 衍生版本上,它可能会与 xendomains 脚本发生冲突,因为该脚本假设 domU 名称不超过 18 个字符。
使用之前显示的配置文件,这将创建两个逻辑卷,/dev/verona/mercutio.prgmr.com-disk和/dev/verona/mercutio.prgmr.com-swap。然后挂载磁盘卷,并使用debootstrap安装 sarge(Debian 3.1)。
容易。
Xen-tools 和基于 RPM 的 DomU 镜像
Xen-tools 的第一版是为考虑使用debootstrap安装 Debian 而开发的。然而,这个包已经走了很长的路,并且它已经被推广到支持几乎所有的系统。基于 RPM 的发行版通过类似debootstrap的工具得到支持。其他系统——甚至是非 Linux 系统——可以通过复制原始文件系统镜像或提取 tar 包来安装。
尽管 Xen-tools 的旧版本使用了 RPMstrap,我们过去曾成功使用过它,但 RPMstrap 的作者已经停止了开发。因此,Xen-tools 的作者一直在开发一个名为rinse的替代品。这是使用 Xen-tools 安装 CentOS 和 Fedora 的推荐方式,并且它本身也是一个相当整洁的包。
rinse的首页位于xen-tools.org/software/rinse/。您可以从该网站的下载页面下载,或者通过添加他的apt仓库并通过您的包管理器下载。
对rinse配置选项的全面讨论可能在这里不合适。我们敦促您阅读精美的手册。然而,它默认情况下与xen-create-image的安装方法配合使用,使用以下简单的命令行:
# xen-create-image --hostname tybalt.prgmr.com --install-method=rinse
dist=centos-5
没问题。
Xen-tools 安装后操作
在镜像安装后,但在它第一次启动之前,xen-create-image会做一些安装后工作。首先,它在挂载的 domU 文件系统中运行一些脚本以执行设置任务,例如设置主机名和禁用不需要的 getty。最后,它创建一个配置文件,以便您可以启动域。
在这个阶段,您也可以让机器通过角色来自行配置——指定--role <script>命令行选项,在安装结束时运行位于/etc/xen-tools/role.d中的相应脚本,以 domU 根文件系统的挂载点作为参数。您需要的角色将取决于您的需求。例如,您可能需要区分 Web、邮件和 DNS 服务器角色的角色。Xen-tools 发行版附带了一些您可以在此基础上构建的示例。
在填充 domU 镜像后,xen-create-image脚本将基于/etc/xen-tools/xm.tmpl中的模板创建一个配置文件。您也可以使用--template选项在命令行上指定一个模板。
扩展配置文件模板
您可以像您所想象的那样自由地编辑模板。Xen-tools 通过读取环境变量将选项传递给设置脚本,这使得通过传递新变量并添加解释它们的代码来扩展模板变得容易。
例如,因为我们喜欢使用 PyGRUB,我们可能会通过在kernel和initrd部分下方添加一个bootloader选项来编辑模板:
{ if ( $bootloader )
{
$OUT.= "bootloader = '$bootloader'";
}
}
现在我们可以通过指定环境变量中的附加值来创建镜像:
# bootloader=/usr/bin/pygrub xen-create-image --hostname tybalt.prgmr.com
--install-method=rinse --dist=centos-5
就像魔法一样,配置文件将会有一个bootloader条目。
我们还可以更新解析配置文件的脚本,让它将值作为环境变量传递,就像其他选项一样。
xen-list-images
在使用xen-create-image或其他方式创建了一些域之后,您可能会想查看机器上存在的域的摘要。因此,Xen-tools 套件还包括一个列出现有域的工具,即xen-list-images。在我们的测试系统上运行它将显示:
# xen-list-images
Name: mercutio.prgmr.com
Memory: 128
DHCP
Name: benvolio.prgmr.com
Memory: 96
IP: 192.168.1.93
Name: tybalt.prgmr.com
Memory: 128
DHCP
工具解析 Xen 配置文件——无论是 Xen-tools 创建的还是其他方式创建的——并打印一些信息。
xen-delete-image
最后,我们有xen-delete-image,它确实如名称所暗示的那样工作。它只适用于遵循xen-create-image使用的命名约定的镜像,也就是说,它没有解析任意域定义所需的智能。尽管如此,如果您已经标准化了 Xen-tools 或使用 Xen-tools 使用的格式命名磁盘,它可能很有用。
警告
当以 root 身份运行此命令时,即使您已指定 --test 选项,它也会不确认地销毁数据。
按照这种方式运行xen-delete-image,但请非常小心:
# xen-delete-image --lvm verona mercutio.prgmr.com
这将删除 mercutio.prgmr.com-disk 和 mercutio.prgmr.com-swap 从 verona VG,并删除配置文件。如果未指定数据源选项,则默认为 /etc/xen-tools/xen-tools.conf 中的值。
libvirt、virsh 和 virt-manager
在 RPM 方面,包括 SUSE、CentOS 和 Fedora,我们有一套基于 libvirt 的工具。尽管 Debian 基础发行版和 Solaris 也提供了相应的包,但 libvirt 主要是在 Red Hat 上、为 Red Hat 开发并由 Red Hat 大量贡献的,这在项目焦点上有所体现。
libvirt 本身不是一个管理工具,但在这里提一下作为 Xen 前端,它是位于 Xen 前面的框架的一部分,使得管理工具的开发更加容易。libvirt 项目(在 libvirt.org/)的既定目标是“提供一个长期稳定的 C API 用于虚拟化。”换句话说,libvirt 的目标是允许单个工具控制 libvirt 支持的任何类型的虚拟化,包括 Xen。这听起来很棒。然而,基于 libvirt 的工具仍然不完整。特别是,它们对 Red Hat 的关注有时会带来不便。
libvirt 的主要优势是它与 Red Hat 的工具集成非常紧密,并且管理工具 virt-manager 对于与实时虚拟机交互来说非常出色。
基本的基于 libvirt 的工具——或者至少是这个工具的第一代、概念验证版本——是 virsh,或称为 虚拟化外壳。目前它可以在 Xen、QEMU、KVM 或 OpenVZ 域上执行与 xm 相同的大多数操作。
这里不是提供 virsh 的完整指南的地方;我们正在撰写关于 Xen 的文章,因此我们专注于 xm。然而,virsh 是 Red Hat 的首选前端,因此我们将提供一些讨论和示例,但我们将坚持使用 Xen 和 virsh 作为 xm 替代品的特性,而不是强调 virsh 引入的新功能。
关于 virsh 的第一点要提到的是,它在域定义方面使用与 xm 完全不同的语法。virsh 有一个 create 命令,就像 xm 一样,但它期望一个 XML 文件作为参数。
幸运的是,virsh 允许您从 Xen 域创建 XML 定义。例如,要获取正在运行的域 ophelia 的 XML 定义:
# virsh dumpxml ophelia
<domain type='xen' id='8'>
<name>ophelia</name>
<uuid>162910c82a0c03332349049e8e32ba90</uuid>
<bootloader>/usr/bin/pygrub</bootloader>
<os>
<type>linux</type>
<kernel>/var/lib/xen/vmlinuz.8gmQDM</kernel>
<initrd>/var/lib/xen/initrd.H3wHj2</initrd>
<cmdline>ro root=/dev/VolGroup00/LogVol00 rhgb quiet</cmdline>
</os>
<memory>105472</memory>
<vcpu>1</vcpu>
<on_poweroff>destroy</on_poweroff>
<on_reboot>restart</on_reboot>
<on_crash>restart</on_crash>
<devices>
<interface type='bridge'>
<source bridge='xenbr0'/>
<mac address='00:16:3e:4b:af:c2'/>
<script path='vif-bridge'/>
</interface>
<graphics type='vnc' port='5900'/>
<disk type='file' device='disk'>
<driver name='tap' type='aio'/>
<source file='/opt/xen/images/ophelia.img'/>
<target dev='xvda'/>
</disk>
<console tty='/dev/pts/6'/>
</devices>
</domain>
您可以看到这个 XML 定义与域配置文件之间的对应关系;它以不同但仍然可识别的格式定义了相同的基本资源。我们可以将其重定向到文件,例如 ophelia.xml,关闭原始的 ophelia,并创建一个域:
# virsh dumpxml ophelia > ophelia.xml
# virsh shutdown ophelia
# virsh create ophelia.xml
virsh 也可以列出域,就像 xm 一样:
# virsh list
Id Name State
----------------------------------
0 Domain-0 running
4 ophelia blocked
最后,就像 xm 一样,virsh 可以使用明显的命令来 shutdown、restart 或 destroy 一个域。
virt-manager
除了我们在第三章中讨论的virt-install之外,套件中最有用的工具可能是virt-manager。它相当不错,在 Xen-tools 脚本未覆盖的领域表现得很出色:与实时虚拟机交互。如图 6-1 所示,virt-manager提供了一个集中位置,可以查看性能数据、虚拟帧缓冲和控制台。它还提供了资源分配的快速概述。像大多数 GUI 工具一样,virt-manager可能需要更多的手动操作和对话框点击,比您用于日常 domU 创建的要多。尽管如此,它支持 Xen 的基本生命周期:创建和销毁。它还与 Red Hat 的 Kickstart 部署方法集成,方便半自动化安装;您只需在安装对话框中指定一个.ks文件即可。
virt-manager 入门
由于virt-manager随 Red Hat 系列发行版中的操作系统一起提供,假设您在安装过程中选择了虚拟化目标,您可以在不按键盘的情况下调用它。从默认的 GNOME 桌面,点击左上角的应用程序菜单,然后系统工具 >> 虚拟机管理器。当提示时,输入您的 root 密码,并选择本地虚拟机管理程序以连接到xend的本地实例。^([38]) 您将看到一个看起来有点像图 6-1 的东西。

图 6-1。这里可以看到 virt-manager 的用户界面。它有一个主屏幕,列出了虚拟机;一个详细视图,显示了虚拟机资源、性能和统计信息;以及一个帧缓冲控制台和文本控制台界面。
要使用virt-manager创建镜像,请点击文件菜单,然后选择新建虚拟机。virt-manager随后将引导您通过一系列友好的对话框。
第一个提示要求输入机器的名称。输入一个合适的名称,但请确保它只包含字母、数字和下划线——完全合格的域名将不起作用。
选择新域应该是半虚拟化还是完全虚拟化。如果你没有 HVM,对话框会责备你硬件不足,并将完全虚拟化选项变灰。在这个示例中,我们选择半虚拟化。
然后 virt-manager 会要求安装媒体。因为它在后台调用 virt-install,所以适用相同的约束;输入一个可网络访问的 Red Hat 风格目录树。例如,archive.fedoraproject.org/pub/archive/fedora/linux/releases/7/Fedora/i386/os/ 将从 HTTP Fedora 镜像安装 Fedora 7。
在这个阶段,你也可以使用相同的语法指定一个 Kickstart 文件。这是一种方便的自动化安装过程的方法。例如,为了复制 dom0 的安装配置,你可以将你的 /root/anaconda-ks.cfg 文件上传到某个方便的地方,并指定它。
选择为新虚拟机选择存储后端。这两个选项映射到 phy: 和 tap:aio: 设备。GUI 还提供了创建稀疏文件选项,但我们不建议这样做,原因我们在 第三章 中详细描述过。
选择一个网络选项。这两个选项对应于 network-nat 工作类似和标准的 network-bridge。
最后,选择内存和 CPU 分配。
最后,virt-manager 将列出你的配置,并给你一个退出的机会。确保一切看起来正确,然后点击 完成。它将验证你的选择,然后使用 virt-install 开始创建域。
域的创建本身可能是 libvirt 套件中最酷的功能。它不是从 dom0 中填充文件系统然后启动一个 Xen 实例,而是下载一个 Xen 兼容的 net 安装镜像,立即从安装内核启动域,然后使用该内核下载软件包并填充系统。安装看起来就像一个正常的安装,使用帧缓冲控制台提供完全普通的 Red Hat 安装体验。因为 virt-manager 集成了 VNC 查看器,你可以在管理应用程序内观看安装过程。
当域正在运行时,你可以暂停它,关闭它,或从主 virt-manager 窗口中检查其配置。右键单击域名以获取一个包含操作列表的上下文菜单,或者通过单击它来选择域,并使用顶部按钮栏。
注意
早期版本的 virt-manager,包括与 Red Hat Enterprise Linux 5.0 一起发布的版本,存在一个疏忽,即当域停止时,它将从 GUI 列表中消失,因此无法在没有降级到命令提示符的情况下重新启动。如果你有一个受影响的版本,你可以很容易地使用 xm 以正常方式重新启动由 virt-manager 配置的域。
然而,virt-manager对于大型安装来说交互性太强且限制太多,不适合使用。为了解决这个问题,红帽的先进技术组(et.redhat.com/)也在开发一个名为 oVirt 的工具,该工具旨在在整个数据中心内扩展基于 libvirt 的管理。另一个工具,Puppet Recipe Manager,强调虚拟化的软件设备方面。它允许管理员构建软件配方并在虚拟机上自动安装它们。我们还在第三章中提到了 Cobbler,这是一个可以自动配置虚拟机的自动化工具。
你可能还想看看的一个基于 libvirt 的工具是virt-clone,它能够在改变必须唯一的任何项目(如 MAC 地址)的同时,复制一个 domU 镜像及其配置文件——在便利性和控制之间取得了很好的平衡。
它运行起来很简单,大部分输入都来自命令行选项。例如,要将机器sebastian克隆为viola:
# virt-clone -o sebastian -n viola -f /opt/xen/viola-root.img -f /opt/xen/
viola-swap.img preserve-data
^([34]) 一个不太可能引起系统管理员太多争议的位置。
^([35]) 我们责备 Python 对兼容性的焦土政策。
^([36]) 当然有软件包,但它们的集成程度较低。
^([37]) 有没有人知道 Cdrecord?
^([38]) 嗯,如果你是以 root 身份登录的,你就不需要输入任何内容了。当然,我们并不推荐这样做。
虚拟化数据中心的管理
这些前端的主要好处在于执行那些对于简单工具来说太大或太复杂的任务,尽管有些人认为没有问题对于编写良好的 shell 脚本来说太大。这些工具中最大和最好的能够让 Xen 真正发挥其能力,从而产生像我们在亚马逊的 EC2 中看到的那样的大型自动化系统。在这个类别中包括几个软件包,如 OpenQRM、ConVirt 和 Enomalism。这三个都有其支持者。然而,我们选择在更高级的管理前端稳定下来之前,专注于更低级别、更常见可用的工具。
虚拟机客户管理
尽管有许多软件包旨在允许客户管理他们的虚拟机,但我们认为在这个上下文中控制平面操作并不是真正必要的。此外,大多数面向客户的工具仍在变化之中。在这个阶段,我们很难推荐它们。
至少目前,最好的解决方案似乎是通过一个合理简单的菜单,让客户可以连接到控制台、重启他们的机器、关闭他们的机器以及重新创建他们的 domU 镜像。有很多种方法可以做到这一点。我们最喜欢的方法是允许客户 SSH 到一个控制服务器,并拥有严格限制的账户。
Xen-shell
虽然我们喜欢在第七章(第七章. 在 XEN 下托管不受信任的用户:来自战壕的经验教训)中描述的管理方法,但对于那些认为即使他们没有亲自编写软件,软件也可以完全足够的人来说,还有其他选择。在这些选择中,我们最喜欢的是 Xen-shell。它是 Xen-tools 的作者编写的,也是他无装饰风格的另一个例子。我们推荐它,不仅仅是因为我们喜欢 Xen-tools 或因为它有一个好的功能集,而是因为它没有庞大的依赖列表。这是一个简单但能很好地完成工作的产品。
它可以在 xen-tools.org/software/xen-shell/ 找到。下载后,使用标准的 unpack && make install 过程进行安装。
到目前为止,还有一些配置需要完成。Xen-shell 通过接收用户命令并对其输入做出 sudo xm 的响应来工作。您需要将 xm 添加到它们的路径中,或者相反,修改它们的路径以包含 xm。我们采取了前者方法:
# ln -s /usr/sbin/xm /usr/bin
我们还需要配置 /etc/sudoers,以确保用户可以使用 sudo 在他们的域名上运行 xm(并且仅限于他们的域名)。这涉及到对文件的大量添加,每个命令一个:
marlowe ALL=NOPASSWD:/usr/sbin/xm create goneril
marlowe ALL=NOPASSWD:/usr/sbin/xm create -c goneril
marlowe ALL=NOPASSWD:/usr/sbin/xm destroy goneril
marlowe ALL=NOPASSWD:/usr/sbin/xm shutdown goneril
marlowe ALL=NOPASSWD:/usr/sbin/xm list goneril
marlowe ALL=NOPASSWD:/usr/sbin/xm console goneril
marlowe ALL=NOPASSWD:/usr/sbin/xm reboot goneril
然后将适当用户的 shell 更改为 Xen-shell。例如:
# chsh -s /usr/local/bin/xen-login-shell marlowe
要标记一个用户有权管理一个域名,只需将该用户添加到域名配置文件中的一行——这是一个优雅且巧妙的解决方案。我们将以域名 goneril 为例:
name = 'goneril'
xen-shell = 'marlowe'
现在,当 marlowe 登录时,他将看到 Xen-shell 接口,他可以从该接口执行各种命令(通过输入 Help 获取列表)。
注意
尽管 Xen-shell 读取域名配置文件以查找用户可以管理的域名,但它实际上并没有跟踪配置文件的名称,截至本文写作时。为了与 Xen-shell 的 boot 命令一起工作,域名配置文件名必须采用以下形式 <domU name>.cfg。因此,goneril 的配置文件必须是 /etc/xen/goneril.cfg。
为了扩展这个例子,假设 marlowe 可以管理多个域名。只需将用户名添加到这两个域名中,并使用 Xen-shell 中的 control 命令在它们之间切换。Xen-shell 的一个优点是,只有当命令必要时才会显示。
xen-shell[goneril]> control regan
Controlling: regan
xen-shell[regan]>
方便,不是吗?
然而,这仅仅是开始。Xen 的客户端软件仍然处于混乱之中,由多个派系不断开发。
你可能已经注意到我们遗漏了一些突出的前端。一方面,我们甚至没有提到思杰的产品,因为我们已经在第十一章中对其进行了介绍。同样,我们也没有涉及亚马逊的 EC2,这可能是目前最接近实用计算的服务。一如既往,工具领域广阔无垠,我们的目标只是让它们看起来易于管理,并讨论对我们有效的方法。
第七章。在 Xen 下托管不受信任的用户:来自战壕的经验教训

现在我们已经了解了 Xen 管理的基础——存储、网络、配置和管理工作——让我们看看如何在实践中应用这些基础知识。本章主要是一个案例研究,关于我们的 VPS 主机公司 prgmr.com,以及我们从向公众出租 Xen 实例中学到的经验教训。
公共 Xen 主机托管最重要的教训是,用户不能被信任与他们或彼此合作。有些人总是会试图尽可能多地获取资源。我们的重点将在于防止这种公共资源的悲剧。
用户优势
用户想要使用 Xen VPS 而不是支付在您的数据中心共同放置一个盒子的费用,只有一个基本原因:它便宜,尤其是对于那些只对一些基本服务感兴趣的人,而不是对大量原始性能感兴趣的人。
网格计算与虚拟化
与 Xen 相关的一个经常听到的术语是 网格计算。网格计算背后的基本思想是你可以快速自动地配置和销毁节点。亚马逊的 EC2 服务是一个很好的网格计算平台示例,允许你按小时租用 Linux 服务器。
网格计算不需要虚拟化,但这两个概念非常紧密地联系在一起。一个人可以设计一个使用物理机器和 PXEboot 的系统,以实现快速、简单、自动化的配置,而不使用 Xen,但虚拟化系统会使设置更加轻量级、灵活和高效。
有几个开源项目正在尝试创建一个标准且开放的接口来配置“网格计算”资源。其中一个这样的项目是 Eucalyptus (www.eucalyptus.com/)。我们觉得像这样的标准框架——允许你轻松地在网格计算提供商之间切换——如果“网格”要生存下去,是必不可少的。
Xen 还为用户提供与在数据中心共同放置一个盒子几乎相同的所有优势:他们自己的公开路由网络接口、他们自己的磁盘、root 访问等等。使用 128MB 的虚拟机,他们可以运行 DNS、轻量级邮件服务、Web 服务器、IRC、SSH 等等。对于这些轻量级服务,盒子的功率远不如其基本存在重要——仅仅有东西可用并且公开可访问就使生活更加便利。
您还有虚拟化的基本优势,即,托管一个具有 32GB RAM 的服务器比托管 32 个每个 1GB RAM 的服务器(或者甚至 4 个每个 8GB RAM 的服务器)便宜得多。实际上,考虑到 RAM 的价格,我认为即使是经济上证明托管一个小于 32GB RAM 的一般用途服务器也是困难的。
Xen 的最后一个重要特性是,与其他虚拟化系统相比,它拥有轻量级、强大分区和稳健资源控制的良好组合。与一些其他虚拟化选项不同,它是连贯的——用户可以依赖获得他注册的确切数量的内存、磁盘空间和网络带宽,以及大约相同数量的 CPU 和磁盘带宽。
共享资源及其保护
Xen 的设计与良好的安全性相一致。
— Tavis Ormandy taviso.decsystem.org/virtsec.pdf
在安全专家的标准下,这是一个响亮的认可。总的来说,使用 Xen,我们不必担心人们从虚拟机中逃逸——Xen 本身应该提供适当的隔离级别。在半虚拟化模式下,Xen 不会将硬件驱动程序暴露给 domUs,这消除了一个主要的攻击向量.^([39]) 在大多数情况下,保护 dom0 就像保护任何其他服务器一样,除了在一个领域。
那个可能引起关注的领域是共享资源的访问控制,它们并不完全万无一失。主要担忧是恶意用户可能会获得比他们应得的更多资源,或者在极端情况下,通过利用 Xen 的会计漏洞来造成拒绝服务攻击。换句话说,我们是在执行性能隔离的业务,而不是特别试图通过 domUs 保护 dom0 免受攻击。
我们在这里展示的大多数资源控制都是针对那些不一定是有恶意——只是可能过于热情——的用户。
调整 CPU 使用率
最感兴趣的第一个共享资源是 CPU。虽然内存和磁盘大小很容易调整——你可以在配置文件中指定内存,而磁盘大小由后端设备的大小决定——细粒度 CPU 分配需要你调整调度器。
调度器基础
Xen 调度器在运行域之间充当裁判。在某种程度上,它很像 Linux 调度器:它可以在需要时抢占进程,它尽力确保公平分配,并确保 CPU 尽可能少地浪费周期。正如其名所示,Xen 的调度器负责在物理 CPU 上调度域。这些域反过来,从它们内部的运行队列中调度和运行进程。
由于 dom0 在 Xen 看来只是另一个域,因此它受到与 domUs 相同的调度算法的影响。如果它没有被分配足够高的权重,这可能会导致问题,因为 dom0 必须能够响应 I/O 请求。我们将在描述调整域权重的通用程序之后,稍后更详细地讨论这个话题。
Xen 可以使用各种调度算法,从简单的到复杂的。尽管 Xen 过去已经附带了许多调度器,但我们将专注于信用调度器;它是当前默认且推荐的选择,也是 Xen 团队表示有兴趣保持的唯一调度器。
xm dmesg命令会告诉您,包括但不限于 Xen 正在使用哪个调度器。
# xm dmesg | grep scheduler
(XEN) Using scheduler: SMP Credit Scheduler (credit)
如果您想更改调度器,可以将它设置为引导参数——例如,要将调度器更改为 SEDF 调度器,请将sched=sedf附加到 GRUB 中的内核行。(这是 Xen 内核,而不是由第一个module行加载的 dom0 Linux 内核。)
虚拟 CPU 和物理 CPU
为了方便起见,我们认为每个 Xen 域都有一个或多个虚拟 CPU(VCPUs),这些虚拟 CPU 定期在物理 CPU 上运行。这些是在运行时消耗信用点的实体。要检查虚拟 CPU,请使用xm vcpu-list <domain>:
# xm vcpu-list horatio
Name ID VCPUs CPU State Time(s) CPU Affinity
horatio 16 0 0 --- 140005.6 any cpu
horatio 16 1 2 r-- 139968.3 any cpu
在这种情况下,该域有两个虚拟 CPU(VCPUs),0 和 1。虚拟 CPU 1 在(物理)CPU 1 上处于运行状态。请注意,Xen 会尽可能地将虚拟 CPU 分散到各个 CPU 上。除非您手动固定,否则虚拟 CPU 有时会切换到其他物理 CPU,具体取决于可用的物理 CPU。
要指定域的虚拟 CPU 数量,请在配置文件中指定vcpus=指令。您还可以在域运行时使用xm vcpu-set更改虚拟 CPU 的数量。但是,请注意,您可以通过这种方式减少虚拟 CPU 的数量,但不能增加超过初始计数的虚拟 CPU 数量。
要设置 CPU 亲和性,请使用xm vcpu-pin <domain> <vcpu> <pcpu>。例如,要切换域horatio中的 CPU 分配,使 VCPU0 在 CPU2 上运行,VCPU1 在 CPU0 上运行:
# xm vcpu-pin horatio 0 2
# xm vcpu-pin horatio 1 0
同样,您可以在域配置文件中固定虚拟 CPU(/etc/xen/horatio,如果您使用我们标准的命名约定)如下:
vcpus=2
cpus=[0,2]
这为域提供了两个虚拟 CPU,将第一个虚拟 CPU 固定在第一个物理 CPU 上,并将第二个虚拟 CPU 固定在第三个物理 CPU 上。
信用调度器
Xen 团队设计了信用调度器以最小化浪费的 CPU 时间。这使得它成为一个节能调度器,因为它试图确保 CPU 在有任何工作要做时始终在工作。
因此,如果有比 domUs 需求更多的真实 CPU 可用,所有 domUs 都将获得它们想要的全部 CPU。当存在竞争时——也就是说,当 domUs 总体上需要的 CPU 比实际存在的 CPU 多时——调度器将在需要 CPU 的域之间公平仲裁。
Xen 尽力做到公平分配,但调度并不完美。特别是,由域 0 服务 I/O 所花费的周期不计入责任域,导致 I/O 密集型客户端获得不成比例的 CPU 使用量。尽管如此,在非病态情况下,您可以得到相当好的分配。(此外,根据我们的经验,CPU 大部分时间都是空闲的。)
信用额调度器为每个域分配一个权重和可选的上限。权重表示域的相对 CPU 分配——如果 CPU 稀缺,权重为 512 的域将比权重为 256(默认值)的域获得两倍的 CPU 时间。上限设置了一个域可以使用的 CPU 时间的绝对限制,以 CPU 的百分之一表示。请注意,在多处理器主机上,CPU 上限可以超过 100。
调度器将权重转换为每个 VCPU 的信用额分配,使用一个单独的会计线程。随着 VCPU 的运行,它会消耗信用额。如果一个 VCPU 耗尽了信用额,它只有在其他更节俭的 VCPU 执行完毕后才能运行,如图图 7-1 所示。定期地,会计线程会遍历并给每个人更多的信用额。

图 7-1. VCPUs 等待在两个队列中:一个用于有信用额的 VCPUs,另一个用于超出分配额的 VCPUs。一旦第一个队列耗尽,CPU 将从第二个队列中获取。
在这种情况下,细节可能不如实际应用重要。使用xm sched-credit命令,我们可以根据每个域调整 CPU 分配。例如,这里我们将增加域的 CPU 分配。首先,列出域 horatio 的权重和上限:
# xm sched-credit -d horatio
{'cap': 0, 'weight': 256}
然后,为了修改调度器的参数:
# xm sched-credit -d horatio -w 512
# xm sched-credit -d horatio
{'cap': 0, 'weight': 512}
当然,"512"这个值只有相对于机器上运行的其它域才有意义。确保适当地设置所有域的权重。
要为域设置上限:
# xm sched-credit -d domain -c cap
提供商的调度
我们决定按照可用的 RAM 来划分 CPU——从逻辑上讲,支付盒子一半 RAM 的用户会比拥有 64MB 域的用户需要更多的 CPU。因此,在我们的设置中,拥有 25%RAM 的客户也至少拥有 25%的 CPU 周期。
做这件事的简单方法是为每个 CPU 分配一个等于其内存兆字节的权重,并留空上限。然后,调度器将处理将其转换为公平的比例。例如,我们之前提到的拥有半数 RAM 的用户将获得与其他用户加在一起相当的 CPU 时间。
当然,这是最坏的情况;这就是用户在 CPU 不断争夺的环境中会得到的结果。空闲域会自动释放 CPU。如果除了一个域之外的所有域都空闲,那么这个域可以独占整个 CPU。
注意
确保 dom0 有足够的 CPU 来处理 I/O 请求是至关重要的。你可以通过为 dom0 分配一个 CPU 或者给 dom0 一个非常高的权重来实现这一点——足够高以确保它永远不会耗尽信用额度。在 prgmr.com,我们通过为每个 domU 根据其 RAM 量分配权重,并将 dom0 的权重设置为 6000 来解决这一问题。
当处理多处理器系统时,这个简单的权重=内存公式会变得稍微复杂一些,因为独立的 CPU 分配系统开始发挥作用。一个好的规则是按内存比例(因此按权重比例)分配 VCPUs。例如,在一个具有四个核心(且关闭超线程)的机器上,拥有半数 RAM 的域至少应该有至少两个 VCPUs。另一个解决方案是给所有域分配与机器中物理处理器数量相等的 VCPUs——这将允许所有域达到物理机器的完整 CPU 容量,但可能会导致上下文交换带来的开销增加。
控制网络资源
网络资源控制对于任何类型的共享托管操作来说都是至关重要的。我们从 Xen 托管中学到的许多经验之一是,如果你提供免费带宽,一些用户会充分利用它。这不是 Xen 特有的观察结果,但在 Xen 易于提供的廉价 VPS 托管中尤为明显。
我们更喜欢使用network-bridge,因为这是默认设置。要更深入地了解network-bridge,请参阅第五章。
监控网络使用
由于一些用户可能会尽可能多地消耗带宽,因此拥有一种监控网络流量的方式至关重要.^([40])
为了监控网络使用情况,我们在物理 SPAN 端口上使用 BandwidthD。这是一个简单的工具,用于计算通过交换机的字节数——这里没有 Xen 特有的内容。我们对此感到放心,因为我们的提供商只允许进出 IP 数据包,并且我们的反欺骗规则足够强大,足以保护我们免受用户在出站数据包上欺骗 IP 的侵害。
一种类似的方法是扩展dom0 是一个交换机的类比,并使用 SNMP 监控软件。如第五章中所述,如果你这样做,为每个域指定一个vifname是很重要的。无论如何,我们将带宽监控的细节留给你。
ARP CACHE POISONING
如果你使用默认的network-bridge setup,你将像在任何二层交换机上一样容易受到 ARP 缓存中毒的攻击。
想法是,第二层交换机(如network-bridge使用的虚拟交换机)上的接口计数器在流量通过特定端口时监控流量。每当交换机看到一个以太网帧或 ARP is-at 时,它会记录它来自哪个端口和 MAC 地址。如果它收到一个目的地为缓存中 MAC 地址的帧,它会将那个帧发送到正确的端口(并且只有正确的端口)。如果桥接器看到一个目的地为不在缓存中的 MAC 地址的帧,它会将那个帧发送到所有端口。41]
聪明吗?在大多数情况下,这意味着你几乎从未看到目的地为其他 MAC 地址的以太网帧(除了广播等)。然而,这个特性纯粹是为了优化,而不是安全措施。正如那些有电缆提供商并且对 MAC 地址验证非常了解的人所知,伪造 MAC 地址相当简单。这意味着恶意用户可以用虚假的 MAC 地址填满(大小有限的)ARP 缓存,驱逐好的数据,并迫使所有数据包通过所有接口。此时,交换机基本上变成了一个集线器,所有端口的计数器都会显示任何端口的流量。
我们已经找到了两种绕过这个问题的方法。你可以使用 Xen 的network-route网络模型,它不使用虚拟桥接。另一种方法是忽略接口计数器,并使用类似 BandwidthD 的东西,它基于 IP 数据包进行计费。
一旦你能够快速检查流量,下一步就是塑造用户。网络流量整形和监控的原则与独立盒子相同,只是你还可以在 Xen 主机上实施策略。让我们看看如何限制特定接口的入站和出站流量——比如说,你有一个客户超出了他的带宽配额。
网络整形原则
关于整形,首先要知道的是,它只适用于出站流量。尽管可以对入站流量进行监控,但效果并不理想。幸运的是,在它们通过 dom0 的过程中,两个方向的流量在某个时刻看起来都像是出站流量,如图图 7-2 所示。(在以下描述中,当我们提到出站和入站流量时,我们是指从 domU 的角度来看。)

图 7-2. 入站流量来自互联网,通过虚拟桥接,并由一个简单的非层次化过滤器进行整形。另一方面,出站流量需要通过一个将数据包分配到层次队列纪律类别的过滤系统。
调整入站流量
我们将从入站流量开始,因为它比出站流量更容易限制。调整入站流量的最简单方法可能是令牌桶过滤器队列纪律,这是一种简单、有效且轻量级的方法来降低接口速度。
令牌桶过滤器,或 TBF,其名称来源于令牌桶的隐喻。令牌以定义和恒定的速率流入桶中。发送的每个数据字节从桶中取走一个令牌并立即出去——当桶为空时,数据只能以令牌流入的速度传输。桶本身具有有限的容量,这保证了只会一次性发送合理数量的数据。要使用 TBF,我们需要添加一个 qdisc(队列纪律)来执行实际的流量限制工作。要将虚拟接口 osric 限制为每秒 1 兆比特,突发速率最高为 2 兆比特,最大允许延迟为 50 毫秒:
# tc qdisc add dev osric root tbf rate 1mbit latency 50ms peakrate 2mbit maxburst 40MB
这将在设备 osric 上添加一个 qdisc。下一个参数指定了添加的位置(root)以及它是什么类型的 qdisc(tbf)。最后,我们指定了速率、延迟、突发速率和可以以突发速率传输的量。这些参数对应于令牌流量、数据包允许的延迟量(在驱动程序向操作系统发出其缓冲区已满的信号之前),桶可以清空的最大速率以及桶的大小。
调整出站流量
在调整入站流量后,我们可以专注于限制出站流量。这稍微复杂一些,因为所有域的出站流量都通过单个接口,所以单个令牌桶不起作用。警察过滤器可能有效,但它们通过丢弃数据包来处理问题,这是……不好的。相反,我们将对出站物理以太网设备 peth0 应用流量整形,使用层次令牌桶,或 HTB qdisc。
HTB 纪律类似于简单的令牌桶,但具有桶的层次结构,每个桶都有自己的速率,以及一个将数据包分配到桶的过滤系统。以下是设置方法。
首先,我们必须确保 Xen 虚拟桥上的数据包通过 iptables:
# echo 1 > /proc/sys/net/bridge/bridge-nf-call-iptables
这样我们就可以根据哪个 domU 发射的数据包来标记数据包。还有其他原因,但就我们的流量整形设置而言,这是重要的一个。接下来,对于每个 domU,我们添加一个规则来标记来自相应网络接口的数据包:
# iptables -t mangle -A FORWARD -m physdev --physdev-in baldr -j MARK --set-mark 5
这里数字 5 是一个任意的标记——数字本身并不重要,只要数字与域之间有一个有用的映射即可。我们使用域 ID。我们也可以直接使用匹配源 IP 地址的tc过滤器,但将所有内容与域的物理网络设备相关联感觉更优雅。请注意,我们使用physdev-in——从 domU 出去的流量进入 dom0,正如图 7-3 所示。

图 7-3. 我们将物理设备进入 dom0 的流量形状为 domU 的流量,并将 domU 离开的流量形状为在虚拟设备上进入 dom0 的流量。
接下来我们创建一个 HTB qdisc。我们不会过多地介绍 HTB 选项——有关更多详细信息,请参阅luxik.cdi.cz/~devik/qos/htb/manual/userg.htm上的文档:
# tc qdisc add dev peth0 root handle 1: htb default 12
然后我们创建一些类别来放置流量。每个类别将从一个 domU 接收流量。(如 HTB 文档所述,我们还在创建一个父类别,以便它们可以共享多余的带宽。)
# tc class add dev peth0 parent 1: classid 1:1 htb rate 100mbit
# tc class add dev peth0 parent 1:1 classid 1:2 htb rate 1mbit
现在我们已经为 domU 的流量定义了一个类别,我们需要一个过滤器来将数据包分配给它。
# tc filter add dev peth0 protocol ip parent 1:0 prio 1 handle 5 fw flowid 1:2
注意,我们正在匹配之前使用iptables设置的“处理”方式。这会将数据包分配到 1:2 类别,我们之前将其限制为每秒 1 兆比特。
到目前为止,目标 domU 的进出流量基本上已经被形状,如图 7-4 所示。你可以轻松地将这些命令添加到你的vif脚本末尾,无论是vif-bridge、vif-route还是包装器。我们还想强调,这只是一个示例,而且lartc.org/上的 Linux 高级路由和流量控制指南是一个寻找进一步文档的优秀地方。tc手册页也是信息丰富的。

图 7-4. 形状过滤器的影响
^([39]) 在 HVM 模式下,模拟的 QEMU 设备有一定的风险,这也是我们不提供 HVM 域的部分原因。
^([40]) 在这种情况下,我们谈论的是带宽监控。你也应该运行某种类型的入侵检测系统(IDS),例如 Snort,以监视外出滥用(我们确实这样做),但这与 Xen 没有特定关系。
^([41]) 在这里,我们使用“端口”和“接口”这两个词可以互换。在具有 SNMP 功能的交换机上的接口计数器上下文中,这是一种合理的简化。
共享托管环境中的存储
就像系统管理中的许多其他事情一样,一点规划可以避免很多麻烦。事先想清楚你将存储原始文件系统镜像的位置,配置文件将放在哪里,客户数据将存放在哪里。
对于原始镜像,有很多约定——有些人使用/diskimages,有些人使用/opt/xen, /var/xen或类似路径,有些人使用/home的子目录。选择一个并坚持下去。
配置文件应该无一例外地放在/etc/xen中。如果你没有为xm create提供一个完整路径,它将在/etc/xen中查找文件。不要让它失望。
至于客户数据,我们建议严肃的托管提供商使用 LVM。这比 blktap-mapped 文件提供了更大的灵活性和可管理性,同时保持了良好的性能。第四章涵盖了与 LVM(或至少足够开始)一起工作的细节,以及许多其他可用的存储选项及其优点。在这里,我们只关注我们从共享托管冒险中学到的经验教训。
使用ionice调节磁盘访问
VPS 托管的一个常见问题是客户——或者你自己的维护过程,如备份——会使用足够的 I/O 带宽来减慢机器上所有人的速度。此外,I/O 实际上并不受前面讨论的调度器调整的影响。一个域可以请求数据,交出 CPU,并保存其信用额度,直到它被通知数据到达。
虽然你不能像网络 QoS 那样设置磁盘访问速率的硬限制,但你可以使用ionice命令将不同的域优先级划分为子类,语法如下:
# ionice -p <PID> -c <class> -n <priority within class>
在这里,-n是你通常会调整的旋钮。它可以从 0 到 7 不等,数字越小优先级越高。
我们建议始终指定类为 2。其他类也存在——3 是空闲,1 是实时——但空闲非常保守,而实时则非常激进,有可能锁定系统。类内优先级旨在实现比例分配,因此更有可能是你想要的。
让我们看看ionice的实际应用。在这里,我们将使用两个不同的域来测试ionice,一个具有最高的正常优先级,另一个具有最低的优先级。
首先,ionice只与 CFQ I/O 调度器一起工作。为了确认你正在使用 CFQ 调度器,请在 dom0 中运行以下命令:
# cat /sys/block/[sh]d[a-z]*/queue/scheduler
noop anticipatory deadline [cfq]
noop anticipatory deadline [cfq]
括号中的词是选定的调度器。如果不是[cfq],请使用参数elevator =cfq重新启动。
接下来,我们找到我们想要ionice的过程。由于在这个例子中我们使用tap:aio设备,dom0 进程是tapdisk。如果我们使用phy:设备,它将是[xvd <domain id> <device specifier>]。
# ps aux | grep tapdisk
root 1054 0.5 0.0 13588 556 ? Sl 05:45 0:10 tapdisk
/dev/xen/tapctrlwrite1 /dev/xen/tapctrlread1
root 1172 0.6 0.0 13592 560 ? Sl 05:45 0:10 tapdisk
/dev/xen/tapctrlwrite2 /dev/xen/tapctrlread2
现在我们可以对域进行ionice处理。请注意,tapctrl设备的数量对应于域启动的顺序,而不是域 ID。
# ionice -p 1054 -c 2 -n 7
# ionice -p 1172 -c 2 -n 0
为了测试ionice,让我们运行几个 Bonnie++进程并计时。(在 Bonnie++完成后,我们dd一个负载文件,只是为了确保其他域的条件保持不变。)
prio 7 domU tmp # /usr/bin/time -v bonnie++ -u 1 && dd if=/dev/urandom of=load
prio 0 domU tmp # /usr/bin/time -v bonnie++ -u 1 && dd if=/dev/urandom of=load
最后,根据墙上的时钟,优先级为 0 的 domU 花费了 3:32.33 来完成,而优先级为 7 的 domU 需要 5:07.98。如您所见,ionice优先级提供了一个有效的方法来进行比例 I/O 分配。
应用ionice的最佳方式可能是查看 CPU 分配并将它们转换为优先级类别。CPU 分配最高的域获得优先级 1,其次是优先级 2,依此类推。dom0 中的进程应根据适当的方式进行 ionice 处理。这将确保合理的优先级,但不会允许大 domU 占用全部 I/O 带宽。
备份 DomUs
作为服务提供商,人们很快就会了解到客户不会自己进行备份。当磁盘失败(不是如果——而是当),客户会期望您有他们数据的完整备份,如果您没有,他们会非常难过。所以让我们来谈谈备份。
当然,您已经对如何备份物理机器有了很好的了解。备份 Xen 域有两个方面:首先,是域的虚拟磁盘,我们希望像备份真实机器的磁盘一样备份它。其次,是域的运行状态,可以从 dom0 中保存和恢复。通常,我们所说的备份纯粹是指磁盘,就像物理机器一样,但有一个优势,即我们可以使用域快照来暂停域足够长的时间,以获取一个干净的磁盘镜像。
我们使用xm save和 LVM 快照来备份域的存储和运行状态。LVM 快照不是实现全写时复制的良好方式,因为它们处理“快照空间不足”的情况不佳,但如果您想保留足够长的文件系统状态以进行一致的备份,它们是非常好的。
我们的实现使用普通的cp(在基于文件的 domU 的情况下)或dd(对于phy:设备)来复制整个磁盘镜像。这是因为我们非常希望避免在 dom0 中挂载可能不干净的文件系统,这可能导致整个机器恐慌。此外,如果我们进行原始设备备份,domU 管理员将能够使用 dom0 无法读取的文件系统(例如 OpenSolaris domU 上的 ZFS)。
一个适合我们描述的适当脚本可能是:
#!/usr/bin/perl
my @disks,@stores,@files,@lvs;
$domain=$ARGV[0];
my $destdir="/var/backup/xen/${domain}/";
system "mkdir -p $destdir";
open (FILE, "/etc/xen/$domain") ;
while (<FILE>) {
if(m/^disk/) {
s/.*\[\s+([^\]]+)\s*\].*/\1/;
@disks = split(/[,]/);
# discard elements without a :, since they can't be
# backing store specifiers
while($disks[$n]) {
$disks[$n] =~ s/['"]//g;
push(@stores,"$disks[$n]") if("$disks[$n]"=~ m/:/);
$n++;
}
$n=0;
# split on : and take only the last field if the first
# is a recognized device specifier.
while($stores[$n]) {
@tmp = split(/:/, $stores[$n]);
if(($tmp[0] =~ m/file/i) || ($tmp[0] =~ m/tap/i)) {
push(@files, $tmp[$#tmp]);
}
elsif($tmp[0] =~ m/phy/i) {
push(@lvs, $tmp[$#tmp]);
}
$n++;
}
}
}
close FILE;
print "xm save $domain $destdir/${domain}.xmsave\n";
system ("xm save $domain $destdir/${domain}.xmsave");
foreach(@files) {
print "copying $_";
system("cp $_ ${destdir}") ;
}
foreach $lv (@lvs) {
system("lvcreate --size 1024m --snapshot --name ${lv}_snap $lv");
}
system ("xm restore $destdir/${domain}.xmsave && gzip $destdir/${domain}.xmsave");
foreach $lv (@lvs) {
$lvfile=$lv;
$lvfile=~s/\//_/g;
print "backing up $lv";
system("dd if=${lv}_snap | gzip -c > $destdir/${lvfile}.gz" ) ;
system("lvremove ${lv}_snap" );
}
将其保存为,比如说,/usr/sbin/backup_domains.sh,并告诉cron在适当的间隔执行脚本。
该脚本通过保存每个域,复制基于文件的存储,并快照 LVs 来实现。当这些操作完成后,它将恢复域,备份保存文件,并通过dd备份快照。
注意,当域暂停并快照时,用户将看到服务出现短暂的故障。我们测量了不到三分钟的停机时间,以获取一个具有千兆内存的域的一致备份——这对于大多数应用程序来说都在可接受的参数范围内。然而,对整个磁盘进行位对位复制可能会在一定程度上降低性能。^([42)] 我们建议在非高峰时段进行备份。
要查看 prgmr.com 上使用的其他脚本,请访问 book.xen.prgmr.com/。
^(42)) 幽默的夸张。
对 DomU 的远程访问
对于 VPS 用户来说,正常访问的故事表面上很简单:Xen 虚拟机与托管设施中的普通机器完全一样。他们可以 SSH 进入它(或者如果你提供 Windows,可以使用 rdesktop)。然而,当出现问题时,用户将需要一种方式来以更低级别访问该机器,就像他们坐在 VPS 的控制台前一样。
为此,我们提供了一个他们可以 SSH 进入的控制台服务器。最简单的方法是将 dom0 作为他们的控制台服务器,并严格限制他们的账户。
注意
类似地,我们认为任何托管机器都应该连接一个串行控制台。^([43)] 我们在 第十四章 中讨论了我们的理由和使用 Xen 与串行控制台的具体细节。
模拟串行控制台
Xen 通过 xm 提供了基本的串行控制台功能。您可以在 dom0 内通过输入 xm console <domain> 访问一个虚拟机的控制台。输入命令后,完成操作时按 ctrl-] 退出串行控制台。
这种方法的缺点是 xm 必须以 dom0 的有效 UID 0 运行。虽然这在有信任的 domU 管理员的环境中是合理的,但当您给任何拥有 5 美元的人提供账户时,这并不是一个好主意。在 VPS 托管环境中处理不受信任的 domU 管理员,需要做一些额外的工作来限制使用 ssh 和 sudo 的访问。
首先,配置 sudo。编辑 /etc/sudoers 并为每个用户追加:
<username> ALL=NOPASSWD:/usr/sbin/xm console <vm name>
接下来,为每个用户,我们创建一个类似于这样的 ~/.ssh/authorized_keys 文件:
no-agent-forwarding,no-X11-forwarding,no-port-forwarding,command="sudo xm
console <vm name>" ssh-rsa <key> [comment]
这行允许用户使用其密钥登录。一旦登录,sshd 将连接到命名的域控制台并将其自动呈现给用户,从而将 domU 管理员排除在外。此外,请注意以 no 开头的选项。它们很重要。我们不是提供 shell 账户的业务。这是一个纯控制台服务器——我们希望人们使用他们的 domU 而不是 dom0 来处理标准的 SSH 事务。这些设置将允许用户通过 SSH 访问其域控制台,同时将他们对 dom0 的访问降到最低。
为用户提供的菜单
当然,让每个用户访问他的控制台只是开始。通过将 authorized_keys 中的 command 字段更改为自定义脚本,我们可以提供一个具有令人惊讶的功能系列的菜单!
这里是一个我们称之为 xencontrol 的示例脚本。将其放置在文件系统中的某个位置——比如 /usr/bin/xencontrol——然后在 authorized_keys 文件中设置一行来调用 xencontrol 而不是 xm console。
#!/bin/bash
DOM="$1"
cat << EOF
`sudo /usr/sbin/xm list $DOM`
Options for $DOM
1\. console
2\. create/start
3\. shutdown
4\. destroy/hard shutdown
5\. reboot
6\. exit
EOF
printf "> "
read X
case "$X" in
*1*) sudo /usr/sbin/xm console "$DOM" ;;
*2*) sudo /usr/sbin/xm create -c "$DOM" ;;
*3*) sudo /usr/sbin/xm shutdown "$DOM" ;;
*4*) sudo /usr/sbin/xm destroy "$DOM" ;;
*5*) sudo /usr/sbin/xm reboot "$DOM" ;;
esac
当用户通过 SSH 登录时,SSH 守护进程会代替用户的登录 shell(我们建议将其设置为 /bin/false 或您平台上的等效项)运行此脚本。脚本随后会输出一些状态信息、一条信息性消息和一系列选项。当用户输入一个数字时,它会运行相应的命令(我们已经通过配置 sudo 允许用户运行这些命令)。
^([43]) 我们使用其他远程控制台工具的经验总体上并不愉快。串行重定向系统工作得相当好。IP KVM 几乎比在前面面板上的代码切换更可取。在好日子里。
PyGRUB,一个 DomUs 的引导加载程序
到目前为止,我们描述的配置基本上都在配置文件中指定了 domU 的引导配置,使用 kernel、ramdisk 和 extra 行。然而,还有一种替代方法,即在配置文件中指定一个 bootloader 行,然后使用它来从 domU 的文件系统加载内核。
最常用的引导加载程序是 PyGRUB,或 Python GRUB。解释 PyGRUB 的最佳方式可能是回顾它基于的程序,GRUB,即 GRand Unified Bootloader。GRUB 本身是一个传统的引导加载程序——一个程序,它位于硬盘上的某个位置,BIOS 可以加载并执行它,然后它自己加载并执行内核。
因此,PyGRUB 就像 domU 的 GRUB。Xen 域构建器通常在虚拟机启动时直接从 dom0 文件系统加载操作系统内核(因此本身就像一个引导加载程序)。相反,它可以加载 PyGRUB,然后充当引导加载程序并从 domU 文件系统加载内核。^([44)]
PyGRUB 很有用,因为它允许 dom0 和 domU 的管理职责之间有更完美的分离。在虚拟化数据中心时,您希望将虚拟硬件交给客户。PyGRUB 更有效地虚拟化了硬件。特别是,这意味着客户可以更改自己的内核,而无需 dom0 管理员的干预。
注意
PyGRUB 被提及为可能的安全风险,因为它直接从 dom0 读取未信任的文件系统。PV-GRUB(见“PV-GRUB:PyGRUB 的一个更安全的替代方案?”PV-GRUB:PyGRUB 的一个更安全的替代方案?),它从 dom0 加载一个可信的半虚拟化内核,然后使用它来加载和跳转到 domU 内核,应该会改善这种情况。
PV-GRUB:PyGRUB 的一个更安全的替代方案?
PV-GRUB 是升级到 Xen 3.3 的绝佳理由。PyGRUB 的问题在于,虽然它是一个很好的引导加载程序的模拟,但它必须在 dom0 中挂载 domU 分区,并且与 domU 文件系统交互。这至少导致了至少一个远程执行漏洞。PV-GRUB 通过加载一个实际上是 GRUB 引导加载程序的虚拟化版本的可执行文件来避免这个问题,然后它完全在 domU 中运行。
这还有一些其他优点。您实际上可以在 domU 内部加载 PV-GRUB 二进制文件,这意味着您可以从只读分区加载您的第一个menu.lst文件,然后它将传递到用户分区,这意味着与我的 PyGRUB 设置不同,用户永远不可能将他们的menu.lst搞到无法进入救援镜像的程度。
注意,Xen 可以在 32 位或 64 位模式下创建域,并且之后无法切换。这意味着 64 位的 PV-GRUB 无法加载 32 位 Linux 内核,反之亦然。
我们在prgmr.com的 PV-GRUB 设置从正常的xm配置文件开始,但没有引导加载程序,并且有一个指向 PV-GRUB 的kernel=行,而不是 domU 内核。
kernel = "/usr/lib/xen/boot/pv-grub-x86_64.gz"
extra = "(hd0,0)/boot/grub/menu.lst"
disk = ['phy:/dev/denmark/horatio,xvda,w','phy:/dev/denmark/rescue,xvde,r']
注意,我们调用 PV-GRUB 的架构特定二进制文件。32 位(PAE)版本是pv-grub-x86_32。
这足以加载一个常规的menu.lst,但关于我所说的那个坚不可摧的救援镜像怎么办?这是我们在新的prgmr.com Xen 3.3 服务器上这样做的方法。在xm配置文件中:
kernel = "/usr/lib/xen/boot/pv-grub-x86_64.gz"
extra = "(hd1,0)/boot/grub/menu.lst"
disk = ['phy:/dev/denmark/horatio,xvda,w','phy:/dev/denmark/rescue,xvde,r']
然后,在救援磁盘上的/boot/grub/menu.lst文件中:
default=0
timeout=5
title Xen domain boot
root (hd1)
kernel /boot/pv-grub-x86_64.gz (hd0,0)/boot/grub/menu.lst
title CentOS-rescue (2.6.18-53.1.14.el5xen)
root (hd1)
kernel /boot/vmlinuz-2.6.18-53.1.14.el5xen ro root=LABEL=RESCUE
initrd /boot/initrd-2.6.18-53.1.14.el5xen.img
title CentOS installer
root (hd1)
kernel /boot/centos-5.1-installer-vmlinuz
initrd /boot/centos-5.1-installer-initrd.img
title NetBSD installer
root (hd1)
kernel /boot/netbsd-INSTALL_XEN3_DOMU.gz
第一个条目是正常引导,使用 64 位的 PV-GRUB。其余的是各种救援和安装引导。请注意,我们为救援条目指定了(hd1);在这种情况下,第二个磁盘是救援磁盘。
正常引导加载 PV-GRUB 和用户的/boot/grub/menu.lst文件,从(hd0,0)加载。我们的默认用户可编辑的menu.lst看起来像这样:
default=0
timeout=5
title CentOS (2.6.18-92.1.6.el5xen)
root (hd0,0)
kernel /boot/vmlinuz-2.6.18-92.1.6.el5xen console=xvc0
root=LABEL=PRGMRDISK1 ro
initrd /boot/initrd-2.6.18-92.1.6.el5xen.img
PV-GRUB 仅在 Xen 3.3 及以上版本上运行,并且看起来 Red Hat 没有计划将 PV-GRUB 回滚到 RHEL 5.x使用的 Xen 版本。
使 PyGRUB 工作
域的文件系统需要包含一个包含适当文件的/boot目录,就像常规的 GRUB 设置一样。我们通常为/boot创建一个单独的块设备,并将其作为配置文件中的第一个磁盘条目提供给 domU。
要尝试 PyGRUB,请向 domU 配置文件中添加bootloader=行:
bootloader = "/usr/bin/pygrub"
当然,由于这是 Xen,可能不会这么简单。如果您使用 Debian,请确保您已安装libgrub, e2fslibs-dev和reiserfslibs-dev。(Red Hat Enterprise Linux 和相关发行版使用默认的 Xen 设置中的 PyGRUB,并且它们将必要的库包含在 Xen 软件包中。)
即使安装了这些库,也可能在没有人工干预的情况下无法工作。较旧的 PyGRUB 版本期望虚拟磁盘有一个分区表而不是原始文件系统。如果您遇到问题,这可能就是原因。
在 PyGRUB 的现代版本中,在 domU 的虚拟磁盘上不需要分区表。
使用 PyGRUB 进行自我支持
在 prgmr.com,我们给 domU 管理员提供修复和自定义他们自己的系统的能力,这也为我们节省了大量安装和支持不同发行版的工作。为了实现这一点,我们使用 PyGRUB 并确保每位客户都有一个可引导的只读救援镜像,如果他们的操作系统安装出现问题,他们可以引导进入。不想让我们进行镜像的客户域配置文件看起来如下。
bootloader = "/usr/bin/pygrub"
memory = 512
name = "lsc"
vif = [ 'vifname=lsc,ip=38.99.2.47,mac=aa:00:00:50:20:2f,bridge=xenbr0' ]
disk = [
'phy:/dev/verona/lsc_boot,sda,w',
'phy:/dev/verona_left/lsc,sdb,w',
'phy:/dev/verona_right/lsc,sdc,w',
'file://var/images/centos_ro_rescue.img,sdd,r'
]
注意,我们现在正在向虚拟主机导出四个磁盘:虚拟 sda 上的 /boot 分区,为 PyGRUB 保留;两个用于用户数据的磁盘,sdb 和 sdc;以及作为 sdd 的只读 CentOS 安装。
一个技术足够的用户,有了这个设置和控制台访问权限,几乎不需要从 dom0 管理员那里获得帮助。他或她可以更改操作系统,引导自定义内核,设置软件 RAID,如果出现问题,可以引导 CentOS 安装来修复设置。
设置 PyGRUB 的 DomU
使其工作唯一重要的其他部分是有效的 /grub/menu.lst,它看起来非常像常规 Linux 安装中的 menu.lst。我们的默认设置如下,并存储在作为 sda 导出的磁盘上:
default=0
timeout=15
title centos
root (hd0,0)
kernel /boot/vmlinuz-2.6.18-53.1.6.el5xen console=xvc0 root=/dev/sdb ro
initrd /boot/initrd-2.6.18-53.1.6.el5xen.XenU.img
title generic kernels
root (hd0,0)
kernel /boot/vmlinuz-2.6-xen root=/dev/sdb
module /boot/initrd-2.6-xen
title rescue-disk
root (hd0,0)
kernel /boot/vmlinuz-2.6.18-53.1.6.el5xen console=xvc0 root=LABEL=RESCUE
ro
initrd /boot/initrd-2.6.18-53.1.6.el5xen.XenU.img
注意
/boot/grub/menu.lst 通常被链接到 /boot/grub/grub.conf 或 /etc/grub.conf。/boot/grub/menu.lst 仍然是重要的文件。
与原生 Linux 一样,如果你为 /boot 分区使用单独的分区,你需要要么在 /boot 的根目录下创建一个指向 . 的符号链接,要么使你的内核名称相对于 /boot。
在这里,第一个和默认条目是 CentOS 发行版的内核。第二个条目是一个通用的 Xen 内核,第三个选择是只读救援镜像。就像在原生 Linux 中一样,你也可以通过标签而不是磁盘号来指定设备。
在虚拟磁盘上处理分区
在标准配置中,分区 1 可能是 /boot,分区 2 是 /。在这种情况下,分区 1 将具有与正常 GRUB 相同的配置文件和内核格式。
使用 fdisk 在 LVM 设备上创建这些分区很简单。对于文件来说,这样做要困难一些。首先,使用 losetup 将文件附加到循环:
# losetup /dev/loop1 claudius.img
然后以通常的方式创建两个分区,使用你喜欢的分区编辑器:
# fdisk /dev/loop1
然后,无论你是使用 LVM 设备还是循环文件,都使用 kpartx 从该设备的分区表中创建设备节点:
# kpartx -av /dev/loop1
设备节点将在 /dev/mapper 下以 devnamep# 的格式创建。在新分区上创建你喜欢的文件系统类型:
# mke2fs /dev/mapper/loop1p1
# mke2fs -j /dev/mapper/loop1p2
# mount /dev/mapper/loop1p2 /mnt
# mount /dev/mapper/loop1p1 /mnt/boot
将你的文件系统镜像复制到 /mnt,确保有效的 GRUB 支持文件在 /mnt/boot 中(就像常规的 GRUB 设置一样),然后你就完成了。
^([44]) 这是一个过于简化的说法。实际上发生的情况是 PyGRUB 从 domU 文件系统复制一个内核,将其放在 /tmp 目录下,然后写入适当的域配置,以便域构建者能够完成其工作。但这个区别通常并不重要,所以我们选择将 PyGRUB 视为它假装的引导加载程序。
总结
本章讨论了我们多年来依赖 Xen 所学到的内容。主要涉及如何在独立、不合作的虚拟机之间分区和分配资源,特别是针对 VPS 托管。我们描述了为什么你可能会在 Xen 上托管 VPS;针对 CPU、磁盘、内存和网络访问的具体分配问题;备份方法;以及让客户通过脚本和 PyGRUB 进行自助服务。
注意,本章与其他章节之间有一些重叠。例如,我们提到了一些关于网络配置的内容,但在 第五章 网络中,我们对此进行了更详细的讨论。我们在备份的上下文中描述了 xm save,但在 第九章 中,我们对其进行了更多讨论,并探讨了它与迁移的关系。Xen 主机托管非常有趣。它并没有让我们变得富有,但它带来了一系列挑战,并给了我们机会做一些有趣的事情。
第八章。超越 Linux:使用 Xen 与其他类 Unix OSS

我们之前忽略的一个主要优势是能够在单个虚拟化物理机上运行多个操作系统。尽管 Linux 是在 Xen 下运行的最受欢迎的操作系统,但并非唯一的选择。几个其他类 Unix 操作系统可以作为 dom0 运行,而且更多已经被修改为作为虚拟化 domUs 运行。
除了 Linux 之外,只有 Solaris 和 NetBSD 能够在当前版本的 Xen 中作为 dom0 运行。其他 BSD 和 Plan9 也进行了一些工作,但这些操作系统要么只能作为 domU 运行,要么只能与较旧的 Xen 版本一起工作。然而,支持正在迅速发展。(FreeBSD 似乎已经非常接近拥有功能性的 Xen 位元。)
在本章中,我们将重点关注 Solaris 和 NetBSD。部分原因是它们拥有成熟的 Xen 支持,包括积极的社区参与和持续的开发。但最重要的是,我们已经在生产环境中运行了它们。在后续章节中,我们将讨论 Windows。
Solaris
Sun 在最近发布的 OpenSolaris 社区版本中大力推广 Xen 虚拟化,并且他们的努力得到了体现。Solaris 既可以作为 dom0 也可以作为 domU 运行,并且与 Xen 集成紧密。唯一的缺点是,截至本文撰写时,OpenSolaris 不支持 Xen 3.3 和 paravirt_ops domUs。
注意
Sun 实际上并没有将他们提供的 Xen 版本称为 Xen。他们使用 xVM 这个术语进行市场营销,并将无关的 VirtualBox 包含在 xVM 标签下。然而,我们将继续称其为 Xen,因为我们已经习惯了这个名字。
只有 x86 版本的 Solaris 支持 Xen——Solaris/SPARC 使用其他虚拟化技术。
使用 Solaris 进行虚拟化
Sun 作为一家传统的“中等铁”公司,长期以来一直强调虚拟化,并采用了几种不同的、互补的技术来实现不同层次的虚拟化。以下是它们非 Xen 虚拟化产品概述。
在基于新 UltraSparc Niagara 的系统上,纯硬件虚拟化是通过逻辑域(LDoms)或 LDoms 提供的。这些是早期 Sun Enterprise 平台上发现的 动态系统域 的后继者,允许你将 CPU 和内存板分配给独立的操作系统实例。同样,在相对较新的 SPARC 机器上,你可以使用处理器的硬件虚拟化支持来分区 CPU 和内存,以运行多个独立的操作系统。
在 x86 上,Sun 通过他们的 VirtualBox 产品解决全虚拟化问题。VirtualBox 尽可能直接执行客户代码,并在必要时进行模拟,这与 VMware 类似。
最后,Sun 通过 Solaris Zones 解决了操作系统级别的虚拟化问题,^([45)) Zones 本身是一个有趣且轻量级的虚拟化选项。与其他操作系统级别的虚拟化平台一样,Zones 在操作环境之间提供了相当大的隔离,同时开销很小。
Sun 甚至提供了在 x86_64 上的 Solaris 下运行 Linux 二进制文件的选择,通过lx品牌的 Zones。(lx品牌的 Zones 在 Solaris 内核和 Linux 用户空间之间提供了一个薄薄的兼容层。相当酷。)然而,Linux 仿真并不完美。例如,由于lx品牌的 Zones 使用与实际硬件上运行的相同 Solaris 内核,因此你不能加载 Linux 设备驱动程序。
Solaris 入门
要在 Xen 下运行 Solaris,你需要获取一份 Solaris 的副本。有几个版本,所以请确保你选择正确的版本。
你不希望使用 Solaris 10,这是当前 Sun 的 Solaris 版本。尽管它是一个不错的操作系统,但由于其开发落后于前沿,它没有 Xen 支持。(在这方面,它迎合了其市场细分。我们认识一些运行 Solaris 8 的人——与普遍的 Linux 观点形成鲜明对比,即六个月以上的软件是一种历史遗迹。)
幸运的是,Solaris 10 并非唯一的选择。Solaris Express 作为下一个官方 Solaris 版本的预览,本身就是一个完全能够胜任 Xen 的操作系统。它集成了 Xen,但仍然略落后于最新的开发。它也不像 OpenSolaris 那样受欢迎。
最后,还有 OpenSolaris。Sun 在一段时间前根据通用开发与分发许可协议^([46))(CDDL)发布了大量的 Solaris 源代码,自那以后社区一直在对其进行开发。OpenSolaris 就是其结果——它类似于 Sun 发布的 Solaris,但采用了新技术和更快的发布周期。将两者之间的关系想象成类似于 Red Hat Enterprise Linux 和 Fedora,只是更加紧密。
Solaris Express 和 OpenSolaris 都集成了 Xen 支持。Solaris Express 在 DVD 上包含了 Xen 软件包,而 OpenSolaris 则需要你作为附加组件下载 Xen。它们都提供了相当完善的体验。尽管有其他基于发布版 Solaris 代码的发行版,但它们都没有特别针对 Xen,因此官方认可的发行版可能是开始的最佳选择。
运行 Solaris Express
在撰写本章时,我们遇到了一些困难,决定是专注于 OpenSolaris 还是 Solaris Express。我们决定选择 OpenSolaris,因为它似乎更受欢迎,这是基于我们对朋友进行的一次完全非科学的调查。
然而,Solaris Express 仍然是一个功能完善的操作系统,拥有出色的 Xen 支持,因此我们也包括了一些关于如何设置它的说明。
信不信由你,Xen 支持应该几乎完全预装.^([47]) 当您在支持 Xen 的系统上安装 Solaris Express 时,它会安装一个 Xen 内核,并为您提供从 GRUB 启动它的选项——只需选择 Solaris xVM 然后出发。(包含的 Xen 版本为 3.1.4,截至 snv_107。)
从那里,您可以正常安装 domUs。它甚至有 virt-manager。请参阅下一节以获取有关设置 domUs 的更多详细信息。这些步骤中的大多数将同样适用于 Solaris Express 和 OpenSolaris。
通常情况下,在关于 Xen 的讨论中,有三个可能的 (Open)Solaris 配置值得关注。
-
首先,我们有 Solaris dom0。
-
第二,有一个 Solaris domU 在 Solaris dom0 上。这是一个相当直接的设置。
-
最后,您可以在 Linux 下以最小的麻烦运行 Solaris domU。
Solaris Dom0
让我们从设置 OpenSolaris dom0 开始,因为您将在下一节中需要它。(尽管我们认为这仅适用于您在做一些疯狂的事情,比如按顺序运行我们所有的示例。)
注意,我们将使用 pfexec,这是 Solaris 的 sudo 等效物,^([49]) 在这些示例中,因此不需要以 root 身份执行这些步骤。
首先,从 opensolaris.org/os/downloads/ 下载发行版。按照指示解包并刻录到 CD 上,然后从 CD 启动,就像安装任何其他操作系统一样。
OpenSolaris LiveCD 对于安装过 Ubuntu 的人来说可能很熟悉。它实际上非常相似,有一个标准的 GNOME 桌面,一些生产力软件,以及一个可爱的 安装 OpenSolaris 图标在桌面上。双击 安装 OpenSolaris 图标以启动安装程序,然后按照其指示操作。
当安装程序完成时,它会提示您重新启动。
设置 Xen
如果您重新启动后注意到您没有 Xen 可用,请不要慌张。与 Solaris Express 不同,OpenSolaris 在初始安装中不包括 Xen 软件包。(毕竟,所有内容都必须适合在 CD 上。)您将需要手动安装和设置它们。
首先,我们创建一个 ZFS 引导环境。(如果您不熟悉引导环境,可以将单词 快照 替换掉。想法是,如果您在尝试安装 Xen 时破坏了系统,您可以重新启动到原始环境并再次尝试。)
$ pfexec beadm create -a -d xvm xvm
$ pfexec beadm mount xvm /tmp/xvm
接下来,我们使用 OpenSolaris 的 pkg 命令在新引导环境中安装 Xen 软件包。
$ pfexec pkg -R /tmp/xvm install xvm-gui
截至 OpenSolaris 2008.11,xvm-gui 软件包集群提供了所有必要的 Xen 软件包。之前的版本可能需要您单独安装这些软件包。如果您需要这样做,您应该能够通过运行以下命令来解决问题:
# pkg install SUNWxvmhvm
# pkg install SUNWvirtinst
# pkg install SUNWlibvirt
# pkg install SUNWurlgrabber
这些软件包提供了 Xen(带有 HVM)、virt-install 以及 virt-install 的依赖项。
接下来,我们需要更新 GRUB 以正确引导 Xen 内核。
在 OpenSolaris 中,menu.lst 位于 /rpool/boot/grub/menu.lst。编辑 xvm 菜单项,使其看起来像以下内容:
title xvm
findroot (pool_rpool,0,a)
bootfs rpool/ROOT/xvm
kernel$ /boot/$ISADIR/xen.gz
module$ /platform/i86xpv/kernel/$ISADIR/unix /platform/i86xpv/kernel/$ISADIR/
unix -B $ZFS-BOOTFS,console=text
module$ /platform/i86pc/$ISADIR/boot_archive
注意,我们正在使用扩展 GRUB,它允许在 menu.lst 中使用变量,例如 $ISADIR(用于指令集架构)。除此之外,它是一个相当正常的 Xen GRUB 配置,包括虚拟机管理程序、内核和 ramdisk。
重新启动。
Solaris SMF
当你开始配置 Solaris dom0 时,你可能会立即注意到一些文件并不完全在你预期的位置。首先,Solaris 没有名为 /etc/xen 的目录,也没有在 /etc/init.d 中的常规脚本。各种支持脚本位于 /etc/xen/scripts 中,而不是 /usr/lib/xen/scripts。你可以将域配置放在你喜欢的任何位置。(我们实际上创建了一个 /etc/xen 目录并将域配置放在里面。)
与依赖标准的 Xen 配置文件不同,Solaris 通过其自身的管理框架 SMF(服务管理设施)来处理配置和服务启动。你可以使用 svccfg 命令检查和更改 xend 的设置:
# svccfg -s xend listprop
这将输出 xend 服务的属性列表。例如,要启用迁移:
# svccfg -s xend setprop config/xend-relocation-address = \"\"
# svcadm refresh xend
# svcadm restart xend
你可能需要使用 svcadm 手动启用与 Xen 相关的服务,尤其是如果你最初启动的是非 Xen 内核。要查看哪些服务已停止,请使用 svcs:
# svcs -xv
如果 Xen 服务因维护或禁用而停止,你可以使用 svcadm 启用它们:
# svcadm enable store
# svcadm enable xend
# svcadm enable virtd
# svcadm enable domains
# svcadm enable console
从那个点开始,你应该能够将 Solaris 作为完全正常的 dom0 操作系统使用。它甚至有 libvirt。祝您玩得开心。
创建 Solaris DomU
你真的以为这会那么简单吗?有几个小细节需要注意——这些细节使得在 Solaris 下运行的 Xen 与在 Linux 下有所不同。我们将从在 Solaris dom0 上创建一个 Solaris domU 开始,然后扩展我们的讨论到在 Linux dom0 上的 Solaris domU。
ZFS 后备设备
首先,我们建议在 Solaris 下以不同的方式处理虚拟块设备。虽然你可以创建 domU 文件系统作为普通的循环回挂载文件,但 ZFS 可能是一个更好的选择。它受到了广泛的赞誉,甚至赢得了 Linus Torvalds 一些不情愿的赞誉。实际上,它非常适合这类事情,并且是管理 Solaris 下磁盘的通常方法——尤其是在 OpenSolaris 使用 ZFS 根文件系统之后。
ZFS 非常简单,至少开始时是这样的。LVM 的用户会发现创建池和文件系统是熟悉的任务,尽管命令略有不同。在这里,我们将创建一个池,在池内创建一个 ZFS 文件系统,并设置文件系统的大小:
# zpool create guests c0d0
# zfs create guests/escalus
# zfs set quota=4g guests/escalus
现在,我们可以定义一个使用 phy: 设备 /dev/zvol/dsk/guests/escalus 作为其后备存储的域,如配置文件所示。
我们将把 ZFS 管理的更细微之处留给 Sun 的文档。
通过 PyGRUB 安装 DomU
在创建 domU 之前要做的最后一件事是编写适当的配置文件。这是我们的配置文件:
# cat /etc/xen/escalus
name = "escalus"
memory = 512
disk = [
'file:/opt/xen/install-iso/os200805.iso,6:cdrom,r',
'phy:/dev/zvol/dsk/guests/escalus,0,w'
]
vif = ['']
bootloader = 'pygrub'
kernel = '/platform/i86xpv/kernel/unix'
ramdisk = 'boot/x86.microroot'
extra = /platform/i86xpv/kernel/unix -B console=ttya,livemode=text
on_shutdown = 'destroy'
on_reboot = 'destroy'
on_crash = 'destroy'
注意,磁盘指定符与 Linux domUs 的工作方式不同。我们不是使用符号设备名称,就像在 Linux 下:
disk = ['file:/export/home/xen/solaris.img,sda1,w']
root = "/dev/sda1"
我们不是指定磁盘号,而是:
disk = ['phy:/dev/zvol/dsk/guests/ecalus,0,w']
root = "/dev/dsk/c0d0s0"
在这里,我们使用 PyGRUB 从 ISO 图像 (os200805.iso) 安装 Solaris,从 CD 图像中提取正确的内核和 initrd,引导它,然后进行正常安装。
注意
需要注意的一点是,domU 网络只有在您使用基于 GLD3 的网络驱动程序时才会工作。Solaris 中的驱动程序在这方面都没有问题——然而,您可能会遇到第三方驱动程序的问题。
安装完成后,我们关闭机器并移除 CD 的磁盘条目。
到目前为止,您的 Solaris domU 应该已经准备好使用了。在 Linux 下创建 domU 同样简单直接,因为标准的 Linux domU 镜像和内核在 Solaris 下无需修改即可工作。
接下来,我们将探讨在 Linux 下设置 Solaris domU。
在 Linux 下创建 Solaris DomU
对于大多数情况,domU 与 dom0 操作系统是独立的,因此 Linux 下的安装过程与 Solaris 下的安装过程几乎相同。只有少数几个容易忽视的陷阱。
首先,您可能需要做一些额外的工作来确保域可以找到适当的内核。Solaris 镜像会痛苦地抱怨,实际上不会使用 Linux 内核启动。
如果您在 Xen 3.1 或更高版本系统上使用 PyGRUB,您不需要做任何特殊操作。PyGRUB 本身将从 OpenSolaris 安装介质中加载适当的文件,无需进一步干预,就像上一个示例一样。
如果您不使用 PyGRUB,或者您使用的是标准的 RHEL5.1 虚拟机管理程序,您需要从 OpenSolaris 安装包中提取内核和 miniroot(对于 Linux 用户来说是 initrd)并将其放置在 Xen 可以加载它们的地方。
# mount -o loop,ro osol200811.iso
# cp /mnt/cdrom/boot/platform/i86pv/kernel/unix /xen/kernels/solaris/
# cp /mnt/cdrom/x86.miniroot /xen/kernels/solaris/
# umount /mnt/cdrom
就像在 Solaris 下一样,首先编写一个配置文件。我们将设置这个配置文件以从 CD 加载安装程序,稍后将其修改为引导新安装的 domU。请注意,我们正在从 ISO 中获取内核,使用内核和 ramdisk 选项来指定我们需要的文件。
bootloader = '/usr/bin/pygrub'
kernel = "/platform/i86xpv/kernel/amd64/unix"
ramdisk = "/boot/x86.microroot"
extra = "/platform/i86xpv/kernel/amd64/unix -- nowin -B install_media=cdrom"
cpu_weight=1024
memory = 1024
name = "rosaline"
vif = ['vifname=rosaline,ip=192.0.2.136,bridge=xenbr0,mac=00:16:3e:59:A7:88' ]
disk = [
'file:/opt/distros/osol-0811.iso,xvdf:cdrom,r',
'phy:/dev/verona/rosaline,xvda,w'
]
确保创建您的后备存储(在这个例子中是 /dev/verona/rosaline)。
现在创建域。下一步,安装。
尽管 OpenSolaris 作为 domU 运行时有一个功能齐全的控制台,但它不幸地不包括文本模式安装程序。然而,它确实包括一个 VNC 服务器和 SSH 服务器,任一都可以用来获取远程图形显示。以下是设置 VNC 的方法。
使用用户名 jack 和密码 jack 登录到 domU 控制台。
一旦您本地登录,设置您的网络。(如果您使用 DHCP,它可能已经为您设置好了,但确保这一点并无害处。)
# pfexec ifconfig xnf0
xnf0: flags=201000843<UP,BROADCAST,RUNNING,MULTICAST,IPv4,CoS> mtu 1500 index 2
inet 192.0.2.128 netmask ffffff00 broadcast 192.0.2.255
ether aa:0:0:59:a7:88
您可以看到,我们的网络状况良好,地址为 192.168.2.128。如果尚未设置,请手动分配地址:
pfexec ifconfig xnf0 192.0.2.128/24
VNC 服务器应该已经运行。要启用对它的远程访问,运行 vncpasswd 命令:
pfexec vncpasswd /etc/X11/.vncpasswd
vncpasswd将要求您创建一个密码并输入两次。使用此密码通过您喜欢的 VNC 客户端连接到 VNC 服务器。您应该会看到一个 OpenSolaris 桌面。
最后,点击桌面上的安装 OpenSolaris图标,继续图形安装。
OpenSolaris DomU 安装后配置
一旦安装程序完成其工作,您就可以关闭域并进入下一步:设置 dom0 以从 ZFS 文件系统加载内核。
问题在于在 Xen 3.3 中,PyGRUB 的libfsimage版本无法直接处理 ZFS 的最新版本。我们的解决方案是从xenbits.xen.org/下载 Xen 不稳定源代码树(截至本文写作时,Xen 3.4-rc)并从中构建 PyGRUB。(或者,您可以挂载安装介质,提取内核和 microroot,在配置文件中手动指定这些内容,并将正确的“extra”行传递给内核——这也同样有效。)
# hg clone http://xenbits.xen.org/xen-unstable.hg
# cd xen-unstable
# make tools
# cd xen-unstable.hg/tools/pygrub; make install
# cd xen-unstable.hg/tools/libfsimage; make install
现在我们更新域配置文件。由于我们费尽周折更新了 PyGRUB,我们在这里直接使用它:
bootloader='pygrub'
cpu_weight=1024
memory = 1024
name = "rosaline"
vif = ['vifname=rosaline,ip=192.0.2.136,bridge=xenbr0,mac=00:16:3e:59:A7:88' ]
disk = [
#'file:/opt/distros/osol-0811.iso,xvdf:cdrom,r',
'phy:/dev/verona/rosaline,xvda,w'
]
注意
PV-GRUB,目前,无法正确加载 OpenSolaris 内核。请使用 PyGRUB 代替。
使用xm启动您的新的域:
# xm create rosaline
^([45]) 我们倾向于将Zone和Container互换使用。技术上讲,Solaris Container 在 Zones 之上实现了系统资源控制。
^([46]) CDDL 是一个与 GPL 不兼容的自由软件许可证,但通常是无害的。
^([47]) 这也是我们忽略 Solaris Express 的另一个原因:专注于它并不会,用道格拉斯·亚当斯的话说,“产生像美国市场那样繁荣的厚重的书籍。”
^([48]) 写出“优雅的最小化”的诱惑存在,但这只是不切实际的。
^([49]) 任何计划对pfexec和sudo的比较表示不满的人:请假设我们已经完全被您的论点说服,继续您日常的生活。
NetBSD
NetBSD 由于其小巧和灵活的设计而成为 dom0 操作系统的热门选择,这与 Xen 鼓励的专用虚拟化服务器模式相匹配。根据我们的经验,运行 NetBSD 的 dom0 将使用更少的内存,并且至少与运行 Linux 的 dom0 一样稳定。
然而,Linux 用户常常犯下这样的错误,认为 NetBSD 与 Linux 完全相同。事实并非如此——它有点相似,但 NetBSD 是一个与 Linux 一样漫长的进化产物,并且需要一些实践才能使用。在本节中,我们假设您熟悉 NetBSD 的怪癖;我们只将涵盖与 Xen 相关的差异。
NetBSD 的历史 Xen 支持
NetBSD 很早就支持 Xen 了——从 NetBSD 版本 3.0 开始,该版本集成了对 Xen2 作为 dom0 和 domU 的支持。这种 Xen2 支持相当稳定。然而,它有一个明显的缺点,那就是它是 Xen2,缺乏 Xen3 的特性,如实时迁移和 HVM。它也仅支持 32 位,不支持 PAE(物理地址扩展)。(我们相当多地使用了这个版本。我们最初在 prgmr.com 提供托管服务时使用的第一个 Xen 设置是一个双 Xeon 运行 NetBSD 3.1 和 Xen2,支持 Linux 和 NetBSD domUs。)NetBSD 3.1 引入了对 Xen 3.0.x 的支持——但仅作为 domU。
NetBSD 4.0 添加了对 Xen 3.1 的支持,既可以作为 domU 也可以作为 dom0,并且还引入了对 HVM 的支持。NetBSD 4.0 剩下的唯一问题是,像其前辈一样,它不支持 PAE 或 x86_64,这意味着它无法使用超过 4GB 的内存。它也无法在 64 位或 PAE 系统上作为 domU 运行,例如亚马逊的 EC2 所使用的系统。最后这一点才是真正的杀手——这意味着 NetBSD 4 需要一个非 PAE 的 32 位虚拟机管理程序,这反过来又限制了您只能有 4GB 的地址空间,这大约相当于 3.5GB 的物理内存。(这个限制如此显著,以至于 Xen.org 甚至不再分发非 PAE 的二进制软件包。)
最后,全新的 NetBSD 5 为 NetBSD domUs 添加了 PAE 支持,为 dom0 和 domUs 添加了 x86-64 支持,并在 64 位 dom0 上支持 32 位 domUs(在 Xen 术语中称为 32-on-64)。仍在努力添加功能,以使 NetBSD Xen 支持与 Linux 的 Xen 支持功能对等,但 NetBSD 已经是一个完全可行的平台。
将 NetBSD 作为 Dom0 安装
使用 Xen 开始使用 NetBSD 的基本步骤与任何其他操作系统几乎相同:下载它,安装它,并让它工作。再次强调,我们假设您熟悉基本的 NetBSD 安装程序,所以我们只是简要概述这些说明。
首先下载 NetBSD 并像往常一样安装它。(我们选择从 mirror.planetunix.net/pub/NetBSD/iso/5.0/amd64cd-5.0.iso 下载并烧录 ISO。)根据您的偏好配置系统。
注意
ftp:// 和 http:// *在所有 ftp.netbsd.org URLs 上是可互换的。http:// 通过防火墙更好,而 ftp:// 稍微快一点。选择一个。此外,使用镜像而不是 netbsd.org 网站通常会获得显著更好的速度。如果您的 FTP 安装在中间失败,首先要尝试另一个镜像。
无论您如何安装 NetBSD,都要通过安装程序并重新启动到您的新系统。接下来,使用 NetBSD 的端口系统 pkgsrc 安装 Xen 内核和相关工具。从 ftp.netbsd.org/pub/NetBSD/packages/pkgsrc.tar.gz 获取 pkgsrc。解压 pkgsrc.tar.gz,然后安装 Xen:
# cd pkgsrc/sysutils/xenkernel3 ; make install
# cd pkgsrc/sysutils/xentools3 ; make install
安装 Xen 工具后,NetBSD 会提醒您创建 Xen 设备节点:
# cd /dev ; sh MAKEDEV xen
现在 Xen 已经安装,我们的下一个任务是安装 GRUB 以替换标准 NetBSD 引导加载程序,以便我们可以执行 Xen 所需的分阶段引导:
# cd pkgsrc/sysutils/grub ; make install
我们下一步是下载和安装 NetBSD Xen 内核——我们已经在标准 NetBSD 内核上运行,并且已经安装了虚拟机管理程序,但我们仍然需要 dom0 和 domUs 的内核。从您最喜欢的 NetBSD 镜像下载 netbsd-XEN3_DOM0.gz,netbsd-XEN3_DOMU.gz 和 netbsd-INSTALL_XEN3_DOMU.gz。(我们使用了mirror.planetunix.net/pub/NetBSD/NetBSD-5.0/。)
现在我们已经有了适合与我们在上一步中安装的虚拟机管理程序和辅助工具配合使用的 Xen 内核,我们可以像往常一样设置 GRUB:
# grub-install --no-floppy sd0a
编辑 /grub/menu.lst,使其引导 Xen 内核并将 NetBSD 作为模块加载。以下是一个完整的文件,包含注释(改编自 NetBSD 示例www.netbsd.org/ports/xen/howto.html):
# Boot the first entry by default
default=1
# after 10s, boot the default entry if the user didn't hit keyboard
timeout=10
# Configure serial port to use as console. Ignore this bit if you're
# not using the serial port.
serial --unit=0 --speed=115200 --word=8 --parity=no --stop=1
# Let the user select which console to use (serial or VGA). Default
# to serial after 10s
terminal --timeout=10 console serial
# An entry for NetBSD/xen, using /xen/kernels/xen.gz as the domain0
# kernel, with serial console. Domain0 will have 64MB RAM allocated.
# Assume NetBSD is installed in the first MBR partition.
title Xen 3.3 / NetBSD (sd0a, serial) root(hd0,0) kernel
(hd0,a)/xen/kernels/xen.gz dom0_mem=65536 com1=115200,8n1 module
(hd0,a)/xen/kernels/XEN3_DOM0 root=sd0a ro console=ttyS0
# Same as above, but using VGA console
# We can use console=tty0 (Linux syntax) or console=pc (NetBSD syntax)
title Xen 3.3 / NetBSD (sd0a, vga)
root(hd0,0)
kernel (hd0,a)/xen/kernels/xenkernel3-3.1.0nb2 dom0_mem=65536 noreboot
module (hd0,a)/xen/kernels/XEN3_DOM0 root=sd0a ro console=pc
# Load a regular NetBSD/i386 kernel. Can be useful if you end up with a
# nonworking /xen.gz
title NetBSD 5
root (hd0,a)
kernel (hd0,a)/netbsd-GENERIC
重要的部分是内核名称,XEN3_DOM0,以及我们使用 NetBSD 语法指定的根设备。
注意
我们也设置了此配置文件以使用串行控制台。无论您使用哪种操作系统,我们都强烈建议在 Xen 中使用串行控制台,即使您通常更喜欢使用 KVM 或其他远程管理方法。有关串行控制台多种多样用途的更多讨论,请参阅第十四章。
将基本的 Xen 配置文件复制到 Xen 工具期望找到它们的目录中:
# cp /usr/pkg/share/examples/xen/* /usr/pkg/etc/xen/
现在我们已经拥有了 NetBSD dom0 的所有部分,我们需要启动 xenbackendd 和 xend(按此顺序,否则将无法工作)。
# cp /usr/pkg/share/examples/rc.d/xen* /etc/rc.d/
# echo "xenbackendd=YES">>/etc/rc.conf
# echo "xend=YES">>/etc/rc.conf
最后,为了使网络工作,创建 /etc/ifconfig.bridge0 并包含以下内容:
create
!brconfig $int add fxp0 up
到目前为止,您可能已经完成了。重新启动以测试,或手动启动 Xen 服务:
# /etc/rc.d/xenbackendd start
Starting xenbackendd.
# /etc/rc.d/xend start
Starting xend
您现在应该能够运行 xm list:
# xm list
Name ID Mem VCPUs State Time(s)
Domain-0 0 64 1 r----- 282.1
安装 NetBSD 作为 DomU
即使在 Linux dom0 上,安装 NetBSD 作为 domU 也很简单。事实上,由于 NetBSD 的 INSTALL 内核包含一个 ramdisk,其中包含完成安装所需的一切,因此,只要 PyGRUB 或 PV-GRUB 设置足够灵活,我们甚至可以在不修改 dom0 配置的情况下完成安装。
对于这次讨论,我们假设您已经设置了一个某种类型的 domU——可能是 prgmr.com Linux 域的通用域之一。在这个 domU 中,您需要一个小的引导分区,以便 GRUB^([50])可以读取。这就是我们将存储内核和 GRUB 配置的地方。
首先,在您的域内,下载 NetBSD 内核:
# wget http://mirror.planetunix.net/pub/NetBSD/NetBSD-5.0/amd64/binary/kernel/
netbsd-INSTALL_XEN3_DOMU.gz
# wget http://mirror.planetunix.net/pub/NetBSD/NetBSD-5.0/amd64/binary/kernel/
netbsd-XEN3_DOMU.gz
然后,编辑域的 GRUB 菜单(最可能是 /boot/grub/menu.lst),以便在下次重新启动时加载 INSTALL 内核。(在那次重新启动之后,当安装完成时,您将选择 NetBSD 运行选项。)
title NetBSD install
root (hd0,0)
kernel /boot/netbsd-INSTALL_XEN3_DOMU
title NetBSD run
root (hd0,0)
kernel /boot/netbsd-XEN3_DOMU root=xbd1a
重新启动,选择NetBSD 安装选项。
就像魔法一样,你的域将开始运行 NetBSD 安装程序,直到你进入一个完全普通的 NetBSD 安装会话。按照 NetBSD FTP 安装的步骤进行。在 netbsd.org/docs/guide/en/chap-exinst.html 有一些非常好的文档。
注意
在这个阶段,你必须小心不要覆盖你的引导设备。例如,prgmr.com 只给你一个物理块设备,你需要从这个设备中划分出一个 /boot 分区,除了正常的文件系统布局之外。
唯一需要注意的是,你必须小心设置一个 PyGRUB 可以读取的引导设备,在 PyGRUB 期望的位置。(如果你有多个物理设备,PyGRUB 将尝试从第一个设备启动。)由于我们是在标准的 prgmr.com domU 设置中安装,我们只有一个物理块设备可以操作,我们将将其划分为单独的 /boot 和 / 分区。我们的 disklabel,包含一个 32 MB FFS /boot 分区,看起来是这样的:
We now have your BSD-disklabel partitions as:
This is your last chance to change them.
Start MB End MB Size MB FS type Newfs Mount Mount point
--------- --------- --------- ---------- ----- ----- -----------
a: 31 2912 2882 FFSv1 Yes Yes /
b: 2913 3040 128 swap
c: 0 3071 3072 NetBSD partition
d: 0 3071 3072 Whole disk
e: 0 30 31 Linux Ext2
f: 0 0 0 unused
g: Show all unused partitions
h: Change input units (sectors/cylinders/MB)
>x: Partition sizes ok
安装完成后,重新启动。在 PyGRUB 中选择常规内核,你的 domU 应该就可以使用了。
在 NetBSD 启动后,如果你想更改引导加载程序配置,你可以这样挂载 ext2 分区:
# mount_ext2fs /dev/xbd0d /mnt
这将允许你升级 domU 内核。只需记住,每次你想升级内核时,你需要挂载 PyGRUB 加载内核的分区,并确保更新那个内核和 menu.lst。将 NetBSD 内核安装到 domU 文件系统的根目录中也是一个好主意,但这并不是严格必要的。
就这样,你就有了一个完整、完全功能的 NetBSD domU,没有任何 dom0 的干预。(如果你有 dom0 访问权限,你可以像往常一样在域配置文件的 kernel= 行上指定安装内核——但那样有什么乐趣呢?)
^([50]) 当然,更准确地说,是你的 GRUB 模拟器。如果是 PyGRUB,它依赖于 libfsimage。
超越 Para 虚拟化:HVM
在本章中,我们概述了使用 Solaris 和 NetBSD 作为 dom0 和 domU 操作系统的必要步骤。这并不是要详尽无遗地列出与 Xen 兼容的操作系统——特别是,我们完全没有提到 Plan9 或 FreeBSD——但它确实给你一个很好的概念,你可能遇到的不同类型以及至少使用两个系统(除了 Linux 之外)的简单方法。
此外,它们各自都有它们的优势:NetBSD 是一个非常轻量级的操作系统,在处理低内存条件方面比 Linux 更好。这对于 Xen 来说非常有用。Solaris 不那么轻量,但它非常健壮,并且拥有有趣的技术,如 ZFS。这两个操作系统都可以支持任何操作系统作为 domU,只要它已经被修改为与 Xen 兼容。如果你喜欢,这就是虚拟化的实际应用。
注意
包含在 kernel.org 内核中的新 Linux paravirt_ops 功能需要 Xen 虚拟机管理程序版本 3.3 或更高版本,因此它与 NetBSD 兼容,但不与 OpenSolaris 兼容。
最后,最近处理器中硬件虚拟化扩展的添加意味着几乎任何操作系统都可以用作 domU,即使它没有专门修改过以与 Xen 一起工作。我们在第十二章中讨论了 Xen 对这些扩展的支持,然后在第十三章中描述了如何使用 HVM 在 Xen 下运行 Windows。敬请关注。
第九章。XEN 迁移
在这些情况下,虚拟化和迁移的结合显著提高了可管理性。
— 克拉克等人,《虚拟机的实时迁移》
因此,让我们回顾一下:用诗意的话说,Xen 是一种抽象,建立在其他抽象之上,围绕更进一步的抽象。所有这些抽象的目标是确保你,在你的舒适和安全 domU 中,甚至不必考虑那些实际上发送电脉冲到网络端口的混乱、嘈杂、易出错硬件。
当然,偶尔硬件会因自身原因无法运行 Xen。可能是因为过载,或者可能需要一些预防性维护。只要你有提前警告,即使这种需求也不必打断你的虚拟机。Xen 提供的这种完全硬件独立性的好处之一是将整个虚拟机实例移动到另一台机器上并透明地恢复操作——这个过程被称为迁移。
Xen 迁移将整个虚拟机——内核的内存状态、所有进程以及所有应用程序状态——转移到另一个位置。从用户的角度来看,实时迁移甚至不明显——最多只是丢失了几個数据包。这有可能使计划中的停机时间成为过去式。(非计划停机时间,就像死亡和税收一样,似乎是无法避免的。^([51]))
迁移可以是实时或冷迁移,^([52]) 区别在于实例在迁移时是否正在运行。在实时迁移中,域在传输过程中继续运行,停机时间保持在最低。在冷迁移中,虚拟机被暂停、保存,并发送到另一台物理机器。
在这两种情况下,保存的机器都期望其 IP 地址和 ARP 缓存在新子网上正常工作。考虑到网络堆栈的内存状态保持不变,这并不令人惊讶。尝试在不同层 2 子网之间启动实时迁移将直接失败。在不同子网之间进行冷迁移将工作,因为虚拟机将成功传输,但很可能需要重新配置其网络。我们将在讨论实时迁移时再次提及这些特性。
首先,让我们检查一种将域从一个主机移动到另一个主机的简单、手动方法。
迁移适用于穴居人
将 Xen 实例从一台物理机迁移到另一台物理机最基本、最不优雅的方法是完全停止它,移动其备份存储,并在远程主机上重新创建域。这需要虚拟机完全关闭和重启周期。这甚至不是正式 Xen 意义上的“迁移”,但如果你需要更换底层块设备或某些特定于机器的属性发生变化,例如,在将虚拟机在不同 CPU 架构之间迁移或在使用 PAE 的机器和不使用 PAE 的机器之间迁移时,你可能需要这样做.^([53])
首先,正常关闭虚拟机,无论是从操作系统内部还是通过在 dom0 上执行xm shutdown。复制其备份存储、内核镜像(如果需要)和配置文件,最后在新的主机上按常规使用xm create创建该机器。
这方法很简单,但至少它几乎肯定能行,而且不需要任何复杂的基础设施。我们主要提到它是为了完整性;这是一种将 Xen 域从一台物理机迁移到另一台物理机的方法。
^([51]) 可能不是;请参阅www.osrg.net/kemari/和dsg.cs.ubc.ca/remus/上的 Project Kemari 或 Project Remus,了解正在进行的为 Xen 添加硬件冗余的工作。
^([52]) 我们还喜欢使用hot和dead这两个术语,它们是更常用术语的较少使用的对应词。
^([53]) 例如,从 NetBurst(奔腾 4 及其同类)到 Core(Core 2 等)。Xen 无法将虚拟机从 x86 迁移到 PPC。
使用 xm save 和 xm restore 进行迁移
除了这种“牛仔”方法之外,所有形式的迁移都是基于在某一台机器上保存域并在另一台机器上恢复域的基本思想。你可以使用xm save和xm restore命令手动完成此操作,模拟自动过程。
Xen 文档将xm save和restore周期比作物理机的休眠。当机器休眠时,它会进入节能模式,将内存镜像保存到磁盘,并物理关闭机器。当机器再次开启时,操作系统从磁盘加载保存的内存镜像,并从上次停止的地方继续。xm save的行为完全相同。就像物理休眠一样,保存的域断开网络连接,暂停和恢复需要一些时间,直到恢复之前不消耗 CPU 或内存。
即使你并没有计划进行任何涉及迁移的复杂操作,你也可能会在物理 Xen 服务器重启时保存机器。Xen 包括一个初始化脚本,在系统关闭时自动保存域,并在启动时恢复它们。为了适应这一点,我们建议确保/var足够大,可以容纳服务器内存的完整内容(包括日志、DNS 数据库等)。
要保存机器,请执行以下命令:
# xm save <domain name or id> <savefile>
此命令指示域暂停自身;域将其资源释放回 domain 0,断开其中断处理程序,并将其实际内存映射转换回域虚拟映射(因为当域恢复时,实际内存映射几乎肯定会发生变化)。
注意
那些始终关注实现细节的人会注意到,这意味着 domU 操作系统对 Xen 的支持。HVM 保存和恢复——也就是说,当无法保证客户机是 Xen 感知的——执行方式略有不同。有关详细信息,请参阅第十二章。
在这一点上,domain 0 接管,停止 domU,并将域状态检查点到一个文件中。在这个过程中,它确保所有内存页面引用都是规范的(也就是说,域虚拟的,因为当域恢复时,对机器内存页面的引用几乎肯定是不有效的)。然后它将页面内容写入磁盘,在写入过程中回收页面。
在此过程完成后,该域已停止运行。其内存的全部内容都保存在一个大小大约等于其内存分配的 savefile 中,您可以随时恢复。在此期间,您可以运行其他域,重启物理机器,备份域的虚拟磁盘,或执行任何其他需要您将域离线的操作。
注意
尽管 xm save 通常在保存时停止域,但您也可以使用 -c 选项调用它,用于检查点。这告诉 xm 保持域运行。尽管如此,设置起来有些复杂,因为您还需要一种方法在保存期间快照域的存储。这通常涉及到一个外部设备迁移脚本。
当完成这些操作后,恢复域变得简单:
# xm restore <savefile>
恢复操作与保存相反;虚拟机管理程序为域分配内存,将保存文件中的页面写入到新分配的内存中,并将影子页面表条目转换为指向新物理地址。当完成这些操作后,域恢复执行,重新设置它在暂停时移除的所有内容,并开始像什么都没发生一样运行。
注意
保存文件保持完整;如果重启的机器出现错误,您可以恢复保存文件并再次尝试。
在本地机器上保存和恢复的能力是 Xen 支持的更复杂迁移形式的基础。
冷迁移
在我们深入了解 Xen 的自动迁移之前,我们将概述一个手动冷迁移过程,以了解涉及到的步骤,并近似模拟实时迁移的流程。
在这种情况下,迁移开始于保存域。管理员手动移动保存文件和域的底层存储到新机器上,并恢复域状态。由于底层块设备是手动移动的,因此不需要两台机器都可以访问相同的文件系统,就像实时迁移那样。唯一重要的是传输 Xen 虚拟磁盘的内容。
这里有一些将 Xen 域进行冷迁移的步骤:
# xm save <domain id> <savefile>
# scp <savefile> <target.domain.tld:/path/>
执行适当的步骤将域的存储复制到目标计算机——rsync, scp, dd 通过 ssh 管道传输,无论您选择哪种方法。无论您选择哪种方法,确保它以位对位相同的方式复制磁盘,并且在两台物理机器上有相同的路径。特别是,不要在机器 A 上挂载 domU 文件系统,并将文件复制到机器 B 上的新 domU 文件系统。这将导致虚拟机在恢复时崩溃。
最后,在新机器上重启域:
# xm restore <savefile>
没有必要将域名配置文件复制到新机器上;保存文件包含了启动机器所需的所有配置信息。相反,这也意味着您在保存和恢复之间无法更改机器的参数,并期望有任何效果。^([54)]
^(54)) 为了避免不可避免的问题,我们确实尝试使用十六进制编辑器在保存文件上操作。结果是立即崩溃。
实时迁移
冷迁移有其位置,但 Xen 最干净利落的功能之一是能够将域从一个物理机透明地移动到另一个物理机,即对外部世界来说不可察觉。这个特性就是实时迁移。
与冷迁移一样,实时迁移将域的配置作为其状态的一部分进行传输;它不需要管理员手动复制配置文件。实际上,根本不需要手动复制。当然,如果您想在新的机器上从头开始重新创建域,您仍然需要配置文件。
实时迁移有一些额外的先决条件。它依赖于域的存储可以从两台机器访问,并且机器位于同一子网中。最后,因为复制阶段是自动通过网络进行的,所以机器必须运行网络服务。
它是如何工作的
我们真的很想说是通过魔法来实现实时迁移的。然而,实际上,它是通过应用足够先进的技术来实现的。
实时迁移只是在最一般的意义上基于“保存和恢复”的基本思想。机器直到迁移的最后阶段才休眠,并且几乎立即从虚拟休眠中恢复过来。
如 图 9-1 所示,Xen 实时迁移首先向目标发送一个请求,或称为 预留,指定迁移域所需的资源。如果目标接受请求,源开始迁移的 迭代预复制 阶段。在此步骤中,Xen 通过 TCP 连接将内存页复制到目标主机。在这个过程中,更改的页面被标记为脏,然后重新复制。机器迭代这个过程,直到只剩下非常频繁更改的页面,此时它开始 停止和复制 阶段。现在 Xen 停止虚拟机,并复制那些在先前阶段更改过于频繁的页面,以有效地复制。实际上,我们的测试表明 Xen 通常在四到八次迭代后达到这一点。最后,虚拟机在新机器上开始执行。
默认情况下,Xen 将迭代最多 29 次,如果脏页数低于某个阈值,则停止。您可以在编译时指定此阈值和迭代次数,但默认值应该可以正常工作。

图 9-1. 实时迁移概述
使 Xen 迁移工作
首先,请注意,除非域名正在使用某种类型的网络可访问存储,否则迁移将不会工作,这一点在本章后面有描述。如果您没有这样的东西,请先设置好,完成后回来。
其次,xend 必须设置成在物理机器上监听迁移请求。请注意,两台机器都需要监听;如果只有目标机器运行了重定位服务器,源机器将无法在正确的时间关闭其 Xen 实例,并且重启的域将像没有干净关闭一样重新启动。
通过在 /etc/xend-config.sxp 中取消以下注释来启用迁移服务器:
(xend-relocation-server yes)
这将导致 xend 在端口 8002 上监听迁移请求,这可以通过 (xend-relocation-port) 指令进行更改。请注意,这有一定的安全风险。您可以通过添加以下类似行在一定程度上减轻这种风险:
(xend-relocation-address 192.168.1.1)
(xend-relocation-hosts-allow '^localhost$' '^host.example.org$')
xend-relocation-address 行将 xend 限制在指定地址上监听迁移请求,这样您可以将迁移限制为例如内部子网或 VPN。第二行指定了一个允许迁移的主机列表,作为空格分隔的引号正则表达式列表。虽然从 localhost 迁移的想法看起来有些奇怪,但它确实在测试中具有一定的价值。Xen 到 其他 主机的迁移在没有 localhost 在允许的主机列表中时也能正常工作,所以如果您想的话,可以随意删除它。
在包含防火墙的分发版上,您必须打开端口 8002(或您使用 xend-relocation-port 指令指定的另一个端口)。如有必要,请参阅您分发版的文档。
在实时迁移过程中,Xen 可以在迁移的同时保持网络连接,这样客户端就不需要重新连接。迁移后的域名会发送一个未经请求的 ARP(地址请求协议)回复来宣传其新位置。(通常这会成功。在某些网络配置中,这取决于您的交换机配置,可能会非常失败。请先测试。)迁移实例只有在迁移到同一物理子网上的机器时才能保持其网络连接,因为它的 IP 地址保持不变。
命令很简单:
# xm migrate --live <domain id> <destination machine>
当虚拟机将自己复制到远程主机时,xm list中的域名会变为migrating-[domain]。此时,它也会出现在目标机器的xm list输出中。在我们的配置中,这个复制和运行阶段每 10MB domU 内存大约需要 1 秒钟,然后大约有 6 秒钟的服务中断。
注意
如果您出于任何原因希望迁移的总时间更短(以增加停机时间为代价),您可以通过简单地删除 --live 选项来消除重复的增量复制。
# xm migrate <domain id> <destination machine>
这会自动停止域名,将其保存为正常状态,发送到目标机器,并恢复。就像 --live 一样,最终产品是一个迁移后的域名。
在迁移过程中,以下是目标机器上的域名列表。请注意,随着迁移域名传输更多数据,内存使用量会增加:
Name ID Mem(MiB) VCPUs State Time(s)
Domain-0 0 1024 8 r----- 169.2
orlando 3 307 0 -bp--- 0.0
大约 30 秒后,域名迁移了数百 MB:
Name ID Mem(MiB) VCPUs State Time(s)
Domain-0 0 1024 8 r----- 184.8
orlando 3 615 0 -bp--- 0.0
再过 30 秒,域名已经完全迁移并运行:
Name ID Mem(MiB) VCPUs State Time(s)
Domain-0 0 1024 8 r----- 216.0
orlando 3 1023 1 -b---- 0.0
我们在迁移过程中也对域名进行了 ping 测试。请注意,当域名移动数据时,响应时间会显著增加:
PING (69.12.128.195) 56(84) bytes of data.
64 bytes from 69.12.128.195: icmp_seq=1 ttl=56 time=15.8 ms
64 bytes from 69.12.128.195: icmp_seq=2 ttl=56 time=13.8 ms
64 bytes from 69.12.128.195: icmp_seq=3 ttl=56 time=53.0 ms
64 bytes from 69.12.128.195: icmp_seq=4 ttl=56 time=179 ms
64 bytes from 69.12.128.195: icmp_seq=5 ttl=56 time=155 ms
64 bytes from 69.12.128.195: icmp_seq=6 ttl=56 time=247 ms
64 bytes from 69.12.128.195: icmp_seq=7 ttl=56 time=239 ms
在大部分域名内存迁移完成后,域名停止,复制最后几页,然后在目标主机上重新启动,这时会出现短暂的故障:
64 bytes from 69.12.128.195: icmp_seq=107 ttl=56 time=14.2 ms
64 bytes from 69.12.128.195: icmp_seq=108 ttl=56 time=13.0 ms
64 bytes from 69.12.128.195: icmp_seq=109 ttl=56 time=98.0 ms
64 bytes from 69.12.128.195: icmp_seq=110 ttl=56 time=15.4 ms
64 bytes from 69.12.128.195: icmp_seq=111 ttl=56 time=14.2 ms
--- 69.12.128.195 ping statistics ---
111 packets transmitted, 110 received, 0% packet loss, time 110197ms
rtt min/avg/max/mdev = 13.081/226.999/382.360/101.826 ms
到这一点,域名已经完全迁移。
然而,迁移工具并不能保证迁移后的域名实际上能在目标机器上运行。当从较新的 CPU 迁移到较旧的 CPU 时,会出现一个常见问题。因为指令在启动时被启用,迁移后的内核尝试执行那些根本不存在的指令是完全可能的。
例如,sfence指令用于显式序列化乱序内存写入;在sfence之前发出的任何写入必须在围栏之后的写入之前完成。这个指令是 SSE 的一部分,因此它并不支持所有支持 Xen 的机器。在一个支持sfence的机器上启动的域名在迁移后会尝试继续使用它,并且很快就会崩溃。这可能在 Xen 的后续版本中有所改变,但到目前为止,我们所知的所有生产 Xen 环境都只在同构硬件之间迁移。
迁移存储
实时迁移只复制 RAM 和处理器状态;确保迁移的域可以访问其磁盘取决于管理员。因此,存储问题归结为一个能力问题。迁移的域将期望其磁盘在新的机器上与旧的机器上完全一致,并且设备名称相同。在大多数情况下,这意味着 domU 要能够进行迁移,必须通过网络拉取其支持存储。在 Xen 世界中,有两种流行的方法可以实现这一点:通过以太网的 ATA(AoE)和 iSCSI。我们还在第四章中讨论了 NFS。最后,您也可以向 NetApp 投掷一箱钱。
除了这些选项之外,您还可以考虑使用 cLVM(带有某种类型的网络存储封装)和 DRBD。
在所有这些存储方法中,我们将讨论一种使用存储服务器将块设备导出到 dom0 的方法,然后 dom0 将存储提供给 domU。
注意,iSCSI 和 AoE 都限制自己只提供简单的块设备。它们都不允许多个客户端在没有文件系统级别支持的情况下共享同一个文件系统!这是一个重要的观点。尝试导出单个 ext3 文件系统并在该文件系统上运行 domUs,几乎会立即导致损坏。相反,配置您的网络存储技术为每个 domU 导出一个块设备。然而,导出的设备不必与物理设备相对应;我们同样可以导出文件或 LVM 卷。
通过以太网的 ATA
通过以太网的 ATA 设置起来很简单,速度合理,并且很受欢迎。它不可路由,但在实时迁移的上下文中这并不重要,因为实时迁移总是在一个 2 层广播域内发生。
人们使用 AoE 来填补与基本 SAN 设置相同的空白:通过网络使集中式存储可用。它导出可以像本地连接的磁盘一样使用的块设备。为了本例的目的,我们将通过 AoE 为每个 domU 导出一个块设备。
让我们先设置 AoE 服务器。这是将磁盘设备导出到 dom0s 的机器,这些 dom0s 反过来托管依赖于这些设备的 domUs。您首先需要做的是确保您有内核 AoE 驱动程序,该驱动程序位于内核配置中:
Device drivers --->
Block Devices --->
<*> ATA over Ethernet support
您也可以将其作为一个模块(m)。如果您选择这条路,请加载该模块:
# modprobe aoe
无论哪种方式,请确保您可以访问 /dev/etherd 下的设备节点。它们应由 udev 创建。如果不是这样,请尝试安装内核源代码并运行内核源代码树中提供的 Documentation/aoe/udev-install.sh 脚本。此脚本将生成规则并将它们放置在适当的位置——在我们的案例中是 /etc/udev/rules.d/50-udev.rules。您可能需要根据您的 udev 版本调整这些规则。我们在 CentOS 5.3 上使用的配置是:
SUBSYSTEM=="aoe", KERNEL=="discover", NAME="etherd/%k", GROUP="disk", MODE="0220"
SUBSYSTEM=="aoe", KERNEL=="err", NAME="etherd/%k", GROUP="disk", MODE="0440"
SUBSYSTEM=="aoe", KERNEL=="interfaces", NAME="etherd/%k", GROUP="disk", MODE="0220"
SUBSYSTEM=="aoe", KERNEL=="revalidate", NAME="etherd/%k", GROUP="disk", MODE="0220"
# aoe block devices
KERNEL=="etherd*", NAME="%k", GROUP="disk"
AoE 还需要一些支持软件。服务器包名为 vblade,可以从aoetools.sourceforge.net/获取。您还需要在服务器和客户端机器上安装客户端工具 aoetools,所以请确保获取这些工具。
首先,在存储服务器上运行aoe-interfaces命令,告诉 vblade 要导出哪些接口:
# aoe-interfaces <ifname>
vblade 可以导出大多数存储形式,包括 SCSI、MD 或 LVM。尽管名为以太网上的 ATA,但它并不仅限于导出 ATA 设备;它可以导出任何可寻址的设备文件或任何普通文件系统镜像。只需在命令行上指定文件名即可。(这又是 UNIX 的“一切皆文件”哲学派上用场的一个例子。)
虽然 vblade 有一个配置文件,但通过命令行指定选项很简单。语法是:
# vblade <shelf id> <slot id> <interface> <file to export>
例如,要导出文件:
# dd if=/dev/zero of=/path/file.img bs=1024M count=1
# vblade 0 0 <ifname> </path/file.img> &
这将/path/file.img导出为/dev/etherd/e0.0。
注意
无论什么原因,新的导出在服务器上不可见。AoE 维护者指出,这实际上不是一个错误,因为它从未是设计目标。
AoE 可能期望设备有一个分区表,或者至少有一个有效的分区签名。如果需要,您可以通过创建跨越整个磁盘的分区来本地分区:
# losetup /dev/loop0 test.img
# fdisk /dev/loop0
完成这些后,创建一个文件系统并断开循环:
# mkfs /dev/loop0
# losetup -d /dev/loop0
或者,如果您想在设备上创建多个分区,使用fdisk对设备进行分区,并创建多个分区,就像通常一样。新的分区将以类似/dev/etherd/e0.0p1的名称出现在客户端。要从 AoE 服务器访问设备,在适当配置的循环设备上执行kpartx -a应该可以工作。
现在我们已经有一个功能性的服务器,让我们设置客户端。AoE 客户端的大部分功能都是作为内核的一部分实现的,所以您需要确保 dom0 内核中包含了 AoE,就像存储服务器一样。如果是模块,您可能希望确保它在启动时加载。如果您使用 CentOS,您可能还需要修复您的 udev 规则,就像服务器一样。
由于我们使用 dom0 来仲裁网络存储,因此不需要在 domU 内核中包含 AoE 驱动程序。所有 Xen 虚拟磁盘设备都通过 domU 的xenblk驱动程序访问,无论它们使用什么技术进行存储.^([55])
从您的发行版的包管理系统中下载 aoetools 或从aoetools.sourceforge.net/下载。如果需要,构建并安装该包。
一旦安装了 aoetools 包,您可以通过以下方式在客户端测试导出的 AoE 设备:
# aoe-discover
# aoe-stat
e0.0 1.073GB eth0 up
# mount /dev/etherd/e0.0 /mnt/aoe
在这种情况下,设备大小为 1GB(或类似大小),已作为 0 号架 0 号槽位导出,并在客户端的 eth0 上找到。如果它成功挂载,您就可以开始了。您可以卸载 /mnt/aoe 并使用 /dev/etherd/e0.0 作为普通 phy: 设备用于 domU 存储。适当的 domU 配置 disk= 行可能如下:
disk = [ phy:/dev/etherd/e0.0, xvda, w ]
如果您遇到任何问题,请检查 /var/log/xen/xend.log。最常见的问题与机器无法找到设备——块设备或网络设备有关。在这种情况下,错误将显示在日志文件中。确保已正确配置了正确的虚拟磁盘和接口。
iSCSI
AoE 和 iSCSI 在管理员的角度上有很多相似之处;它们都是通过网络导出存储而不需要特殊硬件的方法。它们都导出块设备,而不是文件系统,这意味着一次只能有一台机器访问一个导出的设备。iSCSI 与 AoE 的不同之处在于它是一个基于 TCP/IP 的可路由协议。这使得它在 CPU 和带宽方面效率较低,但更灵活,因为 iSCSI 导出可以穿越第 2 层网络。
iSCSI 将世界划分为 目标 和 发起者。您可能更熟悉它们作为 服务器 和 客户端。服务器作为 SCSI 命令的目标,这些命令由客户端机器发起。在大多数安装中,iSCSI 目标将是专用设备,但如果您需要在通用服务器上为测试设置 iSCSI 服务器,以下是方法。
设置 iSCSI 服务器
对于目标,我们推荐使用 iSCSI 企业目标 实现 (sourceforge.net/projects/iscsitarget/)。其他软件也存在,但我们对其不太熟悉。
您的发行版供应商很可能提供了一个软件包。在 Debian 上是 iscsitarget。Red Hat 和其他使用相关的 tgt 软件包,其配置略有不同。尽管我们不涵盖设置 tgt 的细节,但在 www.cyberciti.biz/tips/howto-setup-linux-iscsi-target-sanwith-tgt.html 有一个信息丰富的页面。在本节的其余部分,我们假设您正在使用 iSCSI 企业目标。
如果需要,您可以手动下载和构建 iSCSI 目标软件。从网站上下载目标软件并将其保存到适当的位置(我们在这个例子中将它拖到了我们的 GNOME 桌面上)。解压它:
# tar xzvf Desktop/iscsitarget-0.4.16.tar.gz
# cd iscsitarget-0.4.16
很可能您可以通过常规的 make 进程构建所有组件——内核模块和用户空间工具。确保您已安装了 openSSL 头文件,可能是作为 openssl-devel 软件包或类似软件包的一部分:
# make
# make install
make install 也会将默认配置文件复制到 /etc 目录中。我们的下一步是适当地编辑它们。
主要配置文件是 /etc/ietd.conf。它有大量的注释,并且大多数值可以安全地保留在默认值(目前是这样)。我们主要关心的是目标部分:
Target iqn.2001-04.com.prgmr:domU.orlando
Lun 0 Path=/opt/xen/orlando.img,Type=fileio
我们可以在这里调整许多其他变量,但基本的目标定义很简单:单词 Target 后跟一个符合规范的 iSCSI 合法名称 以及一个逻辑单元定义。注意 Type=fileio。在这个例子中,我们使用的是普通文件,但你很可能也想将此值用于整个磁盘导出和 LVM 卷。
初始化脚本 etc/iscsi_target 也应该被复制到适当的位置。如果你想在启动时启用 iSCSI,还需要创建相应的启动和终止链接。
现在我们可以导出我们的 iSCSI 设备:
# /etc/init.d/iscsi_target start
为了检查它是否工作:
# cat /proc/net/iet/volume
tid:1 name:iqn.2001-04.com.prgmr:domU.orlando
lun:0 state:0 iotype:fileio iomode:wt path:/opt/xen/orlando
你应该能看到你定义的导出(s),以及一些状态信息。
iSCSI 客户端设置
对于启动器,存在各种客户端。然而,似乎最好的支持包是 Open-iSCSI,可在 www.open-iscsi.org/ 找到。Red Hat 和 Debian 都通过它们的包管理器提供版本,分别是 iscsi-initiator-utils 和 open-iscsi。你也可以从网站上下载包,并完成非常简单的安装过程。
当你安装了 iSCSI 启动器,无论你如何安装,下一步就是说出适当的咒语来指示机器在启动时挂载你的 iSCSI 设备。
iSCSI 守护进程 iscsid 使用数据库来指定其设备。你可以使用 iscsiadm 命令与该数据库交互。iscsiadm 还允许你执行目标发现和登录(这里我们使用了长选项形式以提高清晰度):
# iscsiadm --mode discovery --type sendtargets --portal 192.168.1.123
192.168.1.123:3260,1 iqn.2001-04.com.prgmr:domU.orlando
注意,在 iSCSI 术语中,portal 指的是可以通过它访问资源的 IP 地址。在这种情况下,它是导出主机。iscsiadm 告诉我们有一个设备正在导出,iqn.2001-04.com.prgmr:domU.odin。现在我们知道了节点,我们可以更新 iSCSI 数据库:
# iscsiadm -m node -T iqn.2001-04.com.prgmr:domU.orlando
-p 192.168.1.123:3260 -o update -n node.conn[0].startup -v automatic
这里我们使用 iscsiadm 来更新 iSCSI 数据库中的一个节点。我们指定一个目标、一个 portal 以及我们想在数据库节点上执行的操作:update。我们使用 -n 选项指定一个要更新的节点,并使用 -v 选项指定一个新值。我们还可以通过 -o 选项执行其他操作,如 new、delete 和 show。有关更多详细信息,请参阅 Open-iSCSI 文档。
重新启动 iscsid 以传播你的更改。(此步骤可能因你的发行版而异。在 Debian 中脚本为 open-iscsi;在 Red Hat 中为 iscsid。)
# /etc/init.d/open-iscsi restart
注意 dmesg 中的新设备:
iscsi: registered transport (iser)
scsi3 : iSCSI Initiator over TCP/IP
Vendor: IET Model: VIRTUAL-DISK Rev: 0
Type: Direct-Access ANSI SCSI revision: 04
SCSI device sda: 8192000 512-byte hdwr sectors (4194 MB)
sda: Write Protect is off
sda: Mode Sense: 77 00 00 08
SCSI device sda: drive cache: write through
SCSI device sda: 8192000 512-byte hdwr sectors (4194 MB)
注意,这是 dom0 上的第一个 SCSI 设备,因此成为 /dev/sda。进一步的 iSCSI 导出变为 sdb,依此类推。当然,使用本地 SCSI 设备节点作为网络存储显然存在管理问题。我们建议通过使用 /dev/disk/by-path 下的设备来减轻这个问题。在这里 /dev/sda 变为 /dev/disk/by-path/ip-192.168.1.123:3260-iscsi-larry:domU.orlando。当然,你的设备名称将取决于你设置的特定细节。
现在你已经配备了设备,你可以在其上安装一个 Xen 实例,很可能有一个类似于以下 disk= 行:
disk = [ 'phy:/dev/disk/by-path/ip-192.168.1.123:3260-iscsi-larry:domU.orlando ,xvda,rw' ]
由于域由共享 iSCSI 存储支持,因此你可以将域迁移到任何连接的 Xen dom0。
^([55]) 一个自然的扩展是让 domU 通过在 initrd 中包含驱动程序和支持软件直接挂载网络存储。在这种情况下,不需要本地磁盘配置。
Quo Peregrinatur Grex
所以这就是迁移。在本章中,我们描述了:
-
如何手动将域名从一个主机移动到另一个主机
-
主机间域的冷迁移
-
同一子网内主机的实时迁移
-
实时迁移的共享存储
应用这些建议,你会发现你的可管理性显著提高!
第十章。XEN 下的性能分析及基准测试
迪斯雷利非常接近:实际上,有谎言、该死的谎言、统计数据、基准测试和交货日期。
—匿名,归因于 Usenet
我们一直大谈特谈 Xen 作为虚拟化技术,其性能优于竞争技术。然而,当我们谈到证据和迹象时,我们一直在挥舞着手臂,引用权威人士。我们道歉!在本章中,我们将讨论如何使用各种工具亲自测量 Xen 的性能。
我们将仔细研究三种一般性能监控类别,每种类别你可能出于不同的原因使用。首先,我们有基准测试 Xen domU 性能。如果你正在运行托管服务(或从托管服务购买服务),你需要看到你提供的 Xen 镜像(或租用的)与竞争对手相比如何。在这个类别中,我们有通用合成基准测试。
第二,我们希望能够为你的工作负载基准测试 Xen 与其他虚拟化解决方案(或裸机)的性能,因为与其他虚拟化软件包相比,Xen 既有优势也有劣势。这些应用基准测试将有助于确定 Xen 是否是你应用程序的最佳匹配。
第三,有时你在与 Xen 相关或内核相关的程序中遇到性能问题,你想要定位运行缓慢的代码部分。这个类别包括性能分析工具,例如 OProfile。(Xen 开发者也可能在你询问xen-devel列表上的性能问题时要求你提供 OProfile 输出。)
虽然这些技术可能在故障排除时有所帮助,但我们在这里的讨论并不是为了解决问题——相反,我们试图展示各种速度测量工具的概述。有关更具体的故障排除建议,请参阅第十五章。
基准测试概述
我们已经看到,大多数工作负载下,运行在半虚拟化 Xen 域的性能接近原生机器。然而,有些情况下这并不成立,或者这种模糊的真实模拟并不足够精确。在这些情况下,我们从先验科学断言转向直接实验——也就是说,使用基准测试工具和模拟器来找到实际而不是理论上的性能数字。
如你所知,通用基准测试如果不是一个“难题”,至少也是一个相当困难的问题。如果你的负载是 I/O 受限,测试 CPU 将告诉你你需要知道的一切。如果你的负载是 IPC 受限或在某些线程上阻塞,测试磁盘和 CPU 将告诉你很少。最终,最理想的结果来自尽可能接近真实世界负载的基准测试。
例如,测试一个服务器(该服务器提供 HTTP 网络应用)的性能的最好方法,就是嗅探当前 HTTP 服务器上正在发生的实时流量,然后将这些数据回放给新服务器,加快或减慢回放速度,以查看你的容量是否比之前更多或更少。
当然,这既困难又难以概括。大多数人至少会走一步“更容易”和“更通用”的道路。在前面的例子中,你可能会选择一个特别重的页面(或页面的随机样本)并使用一个通用的 HTTP 测试器,如 Siege,来测试服务器。这通常仍然会给你相当好的结果,更容易操作,并且比运行上述实时数据有更少的隐私问题。
然而,有时尽管通用基准测试有其不足之处,但它可能是最好的工具。例如,如果你正在尝试比较两个虚拟专用服务器提供商,一个标准化的、通用的测试可能比现实世界的、具体的测试更容易获得。让我们先检查一下我们使用过的几个合成基准测试。
UnixBench
一个经典的基准测试工具是 1990 年由 BYTE 杂志发布的公共领域 UnixBench,可以从 www.tux.org/pub/tux/niemi/unixbench/ 获取。该工具最后更新于 1999 年,所以它相当古老。然而,它似乎在基准测试 VPS 提供商方面非常受欢迎——通过比较一个提供商的 UnixBench 数值与另一个,你可以大致了解他们提供的虚拟机的容量。
UnixBench 安装简单——下载源代码,解压,构建,然后运行。
# tar zxvf unixbench-4.1.0.tgz
# cd unixbench-4.1.0
# make
# ./Run
(最后一个命令是一个字面上的“运行”——它是一个脚本,按顺序循环执行各种测试,并输出结果。)
你可能会收到一些关于 UnixBench 使用的 -fforce-mem 选项的警告,甚至错误,这取决于你的编译器版本。如果你编辑 Makefile 以删除所有 -fforce-mem 实例,UnixBench 应该可以成功构建。
如果可能的话,我们建议在单用户模式下对 Xen 实例进行基准测试。以下是一些示例输出:
INDEX VALUES
TEST BASELINE RESULT INDEX
Dhrystone 2 using register variables 116700.0 1988287.6 170.4
Double-Precision Whetstone 55.0 641.4 116.6
Execl Throughput 43.0 1619.6 376.7
File Copy 1024 bufsize 2000 maxblocks 3960.0 169784.0 428.7
File Copy 256 bufsize 500 maxblocks 1655.0 53117.0 320.9
File Copy 4096 bufsize 8000 maxblocks 5800.0 397207.0 684.8
Pipe Throughput 12440.0 233517.3 187.7
Pipe-based Context Switching 4000.0 75988.8 190.0
Process Creation 126.0 6241.4 495.3
Shell Scripts (8 concurrent) 6.0 173.6 289.3
System Call Overhead 15000.0 184753.6 123.2
=========
FINAL SCORE............................... 264.5
拥有一个 UnixBench 数值,你至少可以比较不同 VPS 提供商之间的一些基础。它不会告诉你太多关于你将获得的具体性能,但它有一个优点,那就是它是一个广泛发布的、易于获取的基准。
其他工具,如 netperf 和 Bonnie++,可以提供更详细的表现信息。
分析网络性能
一个用于测量低级网络性能的流行工具是 netperf。该工具支持各种性能测量,重点在于测量网络实现的效率。它也被用于与 Xen 相关的论文中。例如,参见 Muli Ben-Yehuda 等人撰写的“安全性的代价:评估 IOMMU 性能”。
首先,从netperf.org/netperf/DownloadNetperf.html下载 netperf。我们选择了版本 2.4.4。
# wget ftp://ftp.netperf.org/netperf/netperf-2.4.4.tar.bz2
解压并进入 netperf 目录。
# tar xjvf netperf-2.4.4.tar.bz2
# cd netperf-2.4.
配置、构建和安装 netperf。(注意,这些说明与文档略有不同;文档声称/opt/netperf是硬编码的安装前缀,但对我来说它似乎安装在/usr/local。此外,手册似乎早于 netperf 使用 Autoconf。)
# ./configure
# make
# su
# make install
netperf 通过在基准测试的机器上运行客户端netperf来工作。netperf连接到netserver守护进程,并测试它发送和接收数据的能力。因此,要使用netperf,我们首先需要设置netserver。
在标准服务配置中,netserver会在inetd下运行;然而,inetd已经过时。许多发行版默认甚至不包括它。此外,你可能不希望基准服务器一直运行。因此,而不是配置inetd,我们可以以独立模式运行netserver:
# /usr/local/bin/netserver
Starting netserver at port 12865
Starting netserver at hostname 0.0.0.0 port 12865 and family AF_UNSPEC
现在,我们可以不带任何参数运行netperf客户端,以执行与本地守护进程的 10 秒测试。
# netperf
TCP STREAM TEST from 0.0.0.0 (0.0.0.0) port 0 AF_INET to localhost (127.0.0.1)
port 0 AF_INET
Recv Send Send
Socket Socket Message Elapsed
Size Size Size Time Throughput
bytes bytes bytes secs. 10⁶bits/sec
87380 16384 16384 10.01 10516.33
好吧,看起来不错。现在我们将从 dom0 测试到这个 domU。为此,我们按照之前描述的方式安装 netperf 二进制文件,并使用-H选项运行netperf来指定目标主机(在这种情况下,.74 是我们正在测试的 domU):
# netperf -H 216.218.223.74,ipv4
TCP STREAM TEST from 0.0.0.0 (0.0.0.0) port 0 AF_INET to 192.0.2.74
(192.0.2.74) port 0 AF_INET
Recv Send Send
Socket Socket Message Elapsed
Size Size Size Time Throughput
bytes bytes bytes secs. 10⁶bits/sec
87380 16384 16384 10.00 638.59
好的。显然没有这么快,但我们预料到了。现在从另一台物理机器到我们的测试 domU:
# netperf -H 192.0.2.66
TCP STREAM TEST from 0.0.0.0 (0.0.0.0) port 0 AF_INET to 192.0.2.66
(192.0.2.66) port 0 AF_INET
Recv Send Send
Socket Socket Message Elapsed
Size Size Size Time Throughput
bytes bytes bytes secs. 10⁶bits/sec
87380 16384 16384 10.25 87.72
哎呦。那么,其中有多少是 Xen,又有多少是我们正在通过的网络?为了找出答案,我们将在托管测试 domU 的 dom0 上运行netserver守护进程并连接到它:
# netperf -H 192.0.2.74
TCP STREAM TEST from 0.0.0.0 (0.0.0.0) port 0 AF_INET to 192.0.2.74
(192.0.2.74) port 0 AF_INET
Recv Send Send
Socket Socket Message Elapsed
Size Size Size Time Throughput
bytes bytes bytes secs. 10⁶bits/sec
87380 16384 16384 10.12 93.66
我想情况可能更糟。这个故事的意义是什么?xennet引入了明显的但合理的开销。此外,netperf 可以是一个有用的工具,用于发现你实际可用的带宽。在这种情况下,机器通过 100Mbit 连接连接,netperf 列出的实际吞吐量为 93.66Mbits/second。
使用 Bonnie++衡量磁盘性能
机器整体性能的一个主要因素是其磁盘子系统。通过锻炼其硬盘,我们可以得到一个有用的指标,用于比较 Xen 提供商或 Xen 实例与,比如说,VMware 虚拟机。
我们,就像地球上几乎所有人一样,使用 Bonnie++来衡量磁盘性能。Bonnie++试图衡量随机和顺序磁盘性能,并且很好地模拟了真实世界的负载。这在 Xen 环境中尤为重要,因为域的分区程度——尽管域共享资源,但它们无法协调资源使用。
这个观点的一个例子是,如果有多个域名同时尝试访问磁盘,从单个虚拟机的角度来看,这看起来像是顺序访问,但实际上是对磁盘的随机访问。这使得诸如寻道时间和你的标记队列系统的鲁棒性变得更加重要。为了测试这些优化对 domU 性能的影响,你可能需要一个像 Bonnie++这样的工具。
Bonnie++的作者在 www.coker.com.au/bonnie++/ 上维护一个主页。下载源代码包,构建它,并安装它:
# wget http://www.coker.com.au/bonnie++/bonnie++-1.03c.tgz
# cd bonnie++-1.03c
# make
# make install
在这一点上,你可以简单地使用如下命令调用 Bonnie++:
# /usr/local/sbin/bonnie++
此命令将运行一些测试,并在运行过程中打印状态信息,最终生成如下输出:
Version 1.03 ------Sequential Output------ --Sequential Input- --Random-
-Per Chr- --Block-- -Rewrite- -Per Chr- --Block-- --Seeks--
Machine Size K/sec %CP K/sec %CP K/sec %CP K/sec %CP K/sec %CP /sec %CP
alastor 2512M 20736 76 55093 14 21112 5 26385 87 55658 6 194.9 0
........... ------Sequential Create------ --------Random Create--------
-Create-- --Read--- -Delete-- -Create-- --Read--- -Delete--
files /sec %CP /sec %CP /sec %CP /sec %CP /sec %CP /sec %CP
256 35990 89 227885 85 16877 28 34146 84 334227 99 5716 10
注意,某些测试可能仅仅输出一行加号。这表示机器在 500 毫秒内完成了这些测试。使工作负载更加困难。例如,你可能指定如下:
# /usr/local/sbin/bonnie++ -d . -s 2512 -n 256
这指定了写入 2512MB 文件以进行 I/O 性能测试。(这是默认文件大小,是这台特定机器 RAM 大小的两倍。这很重要,以确保我们不仅仅是在锻炼 RAM 而不是磁盘。)它还告诉 Bonnie++在其文件创建测试中创建 256*1024 个文件。
我们还推荐阅读 Bonnie++的在线手册,其中包含大量精辟的基准测试智慧,详细说明了作者为什么选择包含这些测试,以及不同数字的含义。
^([56]) “难题”这个短语通常被用作干巴巴的幽默。经典的“难题”包括自然语言和强人工智能。另见:“有趣”。
^([57]) 查看 ols.108.redhat.com/2007/Reprints/ben-yehuda-Reprint.pdf。
应用程序基准测试
当然,服务器的目的是运行应用程序——我们并不真正关心虚拟机每秒可以做多少次绝对无意义的事情。为了测试应用程序的性能,我们使用计划放在机器上的应用程序,然后向它们施加负载。
由于这是特定于应用程序的,我们无法在具体细节上提供太多指导。许多流行的库都有好的测试套件。例如,我们曾有过客户使用流行的 Web 框架 Django 对 Xen 实例进行基准测试.^([58])
httperf:HTTP 服务器的负载生成器
在测试了您域的网络接口的有效性之后,您可能想了解该域通过该接口提供应用时的表现如何。由于 Xen 的服务器导向传统,测试其在基于 HTTP 的实际情况中的性能的一种流行方法是使用httperf。该工具生成 HTTP 请求并总结性能统计信息。它支持 HTTP/1.1 和 SSL 协议,并提供各种工作负载生成器。例如,如果您试图找出您的 Web 服务器在崩溃之前可以处理多少用户,您可能会发现httperf很有用。
首先,在您要测试的机器上安装httperf——它可以是一个另一个 domU,但我们通常更喜欢将其安装在完全不同的东西上。这个“负载”机器也应该尽可能接近目标机器——最好是连接到同一个以太网交换机。
您可以通过您发行版的包管理机制或从www.hpl.hp.com/research/linux/httperf/获取httperf。
如果您已下载源代码,请使用标准方法构建它。httperf的文档建议使用单独的构建目录而不是直接在源树中构建。因此,从httperf源目录:
# mkdir build
# cd build
# ../configure
# make
# make install
接下来,运行适当的测试。我们通常的做法是使用类似以下命令的httperf:
# httperf --server 192.168.1.80 --uri /index.html --num-conns 6000
--rate 1500
在这种情况下,我们只是要求一个静态 HTML 页面,因此请求速率非常高;通常在测试现实世界数据库支持的网站时,我们会使用一个远小得多的数字。
httperf将随后为您提供一些统计信息。根据我们的经验,重要的数字是连接速率、请求速率和回复速率。所有这些都应该接近命令行上指定的速率。如果它们开始从该数字下降,这表明服务器已达到其容量。
然而,httperf不仅限于对单个文件的重复请求。我们更喜欢通过指定--wsesslog工作负载生成器以会话模式使用httperf。这给出了更接近实际负载的近似值。您可以使用一些 Perl 从您的 Web 服务器日志创建会话文件,最终得到一个简单的格式化 URL 列表:
/newsv3/
....../style/crimson.css
....../style/ash.css
....../style/azure.css
....../images/news.feeds.anime/sites/ann-xs.gif
....../images/news.feeds.anime/sites/annpr-xs.gif
....../images/news.feeds.anime/sites/aod-xs.gif
....../images/news.feeds.anime/sites/an-xs.gif
....../images/news.feeds.anime/header-lite.gif
/index.shtml
....../style/sable.css
....../images/banners/igloo.gif
....../images/temp_banner.gif
....../images/faye_header2.jpg
....../images/faye-birthday.jpg
....../images/giant_arrow.gif
....../images/faye_header.jpg
/news/
/events/
....../events/events.css
....../events/summergathering2007/coverimage.jpg
*`(and so forth.)`*
此会话文件列出了httperf请求的文件,缩进用于定义突发;以空白字符开始的行组是一个突发。当运行时,httperf将请求第一个突发,等待一定时间,然后移动到下一个突发。配备此会话文件,我们可以使用httperf来模拟用户:
# httperf --hog --server 192.168.1.80 --wsesslog=40,10,urls.txt --rate=1
这将每秒启动 40 个会话。新参数--wsesslog从urls.txt读取输入并在突发中运行,突发之间暂停 10 秒以模拟用户思考。
再次,将此命令应用到您的服务器上,逐渐增加速率,直到服务器无法满足需求。当服务器失败时,恭喜!您已经得到了一个基准。
另一个应用基准测试:POV-Ray
当然,根据您的应用,httperf可能不是一个合适的工作负载。假设您已经决定使用 Xen 来渲染由流行的开源光线追踪器 POV-Ray 创建的场景。(如果不是其他原因,这也是一种消耗空闲 CPU 周期的不错方式。)
POV-Ray 基准测试易于运行。只需在命令行上给出-benchmark选项:
# povray -benchmark
这将渲染一个标准场景,并给出大量统计数据,最后以总体总结和渲染时间为结束。一个配备 2.8 GHz 奔腾 4 和 256MB 内存的 domU 给出了以下输出:
Smallest Alloc: 9 bytes
Largest Alloc: 1440008 bytes
Peak memory used: 5516100 bytes
Total Scene Processing Times
Parse Time: 0 hours 0 minutes 2 seconds (2 seconds)
Photon Time: 0 hours 0 minutes 53 seconds (53 seconds)
Render Time: 0 hours 43 minutes 26 seconds (2606 seconds)
Total Time: 0 hours 44 minutes 21 seconds (2661 seconds)
现在您得到了一个单一的数字,可以轻松地比较运行 POV-Ray 的各种配置,无论是 Xen 实例、VMware 盒子还是物理服务器。
调优 Xen 以实现最佳基准测试
大多数系统管理工作涉及在机器级别比较结果——分析 Xen 虚拟机相对于另一台机器的性能,无论是有虚拟的还是没有虚拟的。然而,在虚拟化的情况下,有一些性能旋钮并不明显,但它们可以在最终的基准测试结果中产生巨大差异。
首先,Xen 动态分配 CPU,并尽可能保持 CPU 忙碌。也就是说,如果 dom2 没有使用其分配的全部 CPU,dom3 可以接手额外的 CPU。虽然这通常是好事,但它可能会使 CPU 基准测试数据具有误导性。在测试时,您可以通过指定调度器的cap参数来避免这个问题。例如,为了确保域 ID 1 不能超过一个 CPU 的 50%:
# xm sched-credit -d 1 -c 50
其次,在 HVM 模式下运行的客户机绝对必须使用虚拟化驱动程序才能获得可接受的性能。这一点在 XenSource 对 VMware 发布的基准测试结果的分析中得到了强调,其中 XenSource 指出,在 VMware 的基准测试中,“XenSource 的 Windows Xen 工具,它优化了 I/O 路径,没有被安装。因此,VMware 的基准测试应该完全不予考虑。”
此外,共享资源(如磁盘 I/O)难以计算,可能会与 dom0 的 CPU 需求交互,并可能受到其他 domUs 的影响。例如,尽管虚拟化 Xen 可以提供出色的网络性能,但它需要比非虚拟化机器更多的 CPU 周期来完成这项工作。这可能会影响您机器的容量。
这是一个难以解决的问题,我们无法真正提供一个万能的解决方案。有一点需要注意,dom0 可能会使用比直观估计更多的 CPU;在 dom0 的 CPU 分配上给予高度重视,或者在具有四个或更多核心的机器上,可能甚至需要为 dom0 专门分配一个核心。
对于基准测试,我们还建议通过使用合理负载的机器来最小化误差。如果您预计要运行十几个 domUs,那么在基准测试时,它们都应该执行一些合理的合成任务,以便对 VM 的真实世界性能有一个认识。
^([58]) journal.uggedal.com/vps-comparison-between-slicehost-and-prgmr 使用 Django 等工具。
使用 Xen 进行性能分析
当然,有一种更精确地查看共享资源使用情况的方法。我们可以分析运行我们的应用程序工作负载时的虚拟机,以清楚地了解它在做什么,以及——使用一个 Xen 感知的分析器——其他域是如何干扰我们的。
性能分析是指检查特定应用程序以查看它花费时间做什么的实践。特别是,它可以告诉你应用程序是 CPU 还是 I/O 受限,是否某些函数效率低下,或者性能问题是否完全发生在应用程序之外,可能在内核中。
在这里,我们将讨论一个使用 Xen 和 OProfile 的示例设置,使用内核编译作为标准工作负载(这也是大多数 Xen 管理员可能熟悉的工作负载)。
Xenoprof
OProfile 可能是 Linux 上最受欢迎的性能分析包。59 内核包括 OProfile 支持,用户空间工具几乎包含我们知道的每个发行版。如果你有特定程序的性能问题,并想确切地看到导致问题的原因,OProfile 是这项工作的工具。
OProfile 通过在程序被分析执行特定操作时增加计数器来工作。例如,它可以计算缓存未命中次数或执行指令次数。当计数器达到一定值时,它指示 OProfile 守护进程采样计数器,使用不可屏蔽的中断来确保及时处理采样请求。
Xenoprofile,或 Xenoprof,是 OProfile 的一个版本,它已被扩展以在 Xen 下作为系统级性能分析工具使用,通过超调来启用域访问硬件性能计数器。它支持分析完整的 Xen 实例,并计算在虚拟机管理程序或另一个 domU 中花费的时间。
获取 OProfile
到目前为止,Xen 包括对 OProfile 版本高达 0.9.2 的支持(0.9.3 将需要你对 Xen 内核应用补丁)。目前,使用打包版本可能是最好的选择,以最大限度地减少重新编译的繁琐工作。
如果你使用的是较新的 Debian、Ubuntu、CentOS 或 Red Hat 版本,那么你很幸运;他们提供的 OProfile 版本已经设置为与 Xen 一起工作。其他发行版的内核,如果它们包含 Xen,也可能包含 OProfile 的 Xen 支持。
构建 OProfile
如果你没有 Xen 性能分析支持这么幸运,你将不得不下载并构建 OProfile,我们将给出非常简短的说明,以确保完整性。
首先要做的事情是从oprofile.sourceforge.net/下载 OProfile 源代码。我们使用了版本 0.9.4。
首先,解压 OProfile,如下所示:
# wget http://prdownloads.sourceforge.net/oprofile/oprofile-0.9.4.tar.gz
# tar xzvf oprofile-0.9.4.tar.gz
# cd oprofile-0.9.4
然后配置并构建 OProfile:
# ./configure --with-kernel-support
# make
# make install
最后,如果你的内核尚未正确配置,请进行一些 Linux 内核配置。(你可以通过执行gzip -d -i /proc/config.gz | grep PROFILE来检查。)在我们的例子中,它返回:
CONFIG_PROFILING=y
CONFIG_OPROFILE=m
注意
/proc/config.gz是一个可选功能,可能不存在。如果不存在,你必须以其他方式找到你的配置。例如,在 Fedora 8 上,你可以通过查看随发行版提供的内核配置文件来检查分析支持:
# cat /boot/config-2.6.23.1-42.fc8 | grep PROFILE
如果你的内核没有配置为分析,请使用分析支持重新构建它。然后安装并从新内核引导(这里不会详细说明这一步骤)。
OProfile 快速入门
为了确保 OProfile 正常工作,你可以在域 0 中分析一个标准的工作负载。(我们选择了内核编译,因为对于大多数系统管理员来说这是一个熟悉的任务,尽管我们是在 Xen 源树外编译的。)
首先,告诉 OProfile 清除其样本缓冲区:
# opcontrol --reset
现在配置 OProfile。
# opcontrol --setup --vmlinux=/usr/lib/debug/lib/modules/vmlinux
--separate=library --event=CPU_CLK_UNHALTED:750000:0x1:1:1
前三个参数是命令(分析设置)、内核镜像以及为使用的库创建单独输出文件选项。最后的开关event描述了我们指示 OProfile 监控的事件。
你想要采样的精确事件取决于你的处理器类型(以及你试图测量的内容)。对于这次运行,为了得到 CPU 使用率的整体近似值,我们在 Intel Core 2 机器上使用了CPU_CLK_UNHALTED。在 Pentium 4 上,等效的度量将是GLOBAL_POWER_EVENTS。剩余的参数表示计数器的尺寸,单位掩码(在这种情况下,0x1),以及我们想要内核和用户空间代码。
在基于 Red Hat 的发行版上安装未压缩的内核
你可能会遇到与 OProfile 和 kdump 相关的问题,就像任何深入内核内部结构的工具一样,这些工具期望找到一个未压缩的带有调试符号的内核以获得最大效益。如果你自己构建了内核,这很简单,但如果使用的是发行版内核,可能会更困难。
在 Red Hat 和其他系统中,这些内核(以及为调试构建的其他软件)包含在特殊的-debuginfo RPM 软件包中。这些软件包不在标准的yum仓库中,但你可以从 Red Hat 的 FTP 站点获取它们。例如,对于 Red Hat Enterprise Linux 5,那将是 ftp://ftp.redhat.com/pub/redhat/linux/enterprise/5Server/en/os/i386/Debuginfo。
对于默认内核,你需要以下软件包:
kernel-debuginfo-common-`uname -r`.`uname -m`.rpm
kernel-PAE-debuginfo-`uname -r`.`uname -m`.rpm
下载这些并使用 RPM 安装它们。
# rpm -ivh *.rpm
要开始收集样本,请运行:
# opcontrol --start
然后运行你想要分析的实验,在这种情况下是一个内核编译。
# /usr/bin/time -v make bzImage
然后停止分析器。
# opcontrol --shutdown
现在我们有了样本,我们可以通过标准的后分析工具从大量原始数据中提取有意义和有用的信息。主要分析命令是opreport。为了获取消耗 CPU 的进程的基本概述,我们可以运行:
# opreport -t 2
CPU: Core 2, speed 2400.08 MHz (estimated)
Counted CPU_CLK_UNHALTED events (Clock cycles when not halted) with a unit mask
of 0x01 (Unhalted bus cycles) count 750000
CPU_CLK_UNHALT...|
samples| %|
------------------
370812 90.0945 cc1
CPU_CLK_UNHALT...|
samples| %|
------------------
332713 89.7255 cc1
37858 10.2095 libc-2.5.so
241 0.0650 ld-2.5.so
11364 2.7611 genksyms
CPU_CLK_UNHALT...|
samples| %|
------------------
8159 71.7969 genksyms
3178 27.9655 libc-2.5.so
27 0.2376 ld-2.5.so
这告诉我们哪些进程在编译期间占用了 CPU 使用率,阈值为 2%(由-t 2选项指示)。然而,这并不十分有趣。我们可以使用opreport的--symbols选项获得更多的粒度,它给出了关于哪些函数占用了 CPU 使用率的最佳猜测。试试看。
你可能对其他事件感兴趣,例如缓存未命中。要获取针对你的硬件定制的可能计数器的列表,请执行以下命令:
# ophelp
协同分析多个域
到目前为止,所有这些都涵盖了 OProfile 的标准用法,没有涉及 Xen 特定的功能。但在 Xen 环境中,OProfile 最有用的功能之一是能够对整个域进行相互分析,分析不同的调度参数、磁盘分配、驱动程序和代码路径如何相互作用以影响性能。
当分析多个域时,dom0 仍然协调会话。目前无法在 dom0 不参与的情况下简单地在一个 domU 中进行分析——domUs 没有直接访问 CPU 性能计数器的权限。
主动与被动分析
Xenoprofile 支持域分析中的主动和被动模式。
在被动模式下进行分析时,结果指示在采样时间运行的是哪个域,但不会深入挖掘正在执行的内容。快速查看哪些域正在使用系统很有用。
在主动模式下,每个 domU 运行其自己的 OProfile 实例,它在其虚拟机内部采样事件。主动模式比被动模式提供了更好的粒度,但不太方便。只有半虚拟化域才能在主动模式下运行。
主动分析
主动分析更有趣。在这个例子中,我们将使用三个域:dom0,用于控制分析器,以及 domUs 1 和 3 作为主动域。
0 # opcontrol --reset
1 # opcontrol --reset
3 # opcontrol --reset
首先,在 dom0 中设置守护进程并使用一些初始参数:
0 # opcontrol --start-daemon --event=GLOBAL_POWER_EVENTS:1000000:1:1
--xen=/boot/xen-syms-3.0-unstable
--vmlinux=/boot/vmlinux-syms-2.6.18-xen0 --active-domains=1,3
这引入了--xen选项,它提供了未压缩的 Xen 内核镜像的路径,以及--active-domains选项,它列出了以主动模式进行分析的域。事件选项末尾的:1 s告诉 OProfile 在用户空间和内核空间中计数事件。
注意
通过数字 ID 指定域。OProfile 不会解释名称。
接下来,在主动 domUs 中启动 OProfile。守护进程必须在 dom0 中已经运行,否则 domU 将没有权限访问性能计数器。
1 # opcontrol --reset
1 # opcontrol --start
在域 3 中运行相同的命令。最后,在域 0 中开始采样:
0 # opcontrol --start
现在我们可以运行感兴趣域中的命令。让我们继续使用内核编译作为我们的测试工作负载,但这次通过在另一个域中运行磁盘密集型基准测试来复杂化问题。
1 # time make bzImage
3 # time bonnie++
当内核编译和 Bonnie++完成时,我们停止 OProfile:
0 # opcontrol --stop
0 # opcontrol --shutdown
1 # opcontrol --shutdown
3 # opcontrol --shutdown
现在,每个 domU 都将有自己的样本集,我们可以使用 opreport 来查看。这些报告综合起来,形成了一个关于各个域活动的完整画面。我们可能会建议尝试调整 CPU 分配,看看这如何影响 OProfile 的结果。
OProfile 示例
现在让我们尝试将 OProfile 应用于实际的问题。这里是场景:我们已经迁移到一个使用一对 1 TB SATA 磁盘上的 LVM 镜像的设置。硬件是一台四核英特尔 QX6600,8GB 内存和一个 ICH7 SATA 控制器,使用 AHCI 驱动程序。我们为 dom0 分配了 512MB 内存。
我们注意到,通过 xenblk 访问的镜像逻辑卷的性能大约是非镜像 LV 或使用 --corelog 选项镜像的 LV 的十分之一。在 dom0 内部正常访问时,具有和没有 –corelog 的镜像 LV 表现良好,但通过 xm block-attach 访问时性能下降。在我们看来,这是荒谬的。
首先,我们在卷组 test 中创建了两个逻辑卷:一个具有镜像和镜像日志,另一个使用 --corelog 选项。
# lvcreate -m 1 -L 2G -n test_mirror test
# lvcreate -m 1 --corelog -L 2G -n test_core test
然后,我们创建了文件系统并将它们挂载:
# mke2fs -j /dev/test/test*
# mkdir -p /mnt/test/mirror
# mkdir -p /mnt/test/core
# mount /dev/test/test_mirror /mnt/test/mirror
接下来,我们启动了 OProfile,使用 --xen 选项提供未压缩的 Xen 内核映像的路径。经过几次测试运行,分析各种事件,很明显我们的问题与花费在等待 I/O 上的时间过多有关。因此,我们指示分析器计数 BUS_IO_WAIT 事件,这些事件表示处理器在等待输入时卡住:
# opcontrol --start --event=BUS_IO_WAIT:500:0xc0
--xen=/usr/lib/debug/boot/xen-syms-2.6.18-53.1.14.el5.debug
--vmlinux=/usr/lib/debug/lib/modules/2.6.18-53.1.14.el5xen/vmlinux
--separate=all
然后,我们按顺序在每个设备上运行 Bonnie++,每次停止 OProfile 并保存输出。
# bonnie++ -d /mnt/test/mirror
# opcontrol --stop
# opcontrol --save=mirrorlog
# opcontrol --reset
如预期的那样,具有核心日志的 LV 显示了可忽略的 iowait。然而,其他设备经历了很多,正如您在这份关于所讨论 LV 的测试输出中看到的那样:
# opreport -t 1 --symbols session:iowait_mirror
warning: /ahci could not be found.
CPU: Core 2, speed 2400.08 MHz (estimated)
Counted BUS_IO_WAIT events (IO requests waiting in the bus queue) with a unit mask of 0xc0 (All
cores) count 500
Processes with a thread ID of 0
Processes with a thread ID of 463
Processes with a thread ID of 14185
samples % samples % samples % app name symbol name
32 91.4286 15 93.7500 0 0 xen-syms-2.6.18-53.1.14.el5.debug pit_read_counter
1 2.8571 0 0 0 0 ahci (no symbols)
1 2.8571 0 0 0 0 vmlinux bio_put
1 2.8571 0 0 0 0 vmlinux hypercall_page
在这里,我们可以看到 Xen 内核在 pit_read_counter 函数中经历了大量 BUS_IO_WAIT 事件,这表明这个函数很可能是我们的罪魁祸首。对那个函数名称进行一点搜索发现,它已经被从 Xen 的最新版本中移除,所以我们决定走捷径进行升级。问题解决了——但现在我们有一些想法为什么。
正确使用,分析可以是一个跟踪性能瓶颈的优秀方法。然而,它并不是任何一种魔法子弹。分析产生的大量数据可能会很有吸引力,而整理分析器的输出可能需要比其价值更多的时间。
^([59]) 当然,不包括 top(1)。
结论
这样就介绍了一个使用 Xen 进行性能测量的系统管理员入门指南。在本章中,我们描述了从通用到特定、从硬件导向到应用导向的各种性能测量工具。我们还简要讨论了 OProfile 的 Xen 相关特性,这些特性旨在将分析器扩展到多个 domU 和虚拟机管理程序本身。
第十一章。思杰 XenServer:面向企业的 Xen

一直以来,我们只关注 Xen 的开源版本。然而,这并不是唯一的选择。Xen 团队还发布了一个打包的 Xen 版本,旨在将 Xen 转变为适合企业的产品。^([60])
你在阅读本书时可能已经隐约感觉到,Xen 仍然处于开发状态。一句话来说,它是黑客软件。它是好的软件——显然我们认为它足够稳定,可以让真实的人们每天使用——但它仍然需要大量的工作来设置和启动。
对于这种状况,有几个合理的解释。部分原因是因为黑客作为一个群体,并不擅长完成事情。将产品从 90%完成到 100%完成的工作通常并不困难,只是有点繁琐。开源软件很棒,但它在生产完整的商业产品方面并不出色。^([61]) 另一个问题在于,Xen 本质上具有侵入性和基础性。人们犹豫是否使用“范式”这样的词,但就是这样——虚拟化是一种不同的计算方式,一种不同的思考计算机的方式,它需要大量的非常精致的软件支持。
思杰(该公司收购了由原始 Xen 团队创立的 XenSource 公司)通过提供这种软件来简化过渡——创建软件堆栈,开发认证流程,并建立最佳实践,以便管理员可以以最小的麻烦和不确定性推出 Xen。他们致力于 Xen 的开源版本,并向其贡献更改,但他们还进行了一个额外的质量保证级别,旨在将 Xen 转变为你可以放心信任你的业务的产物。
你可能会问这是如何可能的,考虑到 Xen 仍然处于 GPL 协议之下。思杰可以这样做,同时遵守 Xen 许可条款,因为 Xen 的客户端/服务器架构和模块化设计允许他们扩展基本虚拟机管理程序,添加作为模块和与 GPL 软件协同工作的用户空间进程的新功能。思杰使用开源虚拟机管理程序与开源 Linux 相结合,加上额外的模块和专有控制软件,提供 Xen 的集成发行版,就像传统的 Linux 发行版一样,但强调虚拟化。
思杰的 Xen 产品
思杰的产品由两个组件组成,XenServer 和 XenEssentials。XenServer 是虚拟机管理程序和基本管理工具,它是免费的。^([62]) XenEssentials 是一套付费的实用程序。
基本免费产品简单地称为 XenServer。XenServer 支持付费 Citrix 产品的大多数功能,拥有相同的管理界面。它面向开发、测试和非关键生产部署,以及想要测试或玩转 Xen 的人。
Citrix 的付费产品称为 Citrix Essentials for XenServer,具有各种级别的许可。它并不具备开源 Xen 的所有功能,但它拥有 Citrix 认为可以舒适支持的所有功能以及一些商业产品的独家功能。据我们所知,Citrix 为这个版本收取的金额与市场承受能力相当.^([63]) 当然,这随时可能改变。最好与你的 Citrix 代表协商,最好是进行某种形式的角斗士战斗.^([64])
总体而言,我们将专注于免费提供的基产品和组件。
^([60]) 我们知道,这是营销术语。但这是我们传达产品目标的最简单方式。
^([61]) 这并不是贬低我们日常使用的精美产品背后的人们的优秀工作,比如 Linux、Mozilla 和 Vim。我们只是说,最后的 10%是最困难的,并不是说它永远不会完成。
^([62]) 正如老人们所说,这是免费的啤酒。
^([63]) 我们无法找到连贯的定价信息。
^([64]) 在花费数周时间试图从销售人员那里获取托管定价信息后,Luke 怀疑角斗士战斗会比传统的谈判价格方法更愉快。prgmr.com 更喜欢“网站上的价格就是你要支付的价格”模式。
使用 Citrix XenServer 的好处
XenServer 产品在可管理性方面对开源 Xen 进行了改进。他们在简化并自动化常见任务的同时,保留了开源 Xen 的大部分透明度。
十分钟到达异域
我们的模式是 CD 进入驱动器,计算机因此成为一台更好的机器(在十分钟或更短的时间内)。这正是 XenExpress^([65])的全部内容。
— 弗兰克·阿塔莱,XenSource
这其中最好的演示之一就是 Citrix 所称之为的“十分钟 Xen”或“十到 Xen”。他们极大地简化了 Xen 的引导部分,在这一部分中,你需要安装一个 dom0 操作系统,并修改它以便与 Xen 的控制软件和虚拟机管理程序良好地协同工作。
Citrix 认为,你实际上不应该对 dom0 进行任何操作,除了控制 domUs。因此,该产品安装了一个基本的 Linux 操作系统,其中只包含运行 Xen 所需的组件:一个内核、一个外壳、一些库、一个文本编辑器、Python、syslog、SSH(等等),以及 Xen 软件。在这种方法中,不需要控制 Xen 的软件,例如提供服务器存在理由的守护进程,应该安装在 domU 中。当然,它仍然是基于 Linux 的——实际上是基于 CentOS 的——而且没有任何阻止你安装其他软件的东西。然而,我们建议坚持使用 Citrix 的方法,并保持你的核心虚拟化服务器整洁。
基本包实际上确实需要大约 10 分钟来安装,正如广告中所说的那样。务必获取补充的 Linux 包,其中包含 Debian 模板和 Linux 虚拟机的支持工具。完成这些后,从包含的 Debian 模板或安装介质创建 domUs 就是一件简单的事情。
Citrix XenServer 还有其他优点。也许最重要的是,它感觉比开源 Xen 更集中。我们一直在讨论的所有决策——存储、网络等等——都是以集中的方式处理的,使用一致的界面。在可能的情况下,他们已经为你做出了合理的默认决策。这些决策不一定适用于所有情况,但至少对于 Xen 的用途来说将是合理的。
以存储为例。Citrix 使用与开源 Xen 相同的架构,在 dom0 中使用未经修改的 Linux 驱动程序来访问物理设备。他们在其上叠加 LVM 以抽象物理存储并增加灵活性,正如我们在其他地方概述的那样。Citrix 通过提供一种通过与系统更具体的 Xen 特性相同的 GUI 来管理存储的方式,来构建这些开源工具,这样你可以专注于虚拟机而不是晦涩的磁盘管理命令。如果你愿意,你仍然可以使用熟悉的命令。Citrix 的 Xen 产品并不是要重新发明轮子或使系统的基本工作原理变得晦涩;他们只是提供了一个替代方案,使常见任务变得稍微容易一些。
^([65]) 当 XenSource 还是 XenSource 时,XenExpress 是免费产品的名称,在 Citrix 收购他们之前。
使用 Citrix XenServer 的缺点
即使是高端 Essentials 产品,稳定性和功能之间也存在权衡。Citrix 只公开他们认为足够成熟,可以在生产环境中使用的虚拟化功能。例如,迁移是在开源版本推出两年后添加的。
目前还没有简单的方法在开源 Xen 和商业 Xen 之间迁移虚拟机。(当然,你可以通过使用第九章中概述的底层方法手动迁移虚拟机。)如果你标准化使用开源或商业 Xen,以后可能很难改变这个决定,尽管 Open Virtualization Format (OVF)(它得到了一些开源工具的支持,^([66]))承诺将改善这种情况。
除此之外,开源仍然是一个意识形态问题。有些人尽可能使用它;有些人则像躲避瘟疫一样避免它。我们使用开源产品,因为它对我们来说足够好,而且显然我们的时间是毫无价值的。Citrix 提供了一种直接的交易:给他们钱,他们就会以 Xen 产品的形式给你 Xen,而不是高度可定制的黑客软件。登上船并承担你的风险。
^([66]) open-ovf.wiki.sourceforge.net/ 是一个不错的起点。
入门
说了这么多,开始使用 Citrix 的 XenServer 的最佳方式可能就是尝试这个产品,看看你是否喜欢它。入门级版本是免费的。你可以在 www.citrix.com/xenserver/getitfree/ 下载它,并通过输入许可证密钥在任何时候升级它。此外,他们所说的安装大约需要 10 分钟是真实的,所以为什么不试试呢?
先决条件
首先,检查以确保你满足最低系统要求:
-
64 位 CPU,即 AMD Opteron、Athlon 64、Phenom 或 AMD 市场营销部门想出的任何其他东西,以及过去几年中的大多数 Intel Xeon,以及 Core 2(但不包括 Core)。
-
根据你想要多少虚拟机,需要一定量的内存。Citrix 的最低要求是 1GB,这对我们来说听起来是合理的。
-
足够的磁盘空间。XenServer 后端将占用 8GB,其余的可用空间留给 domUs。当然,你也可以为虚拟机使用网络存储。
-
如果你想要运行 Windows domUs,则需要 HVM 支持,但否则它是可选的。
安装 Citrix XenServer
正如我们提到的,Citrix 的产品是一个完整的系统;像安装任何其他操作系统一样安装它。对我们来说,这意味着下载 ISO 文件,将其烧录到 CD 上,并从 CD 引导目标机器。我们还抓取了 Linux Guest Support disc,它包括对 Linux 虚拟机的支持。
机器将进行非图形安装,并询问一些关于键盘、时间和网络设置的常规问题——通常是这些。与正常的 Linux 安装相比,它极其简洁和精简,因为该产品本身只有一个虚拟化的焦点。例如,没有设置分区的机会。最后,它提示我们插入补充 CD,所以我们放进了 Linux 支持 CD。
十分钟后,一次重启后,我们面对一个屏幕,建议我们通过管理前端 XenCenter 登录。
使用 XENSERVER 的串行控制台
我们永远不会考虑使用没有串行控制台访问权限的服务器。尽管 Citrix 的 Xen 产品默认不支持串行控制台,但通过一些配置可以支持串行控制台。
这比您预期的要困难一些,因为 Citrix 使用 Extlinux 启动而不是 GRUB。然而,Extlinux 的配置类似。我们唯一需要调整的文件是 /boot/extlinux.cfg。请注意,我们在同一长行上指定了 Xen 和 Linux 内核的选项:
SERIAL 0 115200
default xe
prompt 1
timeout 50
label xe
# XenServer
kernel mboot.c32
append /boot/xen.gz dom0_mem=752M lowmem_emergency_pool=16M \
crashkernel=64M@32M com1=115200,8n1 console=com1 --- \
/boot/vmlinuz-2.6-xen root=LABEL=root-jhawazvh ro \
console=ttyS0,115200n8 --- /boot/initrd-2.6-xen.img
因为这基本上是 CentOS,它已经在 /etc/inittab 中列出了 ttyS0 并带有 getty。重启并享受串行控制台。
Citrix 的 Xen 图形界面:XenCenter
我们当然喜欢遵循建议。
Citrix 的系统,就像 Xen 的开源版本一样,使用客户端/服务器架构来控制虚拟机。与开源版本不同,它们包括一个图形 Xen 控制台,可以自动化运行 Xen 的许多无聊细节.^([67])
事实上,该软件包包括一个图形界面工具和一个命令行工具。截至版本 5,图形界面是一个名为 XenCenter 的 Windows 应用程序,而命令行工具被称为 xe。它们提供大致相同的功能,但 XenCenter 图形界面有更多功能,而 xe 支持某些更复杂的操作。Citrix 建议使用 xe 进行脚本(或自动化)操作,并使用 XenCenter 进行交互式管理。还有一个基于字符的菜单系统,称为 xsconsole,通常在 Xen 服务器的物理控制台上运行,但也可以在 dom0 的任何 shell 会话中运行。它提供了对许多常见操作的访问。
您需要一个 Windows 机器来运行 GUI 客户端。虽然版本 3.2 及之前的版本是用 Java 编写的,因此是跨平台的,但版本 4.0 及以上版本需要基于 .NET 的 XenCenter。之前的客户端将无法连接到 XenServer 主机。客户端必须在 Windows 下运行的要求当然也意味着您不能直接在运行 Citrix 产品的机器上运行客户端.^([68])
与 Xen 的开源版本不同,工具和虚拟机管理程序之间的通信不通过 xend 进行。相反,命令行工具和图形工具都通过 TCP/IP 连接到 Xen 服务器上的 xapi 服务,并使用 SSL 加密流量。
^([67]) XenCenter 无法连接到开源 Xen。我们尝试过。
^([68]) 尽管您可以在 XenSource 产品下 Windows 安装中运行客户端,但这确实引发了一个有趣的“先有鸡还是先有蛋”的问题。
使用 XenCenter 管理虚拟机
成功安装了 Citrix 服务器和 XenCenter 客户端后,我们启动了漂亮、闪亮的 GUI 前端,告诉它我们的 XenServer,并登录。登录过程简单直接,立即将您带入一个综合的双面板界面,如图 图 11-1 所示。
左侧面板以树形视图显示物理和虚拟主机。在右侧,我们可以通过顶部的选项卡与选定的虚拟机交互或更改其参数。大多数任务都分解为基于向导的界面。
这些任务基于 生命周期管理 的概念;您可以通过一系列对话框创建虚拟机、编辑它们以及销毁它们。用户界面旨在使这些步骤,尤其是创建,尽可能简单;毕竟,虚拟计算设备的一个吸引力就是可以轻松添加更多机器或按需缩减。

图 11-1. XenCenter 控制台
安装 DomU 映像
XenServer 提供了多种安装方法:首先,您可以从包含的 Debian Etch 模板安装。其次,您可以使用模板和特定发行版的安装程序安装受支持的发行版。第三,有使用仿真设备的 HVM 安装。最后,我们有使用 P2V 工具的物理到虚拟转换。
Debian 安装是最快、最简单的,但它的灵活性最低。模板安装是一个不错的选择,允许 PV 安装多种 Linux 发行版,尽管不是全部。HVM 安装对几乎所有东西都有效,但需要支持 HVM 的机器,并导致在 HVM 模式下运行的域(这可能会根据您的应用程序而次优)。P2V 允许您克隆现有的基于硬件的 Linux 安装,并基于该现有系统创建模板,但它不方便,并且仅与少数较旧的发行版兼容。
从 Debian 模板安装
安装虚拟机最简单的方法是使用预填充的 Debian Etch 模板。此模板是一个预配置的基本安装,旨在使启动 Xen 实例几乎成为一键操作。(还有一个 Debian Lenny 模板,但它是一个安装程序,而不是一个完全填充的实例。)
要从模板安装,请使用图形界面登录到 Xen 主机,从屏幕左侧面板的列表中选择 XenServer(应该是第一个条目),右键单击它,然后选择 新建虚拟机。它将弹出一个向导界面,允许您配置该机器。选择 Debian Etch 模板。回答有关 RAM 和磁盘空间的问题(默认值应该可以),点击 完成,它将创建一个虚拟机。
客户机启动后,它执行一些首次启动配置,然后作为一个正常的半虚拟化 Xen 实例启动,文本控制台和图形控制台已经设置好并准备好工作,如图 11-2 所示。

图 11-2. 新安装的 domU 的图形控制台
模板化 Linux VM
为了确保 VM 内核与 Xen 和 domU 操作系统环境兼容,XenServer 产品仅支持安装少数基于 RPM 的发行版,当然,还包括前面提到的 Debian VM 模板。这种支持是通过模板实现的,这些模板实际上是预制的 VM 配置。
安装受支持的发行版几乎和安装 Debian 模板一样简单。转到安装对话框,选择你的发行版和安装源(物理介质、ISO 或网络),输入一个名称,如果需要,调整参数,然后点击安装。
安装不受支持的发行版要困难一些。然而,硬件仿真模式允许你通过选择其他安装介质模板并从 OS CD 引导来安装任何 Linux 发行版。从那时起,按照硬件上的正常安装进行操作。
当你安装了域后,你可以将其配置为半虚拟化,然后将其转换为模板。
Windows 安装
通过选择XenServer服务器,从上下文菜单中选择安装 VM,然后填写出现的对话框来安装 Windows。选择与你要安装的 Windows 版本相对应的模板,并更改 CD-ROM/DVD 设置,使其指向安装介质。
点击安装。Xen 将创建一个新的虚拟机。当机器启动时,它将在 HVM 模式下运行,HVM BIOS 配置为从模拟的 CD-ROM 引导。从那时起,你可以以普通方式安装 Windows。这实际上是一个非常简单的过程;Citrix 投入了大量工作来简化 Windows 的安装。
使用 P2V 创建 DomU 镜像
安装的最后一种方式是使用 P2V 安装工具,简称物理到虚拟。该工具可以从物理 Linux 服务器创建 domU 镜像,允许你在不支持 HVM 的硬件上安装 domU。不幸的是,P2V 工具仅支持少数类似 Red Hat 的系统。任何其他系统都会导致它出错并退出。
该工具是 XenServer 安装光盘的一部分。要使用它,从 XenServer 光盘引导源机器。如果你正在虚拟化 32 位系统,则在提示符处输入p2v-legacy中断引导,或者如果你正在虚拟化 64 位系统,则引导到安装程序并选择P2V选项。一系列提示将引导你完成网络设置和选择目标。
机器上的现有文件系统将被复制并发送到远程 Citrix Xen 服务器,该服务器自动创建配置文件并使用适当的内核。请注意,P2V 工具在复制过程中会合并分区。这种方式与我们在 第三章 中描述的 tar(1) 过程类似,增加了自动配置的魔法。
使用 XenConvert 转换现有的虚拟或物理机器
如果你拥有 VMware VMDK、Microsoft VHD 或跨平台 OVF 格式的虚拟机,你可以使用基于 Windows 的 Citrix XenConvert 工具将它们转换为 Xen 虚拟机。XenConvert 也可以在物理 Windows 机器上运行,类似于 P2V 工具。
XenConvert 使用起来相当简单。首先,从 Citrix 网站下载 Windows 安装程序,网址为 www.citrix.com/xenserver_xenconvert_free。安装软件包,运行程序,并按照提示操作。
DomU 中的 XenServer 工具
当你安装了域后,你几乎肯定会想安装 XenServer 工具,这些工具可以改善域与管理界面之间的集成。特别是,这些工具允许 XenCenter 从 domU 收集性能数据。在 Windows 下,Citrix 工具还包括虚拟化驱动程序,它们绕过(速度较慢的)模拟驱动程序,转而使用 Xen 风格的环形缓冲区等。
要安装工具,在 XenCenter 中选择虚拟机,右键单击它,然后从上下文菜单中选择 安装 XenServer 工具 选项以切换模拟 CD。一个警告框将弹出,提示你执行适当的步骤。
在 Windows 下,安装程序将自动运行。回答提示,让它继续安装。^([69]) 重启系统,在引导加载程序中选择 PV 选项。Windows 将检测并配置你的新 PV 设备。
对于 Linux 虚拟机,如提示所述,执行以下命令:
# mount /dev/xvdd /mnt
# /mnt/Linux/install.sh
install.sh 脚本将选择合适的软件包并安装它。重启系统并享受利用图表。
xe:Citrix XenServer 的命令行工具
Citrix 还提供图形控制台之外的命令行界面。这个命令行工具称为 xe,它适用于备份和类似的自动化任务。据我们看来,它在日常使用中可能不如 XenCenter 那么方便。这可能只是我们的偏见,但它似乎也比开源的等效工具 xm 更繁琐。
你可以使用 xe 从单独的管理主机(可以运行 Windows 或 Linux)或直接在 XenServer 主机上以本地模式使用。^([70])
Citrix 在 Linux 补充 CD 的 client_install 目录中包含了 xe 作为 RPM。确保你有所需的 stunnel 软件包。在我们的案例中,要在 Slackware 上安装它,我们执行了以下操作:
# cd /media/XenServer-5.0.0 Linux Pack/client_install
# rpm -ivh --nodeps xe-cli-5.0.0-13192p.i386.rpm
当客户端安装在远程机器上时,您可以运行它。请确保指定 -s,否则它将假设您想连接到本地主机并失败。
# xe help -s corioles.prgmr.com
无论您是在本地还是远程使用xe,命令和参数都是相同的。xe实际上是对 Xen API 的一个非常薄的包装。它几乎暴露了 API 提供的所有功能,但使用起来难度较大。如果您使用help --all命令运行它,它会输出一个令人畏惧的使用信息,详细说明了大量可能的行为。
幸运的是,我们可以将这些命令分成组。一般来说,有与主机和虚拟机交互的命令。有获取日志信息的命令。有池命令。我们有管理虚拟设备(如 vifs 和 vbds)的命令。
虽然一些xe命令与xm命令类似,但xe的语法稍微复杂一些。第一个参数必须是命令名,然后是任何开关,然后是任何命令参数,使用name=value语法。看起来有些繁琐,但 Citrix 提供了一套非常好的 bash 自动完成设置,使得自动补全对xe特定参数工作得很好。它甚至可以填写 UUID。因此:
# xm network-list 1
Idx BE MAC Addr. handle state evt-ch tx-/rx-ring-ref BE-path
0 0 00:16:3E:B9:B0:53 0 4 8 522 /523 /local/domain/0/backend/vif/1/0
使用xe变为:
# xe vm-vif-list vm-name=aufidius
name: eth0
mac: 00:16:3E:B9:B0:53
ip: 192.168.1.64
vbridge: xenbr0
rate: 0
Citrix 网站上的文档和各种提供的食谱提供了更多关于使用xe的建议。
XenServer 的磁盘管理
XenServer 软件为自身预留了一对 4GB 分区,其余磁盘空间可用于 domUs。第一个分区包含活动的 XenServer 安装。第二个分区通常是空的;然而,如果服务器升级,该分区将被格式化并用作之前安装的完整备份。
警告
请注意,此备份仅适用于 dom0 数据;安装程序将擦除磁盘上的 domU 存储库。教训?在升级 XenSource 之前,请手动备份 domUs。
其余空间被放入一个卷组,或者,如 Citrix 所说,是一个存储库。随着 domUs 的创建,服务器使用 LVM 来划分空间。对于单个磁盘的存储设置可以在图 11-3 中看到。每个额外的磁盘成为一个单独的物理卷(PV),并将其添加到存储池中。

图 11-3. XenSource 磁盘布局
每个逻辑卷(LV)都会得到一个非常长的名称,该名称使用 UUID(通用唯一标识符)来将其与虚拟机(VM)关联。
Xen 存储库
如果您使用在安装过程中输入的 root 密码通过控制台或 SSH 登录到 XenServer,您可以使用标准的 Linux 命令来检查已安装的环境。继续我们的例子,您可以使用 LVM 工具:
# vgs
VG #PV #LV #SN Attr VSize VFree
VG_XenStorage-03461f18-1189-e775-16f9-88d5b0db543f 1 0 0 wz--n- 458.10G 458.10G
然而,您通常会想使用 Citrix 提供的更高级的命令,因为这些命令也会更新存储元数据。等效地,要使用xe列出存储库:
# xe sr-list
uuid ( RO) : 03461f18-1189-e775-16f9-88d5b0db543f
name-label ( RW): Local storage
name-description ( RW):
host ( RO): localhost.localdomain
type ( RO): lvm
content-type ( RO): user
注意,SR UUID 与卷组名称匹配。
关于 xe 在存储方面的完整描述最好留给 Citrix 的文档。然而,我们将简要描述一个会话,以说明 LVM、Xen 的存储池和虚拟机管理程序之间的关系。
假设您已向 XenServer 添加了一个新的 SATA 硬盘,/dev/sdb。要将默认 XenServer 存储池扩展到新磁盘,您可以像处理正常的 LVM 卷组一样处理存储池:
# pvcreate /dev/sdb1
Physical volume "/dev/sdb1" successfully created
# vgextend VG_XenStorage-9c186713-1457-6edb-a6aa-cbabb48c1e88 /dev/sdb1
Volume group "VG_XenStorage-9c186713-1457-6edb-a6aa-cbabb48c1e88" successfully extended
# vgs
VG #PV #LV #SN Attr VSize VFree
VG_XenStorage-9c186713-1457-6edb-a6aa-cbabb48c1e88 2 2 0 wz--n- 923.86G 919.36G
# service xapi restart
在这里我们唯一不寻常的操作是重新启动 xapi 服务,以便各种管理工具可以使用新的存储。
然而,Citrix 建议您通过他们的管理堆栈执行这些操作。如果您想进行更复杂的操作,如创建新的存储库,最好使用适当的 xe 命令而不是直接与 LVM 交互。以下是一个使用 xe 执行相同操作的示例:
# xe sr-create name-label="Supplementary Xen Storage" type=lvm device-config-device=/dev/sdb1
a154498a-897c-3f85-a82f-325e612d551d
就这些了。现在 GUI 应该会立即显示 XenServer 机器下的新存储库。我们可以使用 xe sr-list 来确认其状态:
# xe sr-list
uuid ( RO) : 9c186713-1457-6edb-a6aa-cbabb48c1e88
name-label ( RW): Local storage on corioles
name-description ( RW):
type ( RO): lvm
content-type ( RO): user
uuid ( RO) : a154498a-897c-3f85-a82f-325e612d551d
name-label ( RW): Supplementary Xen Storage
name-description ( RW):
type ( RO): lvm
content-type ( RO): disk
Citrix 的网站提供了有关使用 xe 添加存储的更多信息,包括使用基于文件的存储、iSCSI 或 NFS 的选项。他们还涵盖了诸如删除存储库和设置虚拟机存储的 QoS 控制等主题。我们期待他们提供更多详细信息。
模拟 CD-ROM 访问
Citrix 产品最令人印象深刻的特点之一是他们的 CD-ROM 模拟。^[[71]) 除了给虚拟机提供挂载连接到机器的物理驱动器的选项外,它还将 ISO 图像作为可能的 CD 提供。当你更换 CD 时,domU 会立即注册已插入新磁盘。
XenServer 在 /opt/xensource/packages/iso 中查找本地 ISO 图像,并在 /var/opt/xen/iso_import 中查找共享 ISO 图像。这两个路径都在服务器上,而不是管理主机上。请注意,XenServer 主机具有非常有限的根文件系统,并将大部分磁盘空间用于虚拟机;因此,我们建议为 ISO 使用共享的 NFS 或 CIFS 存储。然而,本地 ISO 存储仍然是可能的。例如,为了使 Windows 2003 ISO 图像方便地供 XenServer VM 安装程序使用,我们可以:
# dd if=/dev/cdrom of=/opt/xensource/packages/iso/win2003.iso
然后,像以前一样重新启动 xapi 服务,并在 XenCenter 图形控制台选项卡的下拉菜单中选择新的 ISO。您还可以在创建虚拟机时使用此 ISO 作为安装源。
XenServer VM 模板
模板是 XenCenter 最好的功能之一。它们允许您通过几个点击创建具有预定义规格的虚拟机。尽管 Citrix 包含了一些模板,但您可能希望添加自己的。
创建虚拟机模板的最简单方法是创建一个具有所需设置的虚拟机,然后使用 XenSource 管理软件将其转换为模板。在 GUI 中右键单击机器,并选择转换为模板。从概念上讲,这类似于 SystemImager 等使用的金客户端概念;您首先调整客户端以满足您的需求,然后将其作为未来安装的模型导出。
# xe vm-param-set uuid=<UUID OF VM BEING CONVERTED TO TEMPLATE> is-a-template=true
另一个选项是使用 P2V 工具。要从物理机创建模板,就像创建虚拟机一样从 XenServer CD 启动机器,但将 P2V 工具的输出指向 NFS 共享而不是 XenServer 主机。模板将出现在 XenCenter 客户端的可用模板列表中。
^([69]) 顺便说一下,Citrix 实际上非常认真对待不支持预 SP2 Windows XP 的驱动程序。我们尝试过。
([70])[[70]] 我们被告知您甚至可以在 Windows 上使用xe。并不是说我们会用像 Windows 这样的操作系统来管理 Linux/Xen 服务器。
([71])[[71]] 经过多年懒得设置自动挂载器,我们很容易感到印象深刻。
XenServer 资源池
Citrix 产品中最吸引人的特性之一是他们资源池的集成。这些池是 Xen 的效用计算模型的表现,其中程序与物理机器解耦,并在物理机集群的任何成员上运行的虚拟机上运行。
要创建资源池,只需在 XenCenter 客户端中选择一个 XenServer 虚拟化主机,并从中创建一个池。[1] 完成后,您可以通过界面添加更多机器到池中。(池中最多支持 16 个主机,尽管我们听说有人使用更多。)此外,您可以将存储添加到池中,而不是单个机器,并创建使用共享存储的虚拟机。当您有基于共享存储的域时,您可以通过 XenCenter GUI 轻松地将它们迁移到池中的其他机器,如图 11-4 所示。[2]
如您所见,Citrix 已经使迁移基本上成为一个点选操作。
我们不会详细讨论池管理;我们在这里提到它主要是为了强调该功能的存在。

图 11-4. 通过 XenCenter 向池中添加 NFS 存储
([72])[[72]) 一些文档声称此功能仅对付费客户可用,但我们能够很好地管理。请咨询 Citrix 以获取进一步澄清。
Citrix XenServer:简要回顾
总体而言,我们对 Citrix 的产品非常满意。他们有一个磨砺过的工具,可以消除 Xen 管理的繁琐,他们已经制作了一个稳定的产品。据我们看,它比使用开源版本中可用的任何前端都要好得多,并且至少同样可靠。
除了 XenCenter 前端(最明显的区别)之外,XenServer 在安装和可管理性方面表现良好。模板和简化 domU 创建的组合尤其令人愉快。
XenServer 产品的另一个优点是它包含了 Windows 的半虚拟化驱动程序。尽管 GPL PV 驱动程序正在开发中并且可用(更多信息请参阅第十三章),但它们不如 Citrix 的实现成熟。这些驱动程序带来了巨大的差异,并且开源产品中不可用。它们可能是运行 XenServer 的最具说服力的单一原因。
最后,开源 Xen 的大部分有趣特性都得到了支持。存储和网络选项有所减少,但可用的选项应该足够大多数用途。
然而,并非一切尽善尽美。我们在测试过程中遇到的最大问题是它对一些不为人知的平台或甚至更不受欢迎的 Linux 发行版(如 Gentoo 或 Slackware)的支持范围很窄。尽管可能让其他发行版运行,但这并不方便,而便利性是 XenServer 的关键卖点之一。另一个烦恼是需要一台 Windows 机器来管理 Xen 服务器——之前的版本使用了一个跨平台的 Java 客户端。然而,由于前端显然是用 C#编写的,我们可能会在某个时候看到 Mono 端口。
Citrix 的产品能否取代开源 Xen?一如既往,答案是也许。它在管理和一些有趣的新功能方面提供了显著的改进,但这也平衡了巨大的成本和令人烦恼的限制。我们坚持使用免费版本,但我们的时间毫无价值。
第十二章。HVM:超越 Para 虚拟化

在整本书中,我们描述了标准的 Xen 虚拟化技术,Para 虚拟化。Para 虚拟化是一件好事——正如我们之前概述的,它允许卓越的性能和强大的隔离,这两个目标很难同时实现。(有关更多关于这个主题的内容,请参阅第一章。)
然而,Para 虚拟化需要修改过的操作系统。尽管将操作系统移植到 Xen 相对容易,但按照这类工作的标准,这并不是一个简单的任务,并且它有一个明显的限制,那就是在封闭源代码的操作系统上无法实现。(虽然 Xen 团队在开发过程中将 Windows 移植到了 Xen 上,但没有任何发布版本的 Windows 可以在 Xen 上以 Para 虚拟化模式运行。)
一种解决方法是为处理器添加扩展,使其支持硬件虚拟化,从而允许未经修改的操作系统在“裸机”上运行,但仍然是在虚拟化环境中。英特尔和 AMD 都通过扩展 x86 架构实现了这一点。
英特尔使用VT-x这个术语来指代 x86 的虚拟化扩展。^([73)] (VT-i是安腾的硬件虚拟化。就我们的目的而言,它与 VT-x 基本相同。我们不会单独讨论 VT-i。^([74)]) AMD 同样有一套虚拟化扩展。^([75)] 你可能找到的大部分与 Xen 相关的文档都提到了这些扩展的内部代码名称Pacifica,但你也会看到 AMD 的市场术语SVM,代表安全虚拟机。
虽然 VT-x 和 Pacifica 的实现略有不同,但我们可以忽略低级实现细节,专注于功能。这两个都由 Xen 支持。这两个都允许你以 domU 的形式运行未经修改的操作系统。这两个在 I/O 上都会遭受重大的性能损失。尽管两者之间有差异,但这些差异被抽象层所隐藏。
正确地说,我们所说的这个抽象层就是 HVM(硬件虚拟机)——一种跨平台的方式,可以隐藏繁琐的实现细节给系统管理员。因此,在本章中,我们将重点关注 HVM 接口及其使用方法,而不是英特尔或 AMD 技术的具体细节。
HVM 原理
如果你回顾一下我们在第一章中介绍的“同心环”安全模型,你可以将 HVM 扩展描述为在环 0 内部添加了一个环-1(即,具有比环 0 更高的权限)。新的处理器操作码,对虚拟机不可见,用于在超级特权模式和正常模式之间切换。未经修改的操作系统在环 0 中运行,并按常规操作,不知道它和硬件之间还有另一层。当它执行特权系统调用时,调用实际上会转到环-1 而不是实际硬件,此时虚拟机管理程序会拦截它,暂停虚拟机,执行调用,并在调用完成后恢复 domU。
Xen 还必须以不同的方式处理内存,以适应未经修改的虚拟机。因为这些未经修改的虚拟机不了解 Xen 的内存结构,虚拟机管理程序需要使用影子页面表,这些页面表呈现从地址 0 开始的连续物理内存的假象,而不是 Xen 感知操作系统支持的离散物理页面表。这些影子是硬件使用的页面表的内存副本,如图图 12-1 所示。尝试读取和写入页面表的尝试会被拦截并重定向到影子。在虚拟机运行期间,它直接读取其影子页面表,而硬件使用虚拟机管理程序提供的预先转换的版本。

图 12-1。所有虚拟机页面表写入都被虚拟机管理程序拦截并转到影子页面表。当执行上下文切换到虚拟机时,虚拟机管理程序将影子页面表中找到的伪物理地址转换为机器物理地址,并更新硬件以使用转换后的页面表,然后虚拟机直接访问这些页面表。
HVM 设备访问
当然,如果你到目前为止一直很关注,你可能想知道 HVM 域如果没有修改为使用 Xen 虚拟块和网络设备,如何访问设备。这是一个很好的问题!
答案有两个:首先,在引导过程中,Xen 使用模拟的 BIOS 来提供标准 PC 设备的模拟,包括磁盘、网络和帧缓冲区。这个 BIOS 来自开源的 Bochs 模拟器bochs.sourceforge.net/。其次,在系统引导后,当 domU 期望使用原生驱动程序访问 SCSI、IDE 或以太网设备时,这些设备使用 QEMU 模拟器中找到的代码进行模拟。一个用户空间程序qemu-dm处理原生和模拟设备访问模型之间的转换。
HVM 设备性能
这种类型的转换,其中我们必须通过使用软件设备模拟退出虚拟化模式并重新进入虚拟化操作系统来调解硬件访问,是运行未经修改的操作系统所涉及到的权衡之一。^[[76]) 而不是简单地使用轻量级页面翻转系统查询宿主机的信息,HVM 域访问设备就像它们是物理硬件一样精确。这相当慢。
AMD 和 Intel 都进行了工作,旨在让虚拟机直接使用硬件,使用 IOMMU(I/O 内存管理单元)将域虚拟地址转换为真实的 PCI 地址空间,就像处理器的 MMU 处理虚拟内存的转换一样。^[[77]) 然而,这不太可能在不久的将来取代模拟设备。
HVM 和 SMP
SMP(对称多处理)与 HVM 一起工作,就像与虚拟化域一样。每个虚拟处理器都有自己的控制结构,这反过来又可以被机器的任何物理处理器服务。在这种情况下,我们所说的物理处理器是指机器看到的逻辑处理器,包括由 SMT(同时多线程或超线程)提供的虚拟处理器。
要启用 SMP,请在配置文件中包含以下内容:
acpi=1
vcpus=<n>
(其中n是一个大于 1 的整数。单个 CPU 并不意味着 SMP。事实上,恰恰相反。)
注意
尽管您可以指定比实际存在的 CPU 更多的 CPU,但性能将会…受到影响。我们强烈建议不要这样做。
就像在虚拟化域中一样,SMP 通过为域中的每个虚拟 CPU 提供 VCPU 抽象来实现,如图图 12-2 所示。每个 VCPU 都可以在机器的任何物理 CPU 上运行。Xen 的 CPU 固定机制也按常规方式工作。
很遗憾,SMP 支持并不完美。特别是,在 HVM 和 SMP 中,时间同步似乎完全未被处理,导致我们的测试系统(CentOS 5,Xen 版本 3.0.3-rc5.el5,内核 2.6.18-8.el5xen)的内核不断抱怨。以下是一个例子:
Timer ISR/0: Time went backwards: delta=-118088543 delta_cpu=25911457 shadow=157034917204
off=452853530 processed=157605639580 cpu_processed=157461639580

图 12-2。随着每个域的时间分配到来,其 VCPU 的处理器状态被加载到 PCPU 上以进行进一步执行。对 VCPU 控制结构的特权更新由虚拟机管理程序处理。
该问题的另一个症状是/proc/cpuinfo报告的 bogomips 值——在一个 2.4GHz 核心 2 Duo 系统上,我们看到了从 13.44 到 73400.32 的范围。在 dom0 中,每个核心显示 5996.61,这是一个预期的值。
别担心,这可能会让人不安,但它也是无害的。
HVM 和迁移
从 Xen 3.1 开始,HVM 迁移功能可用。HVM 域中的迁移支持基于半虚拟化域的支持,但扩展以考虑它是在没有客户操作系统默许的情况下进行的。相反,Xen 本身暂停 VCPU,而xc_save处理内存和 CPU 上下文。qemu-dm也扮演了更积极的角色,保存模拟设备的状态。
所有这些的目的是,你可以像处理半虚拟化域一样迁移 HVM 域,使用相同的命令,但也要注意相同的风险。(特别是,记住尝试将 HVM 域迁移到不支持 HVM 的物理机器将不会优雅地失败。)
^([73]) 英特尔在www.intel.com/technology/itj/2006/v10i3/3-xen/1-abstract.htm提供了一个关于他们虚拟化扩展的简介,并在www.intel.com/technology/platform-technology/virtualization/index.htm有一个促销概述页面。它们值得一读。
^([74]) 此外,亲爱的读者,我们谦卑的作者们缺少一台最近的 Itanium 来玩耍。请将硬件提供的提议转发到 lsc@prgmr.com。
^([75]) AMD 在developer.amd.com/TechnicalArticles/Articles/Pages/630200615.aspx提供了他们扩展的简要介绍。
^([76]) 正如英特尔所指出的,HVM 驱动程序的实现实际上比这个天真模型要好得多。例如,设备访问是异步的,这意味着虚拟机可以在等待 I/O 完成时做其他事情。
^([77]) 关于这个主题有一篇有趣的论文,可以在developer.amd.com/assets/IOMMU-ben-yehuda.pdf找到。
Xen HVM 与 KVM
当然,如果你的机器支持硬件虚拟化,你可能会想知道 Xen 的意义何在,而不是 KVM 或 lguest。
考虑这个想法有一些很好的理由。KVM 和 lguest 都比 Xen 更容易安装,侵入性也更小。它们支持强大的虚拟化,性能良好。
然而,目前 KVM 比 Xen 不成熟。即使有内核加速器,它也不够快。Xen 还支持全虚拟化,而 KVM 不支持。Xen PV 提供了一种方便的迁移 domUs 的方法,以及一种良好的虚拟机多路复用方法——即扩展到两级虚拟机层次结构。但说实话,我们没有多少 KVM 经验,而 Xen 我们有相当多的经验。
类似地,lguest 比 Xen 更小、更轻,安装也更简单,但它不支持像 SMP 或 PAE 这样的功能(尽管 64 位内核正在开发中)。Lguest 还不支持挂起、恢复或迁移。
尽管如此,目前很难说哪个更好——所有这些技术都在积极开发中。如果你真的很傻,你甚至可能会决定使用一些组合,在 KVM 下运行 Xen 虚拟机管理程序,并在其下运行全虚拟化域。或者你现在可以使用 Xen,但为未来的部署保留选择,比如当具有 HVM 功能的硬件变得更加普遍时。这些技术很有趣,值得关注,但我们将坚持我们通常的“观望”政策。
事实上,Red Hat 已经选择了这样做,将开发努力集中在平台无关的接口层 libvirt 上,希望(我们希望)能够轻松地在虚拟化选项之间迁移。有关 libvirt 及其相关管理工具套件的更多信息,请参阅第六章。
与 HVM 一起工作
无论你想使用哪种硬件虚拟化,首先要做的是检查你的机器是否支持 HVM。要找出你是否有一个支持的处理器,检查 /proc/cpuinfo。支持 VT-x 的处理器将在标志字段中报告 vmx,而启用 Pacifica 的处理器将报告 svm。
即使你有支持的处理器,许多制造商在 BIOS 中默认关闭了 HVM。检查 xm dmesg 以确保虚拟机管理程序已正确找到并启用了 HVM 支持——它应该为机器中的每个 CPU 报告 "(XEN) VMXON is done"。如果没有,请在 BIOS 中寻找一个选项来打开硬件虚拟化。在我们的板上,它位于 芯片组 特性 下,称为 VT 技术。你的机器可能不同。
虚拟机管理程序还会在 /sys 下报告功能:
# cat /sys/hypervisor/properties/capabilities
xen-3.0-x86_32p hvm-3.0-x86_32 hvm-3.0-x86_32p
在这种情况下,两个 "hvm" 条目表明 HVM 在 PAE 和非 PAE 模式下都受支持。
注意
HVM 的小优点之一是它绕过了我们一直强调的 PAE 匹配问题。您可以在 HVM 模式下运行任何混合的 PAE 和非 PAE 内核和虚拟机管理程序,尽管虚拟化域仍然需要在 HVM 功能机上匹配 PAE。
创建 HVM 域
当您在具有 HVM 功能的机器上运行虚拟机管理程序和域 0 时,创建 HVM 域与创建任何 Xen 客户端类似。
这里是一个 HVM 配置文件的示例。(它开头有一个 Python 片段,用于设置适当的库目录,这是从与 Xen 一起分发的示例配置中借用的。)
import os, re
arch = os.uname()[4]
if re.search('64', arch):
arch_libdir = 'lib64'
else:
arch_libdir = 'lib'
device_model = '/usr/' + arch_libdir + '/xen/bin/qemu-dm'
kernel = "/usr/lib/xen/boot/hvmloader" builder='hvm'
memory = 384
shadow_memory = 16
name = "florizel"
vcpus = 1
vif = [ 'type=ioemu, bridge=xenbr0' ]
disk = [ 'file:/opt/florizel.img,hda,w', 'file:/root/slackware-12.0-install-dvd.iso,hdc:cdrom,r' ]
boot="cda"
sdl=0
vnc=1
stdvga=0
serial='pty'
其中大部分内容相当标准。它从一个 Python 片段开始,选择正确的 qemu-dm 版本,然后启动一个标准的 domU 配置。HVM 客户端的配置文件更改大约如下:
builder = "HVM"
device_model = "/usr/lib/xen/bin/qemu-dm" kernel = "/usr/lib/xen/boot/hvmloader"
注意
您还可以放入其他指令,但这些是您不能省略的指令。
分解来看,域构建器从默认模式切换到 HVM,同时设备从标准的 Xen 虚拟化设备切换到 QEMU 模拟设备。最后,kernel 行指定了一个 HVM 加载器,它从 HVM 域的文件系统中加载内核,而不是在 PV 配置中指定的 Linux 内核。
关于域构建器的插曲
到目前为止,我们避免讨论域构建器,只是简单地指向它并指出它构建域。对于大多数目的来说,将其视为类似于标准引导加载器就足够了。
然而,它比正常的引导加载器具有更困难且复杂得多的任务。当 Xen domU 启动时,它在一个与传统 PC “真实模式”截然不同的环境中启动。因为操作系统已经加载,处理器已经在启用分页的保护模式下。域构建器的任务是使新域达到速度——生成域虚拟内存与物理内存之间的映射,在适当的地址加载 VM 内核,并安装中断处理程序。
默认构建器是 linux,它构建一个基于虚拟化的域。(通常是 Linux,但它适用于大多数基于虚拟化的操作系统。)
由于 HVM 的存在,情况有所变化,因为未经修改的操作系统并不期望在完全启动的机器上运行。为了使操作系统满意,域构建器初始化一个完整的真实模式模拟,在伪物理内存的适当区域插入钩子和安装模拟的 BIOS。
从历史上看,域构建器的实现依赖于具体实现,对于英特尔有“vmx”构建器,对于 AMD 有类似的“svm”构建器。然而,随着 HVM 作为抽象层的出现,管理员可以简单地指定 HVM,让 Xen 解决细节。
当然,我们已经熟悉了kernel行。然而,device_model行是新的。此选项定义了一个用户空间程序,用于处理真实设备和虚拟设备之间的中介。据我们所知,qemu-dm是唯一选项,但并没有理由其他设备模拟器不能被编写。
有些其他指令仅用于 HVM 域。
shadow_memory = 16
boot="dca"
shadow_memory指令指定用于阴影页表要使用的内存量。(阴影页表,当然,是上述将进程虚拟内存映射到物理内存的表的副本。)Xen 建议为每个 MB 的域内存分配至少 2KB,并且每个虚拟 CPU“几个”MB。请注意,此内存是附加于在内存行中指定的 domU 分配的。
最后,我们有boot指令。当然,引导顺序的整个概念不适用于标准的 Xen para-virtualized 域,因为域配置文件指定了内核或引导加载程序。然而,由于 HVM 模拟了传统的引导功能,包括传统的引导程序,Xen 提供了一个配置引导顺序的机制。
在这个方面,值得注意的是,HVM 的一个优点是它可以有效地复制我们已描述的 QEMU 安装程序,用 Xen 代替 QEMU。为了总结,这允许你在强分区虚拟机中安装,使用发行版的安装工具,并最终得到一个可运行的 VM。当然,我们将细节留给读者作为练习(我们不想把所有的乐趣都夺走)。
现在你已经写好了配置文件,按照常规创建域:
# xm create florizel
Using config file "./florizel".
Started domain florizel
# xm list
Name ID Mem(MiB) VCPUs State Time(s)
Domain-0 0 3458 2 r----- 5020.8
florizel 6 396 1 r----- 14.6
与 HVM 域交互
你可能会注意到的第一个变化是,使用xm -c连接到控制台不起作用。Xen 控制台需要一些基础设施支持才能正常工作,而一个对 PV 无知的标准发行版自然没有这些支持。
因此,当机器正在启动时,让我们聊一聊你如何实际登录到你的闪亮新域。
如你所知,我们可能已经厌倦了提到,HVM 基于一个完全硬件模拟的理念。这意味着当机器启动时,它会加载一个模拟的 VGA BIOS,并将其绘制到图形窗口中。
Xen 知道其模拟 VGA 图形的两个目标:VNC 和 SDL。VNC 是来自 AT&T 的熟悉且深受喜爱的网络窗口系统,而SDL,简单直接媒体层更知名的是轻量级硬件加速图形选项。
我们选择继续使用 VNC 控制台来为大多数 Linux domU 带来以网络为中心计算的好处。^[[78]
现在域已经创建,使用 VNC 来访问其控制台:
# vncviewer 127.0.0.1
(或者使用 Xen 机器的 IP 地址。)如果你有多个使用 VNC 控制台的 domU,请附加一个显示编号——例如,要访问第二个 domU 的控制台:
# vncviewer 127.0.0.1:1
如果配置文件中的 vncunused= 选项被设置,域将采用第一个可用的显示编号。如果没有设置,它将采用与其域编号相对应的显示编号。我们倾向于将其设置为默认值,但未设置也是可以的。
令我们有些惊讶的是,X11 使用 vesa 驱动程序直接工作得相当好,接管了 VNC 图形缓冲区控制台,并提供了无需进一步配置即可使用的显示。
让标准 Xen 控制台工作
现在,通过图形控制台登录是一个令人烦恼的额外开销,我们可能会认为这对于服务器来说有点过度。幸运的是,你可以通过使用标准的 Xen 模拟串行控制台来规避这个问题。首先,确保你的 domU 配置文件(例如,/etc/xen/leontes)包含以下内容:
serial='pty'
这个指令告诉 QEMU(因此也告诉 Xen)将串行输出传递到 Xen 控制台。
现在引导加载程序需要被告知将它的消息传递到 serial 线。在 domU 的 /boot/grub.conf 中添加以下内容:
serial --unit=0 --speed=115200 --word=8 --parity=no --stop=1 serial console
这两条线为 GRUB 提供了串行端口的设置,并告诉它实际上使用串行端口作为其控制台。
接下来,设置内核通过串行输出其引导信息:
title CentOS (2.6.18-8.el5)
root (hd0,0)
kernel /vmlinuz-2.6.18-8.el5 ro root=/dev/VolGroup00/LogVol00 rhgb quiet console=ttyS0
module /initrd-2.6.18-8.el5.img
(如果你在 HVM 模式下加载 Xen 虚拟机管理程序——这是一件完全合理的事情——你的 menu.lst 文件当然会有些不同。)
最后,编辑 inittab 以通过添加类似以下内容的行在模拟的 serial 线上启动 getty:
s1:12345:respawn:/sbin/agetty -L ttyS0 9600 vt100
启动机器,你应该能够通过 xm console 和 VNC 看到消息并登录。
^([78]) 我的意思是,我们不想站起来走到测试机器那里去访问控制台。
HVM 设备
如果你探索你的新 HVM 域,你会看到像“QEMU 硬盘”或“RealTek 网络控制器”这样的设备。这些取代了相应的 Xen 设备,如 xenblock 或 xennet。例如,检查这个 dmesg 输出:
PIIX3: IDE controller at PCI slot 0000:00:01.1 PIIX3: chipset revision 0
PIIX3: not 100% native mode: will probe IRQs later PCI: Setting latency timer
of device 0000:00:01.1 to 64
ide0: BM-DMA at 0xc000-0xc007, BIOS settings: hda:pio, hdb:pio ide0: BM-DMA at 0xc008-0xc00f, BIOS settings: hdc:pio, hdd:pio
Probing IDE interface ide0...
hda: QEMU HARDDISK, ATA DISK drive
这显示了 QEMU 模拟的硬盘。进一步看,我们可以看到:
eth0: RealTek RTL8139 at 0xc200, 00:16:3e:0b:7c:f0, IRQ 11 eth0: Identified
8139 chip type 'RTL-8139'
PV 和 HVM 域之间的区别不仅限于 domU。在 HVM 域中,你会在 dom0 中看到 tap 设备。
将 tap 设备视为之前讨论过的 vifs 的 QEMU 类似物——推入它们的位会在 domU 的虚拟网络设备上输出。你可以像管理 vifs 一样管理它们——将它们添加到桥接,配置它们为开启或关闭,等等。
虚拟化驱动程序
在 Xen 的背景下,解决慢速模拟 HVM 设备问题的最佳方案是使用与非 HVM 域相同的分割驱动模型工作的虚拟化驱动程序——后端驱动程序在域 0 中,而在 domU 中有一个小的前端驱动程序,它通过事件通道与后端通信,使用环形缓冲区和页面翻转。(有关 Xen 分割驱动模型的枯燥细节,请参阅第一章 中更详细地讨论这些)。
然而,您也可以为 Linux HVM 域构建 PV 驱动程序。这些驱动程序包含在 Xen 源树中的 unmodified_drivers 目录中。不幸的是,内核 API 不断变化,因此 PV 驱动程序可能无法与您的内核版本编译(带有 Xen 3.1 的驱动程序拒绝与 2.6.20 及以上版本的内核编译)。
编译 HVM Linux 的 PV 驱动程序
尽管如此,确定驱动程序是否可行的最佳方式是尝试。以下是我们从标准 Xen 源树编译驱动程序的方法。
# cd unmodified_drivers/linux-2.6 # ./mkbuildtree
# make -C /usr/src/linux M=$PWD modules
这将标准 Xen 设备作为模块构建——将它们安装到您的模块树中,并像任何其他驱动程序一样使用 insmod 或 modprobe 加载它们。您最终将得到四个模块,每个模块对应于块和网络设备,一个用于 xenbus,一个用于 PCI 仿真。首先加载 xen-platform-pci,然后是 xenbus,然后是块和网络。
# insmod xen-platform-pci
# insmod xenbus
# insmod xenblk
# insmod xennet
由于我们使用 Slackware 作为我们的 domU,因此我们构建了一个最小内核——没有为模拟 IDE 或 Realtek 网络卡提供驱动程序,并构建了一个包含 Xen 设备的 initrd。
我们还需要修改 /etc/fstab 以引用 Xen 后端设备。
最后(这开始看起来像很多麻烦,不是吗?)我们编辑了域的配置,指定了 netfront 和 blkfront 而不是 ioemu 设备。我们通过更改设备行来完成这项工作:
vif = [ 'type=ioemu, bridge=xenbr0' ]
disk = [ 'file:/opt/florizel.img,ioemu:hda,w', 'file:/root/slackware-12.0-
install-dvd.iso,ioemu:hdc:cdrom,r' ]
到:
vif = [ 'bridge=xenbr0' ]
disk = [ 'file:/opt/florizel.img,hda,w', 'file:/root/slackware-12.0-install-
dvd.iso,hdc:cdrom,r' ]
并删除 device_model= 行。
当然,修改这些说明以适应您的设置。
然后,为了我们的下一个技巧...
总是有些工作正在进行中。英特尔和 AMD 都已宣布了处理虚拟机页表的新技术,即在页表结构中添加一个新级别。AMD 将此概念称为 嵌套分页,而英特尔称之为 扩展页表。IOMMU 的发展是另一个令人兴奋的研究领域。
HVM 在一般情况下很好,但当然所有这些都只是 第十三章 的序言,我们将应用所有这些内容来在 HVM 模式下启动和运行虚拟 Windows 机器。请保持关注!
第十三章。XEN 和 Windows

在上一章中,我们描述了 Xen 的硬件虚拟化支持及其使用方法。现在,我们已经有了带有硬件虚拟化的 Xen,我们可以运行未经修改的操作系统,包括 Windows,这个计算世界中的 800 磅巨兽。
为什么要在 Xen 下运行 Windows?
现在,为什么你偏偏想要做这样一件糟糕的事情呢?我们可以说,“因为你可以做到”,这已经足够成为做许多事情的理由了。但可能并不完全令人满意——毕竟,这听起来像是一项艰巨的工作。
幸运的是,理由很多。其中最好的可能是软件——尤其是服务器软件,考虑到 Xen 的优势在于服务器领域.^([79]) 大多数 Windows 服务器软件,如 Exchange 服务器,拥有庞大的安装基础,替换起来会很困难。客户端软件也是如此。以 Office、Outlook、Visual Studio 为例——Microsoft 仍然是生活中不可或缺的一部分。使用 VNC、SDL 或 rdesktop 的 Xen 允许你在可接受的速率下运行生产力软件,同时提供完整的图形支持,尽管没有加速,而你仍然可以保留舒适的 Linux 计算环境。
Xen 还为你提供了一种摆脱旧担忧的方法,即下一个安全修复或驱动程序更新可能会使机器完全无法启动——它提供了类似于 Microsoft 的“系统还原点”的功能,但完全在你的控制之下,而不是操作系统。通过在具有有效存储后端的虚拟机中运行 Windows,你可以快照它,回滚更新,并保护自己免受恶意软件的侵害——而无需涉及 domU。
安全性是运行 Windows 在 Xen 下的另一个原因。虽然常说 Windows 不安全是个陈词滥调,但事实仍然是,如果正确使用,虚拟化可以成为任何服务器(无论是 Windows、*nix 还是其他)的有效隔离层。Windows 作为热门目标使得这种推理更加有说服力。
还值得注意的是,Xen 的设计,通过在隔离域中分区驱动程序,至少有助于提高安全性。Windows 域的入侵,即使它设法利用驱动程序代码与物理硬件交互,也不太可能危害同一硬件上的其他域。这并不意味着 Xen 本身就是安全的,但它确实表明,可能有可能使其变得安全。当然,还需要做很多工作——实际上,QEMU 当前的许多工作正是验证模拟设备访问以改善安全性的领域。但即便如此,Xen 也能帮助减少 Windows 机器的暴露。
此外,运行 Windows 在 domU 中比你想象的要容易。
^([79]) 至少从操作系统的持续商品化来看,这确实是 Xen 的核心之一,对吧?
Xen 下的 Windows:先决条件
在进入虚拟化 Windows 的新世界之前,确保你已经准备好了一些东西。
首先,您需要一个支持 HVM 的盒子。(有关详细信息,请参阅第十二章,了解它是什么,如何工作以及如何判断您是否有它。)该盒子还需要足够的空闲内存和存储空间来安装 Windows——Xen 可以帮助更有效地使用资源,但它不是魔法。例如,我们建议运行 Windows Server 2003 domU 的 Xen 盒子有 512MB 的内存和每个 domU 大约 10GB 的硬盘空间,加上 512MB 和额外的 10GB 用于 dom0。您可能需要咨询 Microsoft 的网站以获取更具体的系统要求或其他 Windows 版本的要求。
虽然听起来很明显,但您还需要一个 Windows 副本,该副本具有允许虚拟化的许可证。这个 Windows 副本应该相对较新。在本章中,我们将重点关注 Windows XP Service Pack 2 和 Windows Server 2003——Vista 在这个阶段太麻烦了。Windows NT 和 9x,虽然在理论上应该可以工作,但在安装步骤中似乎会崩溃。似乎没有人(包括我们)对找出这是为什么感兴趣。生活中充满了神秘。
Xen 上的 Windows:安装
实际上,在 Xen 上安装和运行 Windows 相当简单。基本步骤与任何其他 Xen 安装完全一样,只是有一些额外的配置:
-
获取 Windows 安装介质并将其放置在 Xen 可以找到的地方。
-
创建一个配置文件。
-
从安装介质启动。
-
使用 Windows 安装程序进行安装。
-
从模拟的硬盘重启。
-
安装虚拟化驱动程序。
-
使用 Windows。
很简单,让我们开始吧。
手动安装 Windows
首先要做的事情是获取 Windows 的副本。在我们的例子中,我们使用了一个物理 CD-ROM,并将其放入 Xen 服务器的 CD-ROM 驱动器中。为了方便,当然可以创建一个镜像并像物理光盘一样使用它:
# dd if=/dev/cdrom of=/var/tmp/windows2k3.iso
(如果您选择这条路,在以下步骤中,请将phy:/dev/cdrom替换为file:/var/tmp/windows2k3.iso。)
同时,按照常规方式创建后端存储。在这里,我们将使用基于文件的设备,但您可以使用 Xen 知道的任何存储后端。
# dd if=/dev/zero of=/opt/xen/falstaff/falstaff.img bs=1M count=8192
接下来,创建一个配置文件。这里有一个示例(从第十二章中提取,略有修改)。我们将将其保存为/etc/xen/falstaff:
import os, re
arch = os.uname()[4]
if re.search('64', arch):
arch_libdir = 'lib64'
else:
arch_libdir = 'lib'
device_model = '/usr/' + arch_libdir + '/xen/bin/qemu-dm'
kernel = '/usr/lib/xen/boot/hvmloader'
builder = 'hvm'
memory = 512
name = 'falstaff'
vif = [ 'type=ioemu, bridge=xenbr0' ]
disk = [ 'file:/opt/xen/falstaff/falstaff.img,ioemu:hda,w',
'phy:/dev/cdrom,ioemu:hdc:cdrom,r' ]
boot = 'd'
vnc = 1
到现在为止,这应该已经很熟悉了。注意,我们将 ACPI 和 APIC 保留在默认的“关闭”值,以避免混淆 Windows 安装程序。当然,您需要将disk=行中的条目指向安装的正确位置。您可能还希望通过设置sdl=1而不是vnc来偏离我们的配置——SDL 仅在本地 X 显示上工作,但具有自动弹出的优点。
然后按照常规方式创建机器:
# xm create falstaff
启动一个 VNC 会话,以便您可以与之通信,假设您决定不使用 SDL。输入正确的主机和显示号——在这种情况下,我们在本地机器上,这是第一个运行的 VNC 会话:
# vncviewer localhost:1
现在 Windows 安装程序将以通常的方式启动。像往常一样安装 Windows。
关于 HAL 的讨论
在这个阶段偶尔会出现的一个问题是涉及 Windows HAL(硬件抽象层)。Windows 随带了一系列可能的 DLL 来实现抽象层,在安装过程中选择六个选项之一。与系统一起使用的正确 HAL 受 acpi, apic 和 vcpus 配置指令的影响,如 表 13-1 所示。
表 13-1. Windows 可用的 HAL
| 选项 | HAL | 备注 |
|---|---|---|
acpi=0,apic=0 |
HAL.DLL | 标准 PC 非 ACPI 可编程中断控制器(PIC)与所有设备兼容 |
acpi=0,apic=1 |
HALAPIC.DLL | MPS(多处理器规范)单处理器 PC 非 ACPI APIC 单处理器 HAL 仅适用于单处理器不与 PIC 机器兼容 |
acpi=0,apic=1 |
HALMPS.DLL | 非 ACPI APIC 多处理器 HAL 不与 ACPI 机器兼容 |
acpi=1,apic=0 |
HALACPI.DLL | 高级配置和电源接口(ACPI)ACPI PIC(非 APIC)HAL 这些在硬件中真的存在吗? |
acpi=1,apic=1 |
HALAACPI.DLL | ACPI 单处理器 PC ACPI APIC 单处理器 HAL 仅适用于 ACPI 仅适用于 APIC 单处理器 |
acpi=1,apic=1 |
HALMACPI.DLL | ACPI 多处理器 PC ACPI APIC 多处理器 HAL |
幸运的获胜者成为 $SYSTEMROOT\system32\HAL.DLL。
因此,简单的答案是使用 HAL.DLL,无论 ACPI 和 APIC 的值如何。这应该总是有效,但它可能会降低性能。微软还警告说,这种配置不受支持.^([80]) 我们通常打开 ACPI 和 APIC,以便 Windows 安装 ACPI APIC HAL,而且它还没有导致机器起火。
然而,在 Windows XP 中,这有时不起作用。设置 ACPI 可能会导致安装过程失败,通常是在“正在启动 Windows”时挂起。安装 Windows XP 最简单的方法是在从 CD-ROM 初始启动时关闭 ACPI 和 APIC,然后在第一次进入图形模式之前打开它们。
acpi=0
apic=0
on_reboot = 'destroy'
然后进行初始格式化、复制等操作。当 Windows 安装的第一阶段完成并且虚拟机关闭后,将配置文件更改为读取:
acpi=1
apic=1
on_reboot = 'restart'
这将导致 Windows 在其第二阶段安装时安装正确的 HAL。
如果您以后需要更改 HAL——例如,如果您决定从单处理器配置迁移到多处理器配置——我们建议重新安装 Windows。虽然可以通过覆盖各种驱动程序文件手动更改 HAL,但这可能不是一个好主意。
以 Red Hat 方式安装 Windows
Red Hat 的 virt-manager 应用可以处理设置 Windows 的大部分麻烦。只需从 virt-manager 图形用户界面创建一个机器,在适当的对话框中选择完全虚拟化而不是 Para 虚拟化,并指出 Windows 安装媒体的存放位置(可以是 ISO 文件或物理 CD-ROM)。指出你是否希望使用虚拟网络或共享物理设备(分别对应通过 virbr 和 xenbr 进行网络连接)连接到网络。使用 Microsoft 的安装程序按正常方式安装 Windows。
virt-manager 生成的配置看起来可能像这样:
name = "hal"
uuid = "5b001f4d-7891-90d8-2f55-96a56e8d07df"
maxmem = 512
memory = 512
vcpus = 1
builder = "hvm"
kernel = "/usr/lib/xen/boot/hvmloader"
boot = "c"
pae = 1
acpi = 0
apic = 0
on_poweroff = "destroy"
on_reboot = "restart"
on_crash = "restart"
device-model = "/usr/lib/xen/bin/qemu-dm"
sdl = 0
vnc = 1
vncunused = 1
keymap = "en-us"
disk = [ "file:/var/lib/xen/images/falstaff.img,hda,w" ]
vif = [ "mac=00:16:3e:7e:f3:15,bridge=virbr0,type=ioemu" ]
serial = "pty"
不幸的是,这并不能让你完全完成 Windows 的安装。由于某种原因,在安装过程中的第一次重启后,模拟的 CD-ROM 不会被提供给 Windows,因此 Windows 会抱怨找不到其文件。
Red Hat 的文档会告诉你,Windows 需要将其虚拟磁盘格式化为 FAT 或 FAT32 分区,以便你可以将其安装文件复制到其中。虽然这种方法可行,但我们更喜欢避免使用 FAT32,而是使用 NTFS。为了解决这个问题,我们使用 I/O 仿真器。修改 disk= 行以使用 QEMU 的 I/O 仿真,如下所示:
disk = ['<hda>','file:/mnt/winxp.iso,ioemu:hdc:cdrom,r']
(当然,将您对第一个硬盘的定义放在适当的位置。)第二个段落指定了一个 ISO 文件,用作虚拟 CD-ROM 驱动器,由 Xen 的硬件仿真层(从 QEMU 继承)提供硬件仿真。当你做出这个更改后,CD 将作为 QEMU 仿真设备出现在 domU 上,然后你可以继续安装。
^([80]) 所以,就我们所知,在 Xen 下运行 Windows 的所有其他事情也是如此。
带有虚拟帧缓冲区的 Windows
“Windows NT 的最佳远程管理工具是什么?”
“一辆车。”
—匿名,Usenet
无论你如何安装 Windows,你几乎肯定想在它运行时登录并使用系统。这就是虚拟帧缓冲区发挥作用的地方。
Xen 的虚拟帧缓冲区允许你在所有阶段与 domU 交互——从 BIOS 加载,通过引导加载程序,到系统启动后。它可以通过本地控制台的 SDL 或通过网络上的 VNC 访问。这是 HVM domU 的整洁功能之一,并且它真的有助于巩固真实机器的错觉。
虽然虚拟帧缓冲区很棒,但也有一些烦恼。例如,鼠标跟踪在默认情况下可能会有些不稳定。以下是一些解决我们在 VNC 帧缓冲区中遇到的最常见问题的方法。
首先,默认情况下,Xen 内置的 VNC 服务器不会监听除了回环接口之外的其他接口。要改变这种行为,请在 /etc/xen/xend-config.sxp 中设置 vnc-listen 以监听所有接口:
(vnc-listen '0.0.0.0')
你还可以指定 VNC 服务器要监听的接口的 IP 地址。请注意,这将通过网络暴露机器的控制台,因此可能只应在受信任的网络上进行。
当在 Windows 下使用 VNC 帧缓冲区时,一个有用的技巧是将平板电脑指定为指向设备,而不是鼠标。这通过使用绝对定位来提高鼠标跟踪。
usb=1
usbdevice="tablet"
(usb=1这一行并不是绝对必要的——它被usbdevice=隐式地打开。然而,它是一个有用的提醒,说明 Xen 的 USB 仿真已经被打开。)
最后一个小烦恼:有时 VNC 的鼠标和键盘界面会突然停止工作(或者显示停止更新)。十有八九,如果你关闭并重新打开 VNC 会话,它就会恢复正常。
除了 Xen 的虚拟帧缓冲区之外,你还可以在操作系统级别处理访问——例如,通过在 Windows 下安装 VNC 服务器或使用微软内置的 RDP(远程桌面协议)。这些的优点是允许虚拟机自己处理图形任务,而不是在 dom0 中涉及仿真器。RDP 也是一个比 VNC 更高级、更高效的协议,类似于 X 在处理小部件和图形原语方面的处理。如果可能的话,我们建议使用它。如图 13-1 所示,VNC、RDP 和 SDL 可以共存,在同一个虚拟机上可以有多个独立的会话。
要在管理模式下启用 RDP,访问系统属性,点击远程选项卡,并勾选标记为启用远程桌面的复选框。

图 13-1。在这里我们看到两个域:一个运行 Windows XP 并通过 VNC 访问;另一个 Windows Server 2003 domU 通过 VNC 访问,从 Windows XP 域通过 RDP 访问,以及从 Linux 机器通过 rdesktop 访问。
Windows XP 和 Windows Server 2003 包含了 RDP 客户端。在其他平台上,开源的 rdesktop 客户端允许你从类 Unix 操作系统(包括 Mac OS X)访问 Windows 机器。只需运行以下命令:
# rdesktop <destination address>
Et Voilà!
现在,Windows 已经运行起来了。这是一个备份干净 Windows 安装的好时机,这样当出现问题时你可以方便地重新映像。只需创建一个 LVM 快照或基于文件的 CoW 设备,就像我们在第四章中概述的那样。这将有助于你的安心。
当你有备份时,你可以做你习惯在 Windows 上做的事情。我们不会在这个方面指导你。
然而,关于这个新的 Windows 安装,还有一些事情需要记住。
Windows 激活
除非你有批量许可证,否则 Windows 的许可证和激活与硬件绑定。因此,提前决定硬件配置并保持其不变是一个好主意,以避免计算机要求重新激活。
特别是,指定一个 MAC 地址,这样 Xen 就不会在每次重启时随机生成一个新的地址——这是 Windows XP 硬件哈希计算中最重要的单个值。其他需要注意的事项包括内存量和虚拟光盘。
显卡
Xen 下 Windows 的另一个重大限制是它仍然不允许你使用 3D 硬件——因此,在 Windows domU 中运行游戏的桌面 Linux 机器目前仍然纯粹是幻想。正如我们上面的讨论所显示的,虚拟 Windows 机器通过 SDL 或 VNC 使用模拟的帧缓冲区。这两种模式都不支持任何形式的加速。
在 HVM 模式下硬件访问的问题(这适用于任何 PCI 设备,而不仅仅是显卡)在于无法将硬件的内存空间映射到虚拟机的内存中——虚拟机有一个额外的抽象层,将不连续的物理内存块转换成未经修改的 domU 操作系统可以使用的东西。最近,芯片组已经开始集成IOMMU,这是一种可以以类似于处理器内存管理单元的方式进行这种转换的硬件(因此得名)。Xen 对 Intel 的 IOMMU 实现的名为 VT-d 的支持正在进展中,但还没有达到可以使得显卡在 Windows domU 中可用的程度。
VT-D 支持
如果你想知道你的机器是否支持 VT-d,你可以在 dom0 中运行xm dmesg | grep -i vt-d来查找。带有 VT-d 的机器会显示类似Intel VT-d 已启用的信息。如果你看到这个信息,恭喜你!下一个 Xen 版本可能会包括启用此高级功能的功能。
另一种图形处理方法——不需要替换所有现有硬件的方法——是让图形驱动程序作者在驱动软件中实现从 domU 地址到机器地址的转换。据说 NVIDIA 有一个针对 Xen 的驱动程序,可以分配给 HVM domU 并用于 3D 加速;然而,它尚未发布,所以有很大可能它实际上并不存在。
另一个有希望的途径是使用虚拟 3D 图形驱动程序将 OpenGL 调用转发到实际的图形硬件。有几个基于 Xen 的项目使用这个原理,但目前它们仅限于 Linux。VMware 也进行了一些关于允许 3D 的驱动程序架构的工作,这似乎采取了相同的策略。
我们所知,尚无成品允许在 Windows 下支持硬件 3D。尽管如此,这是一个被广泛请求的功能,并且正在被开发。然而,我们不会将其作为任何 Xen 部署的必要部分。
Windows 虚拟化驱动程序
如我们之前提到的(多次提到),HVM 相对于虚拟化来说要慢一些。部分原因是需要虚拟化内存访问;然而,与模拟 I/O 及其伴随的上下文切换相比,这种开销是微不足道的。(有关令人难以置信的详细信息,请参阅第十二章。)
在安装过程完成后,您可以通过将模拟设备替换为虚拟化设备来解决许多与 HVM 相关的速度问题。这些设备将显著提高 I/O 速度;然而,Windows 驱动程序支持不足。有两个选择:专有且昂贵的驱动程序,或者免费但未完成的驱动程序。
专有 Windows PVM 驱动程序
到目前为止,有三家公司提供了利用虚拟化的 Windows 驱动程序:XenSource、Virtual Iron 和 Novell。所有这些驱动程序都由微软签名,以确保在 Windows 上安装无故障。
Citrix 戴着 XenSource 的帽子,作为其基于 Xen 的虚拟化套件的一部分,为 Windows 生产虚拟化驱动程序。这些驱动程序运行良好,您可以通过下载 XenSource 产品的免费版本自行测试。不幸的是,这些驱动程序与 Xen 的开源版本不兼容。
Virtual Iron (virtualiron.com/) 也为其产品提供 Windows 虚拟化驱动程序。这些驱动程序与开源 Xen 兼容,Virtual Iron 一直在努力向 Xen 社区贡献更改。然而,这些驱动程序本身仍然是闭源的。
最后,Novell 提供与开源 Xen 兼容的 Windows PV 驱动程序,作为独立产品。这些驱动程序相当昂贵(至少可以说)——它们如此昂贵,以至于我们实际上并没有尝试过。如果您好奇,更多信息请访问www.novell.com/products/vmdriverpack/。
到目前为止,尽管所有这些驱动程序(根据我们的经验)都按预期工作,但它们似乎对我们来说并没有特别吸引人。我们满足于仅使用 Windows 和 HVM 驱动程序进行轻量级生产力任务。
GPL Windows Paravirtualized Drivers
如果您足够大胆,可以尝试一件事情。确实存在 GPL Windows PV 驱动程序。它们正在积极开发中,这是开发者语言,意思是“不要将这些用于任何重要的事情。”它们在我们的使用中表现相当不错,但偶尔会做一些令人惊讶的事情(通常是令人不快的)。这些驱动程序试图通过避免一些低效的设备模拟,并使用高级技术,如 TCP 分段卸载(TSO)来提高性能。
GPL PV 驱动程序的安装很简单。首先,我们建议检查 xen-devel 存档以确定哪个版本是最新的。截至本文撰写时,0.8.8 是最新版本,可在 www.meadowcourt.org/WindowsXenPV-0.8.8.zip 获取。不幸的是,没有列出发布的网页,因此您需要搜索 xen-devel 邮件列表的存档以找到最新版本。(或者,您可以使用 Mercurial 检查当前版本——检查 xenbits.xensource.com/ext/win-pvdrivers.hg 上的存储库。)
我们选择在 HVM Windows XP Professional 实例中直接下载二进制驱动程序包。它包括一套相当全面的安装说明,但我们仍然会过一遍我们做了什么,只是为了方便。
首先,解压驱动程序。我们只是将相应的文件夹拖到了桌面上。
接下来,运行 install.bat。Windows 会多次抱怨驱动程序未签名。只需点击 确定。
安装完成后,重新启动以确保一切仍然正常工作。
假设您成功重启,现在您应该能够从 Windows 访问 PV 设备。尝试在 dom0 中创建一个临时设备,然后运行以下类似的 xm block-attach 命令(始终使用适当的名称):
# xm block-attach falstaff phy:/dev/mapper/falstaff_sdb sdb w
这应该会导致 Windows 注意到一个新设备,使用正确的驱动程序,并显示一个空白磁盘,然后我们可以对其进行格式化,如图 图 13-2 所示。同样,您可以使用 xm network-attach 命令附加网络设备。
最后,您需要编辑 boot.ini 文件来告诉 GPL PV 驱动程序激活。 (您可能需要打开“工具”>>“文件夹选项”中的“显示隐藏文件和文件夹”,并取消选中“隐藏受保护的操作系统文件”,以便使 boot.ini 可访问。)
[boot loader]
timeout=30
default=multi(0)disk(0)rdisk(0)partition(1)\WINDOWS
[operating systems]
multi(0)disk(0)rdisk(0)partition(1)\WINDOWS="Windows XP Professional" /noexecute=optin /fastdetect
multi(0)disk(0)rdisk(0)partition(1)\WINDOWS="Windows XP Professional (PV drivers)"
/noexecute=optin /fastdetect /gplpv
在这里,我们通过在末尾添加 /gplpv 来修改引导条目,以告诉 GPL PV 驱动程序激活。

图 13-2. 使用 GPL PV 驱动程序添加虚拟化磁盘
现在,关闭 Windows 安装。
重新启动,从引导菜单中选择 Windows XP Professional (PV Drivers) 条目,您应该有一套完整的 PV 设备。
持续开发
在 Xen 下的 Windows 仍然不成熟,但它已经发展到足够有用的程度。使用 Xen,您可以在一个强大、可管理的平台上合并 Windows 服务器,并在桌面上以原生环境运行客户端软件。您有合理的方式通过帧缓冲区或 rdesktop 访问机器,最后您有 PV 驱动程序以实现合理的速度。
总的来说,Xen 是一个相当好的 Windows 平台。不完美,但确实可用。
第十四章。提示

到现在为止,你已经成为某种 Xen 专家,我们想象。^([81]) 因此,现在我们想要用一章的篇幅来探讨与 Xen 一起工作的更神秘方面。这里有一些似乎不适合其他地方的东西——比如帧缓冲区、转发 PCI 设备,或者将附加功能构建到 XenStore 中。换句话说,就是提示。
在这里的工作示例中,第十五章 中的一些主题也可能很有用。这里讨论的一些软件甚至比 Xen 本身还要前沿,而 Xen 本身就像一把天剑,凶猛而鲜艳。我们试图说明的是,本章中的材料可能不会立即生效。
编译 Xen
尽管我们大部分时间都依赖于发行版维护者提供的 Xen 软件包,但我们认为从头开始编译 Xen 通常是有价值的。这将允许你使用比发行版中提供的版本更新的 Xen 版本。这也让你能够启用发行版维护者可能已禁用的选项。
如果你喜欢冒险,能够玩弄代码——稍作修改,或者添加一些 printk 消息以帮助调试,也是很不错的。
编译的最简单方法是检查 Mercurial 仓库的最新源代码。首先确保你有 Mercurial 和一系列构建依赖项。在 CentOS 5 上,我们使用 yum 安装了这些软件包:^([82])
-
mercurial
-
zlib-devel
-
gcc
-
libX11-devel
-
openssl-devel
-
ncurses-devel
-
bridge-utils
-
python-devel
-
git
-
dev86
-
glibc-devel
如果你想要成功构建文档,你还应该安装以下软件包:
-
texinfo
-
tetex-latex
-
pstoedit
-
transfig
考虑到在线和其他来源提供的 Xen 文档数量庞大,所包含的文档相当可选。
当这些软件包安装完成后,克隆开发仓库。这里我们使用 xen-unstable,但如果你想要使用一个不那么不稳定的仓库,你可能想尝试像 xen-3.3-testing.hg 这样的东西。截至 2009 年初,prgmr.com 运行 xen-3.3-testing.hg。它相当稳定。
# hg clone http://xenbits.xen.org/xen-unstable.hg
RPMFORGE 仓库
如果你想要使用 yum 安装之前列出的所有软件包,你必须使用 RPMForge 仓库。为了安全地这样做,请安装 yum-priorities。在 CentOS 5 上:
# yum install yum-priorities
编辑 /etc/yum.repos.d/* 下的每个文件,并添加行 priority=N,其中 N 是 1 到 99 之间的数字(数字越小,优先级越高)。你希望 base、addons、updates 和 extras 的优先级为 1;centosplus 和 contrib 的优先级为 2;其他所有内容的优先级为 10 或更高。
现在,安装 RPMforge:
wget
http://apt.sw.be/redhat/el5/en/i386/RPMS.dag/rpmforge-release-0.3.6-1
.el5.rf.i386.rpm
当然,如果你的机器是 x86_64,请替换为适当的架构:
rpm --import http://dag.wieers.com/rpm/packages/RPM-GPG-KEY.dag.txt
然后使用以下命令安装 rpmforge:
rpm -K rpmforge-release-0.3.6-1.el5.rf.*.rpm
最后,编辑 /etc/yum.repos.d/rpmforge.repo 并添加 priority=10。
这将把仓库下载到本地目录(在本例中为xen-unstable.hg)。接下来,cd进入该目录并运行make world:
# cd xen-unstable.hg
# make world && make install
这将构建和安装 Xen 虚拟机管理程序、其支持工具以及一个用于 dom0 的 Linux 内核。DomUs 也可以使用它。通常,这将是你需要的一切。然而,如果你想更改你的内核配置,你可以。要配置 Linux 内核,请运行:
# make linux-2.6-xen-config configmode=MENUCONFIG
这将打开标准的 Linux 内核配置器。像往常一样配置内核。
注意
你可能想禁用 dom0 的 8250 串行驱动程序,因为它与 Xen 串行控制台冲突。像往常一样,不要忘记你的启动设备的驱动程序。
然后运行:
# make linux-2.6-build
# make linux-2.6-install
这将构建和安装内核。现在,如果你在使用 CentOS,你可能想创建一个 initrd:
# mkinitrd /boot/initrd-2.6.18.8-xen.img 2.6.18.8-xen
注意
RHEL 5.3 早期版本中存在一个 bug,会导致这个问题。有关详细信息,请参阅bugzilla.redhat.com/show_bug.cgi?id=488991。解决方案是在 mkinitrd 命令行中添加 --allow-missing ,因此: # mkinitrd /boot/initrd-2.6.18.8-xen.img 2.6.18.8-xen --allow-missing。
现在,你需要修复/boot/grub/menu.lst。添加如下段落,但请记住使用适当的设备、路径,以及可能还有文件名:
title Xen.org 2.6.18.8-xen-3.3
root (hd0,0)
kernel /boot/xen-3.3.gz
module /boot/vmlinuz-2.6.18.8-xen ro root=/dev/md0
module /boot/initrd-2.6.18.8-xen.img
重启并享受你的新 Xen 安装。
^([81]) 或者至少,任何没有把这本书扔出窗户的人一定非常擅长填补模糊的方向。
^([82]) 我们还在备用内核(Dom0 和 DomU)")paravirt_ops Dom0 和 paravirt_ops DomU 中包含了一套更以 Debian 为中心的编译指令。
编译时调整
这就是构建 Xen 的快速简单方法,但基本的编译make world只是开始。编译代表了我们有配置 Xen 的第一个机会,而且现在我们已经有所实践,我们可以做更多的事情。
大部分的编译时调整可以通过在 Xen 源树的顶层Config.mk文件中调整变量来完成。这个文件有相当多的注释,并且易于编辑——看看。你会发现有一个简短的段落,你可以决定要构建哪些可选的 Xen 组件。
我们通常打开所有可选组件,除了虚拟可信平台模块(VTPM)工具,导致出现如下部分:
XENSTAT_XENTOP ?= y
VTPM_TOOLS ?= n
LIBXENAPI_BINDINGS ?= y
XENFB_TOOLS ?= y
PYTHON_TOOLS ?= y
注意
Xen 的 VTPM 工具很有趣。它们一直是重点开发对象,对于签名代码有一些有趣的含义,还有 DRM 的阴影,但我们还没有深入研究。如果你决定构建它们,你可以在域配置中的 vtpm= 选项中添加虚拟 TPM。
如果你遇到麻烦(相信我们,你可能在某个时候会遇到),制作一个调试版本可能是个好主意。为此,在文件顶部设置 DEBUG 变量:
DEBUG ?= y
别担心:Xen 不会在调试模式下运行,除非你在运行时明确指示它这样做。
这些可选的 Xen 组件有一系列未记录的依赖项,其中一些在 Makefiles 中没有被检查。特别是,LIBXENAPI_BINDINGS 需要安装 libxml2 和 curl 或这些软件包的 -devel 版本,如果你使用的是 Red Hat 衍生版本。
此外,如果在构建工具时出现问题,为了避免再次运行 make world(因为这需要一段时间),可能是一个好主意。很可能会发现,只需运行 make tools 就可以解决问题。
替代内核(Dom0 和 DomU)
默认的 Xen Makefile 会构建一个可以在 dom0 和 domU 中使用的单个内核。如果你将节省内存作为高优先级,可以为每个构建一个单独的内核。这些内核将各自有一组合理的配置选项:domU 的配置最小化,dom0 的配置模块化。在 make 命令行上指定 KERNELS 变量:
# make KERNELS="linux-2.6-dom0 linux-2.6-domU"
当然,这样做的主要原因是你可以从 domU 内核中移除所有非 Xen 设备驱动程序。这节省了内存,如果你碰巧在测试大量内核,还可以节省编译时间。
paravirt_ops Dom0
要理解为什么 paravirt_ops 被视为一个单独的部分,我们必须回忆起许多早期的 Xen 开发是在虚拟化成为主流之前进行的。为了对 Linux 内核进行 para-virtualization,Xen 开发者进行了广泛的更改,这些更改证明很难与主线内核开发合并。
paravirt_ops 是解决这个问题的通用解决方案。它是一个内核级框架,用于添加代码以使 Linux 能够在各种虚拟机管理程序下运行,包括 Xen。想法是,通过将这些接口作为官方内核的一部分,我们可以使 Xen 更少侵入性,更容易维护。
Xen 自 3.1 版本以来支持 paravirt_ops domUs,官方 Linux 内核自 2.6.23 版本以来对 i386 支持 domU,自 2.6.26 版本以来对 x86_64 支持 domU。不幸的是,截至本文撰写时,kernel.org 内核只支持客户机。
但隧道尽头有光。通过 Jeremy Fitzhardinge 的 paravirt_ops dom0 工作的最新补丁和 Xen 3.4 虚拟机管理程序,实际上可以在基于 Linux 内核版本 2.6.30 的 paravirt_ops dom0 上运行。
这些说明代表了一个非常长的开发过程的快照。它们对我们今天有效。URL 可能会改变。软件的状态肯定也会改变。然而,考虑到这一点,以下是设置一个功能性的 paravirt_ops dom0 的方法。
首先,你需要一些开发包。这次我们使用的是 Debian 软件包名称:
-
mercurial
-
build-essential
-
libncurses5-dev
-
gawk
-
openssl
-
xorg-dev
-
gettext
-
python-dev
-
gitk
-
libcurl4-openssl-dev
-
bcc
-
libz-dev
-
libxml2-dev
接下来,使用 Mercurial 检出 Xen-unstable。我们警告过你,这些功能仍在开发中。
# hg clone http://xenbits.xensource.com/xen-unstable.hg
# cd xen-unstable.hg
# make xen
# make install-xen
# make tools
# make install-tools
然后从 Jeremy Fitzhardinge 的 git 仓库检出当前的 Linux 补丁:
# git clone git://git.kernel.org/pub/scm/linux/kernel/git/jeremy/xen.git linux-2.6-xen
# cd linux-2.6-xen
# git checkout origin/push2/xen/dom0/master -b push2/xen/dom0/master
配置内核。我们将 Ubuntu 的配置复制到 .config 并以此为基础。
# cp /boot/config-2.6.26-11-server .config
# make menuconfig
由于我们正在构建 paravirt_ops dom0,请确保启用适当的支持:
Processor type and features
-> Paravirtualized guest support
........-> Enable Xen privileged domain support
确保在以下位置启用 Xen 块设备前端支持:
Device Drivers
-> Block devices
接下来,构建内核。
# make
# make modules_install install
# depmod 2.6.30-tip
# mkinitramfs -o /boot/initrd-2.6.30-tip.img 2.6.30-tip
将 /proc/xen 添加到 fstab 并挂载它,以便 xend 等工具能够与虚拟机管理程序通信:
none /proc/xen xenfs defaults 0 0
创建一个 GRUB 条目来引导你的新 Xen paravirt_ops dom0:
title Xen 3.4 / Ubuntu 8.10, kernel 2.6.30-tip
kernel /boot/xen-3.4.gz
module /boot/vmlinuz-2.6.30-tip root=/dev/sdb2 ro console=tty0
module /boot/initrd-2.6.30-tip.img
当然,请确保这些值适合你的设置。这就是全部内容。
paravirt_ops DomU
“但是,”你可能会问,“所有这些关于在 domU 中使用 kernel.org 内核是什么意思?”如果你只是想制作自己的 domU 内核,这个过程要简单得多,自 2.6.23 版本以来无需树外补丁即可支持。所有这些说明都是从使用 PV-GRUB 或 PyGRUB 启动的 domU 内部提供的——不需要 dom0 管理员的干预。
首先,下载你偏好的内核源代码:
# wget http://kernel.org/pub/linux/kernel/v2.6/linux-2.6.29.3.tar.bz2
接下来,安装构建内核通常所需的软件包。这个例子是为 Debian 定制的,但应该很容易找到你喜欢的发行版构建内核所需的软件包。
# apt-get install build-essential libncurses5-dev
解包并配置内核。我们个人喜欢 menuconfig,但这只是个人喜好问题:
# tar -jxf linux-2.6.29.3.tar.bz2
# cd linux-2.6.29.3
# make menuconfig
不要忘记启用 Xen 支持:
-> Processor type and features
-> Paravirtualized guest support
-> XEN
不要忘记你的网络驱动程序:
-> Device Drivers
-> Network device support
-> XEN_NETDEV_FRONTEND
或者你的磁盘驱动程序:
-> Device Drivers
-> Block devices
-> XEN_BLKDEV_FRONTEND
Xenfs,它允许你访问 XenBus,有时很有用:
-> Device Drivers
-> XENFS
然后随心所欲地进行自定义。记住,你现在可以移除几乎所有硬件的支持。我们还省略了气球驱动程序。RAM 很便宜,我们喜欢有明确的内存分配。
现在,像往常一样构建内核:
make -j4 ; make install modules_install
按照常规内核构建方式制作你的 initrd。由于我们在这个例子中使用 Debian,这意味着使用 mkinitramfs。如果你将 xenblk 编译为模块,请确保将其包含在内。
mkinitramfs -o /boot/initrd-2.6.29.3.img 2.6.29.3
按照常规设置 GRUB:
title kernel.org paravirt DomU
root (hd0,0)
kernel /boot/vmlinuz-2.6.29.3 root=LABEL=DISK1 ro
initrd /boot/initrd-2.6.29.3.img
在重启之前,最后一件事情:请注意,你的控制台设备名称将是 hvc0,即 虚拟机管理程序控制台。这取代了 Xen 特定的 xvc0。如果你的发行版还没有这样做,你可能想设置域以在 hvc0 上启动 getty。现在,只需重新启动你的域(如果你使用 PyGRUB,请先停止再启动)并享受你的现代内核。
# uname -a
Linux sebastian.xen.prgmr.com 2.6.29.3 #1 SMP Tue May 12 06:32:52 UTC 2009 x86_64 GNU/Linux 2009
Xen API:未来的道路
Xen API 是一个 XML-RPC 接口,用于替代与虚拟机管理程序通信的旧接口。它承诺提供一个标准、稳定的接口,以便人们可以构建 Xen 前端而不用担心接口会发生变化。它还扩展了之前的 Xen 命令集,以便在标准化的工具中利用更多 Xen 的功能。
在当前版本的 Xen 中,API 是一个可选组件,但这不应该阻止你使用它;例如,最新的 Citrix Xen Server 产品完全依赖于 API 来实现管理前端和虚拟化主机之间的通信。
Xen API 是通过在Config.mk文件顶部设置 LIBXENAPI_BINDINGS 标志来启用的:
LIBXENAPI_BINDINGS ?= y
当你用支持 Xen API 的方式构建 Xen 时,API 的使用由/etc/xen/xend-config.sxp中的(xen-api-server)指令控制。
(xen-api-server ((9363 none) (unix none)))
这个指令开启了 API 服务器并指定了如何连接到它。括号中的每个列表都是一个连接方法。在这种情况下,我们使用 TCP 端口 9363 和一个本地 Unix 套接字,每个都没有任何身份验证。
要指定我们想要使用 PAM 进行身份验证,我们可以稍微修改一下这个配置:
(xen-api-server ((9363 pam '192.0.2.*'))
通常,即使在开发 Xen 客户端时,你也不需要以低级别与 Xen API 交互。大多数流行语言都有绑定,包括 C 和当然还有 Python。Xen.org API 文档,可通过wiki.xensource.com/xenwiki/XenApi/访问,是关于这个主题的最后一言。
使用气球驱动程序管理内存
从编译时间和安装问题转向运行 Xen 的日常业务,我们遇到了内存问题。正如我们提到的,大多数 Xen 安装实际上受限于物理内存。
Xen 在虚拟化内存上投入了大量的努力;其方法是半虚拟化的一个定义特征,通常“只需工作”,在足够低的级别上可以完全忽略。然而,有时管理员的一点点关注可能会带来好处。
我们已经围绕内存超订阅的主题绕来绕去很长时间了,我们最好坦白:可以为 domU 分配一定量的动态内存,但我们没有这样做,因为它不适合我们的虚拟专用服务器模式。此外,开发者们从历史上就对这个建议用于生产持谨慎态度。然而,它确实存在,而且有一些很好的理由去使用它,我们相信你能想象到。
Xen 对虚拟机内存重新分配的控制是间接的。首先,domU 配置文件中内存的值是一个最大值——从概念上讲,这是虚拟机可以物理访问的内存量。配置文件中的内存量是内核在启动时看到的。增加内存需要重启。这项工作正在进行中,主要来自 Linux 的内存热插拔方向。我们相信很快会有人提供补丁。
在这个不灵活的最大值内,Xen 可以使用气球驱动程序来减少内存,这只是一个位于 domU 中并膨胀以消耗内存的模块,然后将其归还给虚拟机管理程序。
因为 dom0 也是一个 Xen 域,它也可以拥有一个内存气球,Xen 使用它来回收 dom0 内存以分配给 domUs。
注意
我们倾向于使用 dom0_mem 引导选项直接设置 dom0 内存,这会主动隐藏内存以防止 dom0 使用。通过在 xend-config.sxp 中设置 (dom0-min-mem 0) 和 (enable-dom0-ballooning no) *,我们可以确保 dom0 不会膨胀,从而保持一致的内存预留。^([83])
您可以使用xm手动调整气球使用的内存量:
# xm mem-set sebastian 112
该域将其视为目标,当内存空闲时,会将其分配给气球.^([84]) 因此,一个负载较重的域可能需要一段时间才能将内存释放给气球。
您可以在虚拟机列表中看到气球的效果:
# xm list sebastian
Name ID Mem(MiB) VCPUs State Time(s)
sebastian 71 111 1 -b---- 38.4
您也可以通过/proc/xen/balloon从 domU 内部查看与气球相关的信息:
# cat /proc/xen/balloon
Current allocation: 114688 kB
Requested target: 114688 kB
Low-mem balloon: 24576 kB
High-mem balloon: 0 kB
Driver pages: 136 kB
Xen hard limit: ??? kB
注意
气球相当积极;它可能导致 domU 出现内存不足的情况。请谨慎使用。
^([83]) 在 Xen 的新版本中,您实际上只需要设置* (enable-dom0-ballooning no) *,但这在旧版本中没有效果。在enable-dom0-ballooning选项启用之前,将dom0-min-mem设置为 0 将禁用气球。实际上,您只需将dom0-min-mem设置为 0 即可;我在在 xen-devel 列表上出丑之后测试了它,它有效,但(enable-dom0-ballooning no)既清晰又简洁,这类事情足够重要,值得两次指定。
^([84]) 尽管 Linux 尽力在所有时间都保持内存的使用,但它会将内存分配给气球,而不是用于缓冲区或缓存。
PCI 转发
您可以允许 domU 访问任意 PCI 设备并使用它们,具有完全的权限。当然,没有免费的午餐;Xen 不能神奇地复制 PCI 硬件。为了使 domU 使用 PCI 设备,它必须从 dom0 中隐藏,并且不会转发到任何其他 domUs。

图 14-1. Xen PCI 设备转发
如图 14-1 所示,PCI 转发使用客户端/服务器模型,其中pcifront 驱动程序在 domU 中运行,并直接与绑定到 PCI 设备的pciback 驱动程序通信。
首先,考虑您想要转发到 domU 的设备。我们坐在这台测试机前的设备似乎有七个(!) USB 控制器,所以我们只取其中几个。
使用lspci确定总线 ID:
# lspci
00:1a.0 USB Controller: Intel Corporation 82801H (ICH8 Family) USB
UHCI #4 (rev 02)
00:1a.1 USB Controller: Intel Corporation 82801H (ICH8 Family) USB
UHCI #5 (rev 02)
00:1a.7 USB Controller: Intel Corporation 82801H (ICH8 Family) USB2
EHCI #2 (rev 02)
(&c.)
我们将转发00:1a.1和00:1a.7,这是 USB1 控制器列表中的第二个和 USB2 控制器。您的设备名称可能与这个示例中的不同。
如果 pciback 编译进内核,您可以在内核命令行上使用 pciback.hide 选项来引导 dom0。对于这两个控制器,选项看起来是这样的:
pciback.hide=(00:1a.1)(00:1a.7)
如果 pciback 是一个模块,那么会稍微困难一些。我们需要将 PCI 设备从其驱动程序中分离出来,并将其连接到 pciback 透传。
# insmod pciback hide=(00:1a.1)(00:1a.7)
# echo -n 00:1a.1 > /sys/bus/pci/drivers/uhci_hcd/unbind
# echo -n 00:1a.1 > /sys/bus/pci/drivers/pciback/new_slot
# echo -n 00:1a.1 > /sys/bus/pci/drivers/pciback/bind
现在将这些设备放入 domU 配置文件中:
pci = [ '00:1a.1', '00:1a.7' ]
在下一个 domU 引导时,这些 USB 控制器应该会出现,并可供 domU 中的本地驱动程序使用。在无 IOMMU 的平台上,硬件设备可以 DMA 到任意内存区域。如果您将 PCI 访问权限授予任意域,这可能会成为安全问题。道德是,将所有具有 PCI 总线访问权限的域视为特权域。确保您可以信任它们。
GRUB 配置
当然,我们只是顺便提到了 GRUB,因为它是 Xen 的基本先决条件之一。然而,还有几个关于 GRUB 的方面值得深入探讨。Xen 的许多行为旋钮可以在引导时通过调整传递给虚拟机管理程序的命令行参数来调整。
例如,已经提到的 dom0_mem 参数调整了 Xen 允许 dom0 看见的内存量:
kernel /boot/xen.gz dom0_mem=131072
为了防止系统在内核恐慌时重启,这种情况比我们希望的更常见,尤其是在尝试设置机器时,请将 noreboot 添加到 kernel 行:
kernel /boot/xen.gz dom0_mem=131072 noreboot
以及将 panic=0 添加到 Linux 的 module 行:
module /boot/vmlinuz-2.6.18-53.1.21.el5xen panic=0
这当然是在 Linux 内核支持的众多选项的基础上,您可以根据需要将其添加到 vmlinuz 的 module 行。
串行控制台
另一个重要的与 GRUB 相关的任务是设置您的串行控制台。如前所述,我们认为串行控制台是任何类型服务器控制台访问的黄金标准。它比任何图形界面都要简单得多,可以通过各种设备轻松访问,并且在机器崩溃时最有可能提供有用的信息。此外,由于系统固有的客户端/服务器架构,任何崩溃的机器成功打印的内容都会发送到另一台物理上独立的机器,在那里可以随意分析。
Xen 随带 miniterm,这是一个用于此类操作的简化串行客户端,以防您无法访问串行客户端。这种情况不太可能发生,但客户端很小,为什么不试试呢?
Miniterm 位于 Xen 源树的 tools/misc/miniterm 子目录中。如果您已经使用 Xen 构建了所有工具,它可能已经构建并可能甚至安装了;如果没有,您只需在那个目录中输入 make 并运行生成的可执行文件。
启用串行输出
有四个组件需要将它们的输出重定向到串行端口:GRUB、Xen、Linux 内核和 Linux 的用户空间。前三个组件只需在 GRUB 的 menu.lst 中添加一个指令即可。
首先,在文件顶部附近,添加以下几行:
serial --unit=0 --speed=115200 --word=8 --parity=no --stop=1
terminal --timeout 10 serial console
编辑 Xen 内核行,告诉虚拟机管理器使用第一个串行端口进行输出:
kernel /boot/xen.gz-2.6.18-53.1.21.el5 console=com1 com1=115200,8n1
告诉 Linux 内核在ttyS0上打印其消息:
module /boot/vmlinuz-2.6.18-53.1.21.el5xen ro root=/dev/md0
console=ttyS0,115200n8
最后,编辑/etc/inittab并添加以下类似的行:
7:2345:respawn:/sbin/agetty 115200 ttyS0
你可能还想将ttyS0添加到/etc/securetty中,这样 root 就可以像传统控制台一样登录。
Xen 虚拟机管理器控制台
Xen 通过使用它来访问额外的虚拟机管理器功能,为串行控制台添加了另一层。首先,在串行控制台上按 CTRL-A 三次进入虚拟机管理器控制台。这不会在 VGA 控制台上工作。你会得到一个(XEN)提示。
当你在虚拟机管理器控制台上时,你可以给 Xen 提供几个有用的(或者至少有趣的)命令。尝试输入h以获取帮助或使用其中一个信息性命令,如m。你还可以使机器崩溃、重新启动或转储各种信息。探索并尝试它。
要退出虚拟机管理器控制台,请按 CTRL-A 三次。
Xen 和 LILO
这个部分仅适用于真正的恐龙们,但我们表示同情。为了保持你仿佛消失在神秘过去的感受,我们将使用 Xen 3.0 来展示这个示例。
如果你坚决要使用 LILO 而不是 GRUB,你会很高兴地得知这是可能的。尽管一般认为 LILO 缺少 GRUB 的module指令的等价物,这使得它无法引导 Xen,但可以通过使用mbootpack将虚拟机管理器、dom0 内核和 initrd 合并到一个文件中,来绕过这个问题。
考虑grub.conf中的以下条目:
title slack-xen
root (hd0,0)
kernel /boot/xen.gz
module /vmlinuz-2.6-xen ro root=/dev/hda1 ro
module /initrd-2.6.18-xen.gz
它将虚拟机管理器xen-3.0.gz作为内核加载,然后解压缩vmlinuz-2.6-xen和initrd.gz到内存中。要合并这些文件,首先解压缩:
# cd /boot
# gzcat xen-3.0.gz > xen-3.0
# gzcat vmlinuz-2.6-xen0 > vmlinux-2.6-xen0
# gzcat initrd.gz > initrd.img
注意从vmlinuz到vmlinux的变化。这并不重要,除非它防止你在gzcat过程的开始处覆盖内核。
然后使用mbootpack合并这三个文件:
# mbootpack -o vmlinux-2.6-xen.mpack -m vmlinux-2.6-xen0 -m initrd.gz
-m initrd.img xen3.0
grub.conf条目随后变为lilo.conf条目:
image=/boot/vmlinux-2.6-xen.mpack
label=xen
root=/dev/ram0
最后,运行lilo命令。
# /sbin/lilo
虚拟帧缓冲区
尽管纯粹主义者可能会声称所有管理都应该通过串行端口完成,但我们对于过去 25 年左右一直在使用的这种新奇的图形技术也有话要说。Xen 通过包含一个用于虚拟帧缓冲区的功能,对这些前瞻性信念做出了让步。
你需要编辑你的Config.mk文件来构建 VFB:
XENFB_TOOLS ?= y
在这一点上,你还需要安装 libvncserver 和 libsdl-dev。以你选择的方式安装它们。我们安装了 CentOS 的 SDL-devel 包,并从源代码安装了 libvncserver。然后我们构建了 Xen,并以通常的方式安装它。
要在域内实际使用 framebuffer,你需要在配置文件中指定它。Xen 的最近版本在语法上有所改进。vfb=选项控制虚拟 framebuffer 的所有方面,就像vif=和disk=行控制虚拟接口和虚拟块设备一样。例如:
vfb = [ 'type=vnc, vncunused=1' ]
在这里,我们指定了一个 VNC VFB,并告诉 VNC 服务器在给定数字之上的第一个未使用端口上监听。(我们将在附录 B 中详细介绍可用的选项。)或者,如果你喜欢冒险,还有 SDL 版本:
vfb = [ 'type=sdl' ]
简单。
XenStore 的有趣和有利可图的用途
XenStore 是 Xen 存储运行中的 domUs 信息的配置数据库。尽管 Xen 在设置虚拟设备等关键事务内部使用 XenStore,但你也可以从 domUs 以及 dom0 写入任意数据到其中。将其视为某种跨域套接字。
这打开了许多可能性。例如,理论上,域之间可以协商以获取对共享资源的访问权限。或者,你可以有像过去共享 UNIX 机器上的talk系统一样的东西——在同一主机上运行的人之间的多用户聊天。你可以用它来传播特定于主机的消息,例如,警告人们即将进行的备份或迁移。不过,大多数这样的应用仍然有待编写。
由于没有人提供方便的 shell 样式界面,手动与 XenStore 交互有点不方便。在此期间,我们只能使用查询单个键的工具来凑合。
要查看 XenStore,可以使用xenstore-list命令。以下是从 Xen wiki 中摘录的一个 shell 脚本,它使用xenstore-list递归地导出 xenstore 中的键:
#!/bin/sh
function dumpkey() {
local param=${1}
local key
local result
result=$(xenstore-list ${param})
if [ "${result}" != "" ] ; then
for key in ${result} ; do dumpkey ${param}/${key} ; done
else
echo -n ${param}'='
xenstore-read ${param}
fi
}
for key in /vm /local/domain /tool ; do dumpkey ${key} ; done
你会看到我们有三个硬编码的顶级键:vm、local/domain和tool。这些键对虚拟机管理程序都有明确的用途:vm通过 UUID 存储域信息;local/domain通过 ID 存储域信息(可以说vm以适合迁移的形式导出域数据,而local/domain则用于本地存储);tool存储特定工具的信息。
探索一下,看看键是如何映射你从其他来源(如xm list --long)已知的关于域的信息的。例如,要获取域的内存使用目标,请运行:
# xenstore-read /local/domain/15/memory/target
1048576
XenStore 中的许多键也是可写的。尽管我们不推荐通过写入 XenStore 来调整内存使用,但下一节将给出通过可写 XenStore 键进行跨域通信的示例。
在域启动时自动连接到 VNC 控制台
Xen LiveCD 的一个巧妙特性是,当 Xen 域启动时,它们在完成引导后会自动弹出一个 VNC 窗口。使这一功能成为可能的基础设施是一个位于 domU 中的脚本、一个位于 dom0 中的监听器以及它们之间的 XenBus。
位于 domU 中的脚本vnc-advertiser从 domU 启动脚本中触发,并等待一个 Xvnc 会话开始。当它找到一个会话时,它会写入 XenStore:
xenstore-write /tool/vncwatch/${domid} ${local_addr}${screen}
在 dom0 中,一个相应的脚本会监视对 XenStore 的写入操作。在 LiveCD 上,它被命名为vnc-watcher.py。这个脚本是 XenStore 通用用途的好例子,所以我们将其完整复制在此,并附上详尽的注释:
#!/usr/bin/env python
###
# VNC watch utility
# Copyright (C) 2005 XenSource Ltd
#
# This file is subject to the terms and conditions of the GNU General
# Public License. See the file "COPYING" in the main directory of
# this archive for more details.
###
# Watches for VNC appearing in guests and fires up a local VNC
# viewer to that guest.
###
# Import libraries necessary to interact with the xenstore. Xswatch
# watches a xenstore node and activates a script-defined function
# when the node changes, while xstransact supports standard read and
# write operations.
from xen.xend.xenstore import xswatch
from xen.xend.xenstore.xstransact import xstransact
from os import system
def main():
# first make the node:
xstransact.Mkdir("/tool/vncwatch")
xstransact.SetPermissions("/tool/vncwatch",
{ "dom" : 0,
"read" : True,
"write" : True })
active_connections = {}
# The watchFired method does the actual work of the script. When the
# watcher notes changes to the path "/tool/vncwatch/", it calls
# watchFired with the path (and arguments, which are unused in this
# script).
def watchFired(path, *args, **nargs):
if path == "/tool/vncwatch":
# not interested:
return 1
# If we reach this point, something's changed under our path of
# interest. Let's read the value at the path.
vncaddr = xstransact.Read(path)
print vncaddr
# When the vnc-advertiser notices that Xvnc's shut down in the domU,
# it removes the value from the xenstore. If that happens, the
# watcher than removes the connection from its internal list (because
# presumably the VNC session no longer exists).
if vncaddr == None:
# server terminated, remove from connection list:
if path in active_connections:
active_connections.remove(path)
else:
# server started or changed, find out what happened:
if (not active_connections.has_key(path)) or
active_connections[path] != vncaddr:
# Recall that the vnc-advertiser script writes ${domid}
# ${local_addr}${screen} to the patch /tool/vncwatch/. The watcher
# takes that information and uses it to execute the vncviewer command
# with appropriate arguments.
active_connections[path] = vncaddr system("vncviewer
-truecolour " + vncaddr + " &") return 1
# Associate the watchFired event with a watcher on the path
# "tool/vncwatch"
mywatch = xswatch.xswatch("/tool/vncwatch", watchFired)
xswatch.watchThread.join()
if __name__ == "__main__":
main()
===
我们本希望在这里包含一些其他部分,但截至撰写本文时,它们尚未准备好,例如,目前正在进行的开源努力以构建 Amazon EC2 的克隆或 Project Kemari 正在进行的高可用性工作。
无论如何,请访问我们的网站(prgmr.com/xen/),了解更多关于我们用 Xen 做的酷炫但令人畏惧的日常事情。
此外,如果你在尝试从源代码升级 Xen 时破坏了系统,那么现在正是查看下一章的好时机。
第十五章. 故障排除

希望你只是出于兴趣阅读本章,而不是因为你的服务器刚刚爆发成一座火焰之塔。当然,系统管理员几乎可以说是滑稽地懒惰,后者更有可能,但前者至少是模糊可能的,对吧?
如果机器实际上已经损坏,不要慌张。Xen 很复杂,但这里讨论的问题都是可以通过已知解决方案修复的问题。有一大批工具,大量的信息可以用来工作,以及大量的专业知识可用。
在本节中,我们将概述一系列故障排除步骤和技术,特别关注 Xen 的特有之处。我们将解释一些可能遇到的模糊错误信息,并在所有其他方法都失败时提供一些获取帮助的建议。
让我们从对故障排除方法的概述开始,这将有助于将 Xen 相关问题的具体讨论置于上下文中。
在故障排除时,最重要的是清楚地了解机器的状态:它在做什么,它遇到了什么问题,它吐出了什么电报式错误,以及错误来自哪里。这在 Xen 中尤为重要,因为其模块化和基于标准的架构将各种无关的工具汇集在一起,每个工具都有自己的日志记录和错误处理方法。
我们的常规故障排除技术是:
-
重新复制问题。
-
如果问题生成了错误信息,将其作为起点。
-
如果错误信息没有提供足够的信息来解决问题,请查阅日志。
-
如果日志没有帮助,使用
set -x确保脚本正确执行,并仔细检查系统非 Xen 特定部分的控制流程。 -
使用
strace或pdb跟踪 Xen 特定部分的执行流程,看看哪里失败了。
如果你真的遇到了难题,你可能需要考虑寻求帮助。Xen 有几个优秀的邮件列表(xen-devel和xen-users)和一个有用的 IRC 频道,#xen在irc.oftc.net上。有关如何以及在哪里获取帮助的更多信息,请参阅本章末尾。
故障排除阶段 1:错误信息
最早出现的异常迹象可能是错误信息和突然退出。这些通常是对某些操作的响应——可能是启动机器,或者创建 domU。
Xen 的错误信息可能相当令人恼火。它们有些模糊,面向开发者,通常来自代码深处,难以确定是哪种特定用户错误导致的,甚至无法确定是否是用户错误。
比我们更好的管理员已经疯了,把机器扔出窗外,发誓余生要穿动物皮,用烧硬的矛捕猎。谁能说他们错了?
不论如何,错误信息是有用的诊断工具,并且通常提供足够的信息来解决该问题。
Dom0 引导错误
在引导过程中寻找有关系统级问题信息的地方(如果只有因为机器引导时没有其他事情可做)是引导输出,包括管理程序和 dom0 内核的输出。
读取引导错误信息
当一台机器损坏到无法引导的程度时,它通常会立即重启。这可能导致在尝试诊断问题时遇到困难。我们建议使用带有某种回滚缓冲区的串行控制台来在其他计算机上保留消息。这也使得记录输出变得容易,例如使用 GNU screen。
如果你拒绝使用串行控制台,或者如果你希望在系统重启之前做其他事情,你可以在 GRUB 中的 Xen 和 Linux 内核行上附加 noreboot。(如果你遗漏了任何一个,它将重启。它在这方面很挑剔。)
我们在引导过程中遇到的大多数 Xen 特定问题都与内核/管理程序不匹配有关。Xen 内核必须在 PAE 支持方面与 dom0 内核相匹配,如果管理程序是 64 位,dom0 必须是 64 位或 i386-PAE。当然,如果管理程序是 32 位,dom0 也必须是 32 位。
你可以使用 i386-PAE dom0 与 x86_64 管理程序和 x86_64 domUs 一起运行,但仅限于最近的 Xen 内核(实际上,这是 Citrix Xen 产品的一些版本所做的事情)。在任何情况下,都不能不匹配 PAE。Xen 的现代版本甚至不包含在 i386 非 PAE 模式下运行的编译时选项,如果你想要运行像 NetBSD 4 这样的旧操作系统,这会导致各种问题。
当然,我们在引导过程中遇到的问题中,许多并不是特别针对 Xen 的;例如,如果 initrd 没有正确匹配内核,机器可能无法正确引导。当人们迁移到 Xen.org 内核时,这通常会引起麻烦,因为它将根设备的驱动程序放入 initrd,而不是内核中。
如果你的发行版期望一个 initrd,你可能在安装 Xen.org 内核后想要使用你的发行版的 initrd 创建脚本。对于 CentOS,在安装 Xen.org 内核后,确保 /etc/modprobe.conf 正确描述了你的根设备(例如,有一个条目 alias scsi_hostadapter sata_nv),然后运行类似以下命令:
# mkinitrd /boot/initrd-2.6.18.8-xen.img 2.6.18.8-xen
将 /boot/initrd-2.6.18.8-xen.img 替换为你的新 initrd 所需的文件名,并将 2.6.18.8-xen 替换为你为构建 initrd 的内核运行的 uname -r 的输出。(其他选项,如 --preload,也可能很有用。请参阅发行版手册以获取更多信息。)
假设你已经成功引导,Xen 可以提供各种有用的错误信息。通常这些是对尝试做某事(如启动 xend 或创建一个域)的反应。
DomU 预引导错误
如果您正在使用 PyGRUB(或另一个引导加载程序,如 pypxeboot),您可能会看到消息 VmError: Boot loader didn't return any data! 这意味着由于某种原因,PyGRUB 无法找到内核。通常这是由于磁盘设置不正确或 domU 中没有有效的 GRUB 配置。检查磁盘配置并确保 /boot/grub/menu.lst 存在于第一个 domU VBD 的文件系统中。
注意
有一些灵活性;PyGRUB 会检查一些文件名,包括但不限于 /boot/grub/menu.lst, /boot/grub/grub.conf, /grub/menu.lst, 以及 /grub/grub.conf。记住,PyGRUB 是 GRUB 的良好模拟,但它并不完全精确。
您可以通过手动运行 PyGRUB 来排除 PyGRUB 问题:
# /usr/bin/pygrub type:/path/to/disk/image
这应该会给出一个 PyGRUB 启动菜单。当您从菜单中选择一个内核时,PyGRUB 会退出并显示类似的消息:
Linux (kernel /var/lib/xen/boot_kerne.hH9kEk)(args "bootdev=xbd1")
这意味着 PyGRUB 成功加载了内核并将其放置在 dom0 文件系统中。检查列出的位置以确保它确实在那里。
PyGRUB 对其连接的终端非常挑剔。如果 PyGRUB 退出,抱怨 libncurses,或者如果同一域中的 PyGRUB 对某些人有效而对另一些人无效,您可能遇到了终端问题。
例如,使用 CentOS 5.1 中的 PyGRUB 版本,您可以通过在少于 19 行的终端窗口中执行 xm create -c 来反复遇到失败。如果您怀疑这可能是个问题,请调整您的控制台大小为 80 x 24 并再次尝试。
PyGRUB 还会期望在 terminfo 数据库中找到您的终端类型(TERM 变量的值)。在创建域之前手动设置 TERM=vt100 通常足够。
在低内存条件下创建域
这是 Xen 工具箱中最有信息量的错误消息之一:
XendError: Error creating domain: I need 131072 KiB, but dom0_min_mem
is 262144 and shrinking to 262144 KiB would leave only -16932 KiB
free.
这个错误意味着系统没有足够的内存来创建按请求的 domU。(在这个例子中,系统只有 384MiB,所以这个错误并不令人惊讶。)
解决方案是调整 dom0_min_mem 以补偿或调整 domU 以减少内存需求。或者,在这种情况下,两者都做(并可能添加更多内存)。
在 DomU 中配置设备
很可能,如果 domU 由于缺少设备而无法启动,问题与存储有关。(网络设置损坏通常不会导致启动失败,尽管它们可能会在启动后使您的虚拟机变得几乎无用。)
有时 domU 会加载其内核并通过其启动序列的第一部分,但会抱怨无法访问其根设备,尽管根内核参数已正确指定。很可能是 domU 在 initrd 的 /dev 目录中没有根设备节点。
这可能导致尝试使用语义上更正确的xvd*设备时出现问题。因为许多发行版没有包括适当的设备节点,它们将无法启动。因此,解决方案是使用disk=行中的hd*或sd*设备,如下所示:
disk = ['phy:/dev/tempest/sebastian,sda1,r']
root = "/dev/sda1"
成功启动域后,您可以正确创建xvd设备或编辑您的 udev 配置。
如果 domU 内核包含 SCSI 驱动程序,Xen 块驱动程序可能也难以连接到使用sdX命名约定的虚拟驱动器。在这种情况下,使用xvdX约定,如下所示:
disk = ['phy:/dev/tempest/sebastian,xvda1,r']
故障排除磁盘
大多数与磁盘相关的错误会导致 domU 创建立即失败。这使得它们相当容易进行故障排除。以下是一些示例:
Error: DestroyDevice() takes exactly 3 arguments (2 given)
这些经常出现,通常意味着设备规范中存在问题。检查配置文件中vif=和disk=行是否有误。如果消息指的是块设备,问题通常是你引用了一个不存在的设备或文件。
有一些其他错误具有类似的原因。例如:
Error: Unable to find number for device (cdrom)
这通常也是由于一个phy:设备具有错误指定的后端设备引起的。
然而,这并不是唯一可能的原因。如果你使用的是基于文件的块设备,而不是 LVM 卷,内核可能已经耗尽了可以挂载这些设备的块循环。(在这种情况下,消息尤其令人沮丧,因为它似乎完全独立于域的配置。)你可以通过查找日志中的错误来确认这一点:
Error: Device 769 (vbd) could not be connected. Backend device not found.
虽然这个消息通常意味着你输入了域的后备存储设备名称错误,但它也可能意味着你耗尽了块循环。默认循环驱动程序只创建了七个这样的设备——对于带有根和交换设备的三个域来说几乎不够。
我们可能建议你迁移到 LVM,但这可能是过度杀鸡用牛刀。更直接的回答是创建更多的循环。如果你的循环驱动程序是一个模块,编辑/etc/modules.conf并添加:
options loop max_loop=64
或你选择的另一个数字;每个 domU 基于文件的 VBD 在 dom0 中都需要一个循环设备。(在用作后端的任何域中执行此操作,通常是 dom0,尽管 Xen 的新 stub 域承诺将非 dom0 驱动程序域的普及度提高很多。)然后重新加载模块。关闭所有使用循环设备的域(并将循环从 dom0 中分离),然后运行:
# rmmod loop
# insmod loop
如果循环驱动程序集成在内核中,你可以在 dom0 内核命令行中添加max_loop选项。例如,在/boot/grub/menu.lst中:
module linux-2.6-xen0 max_loop=64
重新启动后,问题应该会消失。
虚拟机重启过快
磁盘问题,如果它们没有通过特定的错误消息宣布自己,通常会表现为以下日志条目:
[2007-08-23 16:06:51 xend.XendDomainInfo 2889] ERROR
(XendDomainInfo:1675) VM sebastian restarting too fast (4.260192
seconds since the last restart). Refusing to restart to avoid loops.
这实际上是 Xen 请求帮助的一种方式;该域卡在重启循环中。使用带有-c选项(用于控制台自动连接)启动域,查看导致它在启动时死亡的原因。在这种情况下,域启动后立即因为缺少根设备而崩溃。
注意
在这种情况下,虚拟机每 4.2 秒重启一次,足够长以获取控制台输出。如果重启速度太快,小于 1 或 2 秒,通常xm create -c不会显示输出。如果发生这种情况,请检查日志以获取信息性消息。本章后面的部分将提供有关 Xen 日志的更多详细信息。
排查 Xen 的联网问题
根据我们的经验,在具备一些基本的网络知识的情况下,排查 Xen 的联网问题是一个直接的过程。除非你修改了网络脚本,否则 Xen 会相当可靠地创建vif设备。然而,如果你遇到问题,这里有一些通用的指南。(我们将重点关注network-bridge,尽管类似的步骤也适用于network-route和network-nat。)
要排查联网问题,你真的需要了解 Xen 是如何进行联网的。有许多脚本和系统协同工作,分解每个问题并将其隔离到适当的组件是很重要的。查看第五章以了解 Xen 网络组件的概述。
首件事是使用status参数运行网络脚本。例如,如果你使用network-bridge,则/etc/xen/scripts/network-bridge status将提供在 dom0 中看到的网络状态的有助于诊断的转储。此时,你可以使用brctl show来更详细地检查网络,并使用xm vnet-create和vnet-delete命令与用户空间工具的其余部分结合,以获得正确配置的桥接和 Xen 虚拟网络设备。
当你解决了后端问题后,你可以处理前端问题。检查日志,并在 domU 内部检查dmesg,以确保 domU 正在初始化其网络设备。
如果这些看起来正常,我们通常会从下到上更系统地解决问题。首先,确保相关的设备出现在 domU 中。Xen 会相当可靠地创建这些设备。如果它们不存在,请检查 domU 的配置和日志,寻找相关的错误信息。
在下一级(因为我们知道 dom0 的联网是正常工作的,对吧?)我们想要检查链路是否正常工作。我们基本的工具是在 domU 内部使用arping,结合在 dom0 中 domU 接口上的tcpdump -i [interface]。
# xm list
Name ID Mem VCPUs State Time(s)
Domain-0 0 1024 8 r----- 76770.8
caliban 72 256 1 -b---- 4768.3
在这里,我们将演示域caliban(IP 地址 192.0.2.86)与 dom0(位于 192.0.2.67)之间的连接性。
# arping 192.0.2.67
ARPING 192.0.2.67 from 192.168.42.86 eth0
Unicast reply from 192.0.2.67 [00:12:3F:AC:3D:BD] 0.752ms
Unicast reply from 192.0.2.67 [00:12:3F:AC:3D:BD] 0.671ms
Unicast reply from 192.0.2.67 [00:12:3F:AC:3D:BD] 2.561ms
注意,当通过 ARP 查询时,dom0 会回复其 MAC 地址。
# tcpdump -i vif72.0
tcpdump: WARNING: vif72.0: no IPv4 address assigned
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on vif1.0, link-type EN10MB (Ethernet), capture size 96 bytes
18:59:33.704649 arp who-has caliban (00:12:3f:ac:3d:bd (oui Unknown)) tell
192.168.42.86
18:59:33.707406 arp reply caliban is-at 00:12:3f:ac:3d:bd (oui Unknown)
18:59:34.714986 arp who-has caliban (00:12:3f:ac:3d:bd (oui Unknown)) tell
192.168.42.86
ARP 查询在 dom0 中正确显示。
现在,大多数情况下,你会在tcpdump中看到适当的输出,如所示。这表明 Xen 正在将数据包从 domU 移动到 dom0。你是否看到了对 ARP who-has 的响应?(应该是 ARP is-at。)如果没有,可能你的 dom0 中的桥接设置不正确。检查桥接的一个简单方法是通过运行brctl show:
# brctl show
bridge name bridge id STP enabled interfaces
eth0 8000.00304867164c no caliban
prospero
ariel
注意
在 Xen.org 版本低于 Xen 3.2 之前,默认的桥接名称是xenbr0,用于network-bridge。然而,Xen 3.2 及以后的版本将桥接名称命名为 eth0(在这种情况下,0 是相关网络接口的编号)。RHEL/CentOS 默认创建另一个桥接,名为virbr0,它是 libvirt 组件的一部分。在实际情况中,它类似于network-nat,由 DHCP 服务器在 dom0 上分配私有地址。
现在,为了故障排除的目的,一个桥接就像一个交换机。确保你的 domU 接口连接到的桥接(交换机)也连接到接触你想要 domU 所在的网络的接口,通常是一个pethX设备。(如第五章中所述,network-bridge在启动时将ethX重命名为pethX,并从vif0.x创建一个假的ethX设备。)
检查简单的事情。桥接上是否有其他设备可以看到来自外部世界的流量?执行tcpdump -n -i peth0。数据包是否正常流动?
检查你的路由。不要忘记更高层次的东西,比如 DNS 服务器。
DomU 接口编号在每次重启时增加
当 Xen 创建一个域时,它会查看vif=[]语句。[]字符内的每个字符串(它是一个 Python 数组)都是另一个网络设备。如果我只说vif=['',''],它就会为我创建两个具有随机 MAC 地址的网络设备。在 domU 中,它们理想上被命名为eth0和eth1。在 dom0 中,它们被命名为vifX.0和vifX.1,其中X是域编号。
大多数现代 Linux 发行版默认在第一次启动时将ethX锁定到特定的 MAC 地址。在 RHEL/CentOS 中,设置是HWADDR=在/etc/sysconfig/network-scripts/ifcfg-ethX中。大多数其他发行版使用udev来处理持久 MAC 地址,如第五章中所述。我们通过在xm config文件中的vif=行上指定 MAC 地址来规避这个问题:
vif=['mac=00:16:3E:AA:AA:AB','mac=00:16:3E:AA:AA:AC']
在这里,我们使用 XenSource MAC 前缀00:16:3E。如果你的 MAC 地址以这个前缀开始,你知道它不会与任何分配的硬件 MAC 地址冲突。
如果你没有指定 MAC 地址,每次 domU 启动时都会随机生成,如果你的 domU 操作系统将ethX锁定到特定的 MAC 地址,这可能会带来一些不便。有关可能的影响以及为什么指定 MAC 地址是一个好主意,请参阅第五章。
iptables
iptables 规则也可能是 Xen 出现问题的原因。与任何 iptables 设置一样,很容易以微妙的方式出错并破坏一切。我们找到的确保 iptables 规则正常工作的最佳方法是发送数据包并观察它们发生了什么。运行 iptables -L -v 以查看每个规则被击中或受链策略影响的包计数器。
注意
从 dom0 端检查的 vif 接口计数器将被反转;出站流量将报告为入站,反之亦然。有关为什么会出现这种情况的更多信息,请参阅第五章。
你可能也会遇到反欺骗无法正常工作的问题。如果你启用了反欺骗但发现你仍然可以在 domU 中欺骗任意 IP 地址,请将以下内容添加到你的网络启动脚本中:
echo 1 >/proc/sys/net/bridge/bridge-nf-call-iptables
这将导致通过网桥发送的数据包穿越前向链路,其中 Xen 放置了反欺骗规则。我们已将命令添加到 /etc/xen/scripts/network-bridge 文件的末尾。
如果你正在使用我们建议在第五章中使用的 vifnames,可能会出现另一个问题。确保名称短——不超过八个字符。较长的名称可能会被截断,并且系统的不同部分可能在不同的长度处截断(至少在 CentOS 5.0 中)。在我们特定的案例中,我们看到了实际 vifnames 在一个长度处被截断,而我们的防火墙规则(用于反欺骗)在另一个长度处被截断,阻止了来自相关域的所有数据包。最好避免这个问题并保持 vifnames 短。
内存问题
当内存不足时,Xen(或者更确切地说,Linux 驱动程序域)可能会表现得相当奇怪。由于 Xen 和 dom0 需要一定量的连续、不可交换的内存,因此在我们经验中,发现 oom-killer 像吃糖果一样吞噬进程是惊人的容易。即使有足够的交换空间,这种情况也可能发生。
我们找到的最佳解决方案——我们坦白地说,这并不完美——是给 dom0 分配更多的内存。我们还更喜欢将其内存分配固定在 512MB 左右,这样它就不必应对 Xen 不断调整其内存大小。
调整 dom0 内存分配的基本方法是调整 dom0_mem 内核参数,它设置一个上限,以及 /etc/xen/xend-config.sxp 文件中的 dom0-min-mem 参数,它设置一个下限。同样,我们通常将这两个参数设置为相同的值。
要设置 dom0 可用的最大内存量,请编辑 menu.lst 文件,并在内核行之后放置选项,如下所示:
kernel /xen.gz dom0_mem=512M noreboot
如果没有单位,Xen 将假设该值以 KB 为单位。
接下来,编辑 /etc/xen/xend-config.sxp 文件并添加一行,内容如下:^([85])
(dom0-min-mem 512)
我们这样做是因为我们看到了 dom0 在膨胀方面存在问题。膨胀通常可以工作,但,就像从非静默文件系统备份一样,“通常可以工作”对于像 dom0 这样重要的东西来说还不够好。
^([85]) Xen 的最新版本也支持(enable-dom0-ballooning no)选项。
其他消息
xenconsole: Could not read tty from store: No such file or directory
这条消息通常是在尝试连接到域的虚拟控制台时出现的(尤其是在 Xen 的内核与其用户空间不匹配时;例如,如果我们已经升级了 Xen 的支持工具而没有更改虚拟机管理程序)。
如果这是一个半虚拟化域,首先尝试杀死并重新启动xenconsoled进程。确保它已经停止。我们见过xenconsoled挂起,必须使用-9强制停止的情况。
# pkill xenconsoled && /usr/sbin/xenconsoled
然后使用xm console重新连接。
如果问题仍然存在,你很可能是试图访问一个没有配置必要的 Xen 前端控制台设备的域。有几种可能性:如果这是一个自定义内核,你可能只是忘记包含它,例如。检查域内核和 initrd 中 xvc 驱动程序的配置。
如果你正在访问运行默认(非启发式)内核的 HVM 域,该内核不包括控制台驱动程序,请尝试使用 framebuffer 或启动不同的内核。你还可以在域配置文件中设置serial=pty,并将 domU 操作系统设置为使用 com1 作为控制台。参见第十二章以获取详细信息。
VmError: (22, 'Invalid argument')
这个错误可能意味着许多事情。通常问题是工具和运行的 Xen 虚拟机管理程序之间的版本不匹配。尽管安装在/usr/sbin中的二进制文件可能是正确的,但底层的 Python 模块可能是错误的。请确保它们是正确的,使用任何可用的证据进行检查:日期、文件中的注释、xm info的输出等等。
这个错误也可能表明 PAE 不匹配。在这种情况下,xend-debug.log将给出关于问题的简短描述:
# tail /var/log/xen/xend-debug.log
ERROR: Non PAE-kernel on PAE host.
ERROR: Error constructing guest OS
顺便说一句,你的 dom0——毕竟,它只是一个特殊的 Xen 客户域——也可能遇到这个问题。如果发生这种情况,虚拟机管理程序将在启动时报告一个大的错误消息中的 PAE 不匹配,并立即重新启动。
"no version for struct_module found: kernel tainted"
我们在尝试在 Slackware 机器上安装二进制 Xen 发行版时遇到了这个错误。二进制发行版附带了一个非常基础的内核,因此需要一个带有适当模块的 initrd。由于某种原因,默认脚本以错误的顺序加载了模块,导致某些加载失败并出现前面的消息。
我们通过更改 initrd 中的加载顺序来解决这个问题;具体方向将取决于你的发行版。
持续的 4GiB 段修复消息流
有时,在启动新安装的 i386 域时,你会看到满屏类似的消息:
4gb seg fixup, process init (pid 1), cs:ip 73:b7ec2fc5
这些与/lib/tls问题相关:Xen 抱怨因为它必须为使用负偏移访问堆栈的一些进程模拟一个 4GiB 段。你也可能在启动时看到一个巨大的消息,提醒你解决这个问题。
为了解决这个问题,你想要使用不执行此操作的 glibc。你可以使用 -mno-tls-direct-seg-refs 选项编译 glibc,或者为你的发行版安装适当的 libc6-xen 软件包(Red Hat 类型和 Debian 类型的发行版都创建了软件包来解决这个问题)。
对于 Red Hat(及其衍生发行版),你还可以运行以下命令:
# echo 'hwcap 0 nosegneg' > /etc/ld.so.conf.d/libc6-xen.conf
# ldconfig
这将指示动态加载器避免这种特定的优化。
对于基于 Debian 的发行版(使用 2.6.18 内核),你可以简单地运行:
# apt-get install libc6-xen
如果所有其他方法都失败了(或者你太懒了,不想找到一个带有 no-tls-direct-seg-refs 的 gcc 版本),你可以按照错误信息建议的那样,将 TLS 库移开:
# mv /lib/tls /lib/tls.disabled
根据我们的经验,移动库没有问题。一切都将按预期继续运行。
磁盘驱动程序的重要性(initrd 问题)
在使用发行版内核时,Xen domU 通常可以引导,但无法找到其根设备。例如:
VFS: Cannot open root device "sda1" or unknown-block(0,0)
Please append a correct "root=" boot option
Kernel panic - not syncing: VFS: Unable to mount root fs on unknown-block(0,0)
在这里,至少在这个案例中,根本问题在于 domU 内核没有编译进必要的驱动程序,并且没有指定 ramdisk。查看引导输出可以确认这一点,其中包含以下消息:
XENBUS: Device with no driver: device/vbd/769
XENBUS: Device with no driver: device/vbd/770
XENBUS: Device with no driver: device/vif/0
几乎所有发行版内核都包含一个最小内核,并且需要带有磁盘驱动程序的 initrd 来完成引导。这些消息可能只是来自在 initrd 加载之前的内核,或者如果 initrd 不包含必要的驱动程序,它们可以指示一个严重问题。
如果内核成功加载了其 initrd 并未能切换到其真实根目录,你将发现自己卡在 initrd 中,文件选择非常有限。在这种情况下,请确保你的设备存在(例如,本例中的 /dev/sda1)并且你已经安装了 Xen 磁盘前端内核模块。
我们也经常在内核升级(以及新的 initrd)后看到 PyGRUB domUs 中出现这种情况,如果模块配置(在 Debian 上为 /etc/modules,在 Red Hat 上为 /etc/modprobe.conf)没有指定 xenblk。对于 RHEL/CentOS domUs,你可以通过运行带有 --preload xenblk 选项的 mkinitrd 来解决这个问题。
如果你使用外部内核并想使用发行版内核,你必须指定域配置文件中的 ramdisk= 行,并指定包含 xenblk(如果你想在引导前使用网络,还需要 xennet)驱动程序的 ramdisk。
解决这个问题的另一个方法是从源代码编译 Xen 并构建一个足够通用的 domU 内核,其中已经编译了 xenblk 和 xennet 驱动程序。即使你继续从发行版内核(可能是一个好主意)引导 dom0,这也会避开 Red Hat 和 Debian 内核中发现的特定于发行版的问题。
这可能会对某些 domU 发行版造成问题,因为预期的 initrd 不会在那里。有时,在带有内置磁盘驱动程序的内核上构建 initrd 可能很困难。然而,通用内核通常至少可以引导。
我们通常发现将这两个通用内核作为 domU PyGRUB 配置中的二级救援启动选项很有用,因为无论 initrd 有多混乱,它们都能正常工作。
XenStore
有时 XenStore 会损坏,或者xenstored进程崩溃,或者由于各种其他原因,XenStore 停止存储和报告信息。例如,如果包含 XenStore 数据库的块设备已满,就可能会发生这种情况。
最明显的症状是xm list将报告域名称错误,例如:
# xm list
Name ID Mem(MiB) VCPUs State Time(s)
Domain-0 0 2554 2 r----- 16511.2
Domain-10 10 127 1 -b---- 1671.5
Domain-11 11 255 1 -b---- 442.0
Domain-14 14 63 1 -b---- 1758.2
Domain-15 15 62 1 -b---- 7507.7
Domain-16 16 127 1 -b---- 11194.9
Domain-6 6 94 1 -b---- 5454.2
Domain-7 7 62 1 -b---- 270.8
Domain-9 9 127 1 -b---- 1715.7
显然,这是问题。首先,这意味着所有可以接受名称或 ID 的命令,如xm console,将不再识别名称。
不幸的是,xenstored 不能被重新启动,所以你必须重新启动。如果你运行的是 Xen 3.1 之前的版本(包括 RHEL 5.x 版本),你必须首先删除 /var/lib/xenstored/tdb,然后重新启动。
Xen 的日志
这些错误信息是 Xen 故障排除的良好起点,但有时它们不足以解决问题。在这些情况下,我们需要深入挖掘。
dmesg 和 xm dmesg
虽然通常意义上的日志文件不是xm dmesg的输出,但它是一个重要的诊断输出源。如果你遇到的问题从错误信息中不明显,首先查看 Xen 内核消息缓冲区。正如你可能知道的,Linux dmesg命令打印出 Linux 内核的消息缓冲区,通常包含自系统上次启动以来的所有内核消息(或者,如果系统运行了一段时间,它将显示一系列无聊的状态消息)。
因为 Xen 可以说是一个自己的内核,它包括一个等效的工具,xm dmesg,用于打印出管理程序启动时的消息(启动消息中以(XEN)开头的行)。例如:
# xm dmesg | tail -3
(XEN) (file=platform_hypercall.c, line=129) Domain 0 says that IO-APIC
REGSEL is good
(XEN) microcode: error! Bad data in microcode data file
(XEN) microcode: Error in the microcode data
在这种情况下,错误是无害的。处理器只是在其出厂预装的微码上运行。
注意
就像内核一样,Xen 只保留固定大小的消息缓冲区。较旧的消息将消失在无垠之中。
日志和 Xen 写入的内容
如果xm dmesg没有提供有用的信息,Xen 的下一条通信途径是其广泛的日志记录。让我们看看 Xen 使用的各种日志以及我们可以做什么。
我们可以按以下顺序总结 Xen 的日志,按重要性粗略排序:
-
/var/log/xen/xend.log
-
/var/log/xen/xend-debug.log
-
/var/log/xen/xen-hotplug.log
-
/var/log/syslog
-
/var/log/debug
大多数的 Xen 故障排除都将涉及前两个日志。xend.log 是主要的 xend 日志,正如你可能想象的那样。它记录了域的启动、关闭、设备创建、调试等,偶尔还会包括巨大的难以理解的 Python 转储。这是首先要检查的。
xend-debug.log 包含与 Xen 的更多实验性功能相关的信息,例如帧缓冲区。当 Xen 遇到问题时,它还会包含详细的回溯信息。
因为xend使用 syslog 设施,Xen 的消息也会出现在系统级的/var/log/syslog和/var/log/debug中。
注意
我们急忙补充说,syslog 的配置几乎是幽默的。即使是术语系统级也仅适用于默认配置;syslog 可以跨多个主机合并日志,将消息分类到各种通道,写入任意文件等等,但我们假设,如果您已经配置了 syslog,您可以将我们关于 Xen 使用它的说法应用到您的配置中。
最后,如果您使用 HVM,qemu-dm将写入它自己的日志。总的来说,您可以安全地忽略这些日志。根据我们的经验,HVM 域的问题并不是 QEMU 设备仿真的过错。
如果内核消息证明无法提供启示,那么是时候查看日志文件了。首先,让我们配置 Xen 以确保它们尽可能圆滑、坚实和完全填充。
调试构建的重要性
对于故障排除(实际上,对于一般使用),我们建议使用所有调试选项构建 Xen。这使得错误信息更加丰富和有用,更容易找出问题所在,并希望消除它们。
虽然大量的调试输出可能会造成性能影响,但根据我们的经验,在正常运行 Xen 时它几乎可以忽略不计。调试构建为您提供了在 Xen 上运行大量调试输出的选项,但如果不使用该模式,其性能与正常构建相当。如果您发现错误信息无帮助,确保您已经将所有调试旋钮设置为完全可能是个好主意。为了为虚拟机管理程序启用完整输出,请将loglvl=all guest_loglvl=all选项添加到您的虚拟机管理程序命令行(通常在/boot/grub/menu.lst中)。
有关构建 Xen 的更多信息,包括如何设置调试选项,请参阅第十四章。
应用调试器
即使是最大详细度的日志记录也不够,那么是时候在 Python 级别上攻击问题,使用调试器。
一个可以尝试的调查是运行xend服务器在前台并观察其调试输出。这将让您看到比仅仅跟踪日志更多的一些信息。
在当前版本的 Xen 中,调试功能包含在发布中.^([86]) 使用以下命令启用调试输出:
# export XEND_DEBUG=1
# export XEND_DAEMONIZE=0
# xend start
这将启动xend在前台,并告诉它在执行过程中打印调试信息。
您还可以通过设置XENSTORED_TRACE=1来获取 XenStore 的大量调试信息,可能是在xend的环境变量中,例如在/etc/init.d/xend的顶部或在 root 的.bashrc中。
Xen 的后端架构:理解调试信息
当然,所有这些调试输出如果对 Xen 的结构有所了解会更有用。
如果你查看实际的xend可执行文件,你首先会注意到它真的很短。里面没什么内容;所有的重活都是在外部 Python 库中完成的,这些库位于 Python 库目录中的/xen/xend/server。 (在我面前的系统中,这是/usr/lib/python2.4/site-packages/xen/xend/server。)
同样,xm也是一个简短的 Python 脚本。这里的关键信息是,你将看到的绝大多数错误消息都来自这个目录树中的某个地方,并且它们会友好地打印出负责的文件和行号,这样你就可以更仔细地检查 Python 脚本。例如,看看/var/log/xen/xend.log中的这一行:
[2007-08-07 20:14:26 6008] WARNING (XendAPI:672) API call:
VM.get_auto_power_on not found
开头是日期、时间和xend的进程 ID (PID)。然后是错误的严重性(在这种情况下,WARNING,这仅仅令人烦恼)。之后是错误发生的位置的文件和行号,接着是错误消息的内容。
XEN 的信息消息层次结构
WARNING只是消息连续体上的一个点。在严重性最低的极端,我们有DEBUG,开发者会使用它来输出任何他们感兴趣的内容。这通常很有用,但会产生大量数据需要处理。稍微重要一些的是INFO。这个级别的消息应该是管理员感兴趣或有用的,但不应该表明存在问题。
然后是WARNING,这表明存在问题,但不是关键问题。例如,之前的消息告诉我们,如果我们依赖于VM.get_auto_power_on函数,我们可能会遇到麻烦,但如果我们不尝试使用它,就不会发生任何坏事。
最后,Xen 使用ERROR来表示真正的、无法否认的错误——那种不能推迟或忽视的事情。通常这意味着一个域正在异常退出。
带着这些信息,你可以做几件事情。继续我们之前的例子,我们将打开/usr/lib/python2.5/site-packages/xen/xend/XendAPI.py,并在文件顶部附近添加一行来导入调试模块pdb。
import pdb
做完这些之后,你可以设置一个断点。只需在行 672 附近添加一行:
pdb.set_trace()
然后尝试重新运行服务器(或重做你关心的任何其他行为),并注意当xend遇到你新设置的断点时,它会启动调试器。
到这个阶段,你可以做在调试器中可能期望做的任何事情:改变变量的值,逐步执行函数,逐步进入子例程等等。在这种情况下,我们可能会回溯,找出为什么它试图调用VM.get_auto_power_on,并可能将其包裹在错误处理块中。
域保持阻塞状态
这个标题有点误导。实际情况是,像xm list这样的工具报告的“阻塞”状态仅仅意味着该域处于空闲状态。真正的问题是该域似乎没有响应。
通常我们发现这个问题与控制台有关;例如:
[root@localhost ~]# xm create -c sebastian.cfg
Using config file "/etc/xen/sebastian.cfg".
Going to boot Fedora Core (2.6.18-1.2798.fc6xen)
kernel: /vmlinuz-2.6.18-1.2798.fc6xen
initrd: /initrd-2.6.18-1.2798.fc6xen.img
Started domain sebastian
rtc: IRQ 8 is not free.
i8042.c: No controller found.
(然后无限期地挂起)。当我们跳出并查看 xm list 的输出时,我们注意到域保持阻塞状态并且消耗的 CPU 时间非常少。
[root@localhost ~]# xm list
Name ID Mem(MiB) VCPUs State Time(s)
Domain-0 0 3476 2 r----- 407.1
sebastian 13 499 1 -b---- 19.9
快速查看 /var/log/xen/xend-debug.log 提示了一个答案:
10/09/2007 20:11:48 Autoprobing TCP port
10/09/2007 20:11:48 Autoprobing selected port 5900
端口 5900 是 VNC。啊!问题是 Xen 没有使用 xm 控制连接到的虚拟控制台设备。在这种情况下,我们将其追溯到用户错误。我们指定了帧缓冲区并忘记了它。内核按照指示,使用帧缓冲区作为控制台而不是我们预期的仿真串行控制台。当我们启动 VNC 客户端并连接到端口 5900 时,它给了我们预期的图形控制台。
注意
如果我们把一个 getty 放在 xvc0 上,即使我们看不到引导输出,当机器启动时至少会得到一个登录提示。
热插拔调试
Xen 在 dom0 和 domU 中广泛使用 udev 来创建和销毁虚拟设备。它与 Linux 的热插拔子系统的交互大部分记录在 /var/log/xen/xen-hotplug.log 中。(我们将热插拔视为与 udev 同义词,因为我们想不出任何仍在使用 pre-udev 热插拔实现的系统。)
首先,我们检查脚本的效果。在这种情况下,我们使用 udevmonitor 来查看 udev 事件。它应该显示每个 vif 和 vbd 的 add 事件以及 vif 的 online 事件。这些事件通过 /etc/udev/rules.d/xen-backend.rules 中的规则进行,该规则在 /etc/xen/scripts 中执行适当的脚本。
到这一点,你可以添加一些额外的日志。在对你感兴趣的设备(例如,blktap)的脚本顶部添加:
set -x
exec 2>>/var/log/xen-hotplug.log
这将导致 shell 扩展脚本中的命令并将它们写入 xen-hotplug.log,使你(希望)能够追踪问题的根源并消除它。
热插拔也可以作为任何虚拟设备问题的万能解决方案。一些与热插拔相关的错误以令人恐惧的 Hotplug 脚本不工作 消息的形式出现,如下所示:
Error: Device 0 (vkbd) could not be connected. Hotplug scripts not working.
这似乎与以下类似的消息有关:
DEBUG (DevController:148) Waiting for devices irq.
DEBUG (DevController:148) Waiting for devices vkbd.
DEBUG (DevController:153) Waiting for 0.
DEBUG (DevController:539) hotplugStatusCallback
/local/domain/0/backend/vkbd/4/0/hotplug-status
在这个情况下,然而,这些信息最终证明是误导。答案出现在 xend-debug.log 文件中,它说:
/usr/lib/xen/bin/xen-vncfb: error while loading shared libraries:
libvncserver.so.0: cannot open shared object file: No such file or
directory
随着问题的逐步发展,libvncserver 被安装在 /usr/local,而运行时链接器之前一直在忽略它。在将 /usr/local/lib 添加到 /etc/ld.so.conf 之后,xen-vncfb 开始顺利启动。
strace
一个重要的通用故障排除技术是使用 strace 来查看 Xen 控制工具实际上在做什么。例如,如果 Xen 无法找到外部二进制文件(如 xen-vncfb),strace 可以通过以下命令揭示该问题:
# strace -e trace=open -f xm create prospero 2>&1 | grep ENOENT | less
不幸的是,它还会在 Python 根据对文件名的粗略猜测拉入其整个运行时环境的同时,给你带来很多其他完全无害的输出。
strace 的另一个有用例子来自我们设置 PyGRUB 时:
# strace xm create -c prospero
(snipped)
mknod("/var/lib/xen/xenbl.4961", S_IFIFO|0600) = -1 ENOENT (No such file or
directory)
结果证明,我们没有 PyGRUB 后端所需的目录。因此:
# mkdir -p /var/lib/xen/
一切都正常工作。
^([86]) 以前你不得不下载补丁并重新构建。幸运的是,现在不再是这种情况了。
Python 路径问题
Python 路径本身可能会引起一些烦恼。就像你有你的 shell 可执行路径、manpath、库路径等等一样,Python 也有它自己的内部搜索路径,它会检查模块。如果路径不包括 Xen 模块,你可能会遇到以下错误:
# xm create -c sebastian.cfg
Using config file "/etc/xen/sebastian.cfg".
Traceback (most recent call last):
File "/usr/bin/pygrub", line 26, in ?
import grub.fsys
ImportError: No module named fsys
不幸的是,调整搜索路径的机制并不完全直观。在大多数情况下,我们只能退而求其次,创建一些符号链接或将 Xen 文件移动到 Python 路径中已经存在的某个目录。
正确的解决方案是在 Python 路径中已经存在的某个目录中添加一个.pth文件。这个.pth文件应该包含包含 Python 模块的目录的路径。例如:
# echo "/usr/local/lib/python2.5/site-packages" >>
/usr/lib/python2.5/local.pth
通过启动 Python 来确认路径是否已正确更新:
# python
>>>> import sys
>>>> print sys.path
['', '/usr/lib/python25.zip', 'usr/lib/python2.5' (etc)
'/usr/local/lib/python2.5/site-packages']
神秘的挂起
神秘的挂起是处理计算机时最令人沮丧的方面之一;有时它们就是不起作用。
如果 Xen(或 dom0)神秘地挂起,那么很可能是 dom0 中发生了内核恐慌。在这种情况下,你有两个问题:首先,崩溃;其次,你的控制台日志不足以完成任务。
串行控制台极大地改善了你的生活。如果你使用串行,你应该在串行控制台上看到一条有用的恐慌信息。如果你没有看到,你可能想尝试在控制台上连续三次按 CTRL-A 来切换到 Xen 虚拟机管理程序。这至少可以确认 Xen 和硬件仍然正常。
如果你没有串行控制台,尽量保持你的 VGA 控制台在 tty1 上,因为恐慌信息通常不会出现在其他地方。有时数码相机可以用来保存内核恐慌的输出。
如果在你能看到控制台上的恐慌信息之前,机器已经重新启动,并且串行不是选项,你可以在 domU menu.lst 文件中指定你的 Linux 内核的module行上尝试添加panic=0。这显然有一个缺点,就是让你的电脑挂起而不是重新启动,但这对测试设置来说是个好主意,因为它至少会让你看到电脑的最终消息。
内核参数:安全模式
如果即使是虚拟机管理程序的串行控制台也不工作——也就是说,如果机器真的冻结了——我们过去在内核参数上取得了一些成功。
Linux 内核的ignorebiostables选项(在module行上)可能有助于避免在特定英特尔芯片组在 I/O 压力下的挂起。如果你的机器崩溃了——硬件完全停止工作——这值得一试。(我知道,这和挥舞死鸡在服务器上没什么区别,但你只能用你拥有的东西。)
类似地,acpi=off 和 nousb 已被报告在某些硬件上提高了稳定性。你也许还希望在 BIOS 中禁用超线程。一些 Xen 版本曾因此遇到问题。
如果你想一次性添加所有这些选项,你的 /boot/grub/menu.lst 中的 Xen 条目看起来可能如下所示:
root hd0(0)
kernel /boot/xen-3.0.gz
module /boot/vmlinuz-2.6-xen ignorebiostables acpi=off noapic nousb
获取帮助
你当然可以直接给我们发送与 Xen 相关的邮件。我们无法保证一定能提供帮助,但提问很容易。Xen 维基上还有一个 Xen 咨询师列表 wiki.xensource.com/xenwiki/Consultants。如果你恰好是 Xen 咨询师,请随时添加自己。
邮件列表
有几个流行的 Xen 邮件列表。你可以在 lists.xensource.com/ 上注册并阅读摘要。我们建议至少阅读 Xen-users 邮件列表。Xen-devel 可能很有趣,但大量的补丁可能会让不积极参与 Xen 开发的人感到沮丧。无论如何,这两个列表都是寻找帮助的好地方,但如果你有一个关于使用 Xen 的问题,Xen-users 是一个更好的起点。
Xen 维基
Xen 在 wiki.xensource.com/ 上有一个相当全面的维基。其中一些内容可能已经过时,但它仍然是一个有价值的起点。当然,新贡献者总是受欢迎的。看看,四处逛逛,并添加你自己的经验、技巧和有趣的小知识。
Xen IRC 频道
有一个相当受欢迎的 Xen IRC 频道,#xen 在 irc.oftc.net 上。随时可以过来聊天。
Bugzilla
Xen 维护了一个类似所有较大规模软件项目的错误数据库。它可以在 bugzilla.xensource.com/ 上公开访问。在搜索框中输入关键词,按按钮,然后阅读结果。
你的发行版供应商
不要忘记查看你的供应商提供的具体文档和支持资源。Xen 是一个复杂的软件,它在不同发行版中的集成方式各不相同。尽管发行版的文档可能不如这本书完整,但它至少能指明正确的方向。
xen-bugtool
如果其他方法都失败了,你可以直接使用 xen-bugtool 来打扰开发者。xen-bugtool 的目的是收集相关的故障排除信息,以便你可以方便地将它们附加到错误报告或提供给邮件列表。
在受影响的机器上(当然是在 dom0 中)简单地运行 xen-bugtool。它将启动一个交互式会话,询问你想要包含哪些数据以及如何处理这些数据。
xen-bugtool 脚本收集以下信息:
-
xm dmesg的输出 -
xm info的输出 -
/var/log/messages(如果需要)
-
/var/log/xen/xend-debug.log(如果需要)
-
/var/log/xen/xen-hotplug.log
-
/var/log/xen/xend.log
xen-bugtool会将这些数据保存为.tar.bz2文件,之后你可以决定如何处理它。我们建议将其上传到可网络访问的地方,并向 Xen-devel 邮件列表发送消息。
一些鼓励的话语
本章描述了一个对我们有效的故障排除工作流程。一般来说,我们试图在升级到更侵入性和劳动密集型的方法之前解决明显的问题。
我们还尝试列出我们见过的错误信息,以及可能的解决方案。显然,我们不可能做到百科全书式的详尽,但我们在与 Xen 合作多年的时间里,可能已经遇到了大多数常见的错误信息,并且至少可以为你提供一个不错的起点。
别灰心!集中注意力!记住,很可能有人之前已经见过并解决了这个问题。而且,别忘了:偶尔放弃并不丢人。你不可能总是打败电脑。嗯,也许你可以,但我们不行。祝你好运。
附录 A. XM 参考

xm 命令可能是你需要了解的第一个 Xen 相关的内容。它是你访问 Xen 控制平面功能的主要接口。使用 xm,你可以创建、查询和销毁域。你可以向客户域发送某些指令(例如,关闭)。你可以连接和断开存储和网络设备,并动态调整资源消耗。
简而言之,了解 xm 是重要的。这就是为什么我们在本节中记录了 xm 的子命令,并提供了对本书其他部分的参考。
注意
其中一些命令(从 Xen 3.1 或更高版本引入的)可能不与 RHEL 5 中包含的 Xen 版本兼容.x,因为 Red Hat 的优先级是保持主要版本之间的兼容性,而不是支持新功能。这些命令带有星号*。
所有 xm 命令都通过向 xend 发送指令来工作,xend 是 Xen 控制守护进程。这是一个在域 0 上运行的 Python 程序。它接收请求并向客户端应用程序(如 xm)发送回复。
如果 xend 没有运行,xm 将返回错误并退出。xm 的许多功能依赖于 XenBus,这是一个在机器上所有域之间的共享通信通道,以及 XenStore,这是一个集中式配置数据库,xend 使用它来保存域配置信息和状态。有关 XenStore 和 XenBus 的更多信息,请参阅第十四章。
话虽如此,让我们看看 xm 命令的一般形式。
xm 的语法
xm 的语法相当简单且一致:
xm <subcommand> <domain specifier> [options]
选项可以放在域指定符之前或之后,但我们通常将它们放在末尾。例如,要干净地关闭域 10:
xm shutdown 10
在这里,我们没有指定任何选项,并且我们通过数字 ID 而不是名称来引用域。域指定符可以是域编号或域名称——名称将内部转换为数字。(注意,如果 XenStore 没有启动,则此操作将不会工作,但那种情况下,你面临的问题更大。)
xm 命令通常是异步的,这意味着命令可能在实际上完成之前就返回了。对于像 xm shutdown 这样的命令,域可能需要几分钟才能真正关闭。在这种情况下,我们通常会轮询 xm list 来确保域已经停止运行。
xm 子命令
这里列出了各种 xm 子命令。我们经常使用其中的一些,而完全不使用其中的一些。带有版本 3.1 的新命令带有星号 (),因为 3.1 标志着 Xen 在域管理方法上的重大变化。正如我们之前提到的,这意味着它们也可能不与 RHEL 5.x* 兼容。例如,尽管 RHEL 5.2 使用 Xen 虚拟机的 3.1 版本,但它使用的是 xend 等用户空间工具的 3.0.3 版本。
addlabel, cfgbootpolicy, dumppolicy, getlabel, labels, loadpolicy, makepolicy, resources, 以及 rmlabel
这些子命令与 Xen 的安全策略基础设施交互。正如我们在第十四章中提到的,我们没有看到 Xen 安全策略的任何实际用途。如果您对安全模块(它们本身也是正在进行的工作的主题)感兴趣,我们建议查看 Xen 源代码分发中包含的示例策略。
block-attach, block-configure, block-detach, 以及 block-list
各种 block 子命令管理附加到域的存储设备。这些命令在第四章中有更详细的说明。
console
控制台子命令连接到指定域的控制台。请注意,这只有在域设置为使用 Xen 的虚拟控制台时才有用。
即使一切设置正确,您可能也需要按 ENTER 键来使其显示登录提示。这对新用户来说可能有些令人困惑,因为他们输入 xm console 并看到空白屏幕,因为自上次使用以来控制台缓冲区中没有任何内容被添加。
create
在 Xen 的最新版本中,xm create 子命令是 xm new 后跟 xm start 的同义词。这是我们全书用来启动域的子命令。
Create 需要配置文件的名称。如果您没有指定文件,它将使用默认值,/etc/xen/xmdefconfig。
create 子命令接受以下选项:
-
-h: 打印帮助信息。 -
-q: 静默模式。 -
--path: 域配置文件的基本路径(默认为 /etc/xen)。 -
-n: 干运行模式。打印将要生成的配置。这用于调试域配置中的 Python 代码。如果您正在自动生成域配置,有某种方式来测试它将是非常好的。 -
-x: 与-n类似,但输出 XML 格式的域定义。请注意,截至 Xen 3.3,此选项仍然依赖于已弃用的xml.dom.ext模块,因此不适用于许多 Python 安装。 -
-c: 自动连接到控制台。这是与 PyGRUB 交互所必需的。 -
-s: 跳过 XML 域配置的 DTD 检查。
如果您没有为 xm create 提供完整路径,它将默认在 /etc/xen 中查找配置文件。您可以使用 --path 选项更改这一点。
debug-keys *
debug-keys 子命令与 Xen 内置的 GDB stub 交互,使您能够发送魔法按键来控制 stub 的输出。这可能在您修改 Xen 内部时非常有用。
注意,这只有在您使用 GDB stub 构建 Xen 时才会生效。
delete *
xm delete 子命令从 Xen 的管理中删除一个域。如果该域正在运行,删除子命令会将其关闭,然后删除其定义。
destroy
在你认为 UNIX 是家庭导向之前,请注意,所有孩子都必须死去。
—埃里克·福斯特-约翰逊,跨平台 Perl
xm destroy 命令相当于在物理机器上拔掉电源插头。如果 domU 完全锁定,可能需要请求 xend 强制终止它。所有资源将立即返回给虚拟机管理程序。
dmesg
类似于 dmesg 系统命令,xm dmesg 子命令会打印出内核启动的诊断信息。我们将在 第十五章 中更多地讨论这些信息。
domid 和 domname
domid 和 domname 命令在你知道域的名称时查找域的 ID,反之亦然。每个子命令接受一个单一参数,即域名称或 ID,并返回相应的 ID 或名称。如果你有很多域在浮动,它们会很有用。
dry-run
虽然 dry-run 子命令在理论上测试 Xen 是否能成功找到并使用其虚拟设备,但我们运气不佳,因为它不太擅长预测我们是否能在启动域时成功。它的一个重要用途是调试包含在域配置中的 Python 代码,如 第十四章 中所述。
此子命令也是 xm create 的子选项,它以 dry-run 模式创建域。
dump-core
dump-core 子命令会触发立即的内存转储。
通常,它会暂停域,将其内存转储到指定的文件,然后解除暂停。然而,你可以指定 -L (--live) 选项,使其以类似实时迁移的方式转储,而无需暂停和解除暂停(或者至少不需要暂停任何明显的时间)。
info
info 子命令会打印出关于 Xen 主机的大量有用信息,包括你使用的 Xen 的精确版本、处理器的功能以及可用于 domUs 的内存。
list
xm list 子命令在最简单的形式下,只是列出域的表格。然而,它也可以打印出有关域的一般信息,包括完整的 s- 表达式(如果提供了 --long 选项)。
list 子命令的简短形式也会显示每个域的状态。
-
'b'(阻塞): 域正在等待某些事情,无论是 I/O 还是调度原因。空闲域将显示为阻塞状态。这是正常的;当它们有事情要做时,它们将被解除阻塞。 -
'p'(暂停): 此状态表示该域已被xm pause暂停。 -
'c'(崩溃): 域已崩溃。 -
'd'(死亡): 域正在关闭,并且正在由虚拟机管理程序销毁的过程中。如果一个域保持在此状态,那么它很可能是存在一个错误。 -
's'(关闭):域正在关闭过程中,无论是由于域内发出的命令(例如,halt)还是来自 dom0(例如,xm shutdown)。此状态还用于已知于 Xen 但尚未启动的域。如果您使用xm new,导入的域定义将在xm list中显示为shutdown,直到您使用xm start启动它。 -
'r'(运行):域目前正在物理计算机上执行。请注意,在单处理器机器上,xm list总是会显示 dom0 作为唯一的运行域,因为 dom0 正在生成和显示xm list输出。
log
xm log 命令简单地打印出 /var/log/xend.log。我们将在 第十五章 中更详细地介绍 Xen 的各种日志文件。
mem-max
mem-max 子命令指定域可以使用的最大内存量(以兆字节为单位)。这与域配置文件中的 maxmem 指令相同。目前,此子命令对正在运行的域没有影响;更改将在域重新启动时生效。
mem-set
xm mem-set 子命令通过向目标 domU 中的气球驱动程序发送消息来工作。以这种方式更改域的内存分配需要 domU 操作系统的合作,因此不能保证。这也提出了从域中获取过多内存的可能性,这将使其变得不稳定。
我们更喜欢避免使用此子命令。然而,有关气球驱动程序的更多信息,请参阅 第十四章 中的相关讨论。
migrate
migrate 子命令,正如您所猜测的,用于迁移域。迁移相当复杂。第九章 完全致力于此主题。
network-attach、network-detach 和 network-list
如您所猜测,这些子命令管理虚拟网络设备(在 Xen 术语中为 vifs,而不是网络本身)。使用这些子命令,您可以连接、断开连接和列出 vifs。我们将在 第五章 中讨论这些子命令。
new *
新增的 new 子命令将域添加到 Xen 的管理中;也就是说,它定义了域,但实际上并不分配资源或运行它。将域导入 Xen 后,您可以使用 xm start 子命令启动它。
您可能希望使用 -f 选项运行 new,指定描述域的文件。这可以是 XML 或标准的 Python 配置格式。
pause
此子命令暂停域。在暂停期间,域将继续占用内存并锁定其设备,但不会被调度在 CPU 上运行。
reboot
reboot子命令命令域干净地重启自己。请注意,如果您使用 PyGRUB,xm reboot不会加载新的内核;为此您需要关闭并重新创建域。例如,shutdown -r在 domU 内部也是如此。
rename
xm rename子命令允许管理员更改与域 ID 相关联的可读名称。
restore 和 save
xm restore和save子命令相互补充。正如我们在第九章中描述的,xm save使域释放其资源并将状态保存到保存文件中,而xm restore则使其从先前创建的保存文件中恢复。这非常类似于休眠。
resume *
resume子命令指示一个域从挂起状态返回。请注意,这仅适用于由xend 生命周期支持管理的域,这本质上是指xend管理非活动域的能力。
sched-credit
信用调度器是 Xen 的默认调度器。sched-credit子命令配置信用调度器,允许您显示或调整域的权重和上限。我们在第七章中详细描述了其用法。
sched-sedf
当然,sedf 调度器已经过时。但是,如果您发现自己在使用它,您可以使用sched-sedf子命令调整域的调度参数。
shell *
shell子命令有点有趣。它从一个交互式 shell 启动,被称为The Xen Master,您可以从该 shell 中发出各种xm子命令。
shutdown
与xm reboot类似,shutdown子命令命令域关闭,不同之处在于它不会立即重启。此子命令需要 domU 合作;如果域没有关闭,xend不会强制终止它。如果xm shutdown不起作用,您可能想尝试xm destroy。
start *
start子命令启动一个受管理的域。请注意,此子命令,就像new和suspend一样,仅存在于 Xen 3.1 中,它添加了xend生命周期支持。
suspend *
xm suspend子命令挂起一个受管理的域。
sysrq
sysrq子命令将一个魔法 sysrq 键发送到 domU。请注意,这不能通过xm控制台完成,因为 dom0 不会将 sysrq 传递给 domU。如果域似乎处于昏迷状态,这是一个有用的最后手段。有关 sysrq 的更多信息,请参阅内核文档(Linux 内核源树中的Documentation/sysrq.txt)。
top
xm top子命令以类似于top(1)子命令的格式显示正在运行的 Xen 域的状态信息。
trigger *
trigger 子命令向域发送 CPU 事件。它可以触发不可屏蔽中断 (NMI)、复位或 init 事件(尽管后两个在 Xen 3.2/i386 上会失败,显示“未实现功能”消息)。这个子命令主要用于调试。
unpause
xm unpause 子命令将使用 xm pause 暂停的域恢复运行。
uptime
xm uptime 子命令将打印所选域的运行时间,如果没有指定域,则为所有虚拟机打印。
vcpu-list、vcpu-pin 和 vcpu-set
vcpu- 子命令控制域在 SMP 系统中将使用哪些 cpus。有关更多信息,请参阅 第七章。
vnet-create、vnet-delete 和 vnet-list
这三个 vnet- 子命令与 Xen 的 VLAN 支持交互。我们没有涵盖 VLAN 支持,因为我们从未有机会使用它,也从未见过其他人使用它。如果你觉得它很有用,请给我们发一封电子邮件。
vtpm-list
vtpm-list 子命令允许你列出附加到域的虚拟 TPM(可信平台模块)。尽管我们没有详细介绍 TPM,但我们确实在 第十四章 中提到了它。
附录 B. XEN 配置文件的结构

域配置文件是定义 Xen 域的传统方式(也是我们在这本书中一直使用的方法)。它通过在配置文件中指定 Python 变量来实现,通常保存在 /etc/xen/xend 执行此文件,并使用它来设置最终将控制域构建器输出的变量。
注意,您还可以从 xm 命令行覆盖配置文件中的值。例如,要创建具有不同名称的域 coriolanus:
xm create coriolanus name=menenius
配置文件——这一点很难过分强调——作为标准的 Python 脚本执行。因此,您可以在配置文件中嵌入任意的 Python 代码,这使得根据外部约束自动生成配置变得容易。您可以在 Xen 随附的示例 HVM 配置文件 /etc/xen/xmexample.hvm 中看到一个简单的例子。在这种情况下,库路径是根据处理器类型(i386 或 x86_64)选择的。
xmexample2 文件将这种技术进一步发展,使用单个配置文件来处理多个域,这些域通过传递的 vmid 变量区分。
配置文件中的 Python 不仅仅限于域配置。例如,如果您使用 Xen 进行托管,我们可能会建议将域配置与计费和支持票务系统关联起来,使用一些 Python 代码将它们同步。通过在配置文件中嵌入此逻辑或在一个由配置文件包含的单独模块中,您可以在 Xen 域周围构建复杂的基础设施。
首先,让我们从域配置的基本元素开始。以下是一个基本的配置文件,指定了虚拟机名称、内核映像、三个网卡、一个块设备和内核参数:
name = coriolanus
kernel = "/boot/linux-2.6-xen"
vif = ['','','']
disk = ['phy:/dev/corioles/coriolanus-root,sda,rw']
root = "/dev/sda ro"
在这里,我们设置了一些变量(name、kernel、disk 等)为字符串或列表。您可以通过它们被括号包围轻松地识别列表。
字符串引号遵循标准的 Python 语法:非解释字符串使用单引号,带有变量替换的字符串使用双引号,使用三个单引号开始和结束多行字符串。
空白符与标准 Python 中的意义相同——换行符是重要的,空格不重要,除了用作缩进时。
注意
尽管这些语法规则通常是正确的,但一些解析配置文件的外部工具可能有更严格的规则。pypxeboot 是一个例子。
这里有一个更复杂的例子,包含一个 NFS 根。此外,我们还将为 vif 指定一些参数:
name = coriolanus
kernel = "/boot/linux-2.6-xen"
initrd = "/boot/initrd-xen-domU"
memory = 256
vif =
['mac=08:de:ad:be:ef:00,bridge=xenbr0','mac=08:de:ad:be:ef:01,bridge=xenbr1']
netmask = '255.255.255.0'
gateway = '192.168.2.1'
ip = '192.168.2.47'
broadcast = '192.168.2.255'
root = "/dev/nfs"
nfs_server ='192.168.2.42'
nfs_root = '/export/domains/coriolanus'
注意
您的内核必须支持 NFS,并且您的内核或 initrd 需要包含 xennet 才能正常工作。
最后,HVM 域还有一些其他选项。以下是我们可能用于安装 HVM FreeBSD domU 的配置文件。
import os, re
arch = os.uname()[4]
if re.search('64', arch):
arch_libdir = 'lib64'
else:
arch_libdir = 'lib'
kernel = "/usr/lib/xen/boot/hvmloader"
builder='hvm'
memory = 1024
name = "coriolanus"
vcpus=1
pae=1
acpi=0
vif = [ 'type=ioemu, bridge=xenbr0' ]
disk = [
'phy:/dev/corioles/coriolanus_root,hda,w',
'file:/root/8.0-CURRENT-200809-i386-disc1.iso,hdc:cdrom,r'
]
device_model = '/usr/' + arch_libdir + '/xen/bin/qemu-dm'
boot="cd"
vnc=1
vnclisten="192.168.1.102"
serial='pty'
在这里,我们添加了指定基于 QEMU 的备份设备模型和控制其某些行为的选项。现在我们传递一个boot选项来告诉它从 CD 启动,以及虚拟帧缓冲区和串行设备的选项。
指令列表
在这里,我们尝试列出我们所知的每个指令,无论我们是否使用它,并在备注中指出我们在本书的主要文本中覆盖它的位置。然而,我们省略了自 Xen 版本 3.3 以来被标记为已弃用的内容。
有一些命令与 Xen.org 版本的 Xen 一起工作,但不与包含在 Red Hat Enterprise Linux/CentOS 5.x中的 Xen 版本一起工作。我们用星号(*)标记了这些命令。
任何布尔参数都期望值为true或false;0、1、yes和no也将有效。
bootargs=string
这是一个传递给引导加载程序的参数列表。例如,为了告诉 PyGRUB 加载特定的内核映像,你可以指定bootargs='kernel=vmlinuz-2.6.24'。
bootloader=string
bootloader行指定了将在 dom0 中运行的程序,用于加载和初始化域内核。例如,你可以指定bootloader=pygrub以获得在启动时显示类似 GRUB 引导菜单的域。我们在第七章和第三章中讨论了 PyGRUB 和 pypxeboot。
builder=string
默认为"Linux",这是虚拟化的 Linux(以及其他类 Unix 操作系统)域构建器。通常,你会保留此选项为空或指定 HVM。其他域构建器通常被视为历史性的奇观。
cpu_capp=int *
这指定了域的 CPU 时间最大份额,以 CPU 的百分之一表示。
cpu=int
此选项指定了域应在哪个物理 CPU 上运行 VCPU0。
cpu_weight=int *
这指定了域在信用调度器中的权重,就像xm sched-credit -w命令一样。例如,cpu_weight = 1024将使域的权重是默认值的两倍。我们将在第七章中更多地讨论 CPU 权重。
cpus=string
cpus选项指定了域可能使用的 CPU 列表。列表的语法相当丰富。例如,cpus = "0-3,5,¹"指定了 0、2、3 和 5,同时排除了 CPU 1。
dhcp=bool
只有当内核在引导时获取其 IP 地址时,此指令才需要,通常是因为你正在使用 NFS 根设备。普通的 DHCP 由域内的标准用户空间守护程序处理,因此不需要 DHCP 指令。
disk=list
disk行指定一个(或多个)虚拟磁盘设备。几乎所有域至少需要一个,尽管对于 Xen 来说这不是一个要求。每个定义都是列表中的一个段落,每个段落至少有三个术语:后端设备、前端设备和模式。我们在第四章中详细介绍了这些术语的含义以及各种存储类型。
extra=string
extra选项指定一个字符串,该字符串将附加到 domU 内核选项中,且不进行更改。例如,要引导 domU 到单用户模式:
extra = "s"
这里列出的许多其他选项实际上都是附加到内核命令行选项上的。
hpet
此选项启用虚拟高精度事件定时器。
kernel=string
此选项指定 Xen 将加载和引导的内核映像。如果没有指定引导器行,则这是必需的。其值应该是从 dom0 的角度看绝对路径到内核,除非你已指定了引导器。如果你使用引导器并指定了内核,域创建脚本将传递内核值给引导器以进行进一步操作。例如,PyGRUB 将尝试从引导介质加载指定的文件。
maxmem=int
这指定了分配给 domU 的内存量。从客机的角度来看,这是它在引导时“连接”的内存量。
memory=int
这是域的目标内存分配。如果没有指定maxmem,则memory=行也会设置域的最大内存。因为我们不会超额订阅内存,所以我们使用这个指令而不是max-mem。我们在第十四章中稍微详细地介绍了内存超额订阅。
name=string
这是域的唯一名称。你可以取任何你喜欢的名字,但我们建议将其保持在 15 个字符以下,因为 Red Hat 的(以及可能的其他发行版)xendomains脚本在处理较长的名称时会有问题。这是少数非可选指令之一。每个域都需要一个名称。
nfs_root=IP nfs_server=IP
这两个参数在通过 NFS 引导时由内核使用。我们在第四章中描述了设置 NFS 根的方法。
nics=int
此选项已弃用,但你可能会在其他文档中看到其引用。它指定分配给域的虚拟 NIC 数量。在实践中,我们总是依赖于vif段落的数量来隐式声明 NIC。
on_crash on_reboot=string `on_shutdown
这三个命令控制域对各种停止状态的反应——on_shutdown用于优雅的关闭,on_reboot用于优雅的重启,on_crash用于域崩溃时。允许的值是:
-
destroy:像往常一样清理域。 -
restart:重启域。 -
preserve:保持域不变,直到你手动销毁它。 -
rename-restart:保留域,同时重新创建一个具有不同名称的另一个实例。
on_xend_start=ignore|start on_xend_stop=ignore|shutdown|suspend
类似地,这两项控制域如何响应xend退出。由于xend有时需要重新启动,而我们更喜欢最小化 domUs 的干扰,所以我们将其保留为默认值:ignore。
pci=BUS:DEV.FUNC
这使用给定的参数向域添加一个 PCI 设备,这些参数可以在 dom0 中使用lspci找到。我们将在第十四章(ch14.html "第十四章。技巧”)中给出 PCI 转发的示例。
ramdisk=string
ramdisk选项的功能类似于 GRUB 中的 initrd 行;它指定一个初始 ramdisk,通常包含用于挂载根文件系统的驱动程序和脚本。
许多发行版在作为 domU 安装时不需要 initrd,因为 domU 只需要为极其简单的虚拟设备提供驱动程序。然而,由于发行版期望有一个 initrd,通常更容易创建一个。我们将在第十四章(ch14.html "第十四章。技巧”)中更详细地介绍这个主题。
root=string
这指定了域的根设备。我们通常在额外的一行中指定根设备。
rtc_offset
rtc_offset允许您为虚拟域指定从机器的实时时钟的偏移量。
sdl=bool
Xen 支持 SDL 控制台以及 VNC 控制台,尽管不是同时使用。将此选项设置为true以启用 SDL 上的帧缓冲区控制台。同样,我们更喜欢vfb语法。
shadow_memory=int
这是域的影子内存(以 MB 为单位)。PV 域默认为无。Xen 使用影子内存来保留域特定的页面表副本。我们将在第十二章(ch12.html "第十二章。HVM:超越 Para 虚拟化”)中更详细地介绍页面表阴影的作用。
uuid=string
XenStore 需要一个 UUID,正如其名称所暗示的,唯一地标识一个域。如果您没有指定,它将为您生成。碰撞的概率足够低,以至于我们不必担心,但您可能会发现它很有用,例如,如果您想将附加信息编码到您的 UUID 中。
vcpu_avail=int
这些是活动的 VCPUs。如果您使用 CPU 热插拔,这个数字可能与 VCPUs 的总数不同,就像max-mem和memory可能不同一样。
vcpus=int
这指定了报告给域的虚拟 CPU 数量。出于性能原因,我们强烈建议这个数量等于或少于域可用的物理 CPU 核心数。
vfb=list
vfb = [type='vnc' vncunused=1]
在这种情况下,我们指定了一个 VNC 虚拟帧缓冲区,它使用 VNC 范围内的第一个未使用端口。(默认行为是使用基本 VNC 端口加上域 ID 作为每个域虚拟帧缓冲区的监听端口。)
vfb行的有效选项包括:vnclisten、vncunused、vncdisplay、display、videoram、xauthority、type、vncpasswd、opengl和keymap。我们将在第十四章中讨论更多关于虚拟帧缓冲区的内容,并在第十二章中简要介绍。有关替代语法,请参阅vnc=和sdl=选项。
videoram=int
videoram选项指定 PV 域可能用于其帧缓冲区的最大内存量。
vif=list
vif指令告诉 Xen 关于域的虚拟网络设备。每个vif规范可以包括许多选项,包括bridge、ip和mac。有关更多信息,请参阅第五章。
vif行中允许的选项有backend、bridge、ip、mac、script、type、vifname、rate、model、accel、policy和label。
vnc=bool
将vnc设置为 1 以启用 VNC 控制台。您还可能想要设置一些其他与 VNC 相关的选项,例如vncunused。我们更喜欢vfb语法,它允许您在一个地方设置与vfb相关的选项,其语法与vif和disk行类似。
vncconsole=bool
如果将vncconsole设置为yes,则xend在域启动时自动启动 VNC 查看器并连接到域控制台。
vncdisplay=int
这指定了要使用的 VNC 显示。默认情况下,VNC 将连接到与域 ID 相对应的显示编号。
vnclisten=IP
这指定了一个用于监听传入 VNC 连接的 IP 地址。它覆盖了xend-config.sxp中相同名称的值。
vncpasswd=string vncpasswd="Swordfish"^([87])
这些选项将 VNC 控制台的密码设置为给定值。请注意,这与 domU 执行的任何认证无关。
vscsi=PDEV,VDEV,DOM *
这向域添加一个 SCSI 设备。虚拟化 SCSI 设备是将物理 SCSI 通用设备传递到域的一种机制。它并不打算取代 Xen 块驱动程序。相反,您可以使用 pvSCSI,SCSI 传递机制,来访问连接到机器物理 SCSI 总线的设备,如磁带驱动器或扫描仪。
vtpm=['instance=INSTANCE,backend=DOM,type=TYPE']
vtpm选项,就像vif或disk选项一样,描述了一个虚拟设备——在这种情况下,是一个 TPM。TPM 实例名称是一个简单的标识符;例如1就足够了。后端是具有访问物理 TPM 的域。通常0是一个好的值。最后,类型指定了 TPM 仿真的类型。这可以是pvm或hvm,分别对应于虚拟化域和 HVM 域。
HVM 指令
某些指令仅在您使用 Xen 的硬件虚拟化,HVM 时适用。这些指令大多数用于启用或禁用各种硬件功能。
acpi=bool
acpi 选项确定域是否使用 ACPI,即高级配置和电源接口。关闭它可能会提高稳定性,并使某些版本的 Windows 安装程序能够成功完成。
apic=bool
APIC,或高级可编程输入控制器,是备受尊敬的 PIC 的现代实现。默认情况下是开启的。如果您发现操作系统在模拟 APIC 上有问题,您可能希望将其关闭。
builder=string
使用 HVM 域时,您将使用 HVM 域构建器。对于大多数基于虚拟化的域,您可能希望使用默认的 Linux 域构建器。域构建器比我们通常使用的部分要低级一些。在大多数情况下,我们愿意让它自行处理。
device_model=string
device_model 指令指定用于为 HVM 域(如果使用帧缓冲区,则为 PV 域)模拟设备的可执行文件的完整路径。在大多数情况下,默认的 qemu-dm 应该可以正常工作。
feature=string
这是一个管道分隔的列表,用于在客户内核中启用功能。从源代码中新鲜提供的功能列表如下:
[XENFEAT_writable_page_tables] = "writable_page_tables",
[XENFEAT_writable_descriptor_tables] = "writable_descriptor_tables",
[XENFEAT_auto_translated_physmap] = "auto_translated_physmap",
[XENFEAT_supervisor_mode_kernel] = "supervisor_mode_kernel",
[XENFEAT_pae_pgdir_above_4gb] = "pae_pgdir_above_4gb"
我们一直使用此选项的默认值非常顺利。
hap=bool
此指令告诉域是否利用最近机器上的硬件辅助分页功能。实现包括 AMD 的 嵌套分页 和 Intel 的 扩展分页。如果硬件支持此功能,Xen 可以通过利用它来显著提高 HVM 性能。
loader=string
这是 HVM 固件的路径。我们一直对默认设置非常满意。
pae=bool
这将启用或禁用在 HVM 域上使用 PAE。请注意,这不会使非 PAE 内核在 PAE 或 64 位机器上运行。此选项默认开启。
设备模型选项
有一些指令指定了设备模型的选项。据我们所知,这些选项是针对基于 QEMU 的模型的,但由于没有其他模型,因此似乎可以安全地将它们视为 Xen 配置的一部分。
access_control_policy=POLICY,label=LABEL
access_control_policy 指令定义了与域关联的安全策略和标签。
blkif=bool netif=bool tpmif=bool
这三个变量都是布尔值。如果它们被启用,构建器将使域成为指定设备类型的后端。
要使用非 dom0 后端,请在您选择的设备定义中指定 backend 参数。
boot=string
将 boot 设置为 a、b、c 或 d,分别从第一个软盘、第二个软盘、硬盘或 CD 驱动器启动。
fda fdb=string
此选项指定用于模拟第一个或第二个软盘驱动器的磁盘镜像或设备文件——分别是 fda 和 fdb。
guest_os_type=string
这是客户操作系统的类型。它是一个自由形式的标识符,限制为八个字符。
ioports=FROM-TO irq=IRQ
这两个选项指示 Xen 将一系列(真实)io 端口和一个中断转发到 domU。我们看到的这个选项的主要用途是用于串行端口,这样 domU 就可以访问服务器上的物理串行端口。
keymap=string
keymap选项指定一个键映射文件。Xen(或者更确切地说,设备模型)将其键映射存储在/usr/share/xen/qemu/keymaps下。在我们的机器上,默认是en-us。
localtime=bool
这是一个简单的布尔选项,表示硬件时钟是否设置为本地时间或 GMT。
monitor=string
如果monitor设置为yes,设备模型将附加 QEMU 监控器,您可以使用它向设备模型发送命令。使用 CTRL-ALT-2 跳出监控器。从那里,您可以发出命令——尝试help。
nographic=bool
这表示设备模型是否应该使用图形。
serial
serial='file:/filename'
serial='/dev/pts/n'
serial='pty'
serial='stdio'
serial选项指定一个文件(或类似文件的实体,如命名管道)作为模拟串行端口使用。其他选项是让 Xen 选择pty,或使用 STDIN 和 STDOUT 作为其串行端口;none也是一个有效的选项。
soundhw=bool
这表示是否模拟音频设备。
stdvga=bool
如果stdvga设置为yes,设备模型将使用标准 VGA 模拟。如果设置为no或省略,它将使用模拟的 Cirrus Logic 图形。通常,默认设置就很好。
usb=bool
这是一个布尔值,表示是否模拟 USB。
usbdevice=HOST:id:id
这项指示要添加的 USB 设备的名称。
^([87]) 特里·普拉切特在《夜巡》一书中关于密码的评论:“每个密码都是'swordfish'!每当有人试图想出一个别人永远猜不到的词时,他们总是选择'swordfish'。这只是人类思维中那些奇怪的怪癖之一。”
^([88]) “这不是愚蠢,这是高级。” ——来自《异形僵尸》


浙公网安备 33010602011771号