在config drive和cloud init之前,先要从制作镜像说起。
一般情况下,我们可以从ubuntu或者fedora等的官网上下载镜像,启动虚机时从镜像启动即可,前面提过启动instance,root disk,swap等的意义,在开发项目
的过程中,如果我们希望自己的镜像中自带某些已经安装好的服务,一些库,或者一些通用的配置文件等,除了使用cloud init,这个之后会说,其实制作自己的
镜像一直都是个不错的方法,没有复杂的配置,虽然灵活性上差一些,但不失为一个好办法。
mark link 1 中是官网的镜像制作过程,有Centos,ubuntu,windows,FreeBSD,Fedora,过程十分详细。
使用vish命令,创建一个磁盘镜像,将系统装到创建的磁盘镜像中,启动系统进行定制化的服务安装,做一些处理之后,创建的磁盘镜像就可以导入openstack做image了。
通过镜像我们可以添加自己的服务,但是有些元数据是变化的,随着不同用户而定制的,我们不可能为了每个用户都去做一个镜像,怎么办呢,于是有了cloud init。
mark link 2是一篇不错的文章,制作镜像时候会安装cloud init并进行配置,它仅在镜像启动(虚机启动)时运行,就像一个agent一样,从各种数据源读取相关数据
并据此对虚拟机进行配置。常见的数据源包括:云平台的metadata服务、ConfigDrive等,常见的配置包括:设定虚拟机的hostname、hosts文件、
设定用户名密码、更新apt -get的本地缓存、调整文件系统的大小(注意不是调整分区的大小)等。
所以这里关系理顺了,使用cloud init做定制化配置,配置的数据源是configDrive,从哪里看合适呢?
还是从client看,openstack的东西,网上能搜到实例,更加实例分析最容易,找不到实例,通过test case看其次,从client看最佳,前面提到从test看大系统
的全局是很好的入口,而openstack的client则是除了发布的rest 文档之外最好的文档。
在novaclient中有三个参数比较感兴趣:
'--user-data',
'--file',
'--config-drive',
在novaclient/v2/shell.py中的do_boot创建新的instance方法:cs.servers.create(*boot_args, **boot_kwargs),在client.py中:
self.servers = servers.ServerManager(self)
在ServerManager的create方法中:
if userdata:
。。。。
userdata_b64 = base64.b64encode(userdata).decode('utf-8')
body["server"]["user_data"] = userdata_b64
if files:
personality = body['server']['personality'] = []
for filepath, file_or_string in sorted(files.items(),
key=lambda x: x[0]):
if hasattr(file_or_string, 'read'):
data = file_or_string.read()
else:
data = file_or_string
if six.PY3 and isinstance(data, str):
data = data.encode('utf-8')
cont = base64.b64encode(data).decode('utf-8')
personality.append({
'path': filepath,
'contents': cont,
})
if config_drive:
body["server"]["config_drive"] = config_drive
这也就是我们在nova中nova/api/openstack/compute/server.py看到:
config_drive = None
if self.ext_mgr.is_loaded('os-config-drive'):
config_drive = server_dict.get('config_drive')
if personality:
injected_files = self._get_injected_files(personality)
user_data = self._extract(server_dict, 'os-user-data', 'user_data')
self._validate_user_data(user_data)
所以--file变成了personality字段,成为inject file. 我们trace nova创建instance的过程,会先在数据库中创建instance的实例,其中user data和config drive(true false,
0或者1)会作为属性成为instance的数据库中记录。
一致trace到Virt Driver创建虚机,这里是LibVirt:
self._create_image(context, instance, #user data和config drive在这里
disk_info['mapping'],
network_info=network_info,
block_device_info=block_device_info,
files=injected_files, #--file 参数
admin_pass=admin_password)
重点在于这一段:
# Config drive
if configdrive.required_by(instance): #如果config drive是True或者CONF.force_config_drive是always,或者image_prop == 'mandatory'
#可以tracerequired_by函数
LOG.info(_LI('Using config drive'), instance=instance)
extra_md = {}
if admin_pass:
extra_md['admin_pass'] = admin_pass
inst_md = instance_metadata.InstanceMetadata(instance,
content=files, extra_md=extra_md, network_info=network_info) #将user data和inject files传入InstanceMetadata
with configdrive.ConfigDriveBuilder(instance_md=inst_md) as cdb:
configdrive_path = self._get_disk_config_path(instance, suffix)
LOG.info(_LI('Creating config drive at %(path)s'),
{'path': configdrive_path}, instance=instance)
try:
cdb.make_drive(configdrive_path)
#首先调用self._write_md_files(tmpdir),将user data等写到一个tmp dir中
#再调用_make_iso9660或者_make_vfat,一般是前者,支持更好,生成一个镜像挂载到image上
except processutils.ProcessExecutionError as e:
with excutils.save_and_reraise_exception():
LOG.error(_LE('Creating config drive failed '
'with error: %s'),
e, instance=instance)
到这里,cloud init在哪里派上用场呢,在instance boot起来时候,cloud init会从数据源中读取user data和meta data,这里的数据源就是前面千辛万苦得到
的config drive,而这些是linux在boot时候的动作,可以在mark link中看cloud init的配置和user data文件的写法等等。
openstack很多思想来源于AWS,这个必须承认,使用镜像,cloud init(配合config drive使用),使得instance的定制化和灵活性变得不输给AWS了。
终于写完这一篇了,几次想trace完都耽搁了,move!
mark link
1. http://docs.openstack.org/image-guide/content/centos-image.html
2.http://www.it165.net/os/html/201404/7848.html
7. http://longgeek.com/2014/05/19/openstack-trove-dedicated-mirror-making/#i
8.http://mathslinux.org/?p=591