【Nova】nova-api-metadata学习

来源:互联网 发布:上海海典软件 编辑:程序博客网 时间:2024/05/22 04:45

nova-api-metadata是针对虚拟机实例的元数据服务

以下针对Icehouse版本的nova-network网络模式进行说明

nova-api-metadata作为wsgi server运行,对外提供RESTful API.需要运行在网络节点上,为计算节点上的实例提供元数据服务。

我们可以为实例创建元数据, 在实例的来宾系统中,我们通过nova-api-metadata的RESTful API获取到自己的元数据。只需要在实例的来宾系统中访问http://169.254.169.254/openstack/latest/meta_data.json即可。


工作原理:

1.在创建wsgi server的实例时,会实例化一个MetadataManager。

def metadata_accept():    # 在iptables的filter表中为元数据服务的端口和IP创建接收规则    # 这个规则是说:源地址为任意地址、目的端口为元数据服务端口(默认8775)、目的地址为元数据服务主机地址的tcp数据包允许通过    rule = '-s 0.0.0.0/0 -p tcp -m tcp --dport %s' % CONF.metadata_port    if CONF.metadata_host != '127.0.0.1':        rule += ' -d %s -j ACCEPT' % CONF.metadata_host    else:        rule += ' -m addrtype --dst-type LOCAL -j ACCEPT'    iptables_manager.ipv4['filter'].add_rule('INPUT', rule)    # 使规则生效, 具体就是使用iptables命令行工具(iptables-save、iptables-restore等)来实现的    iptables_manager.apply()class MetadataManager(manager.Manager):    """Metadata Manager.    def __init__(self, *args, **kwargs):        super(MetadataManager, self).__init__(*args, **kwargs)        # 加载网络驱动, 默认驱动是nova.network.linux_net        self.network_driver = driver.load_network_driver()        # 创建元数据的接收规则        self.network_driver.metadata_accept()
  

2.然后, wsgi server开始运行,接收http请求,并返回响应;但是我们在虚拟机的来宾系统中一般是无法获取元数据服务的主机地址的,那怎么访问呢?我们需要约定一个ip地址,让这个ip地址作为我们的元数据服务主机地址;由于metadata服务最早是由亚马逊提出的,当时规定的metadata服务的地址为169.254.169.254:80,所以OpenStack沿用了这个规定。

3.这还不够,169.254.169.254是一个保留地址,虚拟机的来宾系统压根无法访问这个ip地址,我们首先需要保证169.254.169.254可访问,然后将访问169.254.169.254:80的包转发到metadata_host:metadata_port上。这个工作是借由nova-network服务来完成的:

def ensure_metadata_ip():    # 通过调用ip命令行工具, 为lo回环设备添加169.254.169.254/32辅助IP;    # 这样我们就可以在实例的来宾系统中访问该地址了    _execute('ip', 'addr', 'add', '169.254.169.254/32',             'scope', 'link', 'dev', 'lo',             run_as_root=True, check_exit_code=[0, 2, 254])def metadata_forward():    if CONF.metadata_host != '127.0.0.1':        # 如果元数据主机地址不是127.0.0.1,        # 那么就在PREROUTING链处对访问169.254.169.254:80的tcp包进行DNAT,        # 使之发往metadata_host:metadata_port        iptables_manager.ipv4['nat'].add_rule('PREROUTING',                                          '-s 0.0.0.0/0 -d 169.254.169.254/32 '                                          '-p tcp -m tcp --dport 80 -j DNAT '                                          '--to-destination %s:%s' %                                          (CONF.metadata_host,                                           CONF.metadata_port))    else:        # 如果元数据主机地址是127.0.0.1,        # 那么就在PREROUTING链处对访问169.254.169.254:80的tcp包进行端口重定向到metadata_port                # 这里有个疑问:为什么要对127.0.0.1进行单独处理, 上面的DNAT无法处理这种情况吗?原因还需要进行进一步验证        iptables_manager.ipv4['nat'].add_rule('PREROUTING',                                          '-s 0.0.0.0/0 -d 169.254.169.254/32 '                                          '-p tcp -m tcp --dport 80 '                                          '-j REDIRECT --to-ports %s' %                                           CONF.metadata_port)    iptables_manager.apply()class LinuxNetL3(L3Driver):    def initialize(self, **kwargs):        if self.initialized:            return        LOG.debug("Initializing linux_net L3 driver")        fixed_range = kwargs.get('fixed_range', False)        networks = kwargs.get('networks', None)        if not fixed_range and networks is not None:            for network in networks:                self.initialize_network(network['cidr'])        else:            linux_net.init_host()        # 在初始化L3驱动时,首先为lo回环接口添加元数据ip;        # 然后为元数据建立转发规则        linux_net.ensure_metadata_ip()        linux_net.metadata_forward()        self.initialized = True

4.接下来,虚拟机的来宾系统就能访问元数据服务的RESTful API了;即使不传递任何HTTP头信息,nova-api-metadata也能定位到实例,因为只要虚拟机的来宾系统访问了API,那么nova-api-metadata就能获取到连接的对端地址即虚拟机的fixed_ip,系统正常运行的情况下, fixed_ip与虚拟机是一一对应的关系;然后nova-api-metadata

            首先通过缓存获取对应的InstanceMetadata,如果缓存没有,默认情况下通过rpc访问nova-conductor来获取虚拟机信息和元数据,最后返回


那这个元数据服务有什么意义呢?

我们在很多应用场景下需要通知虚拟机的来宾系统一些信息,如果这些信息经常变动,特别是需要与虚拟机绑定时,元数据服务就能起到非常关键的作用,它能以公开且基本不变的接口同时满足我们的这2项需求。很多公有云或者私有云的厂商,会在虚拟机的来宾系统预装上他们的Agent,假设这个Agent有个作用,就是定期向一个监控系统发送自己的负载信息,如果没有元数据服务,那我们只能通过硬编码的形式来指定监控系统的地址;一旦监控系统的地址或接口发生变化,Agent的这个功能就用不了了,我们需要更新镜像才能重新工作,这是非常不方便的;有了元数据服务,我们就不用硬编码了,Agent可以直接从元数据中获取监控系统的地址。

还有另一种方法,来向虚拟机的来宾系统发送消息,那就是“文件注入“,不过这个也还是远不及元数据服务这么方便,之后会单独讲下“文件注入“。


原创粉丝点击