ZStack中的标签不仅帮助用户聚集资源,也帮助控制软件行为。ZStack有一套完整的规范,用以定义标签的类别、形式和用法。除了用户外,插件也可以创建自己的标签,以记录元数据和拓展现有的资源属性;通过这些手段,标签可以帮助插件引入新的特性,而不改变ZStack的数据库结构,消除了在软件升级对数据库迁移的需求。

动机

随着云中资源的不断增长,用户可能会想要有一种方式,使用人类可读的标签,去分组相似的资源。举个例子,所有Web服务器的虚拟机都可以有一个标签’web-tier-vm’,这样可以从UI和CLI把它们作为一个组来获取。对于IaaS本身,预先定义的业务逻辑也许从来都不能满足用户的需求。以创建虚拟机为例,默认的选择目标主机的算法是,从主机池中随机选择一个,但用户可能需要各种各样的算法来满足它们的使用情景。比如说选择内存超过8G的主机,选择拥有SR-IOV硬件的主机,或选择一个有当前用户的运行中虚拟机的主机。IaaS软件几乎不能为所有无止境的、不可预知的需求提供单独的API,必须有一种机制允许基础API(如APICreateVmInstanceMsg)携带额外信息。

根据各自的业务逻辑,插件可以选择是否创建数据库表。比如,Open vSwitch L2 Network插件,由于需要创建一种新的类型的资源,可能需要添加一张新表;然而,一个允许主机保留内存的插件可能不需要添加一张新表,而仅需在主机上附加一点数据。如果IaaS软件没有为插件提供一种附加数据,它们将开始创造新的、琐碎的模式或添加现有模式的列从而修改现有的模式,导致软件升级时数据库迁移的难处理的情况。
最后,对于建立在ZStack上的第三方软件,允许它们将信息存储到ZStack的数据库可以避免数据完整性问题,并使得它们可以使用ZStack的全部查询API(详见“查询API”)。

问题

大多数IaaS软件都有着标签的概念。然而,它们并不是都为不同场景定义了一个详尽的标签规范。例如,一些IaaS使用标签是为了用户聚合资源,一些IaaS是为了内部业务逻辑。ZStack则为不同场景的标签的每一个层面都精心设计了标签规范。

标签系统

在ZStack中,标签本质上是携带了少量资源相关信息的字符串。一个标签通常由以下几个字段组成:

FIELD DESCRIPTION
uuid 标签的UUID
resourceUuid 标签所关联的资源的UUID
resourceType 标签所关联的资源的类型
Tag 一个包含了有意义信息的字符串
Type 标签类型:System 或者 User

在标签方面,ZStack和其他IaaS软件的本质区别是ZStack将标签分为两类:用户(User)和系统(System)。

1. 用户标签

