简介
首先简单介绍一下Glance项目。Glance项目主要是提供虚拟机镜像的发现、注册和检索服务。它通过提供标准的REST接口,接受对不同后端存储的镜像的查询请求和返回镜像的相关信息。
Glance镜像服务允许上传私有或共有的不同格式的镜像,包括:
与其他OpenStack项目相同,Glance也遵循以下几点设计原则:
1. 基于组件
2. 高可用性
3. 高容错性
4. 可扩展性
5. 开放标准
架构
在对Glance项目有了一定的认识之后,我们还应该了解一下它在OpenStack中所处的位置,请看下图:
可以看出通过Glance,Opentack的3大组件被连接为一个整体。Glacne的存储接口有多种实现,Swift作为其中之一可以为Glance提供实际的存储服务。而在另一方面Glance又为Nova提供镜像的查找操作。同时,这三个组件都需要通过Keystone的认证。
其中Glance的架构如下图所示:
主要组件
Glance-API 主要用来响应各种REST请求然后通过其他模块(主要是glance-registry组件和后端存储接口)完成镜像的上传、删除、查询等操作。可以简单的再分为两部分:一层中间件,它主要是做一些对请求的解析工作(如分析出版本号), 另外一部分提供实际的服务(如与镜像上传下载的后端存储接口交互)。默认绑定端口是9292。
Glance-Registry 镜像注册服务,用于提供镜像元数据的REST接口。主要工作是存储或者获取镜像的元数据,与MySQL数据库进行交互。也可以简单的再细分为两部分,API和具体的Server。元数据是指镜像相关的一些信息(如id,size, status,location, checksum, min_disk, min_ram, owner等),真正的镜像数据保存在实际所使用的后端存储里(如swift,s3,filesystem等)。默认绑定的端口是9191。
Image Store 严格来说image store不属于Glance的组件,这里把它单独分出来只是为了方便理解,它只是一个接口层,提供镜像存储和查询的接口。具体的实现则需要外部存储(Swift,S3)的支持。
Glance添加一个镜像的整个流程
其实,理解了这个流程也就大概掌握glance服务的原理了。
我们使用如下命令:
glance add name="cirros-0.3.0-i386-11-28" is_public=true container_format=ovf disk_format=qcow2 < ./cirros-0.3.0-i386-disk.img
返回结果:
Added new image with ID: 81cbb863-a38e-48d6-9ff3-4c52800ef10d
在使用这条命令的时候,我们实际上是通过命令行向glance-api发送请求,完成我们对镜像的添加操作。glance命令行与nova命令行类似,都是封装了一层http的客户端。客户端从我们输入的命令中获取所需的参数后,将镜像的元数据包装在HTTP包头中,将镜像读入到请求的body中,然后通过POST请求将数据提交给glance-api。
glance-api的作用已经在上面介绍过,但是要想知道他是如何响应RESTAPI的还需要理解一个文件:glance/etc/glance-api-paste.ini。这个文件有点类似nova-api的ini文件。首先要熟悉ini配置文件中的几个概念以及他们之间的关系:
app:实际处理REST API请求的python类。
filter:一种装饰器,为app提供一层封装,在app处理请求之前会先调用filter的对象。
pipeline:所对应的对象是对filter和app的的封装,他将多个filter和某个app绑在一起,在app处理请求之前要先通过pipline指定的在app之前的filter的处理。
router:根据REST请求的URL让不同的对象的不同的方法处理该REST请求。
现在来看glance-api-paste.ini文件,glance/etc/glance-api-paste.ini定义了很多不同的pipeline,他们的区别在于定义了不同的filter来处理请求,而最终请求被glance.api.v1.router:API的对象处理。然后我们看一下router.py文件的API类。它继承了wsgi.Router,可以根据REST请求的URL以及请求的类型(GET、PUT等)将请求映射给不同对象的不同方法进行处理。
glance/api/v1/router.py映射请求的部分代码如下:
images_resource = images.create_resource() mapper.resource("image", "images", controller=images_resource, collection={'detail': 'GET'}) mapper.connect("/", controller=images_resource, action="index") mapper.connect("/images/{id}", controller=images_resource, action="meta", conditions=dict(method=["HEAD"])) members_resource = members.create_resource() mapper.resource("member", "members", controller=members_resource, parent_resource=dict(member_name='image', collection_name='images')) mapper.connect("/shared-images/{id}", controller=members_resource, action="index_shared_images") mapper.connect("/images/{image_id}/members", controller=members_resource, action="update_all", conditions=dict(method=["PUT"]))
通过查看完整的代码(v1和v2),我们可以知道,请求最终都是被images.py、image_data.py、schemas.py、image_access.py以及image_tags.py中的controller类的不同方法处理。 所以上面添加镜像的请求会被glance/api/v1/images.py中的Controller类的create函数处理,该方法会调用_handle_source方法,进而调用_upload_and_activate方法。_upload_and_activate方法做了两件重要的事情:调用self._upload上传镜像,调用self._activate通过glance registry服务更新glance数据库中镜像的状态。具体存储接口实例的选择是在self._upload方法中。之后会调用确定的存储接口中的add方法保存需要上传的镜像。
整个流程看起来如下图所示:
1. 管理员使用上传镜像命令。Glance-API服务收到请求,并通过它的中间件,解析出版本号等信息。
2,3. Glance-Registry服务的api获取一个registry client,调用registry client的add_image函数。此时镜像的状态为“queued”, 标识该镜像ID已经被保留,但是镜像还未上传。
4. Glance-Registry服务执行client的add_image函数,向glance数据库中insert一条记录。
5,6,7. Glance-API调用Glance-Registry的update_image_metadata函数,更新数据库中该镜像的状态为“saving”,标识镜像正在被上传。
8. Glance-API调用后端存储接口提供的add函数上传镜像文件。
9,10,11. Glance-API调用Glance-Registry的update_image_metadata函数,更新数据库中该镜像的状态为 “active”并发通知。“active”标识镜像在Glance中完全可用。
在镜像上传完成后,查看Registry的日志,可以验证Glance-Registry服务的主要任务的确是通过 sqlalchemy与MySQL数据库进行交互:
2012-11-28 09:24:22 INFO sqlalchemy.engine.base.Engine [-] BEGIN (implicit) BEGIN (implicit) 2012-11-28 09:24:22 INFO sqlalchemy.engine.base.Engine [-] INSERT INTO images (created_at, updated_at, deleted_at, deleted, id, name, disk_forma t, container_format, size, status, is_public, location, checksum, min_disk, min_ram, owner, protected) VALUES (%s, %s, %s, %s, %s, %s, %s, %s, % s, %s, %s, %s, %s, %s, %s, %s, %s) INSERT INTO images (created_at, updated_at, deleted_at, deleted, id, name, disk_format, container_format, size, status, is_public, location, che cksum, min_disk, min_ram, owner, protected) VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s)
使用Glance管理镜像
文章的最后介绍一些Glance的简单使用,主要是一些glance客户端命令。
因为Glance服务要经过Keystone认证,所以先设置一些环境变量:
export OS_USERNAME=user export OS_PASSWORD=password export OS_TENANT_ID=tenant export OS_AUTH_URL=http://127.0.0.1:35357/v2.0
完成设置,通过glance index -d -v 查看是否成功。成功后即可通过以下命令来使用Glance:
显示当前存在镜像:
glance index 或者 glance image-list
删除某个镜像:
glance delete ID
显示某个镜像详细信息:
glance show ID
更改已存在镜像的属性:
glance ID 属性=新属性值
例如,改变镜像的protected属性:
glance update ID protected = false
开放私有镜像给某个指定租户使用:
glance member-add ID tenant1
上传镜像的命令已在上面的流程分析中写出。当然我们也可以在这些基本命令的基础上额外添加一些其他参数,如:
-d,打印出调试信息
-v:显示出详细信息
注:以上所有“ID”均为镜像的ID,可以通过glance image-list得到.
更多更详细的Glance客户端命令
请请参:http://docs.openstack.org/developer/glance/glance.html#the-update-command