天天看點

【Nova】nova-api-metadata學習

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可以直接從中繼資料中擷取監控系統的位址。

還有另一種方法,來向虛拟機的來賓系統發送消息,那就是“檔案注入“,不過這個也還是遠不及中繼資料服務這麼友善,之後會單獨講下“檔案注入“。