用户标签,顾名思义,是用户为资源分组而创建的标签。例如,通过标签’apache2-http’将安装了Apache2 HTTP服务器的虚拟机分组,这样用户就可以通过查询API获取这些虚拟机,使用标签’apache2-http’作为查询条件即可:

  1. QueryVmInstance __userTag__=apache2-http`

备注:详见“查询API”

这是最常见的标签使用方法,一个资源可以和多个标签相关联,并且被不同的逻辑组划分。

【ZStack】7.标签系统 - 图1

用户标签也可以通过和系统的标签一起使用来控制ZStack的行为。例如,如果一个用户标签SSD已经在主存储系统上创建好,那么一个系统标签可以指导ZStack在有用户标签SSD的主存储上去创建VM的根目录。在这种情况下,用户标签更像是用户输入的资源元数据。我们很快就会看到,插件也可以使用系统标签创建资源元数据。

2. 系统标签

不像用户标签可以被用户在任意时间、以任意值创建,系统标签有固定的格式,并且是被ZStack的业务服务和插件提前定义好的,可以在以下场景被使用:

2.1元数据

插件可以使用系统标签来记录资源的元数据。例如,主机的数据库表中没有列去记录如hypervisor版本,hypervisor SDK版本这样的元数据;然而,衍生的主机插件,例如,KVM主机插件,可能需要这些元数据来确定当前虚拟机管理程序是否有某些特征;例如,是否能对KVM在线快照是由libvirt和QEMU版本决定的。在ZStack中,当连接到后端主机时,KVM主机插件将OS的版本,libvirt版本,QEMU的版本和qemu-img工具的版本作为系统标签保存。

  1. QuerySystemTag fields=tag resourceUuid=d07066c4de02404a948772e131139eb4
  2. {
  3. "inventories": [
  4. {
  5. "tag": "capability:liveSnapshot"
  6. },
  7. {
  8. "tag": "qemu-img::version::2.0.0"
  9. },
  10. {
  11. "tag": "os::version::14.04"
  12. },
  13. {
  14. "tag": "libvirt::version::1.2.2"
  15. },
  16. {
  17. "tag": "os::release::trusty"
  18. },
  19. {
  20. "tag": "os::distribution::Ubuntu"
  21. }
  22. ],
  23. "success": true
  24. }

2.2资源属性

插件也可以使用系统标签将新属性添加到资源中。例如,虚拟机的数据库模式中没有列来记录该使用什么IP分配算法,什么时候分配虚拟机网卡。这种额外的属性可以用系统标签实现。插件可以创建的系统标签的数量没有限制,附加的插件可以利用这点,并避免干扰数据库模式。

数据库表和系统标签:因为数据库表和系统标签都可以定义资源属性,有时会难以决定属性是应该为数据库模式中的一列,还是应该为一个单独的表中的系统标签。添加新列来修改一个现有的数据库模式,通常需要进行数据库迁移,这是IaaS软件升级的一个主要痛点。所以开发者可能更倾向使用系统标签来代表新属性。然而,滥用系统标签是一种错误的编程方式。按照ZStack的约定,只应该使用系统标签形式引入非固有的资源属性;系统的标签并不能拯救设计的很烂的数据库表。例如,如果VM的数据库表缺失集群UUID(虽然不会),即使需要进行数据库迁移也必须补充回来;但为了私人使用而被用户创建的插件引入的部门ID应该作为一个系统标签实现。这种权衡有时候并不容易,我们会严格控制任何数据库结构的变化。

2.3元编程

系统标签也可以标注资源以影响ZStack的执行流,它在某种程度上类似于Metaprogramming
例如,管理员可以在KVM主机上创建一个系统标签reservedMemory::1G,提示ZStack主机分配器从主机的可用内存保留1G内存;如果管理员改变心意,他可以通过删除标签来回收这1G内存。有很多类似的系统标签。

例如,在用户标签这一节中,我们提到了同时使用用户标签SSD和系统标签来为VM的根云盘指定主存储。系统标签叫primaryStorage::allocator::userTag::{tag}::required,如果一个虚拟机实例规格上有primaryStorage::allocator::userTag::SSD::required,从该虚拟机实例规格上创建的虚拟机根云盘的任务,将只被分配到拥有用户标签为SSD的主存储上。有许多称之为解释点interpreting points的代码,将在执行过程中寻找特定的系统标签,可以改变代码的默认行为。

2.4第三方软件集成

建立在ZStack上的第三方软件可以使用系统标签在ZStack的数据库中存储和资源关联的信息,这能有效避免第三方软件数据库和ZStack数据库的数据不一致性。

例如,一个私有软件可能需要记录虚拟机的部门ID来审计每个部门IT资源的使用情况,这个功能通常由一个私有的数据库完成,并迫使私有软件跟踪虚拟机的生命周期,因为它需要在数据库创建或销毁时,去更新自己的数据库。否则,数据将不会正确反映真实情况。

有了系统标签的帮助,私有软件可以使用系统标签,例如audit::departmentId::{id}将信息存储在ZStack的数据库,将管理部门ID生命周期的责任转移给ZStack。当一个虚拟机被销毁,它的部门ID(例如audit::departmentId::1)将在删除该虚拟机记录的数据库事务中被自动删除。此外,私有软件可以用它们的部门ID调用常规查询API检索虚拟机:

  1. QueryVmInstance fields=uuid __sysTag__=audit::departmentId::1

注:在ZStack版本(0.6)中,我们还没开放允许定义任意系统标签的接口,所有的系统标签都是预先定义的。我们计划在下一个版本中开放这个接口,用户定义的系统标签可以在创建的时候添加一些系统允许的前缀,例如,3rd::

和其他组件的关系

标签系统是ZStack核心组件之一;它不仅具有单独的API和服务,而且还和其他核心组件无缝集成。用户可以在资源创建时或在资源创建后创建标签。ZStack所有创造型的API支持两个固有参数:userTags和systemTags,通过它们传递的标签将随着资源一起创建。例如:

  1. CreateVmInstance name=testTag systemTags=hostname::web-server-1 l3NetworkUuids=6572ce44c3f6422d8063b0fb262cbc62
  2. instanceOfferingUuid=04b5419ca3134885be90a48e372d3895 imageUuid=f1205825ec405cd3f2d259730d47d1d8

如果资源已经存在,用户可以使用标签API来创建或删除标签:

  1. CreateUserTag resourceType=VmInstanceVO resourceUuid=613af3fe005914c1643a15c36fd578c6 tag=web
  2. DeleteTag uuid=596070a6276746edbf0f54ef721f654e

资源被删除时,与资源相关联的标签将被自动删除。
资源可以通过使用两个特殊的查询条件进行查询:userTagandsystemTag标签:

  1. QueryVmInstance __userTag__=web zoneUuid=04b5419ca3134885be90a48e372d3895
  2. QueryHost __systemTag__=capability:liveSnapshot

也有查询API专门用于分类:

  1. QueryUserTag resourceUuid=0cd1ef8c9b9e0ba82e0cc9cc17226a26 tag~=web-server-%
  2. QuerySystemTag resourceUuid=50fcc61947f7494db69436ebbbefda34

总结

在这篇文章中,我们展示了ZStack的标签系统。通过这个系统,用户、插件和第三方软件可以通过各种各样的方式使用标签,而不用改变代码和数据库表结构。这是又一个基本点,激发了一种潜力,使得ZStack在快速进化为一个成熟的、完整的云计算解决方案的同时,又能保持核心架构强壮稳定。