当前位置: 首页 > news >正文

OpenStack Yoga版安装笔记(26)实例元数据笔记

一、实例元数据概述

1.1 元数据

(官方文档:Metadata — nova 25.2.2.dev5 documentation)

Nova 通过一种叫做元数据(metadata)的机制向其启动的实例提供配置信息。这些机制通常通过诸如 cloud-init 这样的初始化软件来广泛使用,用于指定一些实例应该使用信息,比如根密码(root password)等。

这些元数据可以通过配置驱动(config drive)或者元数据服务(metadata service)提供,用户还可以通过用户数据 功能(user data feature)对其进行一定程度的自定义。

详细讲解


Nova 是 OpenStack 中负责管理虚拟机生命周期的组件。当 Nova 启动一个实例时,它需要传递一些配置信息给实例。这些信息通常包括一些关于实例运行环境的设定,例如主机名、SSH 密钥、网络配置、根密码等。Nova 通过 元数据机制 提供这些信息。

元数据机制

  1. 元数据的作用
    元数据就是一些关于实例的信息,这些信息对于实例的启动、配置、以及后续管理非常重要。它通常包括:

    • 实例的唯一标识符(例如,UUID)

    • 网络配置(如 IP 地址、网络掩码等)

    • 用户数据(自定义脚本、配置等)

    • SSH 公钥和其他认证信息

    • 实例的安全设置(如 root 密码)

  2. 传递方式:配置驱动 vs. 元数据服务
    Nova 提供了两种主要方式来将元数据传递给实例:

    • 配置驱动(Config Drive):配置驱动是一种将元数据嵌入到实例的磁盘中,并在实例启动时通过虚拟磁盘读取的方式。它通常用于没有网络连接的情况下,或者在一些特殊场景下。

    • 元数据服务(Metadata Service):元数据服务是一种通过网络连接提供元数据的机制。实例启动后,它可以通过 HTTP 请求从 OpenStack 的元数据服务获取这些信息。它是一个动态的、可以随时更新的服务,实例通过访问它来获取各种配置信息。

  3. 用户数据(User Data)
    用户数据是元数据的一部分,允许用户在实例启动时传递自定义的配置或脚本。这些数据通常以脚本的形式传递,实例在启动时执行这些脚本。这对自动化配置非常有用。例如,用户可以通过用户数据设置实例的主机名、安装软件包、配置防火墙规则等。

    cloud-init 是一个广泛使用的工具,它帮助实例处理这些用户数据。它能够解析用户传递的脚本,并执行相应的配置步骤。

元数据的类型

元数据可以根据不同的需求进行自定义,通常包含以下几种类型:

  1. 系统信息
    包括实例的 ID、镜像 ID、主机名等。通常由 OpenStack 管理,并且对于实例的管理和调度很重要。

  2. 网络信息
    包括实例的 IP 地址、子网掩码、网关等。这些信息由 OpenStack 的网络服务提供。

  3. 用户数据
    自定义的配置或脚本数据,通常由用户指定,在实例启动时由 cloud-init 或其他类似工具执行。

  4. SSH 公钥
    这通常用于实例的 SSH 认证,用户可以在启动实例时提供 SSH 公钥,实例会自动配置该公钥以便用户可以通过 SSH 访问。

  5. 安全信息
    包括实例的安全组、密码等敏感信息。用户可以通过元数据服务来访问这些信息。

总结

Nova 的元数据机制提供了一种灵活的方式来配置和管理实例。在启动实例时,用户可以通过配置驱动或元数据服务将配置信息传递给实例,元数据可以通过 cloud-init 等工具来执行自定义的配置任务。通过元数据,用户可以实现实例的自动化配置,减少手动干预,提升效率。

1.2 元数据服务

(官方文档:Metadata service — nova 25.2.2.dev5 documentation)

元数据服务是 OpenStack 提供的一项非常重要的功能,它允许实例在启动后动态获取与其相关的配置信息和数据。实例可以通过访问特定的地址(http://169.254.169.254)来查询与自己相关的元数据。这种服务通常用于实例的配置管理、自动化部署等场景。

元数据服务可以作为 nova-api 应用的一部分在全局范围内运行,也可以作为独立的 nova-api-metadata 应用在每个 cell 内部运行。

详细讲解


OpenStack 的 Nova 组件负责管理虚拟机(实例)的生命周期,而 元数据服务 是 Nova 中的重要一部分。它为实例提供配置信息,通常通过 HTTP 请求的方式在实例启动后提供与该实例相关的各种元数据。关于元数据服务的部署方式,OpenStack 提供了两种选择:全局模式和按 cell 部署的模式。

1. 全局模式(Global Mode)

在全局模式下,元数据服务是作为 nova-api 应用的一部分进行运行的。nova-api 是 Nova 服务的一个关键组件,负责提供对外的 REST API 接口,供用户和其他 OpenStack 组件进行交互。元数据服务也作为该组件的一部分提供,所有的实例都可以通过统一的 API 端点访问元数据服务。

在这种模式下,元数据服务的实例在整个 OpenStack 部署中是共享的,所有的计算节点和实例都可以通过访问统一的地址(http://169.254.169.254)来获取元数据。这种方式的优势在于简单易部署,但在大规模部署时,可能会面临性能和扩展性方面的问题。

2. 按 Cell 部署模式(Per-Cell Mode)

在按 cell 部署模式下,元数据服务不再作为全局的 nova-api 的一部分,而是作为独立的应用运行在每个 cell 内。cell 是 OpenStack Nova 的一种分布式架构,用于在多数据中心或多个计算资源池中分隔和管理计算资源。通过按 cell 部署,可以将每个 cell 的计算资源和元数据服务独立管理。

在这种模式下,每个 cell 都有自己的 nova-api-metadata 应用,这意味着每个 cell 内的实例会从其所在 cell 内的元数据服务获取元数据。这种方式更适合大规模的 OpenStack 部署,因为它可以减轻中央元数据服务的负担,提高扩展性和性能。

3. 全局模式与按 Cell 部署模式的比较

  • 全局模式

    • 部署简单:只需要一个统一的元数据服务,适用于小规模或中型的 OpenStack 部署。

    • 性能瓶颈:随着实例数量的增加,所有实例都依赖一个元数据服务,这可能会导致性能问题。

    • 维护复杂性低由于元数据服务和 nova-api 是集成在一起的,维护工作较为简化。

  • 按 Cell 部署模式

    • 扩展性强:每个 cell 拥有独立的元数据服务,可以在大规模部署中提高性能。

    • 部署复杂:需要为每个 cell 部署和配置独立的元数据服务,增加了部署和维护的复杂度。

    • 适用于大规模部署:当 OpenStack 部署涉及多个数据中心或计算资源池时,按 cell 部署可以更好地隔离和管理资源,提升性能。

4. 详细比较信息

用户可以根据自身的部署规模、性能需求和维护能力来选择适合的方式。具体来说,选择 全局模式 更适合中小规模的部署,而选择 按 cell 部署模式 则适合大规模的、分布式的 OpenStack 环境。

总结

OpenStack Nova 的元数据服务可以根据部署需求选择不同的运行模式。在全局模式 下,元数据服务作为 nova-api 的一部分提供,适合中小规模部署;而在 按 cell 部署模式 下,每个 cell 内都有独立的元数据服务,适合大规模、高性能需求的环境。选择哪种模式需要考虑 OpenStack 部署的规模、性能要求和管理复杂度。

1.3 客户端发送元数据请求

客户虚拟机通过地址 169.254.169.254fe80::a9fe:a9fe 发送元数据请求,访问元数据服务。

详细讲解:


🧾 关键词:

  • Guests:指的是运行在 OpenStack 中的 虚拟机实例(VM)

  • the service:这里指的是 nova-metadata API 服务,也叫 元数据服务

  • 169.254.169.254:这是一个特殊的 IPv4 地址,称为 Link-local 地址,用于本地网络通信,不经路由器转发

  • fe80::a9fe:a9fe:这是它对应的 IPv6 link-local 地址,不经路由器转发

🧠 为什么虚拟机会访问这个地址?

在云环境(包括 AWS、OpenStack 等)中,虚拟机会在启动时自动访问 169.254.169.254,来获取自己的一些“身份信息”和配置信息,比如:

  • 实例 ID

  • 主机名

  • SSH 公钥

  • 用户数据(user-data)

  • 配置信息(meta-data)

这些信息由 nova-metadata API 服务 提供。

1.4 Neutron转发元数据请求

网络服务 Neutron 负责拦截这些请求,并在将请求转发到元数据 API 服务器之前,添加唯一标识请求来源的 HTTP 头。

对于 Neutron 提供的 Open vSwitch 和 Linux Bridge 后端,其流程大致如下:

  1. 实例发送 HTTP 请求以获取元数据,目标地址为 169.254.169.254。

  2. 该请求会根据实例中的路由表,要么进入路由器命名空间(router namespace),要么进入 DHCP 命名空间。

  3. 命名空间内的元数据代理服务(metadata proxy)会将以下信息添加到请求头中:

    • 实例的 IP 地址(添加 X-Forwarded-For 头)

    • 路由器或网络的 ID(添加 X-Neutron-Network-IdX-Neutron-Router-Id 头)

  4. 元数据代理服务通过 UNIX 域套接字(UNIX domain socket)将该请求发送到命名空间外部的元数据代理(metadata agent)。

  5. neutron-metadata-agent 应用程序会将此请求转发到 Nova 的元数据 API 服务,并添加一些新的头信息(例如实例 ID 和租户 ID)。

详细讲解:


背景

在 OpenStack 中,每个虚拟机(实例)通常会尝试通过 http://169.254.169.254 访问“元数据服务”(Metadata Service),以获取诸如 SSH 密钥、用户数据(User Data)、网络配置等信息。这一过程需要被网络服务 Neutron 拦截并正确转发。

流程详解

1. 实例访问元数据 IP(169.254.169.254)

这是一个 Link-local address,实例操作系统中预设它作为默认元数据服务器地址。

2. 请求进入合适的命名空间

  • Router Namespace:如果网络是基于路由的(如通过 router 通向外网),那么请求首先会路由到虚拟路由器命名空间。

  • DHCP Namespace:如果使用的是更简单的 flat 网络或 DHCP-only 网络,可能直接通过 DHCP namespace。

3. 元数据代理服务拦截请求并添加头部

在命名空间中运行的是 neutron-ns-metadata-proxy 进程,它会:

  • 添加 X-Forwarded-For:记录原始实例 IP 地址。

  • 添加 X-Neutron-Network-IdX-Neutron-Router-Id:记录此请求来自哪个网络或路由器,便于后续定位实例来源。

4. 使用 UNIX 套接字发送到 neutron-metadata-agent

  • 为了安全性与效率,Neutron 使用 UNIX socket(而不是 TCP)将请求发送给位于主机上的 neutron-metadata-agent

5. metadata-agent 转发请求至 Nova 的 metadata API

  • neutron-metadata-agent 根据上述 HTTP headers 信息识别出是哪台实例,然后补全信息:

    • 实例 ID(Instance ID)

    • 租户 ID(Tenant ID)

  • 然后转发给 Nova 的元数据服务(通常监听在 http://127.0.0.1:8775 或类似地址上)。

总结

这个过程的核心目的是实现“多租户隔离的元数据服务”:每个实例发出的请求,都经过 Neutron 的多层拦截、标记、认证后才被允许访问 Nova 提供的元数据信息,确保同一物理主机上的不同虚拟机之间不会泄露元数据。 

二、实例元数据相关配置查看

2.1 当前OpenStack网络类型

OpenStack实体网络拓扑

在 OpenStack 中,实例访问元数据服务的请求路径取决于该实例所连接的网络类型,主要分为两类:Self-service Network(自服务网络)Provider Network(提供者网络或隔离网络)

1. Self-service Network(自服务网络)

Self-service 网络通常是通过路由器(Router)连接到外部网络的。此类网络支持租户级别的子网划分,并提供 NAT 转换,以便虚拟机可以通过浮动 IP 访问外部网络。

  • 网络结构:实例连接到 self-service 网络 → self-service 网络连接到 Router → Router 连接到外部网络。

  • 默认网关:实例的默认网关通常设置为子网的起始地址(如 172.16.1.1)。

  • 元数据服务路径

    • 实例启动时会尝试访问元数据服务(通常是 http://169.254.169.254)。

    • 请求首先被虚拟路由器(qrouter)截获。

    • 然后由 qrouter 中的 HAProxy 组件处理,将元数据请求转发至元数据代理(neutron metadata agent),最终获取并返回元数据。

这种路径依赖于 router 的存在,适用于需要通过 router NAT 出口的网络环境。

2. Provider Network(提供者网络 / 隔离网络)

Provider 网络直接连接到物理网络,不依赖 OpenStack Router。此类网络通常用于无 NAT 的网络拓扑,例如数据中心内部的管理网或裸金属网络,网络由管理员提前配置好。

  • 网络结构:实例连接到 provider 网络 → provider 网络直接连接到外部物理网络(如公有网或企业内网),不经过 Router。

  • 默认网关:实例的默认网关通常设置为一个物理网络中真实存在的网关地址(如 192.168.100.1)。

  • 元数据服务路径

    • 实例仍尝试访问 http://169.254.169.254

    • 请求被该网络对应的 DHCP 代理(qdhcp)拦截。

    • 由 qdhcp namespace 中的 HAProxy 转发请求至 metadata agent,完成元数据的获取和返回。

由于不经过 Router,此类网络也被称为隔离网络,但仍然能够通过 DHCP namespace 提供元数据服务。

总结对比:

网络类型是否经过 Router默认网关元数据服务处理点
Self-service Network子网地址(如 172.16.1.1)qrouter 中的 HAProxy
Provider Network外部真实网关地址(如 192.168.x.x)qdhcp 中的 HAProxy

当前OpenStack网络环境中,创建了两个network,provider network和selfservice network,每个network创建了实例。

root@osclient ~(myproject/myuser)# openstack network list
+--------------------------------------+-------------+--------------------------------------+
| ID                                   | Name        | Subnets                              |
+--------------------------------------+-------------+--------------------------------------+
| 28d343c8-1cbb-4d3a-b69c-7d9afe5840fa | selfservice | 2825e2f9-b894-49ba-8cdb-399285223219 |
| 48f2b88e-7740-4d94-a631-69e2abadf25b | provider    | 8279842e-d7c5-4ba6-a037-831e0a72a938 |
+--------------------------------------+-------------+--------------------------------------+
root@osclient ~(myproject/myuser)# openstack server list
+--------------------------------------+-----------------------+---------+-----------------------------------------+--------+---------+
| ID                                   | Name                  | Status  | Networks                                | Image  | Flavor  |
+--------------------------------------+-----------------------+---------+-----------------------------------------+--------+---------+
| 4dfb51e2-3b48-4cc7-b947-92d13500a8f9 | provider-instance     | SHUTOFF | provider=203.0.113.213                  | cirros | m1.nano |
| 12faa86b-252a-4400-94d8-80dd4585b9d3 | selfservice-instance2 | SHUTOFF | selfservice=172.16.1.152, 203.0.113.124 | cirros | m1.nano |
| 4847a65a-d45f-4adc-971e-f1d905c2c535 | selfservice-instance  | SHUTOFF | selfservice=172.16.1.202, 203.0.113.145 | cirros | m1.nano |
+--------------------------------------+-----------------------+---------+-----------------------------------------+--------+---------+
root@osclient ~(myproject/myuser)#

2.2 当前OpenStack服务安装

2.2.1 Nova/Neutron安装信息

NovaNeutron相关服务安装信息:

2.2.2 Nova配置信息

controller的/etc/nova/nova.conf相关配置:

[neutron]
auth_url = http://controller:5000
auth_type = password
project_domain_name = default
user_domain_name = default
region_name = RegionOne
project_name = service
username = neutron
password = openstack
service_metadata_proxy = true
metadata_proxy_shared_secret = openstack

Nova 的配置文件 nova.conf[neutron] 段的内容,主要用于 Nova 与 Neutron 的通信,尤其是支持 Metadata 服务 的功能。我们来逐行详细解释:


📂 [neutron] 段落:Nova 与 Neutron 的集成配置

auth_url = http://controller:5000

🔸 用途:指定 Keystone 的认证服务地址。Nova 使用这个 URL 去认证自己,向 Neutron 发 API 请求。

auth_type = password

🔸 用途:指定认证方式为 password,这是 Keystone 推荐的标准方式。

project_domain_name = default

user_domain_name = default

🔸 用途:指定 Keystone 中使用的项目域(project domain)和用户域(user domain),通常默认安装的都是 default

region_name = RegionOne

🔸 用途:指定要连接的 Keystone 区域(region)。OpenStack 默认使用 RegionOne,除非你特别配置了多区域部署。

project_name = service

🔸 用途:Nova 将以 service 项目的身份访问 Neutron。这个 service 项目中通常会注册各个服务账号,如 nova、neutron、glance 等。

username = neutron

password = openstack

🔸 用途:Nova 使用这个 Neutron 用户来向 Neutron 发 API 请求,进行网络相关的操作。这个用户必须有权限(通常是 admin 角色)操作网络资源。


重点!与 metadata 服务有关的两行配置:

service_metadata_proxy = true

✅ 启用了对 Neutron metadata proxy 的信任。表示:

  • Nova metadata API 信任 Neutron metadata-agent 的请求

  • Neutron 会向 Nova metadata 发送请求,这些请求中带有特定的 header(如 X-Forwarded-For);

  • Nova 需要信任这些 header 是合法的(即这些请求确实来自 Neutron)。

metadata_proxy_shared_secret = openstack

✅ Neutron 和 Nova 使用此“共享密钥”进行认证。

  • Neutron metadata agent 在请求头中加入这个密钥;

  • Nova metadata API 会校验这个密钥;

  • 确保这些 metadata 请求来自可信的 Neutron 组件,而不是伪造的来源。


🧾 小结:这个配置的作用是?

  • 建立了 Nova 与 Neutron 的身份认证连接;

  • 启用了 支持虚拟机 metadata 请求 的核心选项;

  • 允许 Neutron metadata-agent 成为中介,将虚拟机的 metadata 请求转发到 Nova;

  • 保证 metadata 请求的来源安全可靠。

2.2.3 Neutron配置信息

1、metadata_agent.ini

controller上的/etc/neutron/metadata_agent.ini,这个配置文件是 Neutron metadata 代理(neutron-metadata-agent) 的主配置文件。

[DEFAULT]
nova_metadata_host = controller
metadata_proxy_shared_secret = openstack

 [DEFAULT] 段配置解读

nova_metadata_host = controller

🔸 含义

  • 指定 Nova metadata API 服务 的主机名或 IP。

  • controller 是主机名,通常会在 /etc/hosts 中映射到控制节点的 IP。

  • metadata agent 会把虚拟机的 metadata 请求转发到这个地址的 8775 端口(Nova metadata API 的监听端口)。

🔎 例如,转发的目标地址就是:

http://controller:8775

metadata_proxy_shared_secret = openstack

🔸 含义

  • 设置一个 共享密钥,用于身份校验。

  • 当 Neutron metadata agent 转发请求给 Nova 的 metadata API 时,会在请求头中加上一个签名;

  • Nova 会使用自己配置中的 metadata_proxy_shared_secret 来验证请求是否可信。

必须与 nova.conf[neutron] 段的 metadata_proxy_shared_secret 完全一致,否则 metadata 请求会被拒绝。

2、dhcp_agent.ini 

controller上的/etc/neutron/dhcp_agent.ini这是 Neutron 中负责为虚拟机分配 IP 地址的 DHCP Agent 的配置文件。这个 agent 也负责处理某些类型的 metadata 请求,尤其是在网络没有连接到路由器时。

[DEFAULT]
interface_driver = linuxbridge
dhcp_driver = neutron.agent.linux.dhcp.Dnsmasq
enable_isolated_metadata = true

📂 [DEFAULT] 段配置解读

1️⃣ interface_driver = linuxbridge

🔸 含义

  • 指定 Neutron DHCP agent 用于桥接网络接口的驱动。

  • linuxbridge 表示使用 Linux 的 bridge 功能。

  • 对应的是你使用的 Neutron 网络插件(Linux Bridge)。

📌 如果你用的是 Open vSwitch(openvswitch),这里就会是 interface_driver = openvswitch

2️⃣ dhcp_driver = neutron.agent.linux.dhcp.Dnsmasq

🔸 含义

  • 指定 DHCP 服务的后端实现。

  • 这里选择的是 Dnsmasq,它是 Neutron 默认和推荐的 DHCP 服务进程。

  • 它会在每个网络的 namespace 中以独立的进程运行,为虚拟机分配 IP。

✅ 这个配置几乎是所有部署中标准不变的内容。

3️⃣ enable_isolated_metadata = true

🔸 含义

  • 启用在**“隔离网络”中提供 metadata 服务**。

  • 所谓“隔离网络”是指:

    • 虚拟机连接的私有网络 没有路由器(没有连接到外部网络)

    • 因此 metadata 请求不能像常规网络那样通过 router namespace 走向 nova-metadata 服务。

📌 开启这个配置后:

  • Neutron DHCP Agent 会在这些隔离网络的 namespace 内运行一个 metadata proxy(其实是通过 neutron-metadata-agent 间接处理);

  • 从而使虚拟机依然能通过 169.254.169.254 获取 metadata。

3、l3_agent.ini

controller上的/etc/neutron/l3_agent.ini,这是 Neutron 的 L3 Agent(路由器代理) 的配置文件。
L3 Agent 主要负责管理虚拟路由器(包括 SNAT/DNAT、floating IP、元数据代理等)。

[DEFAULT]
# Allow running metadata proxy. (boolean value)
#enable_metadata_proxy = true

🔸 enable_metadata_proxy = true

✅ 含义:

  • 启用在 router namespace 中运行 metadata 代理进程(通常是 haproxy)。

  • 用于把虚拟机发往 169.254.169.254 的 metadata 请求,从 router namespace 中转发到 neutron-metadata-agent

  • L3 Agent 会监听 metadata 请求并通过本地 socket 传给 metadata agent。

🧩 配置生效条件:

  • 虚拟机网络已经连接到一个 router。

  • 该 router 所属的 namespace(例如:qrouter-<uuid>)中将运行 metadata proxy。

  • neutron-metadata-agent 必须运行正常。

🔐 安全配合:

  • 该代理请求中通常会带上一个 X-Instance-ID 和共享密钥 (metadata_proxy_shared_secret),供 nova 校验。

enable_metadata_proxy = true 在大多数发行版的 neutron-l3-agent 包中是缺省启用的(即使配置文件中它被注释掉),这意味着:

  • 即使你没有显式写出这行配置项,Neutron 在后台默认行为是当作 true 来处理。

2.3 查看元数据服务运行方式

可以一步一步地检查 Nova Metadata API 服务的状态,并确认它是如何运行的。

步骤 1: 检查 nova-api 服务是否正在运行

首先,我们需要确认 nova-api 服务是否正在运行,因为 nova-metadata API 可能作为 nova-api 服务的一部分运行。

root@controller:~# systemctl status nova-api
● nova-api.service - OpenStack Compute APILoaded: loaded (/lib/systemd/system/nova-api.service; enabled; vendor preset: enabled)Active: active (running) since Sun 2025-05-04 22:27:23 UTC; 33min agoDocs: man:nova-api(1)Main PID: 1529 (nova-api)Tasks: 9 (limit: 9350)Memory: 345.5MCPU: 22.662sCGroup: /system.slice/nova-api.service├─1529 /usr/bin/python3 /usr/bin/nova-api --config-file=/etc/nova/nova.conf --log-file=/var/log/nova/nova-api.log├─1632 /usr/bin/python3 /usr/bin/nova-api --config-file=/etc/nova/nova.conf --log-file=/var/log/nova/nova-api.log├─1633 /usr/bin/python3 /usr/bin/nova-api --config-file=/etc/nova/nova.conf --log-file=/var/log/nova/nova-api.log├─1634 /usr/bin/python3 /usr/bin/nova-api --config-file=/etc/nova/nova.conf --log-file=/var/log/nova/nova-api.log├─1635 /usr/bin/python3 /usr/bin/nova-api --config-file=/etc/nova/nova.conf --log-file=/var/log/nova/nova-api.log├─1641 /usr/bin/python3 /usr/bin/nova-api --config-file=/etc/nova/nova.conf --log-file=/var/log/nova/nova-api.log├─1642 /usr/bin/python3 /usr/bin/nova-api --config-file=/etc/nova/nova.conf --log-file=/var/log/nova/nova-api.log├─1643 /usr/bin/python3 /usr/bin/nova-api --config-file=/etc/nova/nova.conf --log-file=/var/log/nova/nova-api.log└─1645 /usr/bin/python3 /usr/bin/nova-api --config-file=/etc/nova/nova.conf --log-file=/var/log/nova/nova-api.logMay 04 22:27:23 controller systemd[1]: Started OpenStack Compute API.
May 04 22:27:25 controller nova-api[1529]: Modules with known eventlet monkey patching issues were imported prior to eventlet monkey patching: urllib3. This warning can usually be ignored if the caller is only importing and not executing nova code.
root@controller:~# 

结论:nova-api 服务已经在运行中,状态是 active (running),这意味着 nova-api 服务确实在正常工作。 

步骤 2: 检查是否存在 nova-api-metadata 服务

接下来,我们要确认 nova-api-metadata 服务是否单独部署。执行以下命令检查系统中是否存在 nova-api-metadata 服务:

root@controller:~# systemctl status nova-api-metadata
Unit nova-api-metadata.service could not be found.
root@controller:~# 

结论:看到 Unit nova-api-metadata.service could not be found 的输出,说明 nova-api-metadata 并没有单独作为服务运行。

这意味着 nova-metadata API 可能是作为 nova-api 服务的一部分运行的。

步骤 3: 检查是否有 nova-metadata API 服务监听默认端口

如果 nova-api-metadata 没有单独作为服务运行,那么 nova-metadata API 服务可能是作为 nova-api 的一部分监听端口的。

默认情况下,nova-metadata API 会监听 8775 端口。我们可以检查该端口是否有服务在监听。

root@controller:~# netstat -tuln | grep 8775
tcp        0      0 0.0.0.0:8775            0.0.0.0:*               LISTEN     
root@controller:~# 

结论:从输出看,nova-metadata API 服务确实在 8775 端口上监听,这表明它正在运行。 

步骤 4: 查看 nova-api 日志 

如果 nova-api 服务正在运行并且监听 8775 端口,但你不确定 nova-metadata API 是否已作为独立进程运行,你可以查看 nova-api 的日志文件。

运行以下命令查看 nova-api 的日志:

root@controller:~# tail -f /var/log/nova/nova-api.log
2025-05-04 22:27:34.551 1633 INFO nova.osapi_compute.wsgi.server [req-f768866c-ff45-42a5-8f42-a512c50d033b - - - - -] (1633) wsgi starting up on http://0.0.0.0:8774
2025-05-04 22:27:34.675 1635 INFO nova.osapi_compute.wsgi.server [req-208b4471-2754-4608-ad6c-7cadea475679 - - - - -] (1635) wsgi starting up on http://0.0.0.0:8774
2025-05-04 22:27:34.697 1632 INFO nova.osapi_compute.wsgi.server [req-3270fa04-267c-464d-bd06-3d252eb9f5d9 - - - - -] (1632) wsgi starting up on http://0.0.0.0:8774
2025-05-04 22:27:34.755 1642 INFO nova.metadata.wsgi.server [req-8c2f3627-28f3-42c2-9081-8f27daf854b0 - - - - -] (1642) wsgi starting up on http://0.0.0.0:8775
2025-05-04 22:27:34.761 1634 INFO nova.osapi_compute.wsgi.server [req-84296c4c-0804-43db-9490-786e2f0e0c5b - - - - -] (1634) wsgi starting up on http://0.0.0.0:8774
2025-05-04 22:27:34.847 1645 INFO nova.metadata.wsgi.server [req-1a91f21e-a8db-4791-9fca-73b41020b28c - - - - -] (1645) wsgi starting up on http://0.0.0.0:8775
2025-05-04 22:27:34.898 1643 INFO nova.metadata.wsgi.server [req-191e75f4-2dcd-45ce-ba4c-a61e177a1d5e - - - - -] (1643) wsgi starting up on http://0.0.0.0:8775
2025-05-04 22:27:34.915 1641 INFO nova.metadata.wsgi.server [req-b5c1f57d-3e9f-4ca7-b727-ce71e771838d - - - - -] (1641) wsgi starting up on http://0.0.0.0:8775
2025-05-04 22:30:32.231 1632 INFO nova.osapi_compute.wsgi.server [req-d1294517-d5ae-4ade-b550-e753d9d1136a 9382b59561c04dd1abf0a4cb7a8252ec f5e75a3f7cc347ad89d20dcfe70dae01 - default default] 10.0.20.100 "GET /v2.1/servers/detail HTTP/1.1" status: 200 len: 4837 time: 1.5150268
2025-05-04 22:30:32.401 1632 INFO nova.osapi_compute.wsgi.server [req-ddc416e5-6304-454e-a068-66ef4a833d14 9382b59561c04dd1abf0a4cb7a8252ec f5e75a3f7cc347ad89d20dcfe70dae01 - default default] 10.0.20.100 "GET /v2.1/flavors/detail?is_public=None HTTP/1.1" status: 200 len: 755 time: 0.0127280

nova-api-metadata.service 不存在是正常的:

  • 原因nova-api-metadata 不是一个独立的 systemd 服务。

  • 真正运行的位置:它是 nova-api 服务的一部分,通过 eventlet/wsgi 内部同时监听

    • 端口 8774 提供计算 API(compute API);

    • 端口 8775 提供元数据服务(metadata service)。

日志已经明确显示了:

ova.metadata.wsgi.server [...] wsgi starting up on http://0.0.0.0:8775

步骤5:检查是否启用了 local_metadata_per_cell 

如果你启用了 local_metadata_per_cell = true,那么每个 cell 会有一个单独的 nova-metadata API 服务。你可以检查是否在每个单元中配置了独立的服务。通过检查 nova.conf 文件中的设置,可以确认这个配置项。

  • 当选择 local_metadata_per_cell = true 时,必须确保每个 Neutron 的 metadata-agent 配置正确,指向对应的 nova-metadata API 服务。

  • 如果选择 local_metadata_per_cell = false,则无需关注单元之间的 metadata API 服务配置,因为它会作为一个全局服务运行。

root@controller:~# vi /etc/nova/nova.conf
#
# Indicates that the nova-metadata API service has been deployed per-cell, so
# that we can have better performance and data isolation in a multi-cell
# deployment. Users should consider the use of this configuration depending on
# how neutron is setup. If you have networks that span cells, you might need to
# run nova-metadata API service globally. If your networks are segmented along
# cell boundaries, then you can run nova-metadata API service per cell. When
# running nova-metadata API service per cell, you should also configure each
# Neutron metadata-agent to point to the corresponding nova-metadata API
# service.
#  (boolean value)
#local_metadata_per_cell = false <--- default is false.

✅ 结论

nova-metadata API 是正常运行的,并且是由 nova-api 服务内部启动的(不是独立服务)。也就是本文提到的全局运行模式。

2.4 查看neutron-metadata-agent

确认 neutron 是否启用了它的 metadata agent进程:

root@controller:~# systemctl status neutron-metadata-agent
● neutron-metadata-agent.service - OpenStack Neutron Metadata AgentLoaded: loaded (/lib/systemd/system/neutron-metadata-agent.service; enabled; vendor preset: enabled)Active: active (running) since Sun 2025-05-04 22:27:23 UTC; 54min agoDocs: man:neutron-metadata-agent(1)Main PID: 1527 (neutron-metadat)Tasks: 4 (limit: 9350)Memory: 126.7MCPU: 3.790sCGroup: /system.slice/neutron-metadata-agent.service├─1527 "neutron-metadata-agent (/usr/bin/python3 /usr/bin/neutron-metadata-agent --config-file=/etc/neutron/neutron.conf --config-file=/etc/neutron/metadata_agent.ini --log-file=/var/log/neutron/neutron-metadata-agent.log)"├─1620 "neutron-metadata-agent (/usr/bin/python3 /usr/bin/neutron-metadata-agent --config-file=/etc/neutron/neutron.conf --config-file=/etc/neutron/metadata_agent.ini --log-file=/var/log/neutron/neutron-metadata-agent.log)"└─1621 "neutron-metadata-agent (/usr/bin/python3 /usr/bin/neutron-metadata-agent --config-file=/etc/neutron/neutron.conf --config-file=/etc/neutron/metadata_agent.ini --log-file=/var/log/neutron/neutron-metadata-agent.log)"May 04 22:27:23 controller systemd[1]: Started OpenStack Neutron Metadata Agent.

Neutron Metadata Agent 服务 已经在运行,也就是说:

  • 它将会拦截虚拟机发送到 169.254.169.254 的 metadata 请求;

  • 并且会通过 UNIX 套接字将这些请求转发给你已经运行的 Nova Metadata API;

  • 所以,整个 OpenStack metadata 流程链路目前看是完整且正常的

当前状态总结

组件状态说明
nova-api✅ 正常运行包含 Metadata API,监听端口 8775
nova-api-metadata❌ 不存在正常,因为 YOGA 版本已整合进 nova-api
neutron-metadata-agent✅ 正常运行用于转发虚拟机中的请求
端口监听0.0.0.0:8775 已监听metadata 服务暴露中
虚拟机访问地址🟡 169.254.169.254还需在虚拟机中测试是否能访问 metadata

2.5 查看 router namespace(qrouter) 中haproxy

root@controller:~# ip netns
qrouter-782e8b74-a13c-4e8c-83dd-066f49e55ac2 (id: 2) <-- router namespace
qdhcp-28d343c8-1cbb-4d3a-b69c-7d9afe5840fa (id: 1)
qdhcp-48f2b88e-7740-4d94-a631-69e2abadf25b (id: 0)root@controller:~# ip netns exec qrouter-782e8b74-a13c-4e8c-83dd-066f49e55ac2 netstat -tnlp
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address           Foreign Address         State       PID/Program name    
tcp6       0      0 :::9697                 :::*                    LISTEN      2334/haproxy   

说明:

router namespace 中运行着 haproxy,而且正在监听 TCP 9697 端口。这就是 Neutron Metadata Proxy 的典型表现。

在较新版本的 OpenStack(比如 Yoga、Zed 等)中,Neutron 使用 haproxy 来代理 metadata 请求时,会监听在一个本地任意端口(如 9697),然后通过内部规则拦截 169.254.169.254 的流量重定向到这个本地监听端口

你可以再执行以下命令确认重定向规则是否存在(仍在 router namespace 内):

root@controller:~# ip netns exec qrouter-782e8b74-a13c-4e8c-83dd-066f49e55ac2 iptables -t nat -S | grep 169.254.169.254
-A neutron-l3-agent-PREROUTING -d 169.254.169.254/32 -i qr-+ -p tcp -m tcp --dport 80 -j REDIRECT --to-ports 9697
root@controller:~# 

Neutron L3 agent 设置的 NAT 重定向规则,它的含义如下:


🔍 规则解读:

  • -d 169.254.169.254/32:匹配目标地址为 169.254.169.254(metadata 固定地址) 的数据包;

  • -i qr-+:只匹配入接口为 qr-xxx 类型(即 router 的内部接口);

  • -p tcp --dport 80:匹配 TCP 80端口 的请求(也就是 HTTP metadata 请求);

  • -j REDIRECT --to-ports 9697:将这些请求 重定向 到本地的 9697 端口(也就是 haproxy 的监听端口)。


✅ 意义总结:

这个规则确保了:

虚拟机发送到 169.254.169.254 的 metadata 请求,会被 Neutron L3 Agent 拦截,并转发到 router namespace 中 haproxy 的 9697 端口,从而走 metadata 服务的完整链路。

这也说明当前Neutron metadata proxy 配置完全生效

2.6 查看DHCP namespace(qdhcp)中 haproxy

root@controller:~# ip netns exec qdhcp-48f2b88e-7740-4d94-a631-69e2abadf25b netstat -tnlp
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address           Foreign Address         State       PID/Program name    
tcp        0      0 169.254.169.254:80      0.0.0.0:*               LISTEN      2058/haproxy        
tcp        0      0 169.254.169.254:53      0.0.0.0:*               LISTEN      2121/dnsmasq        
tcp        0      0 127.0.0.1:53            0.0.0.0:*               LISTEN      2121/dnsmasq        
tcp        0      0 203.0.113.101:53        0.0.0.0:*               LISTEN      2121/dnsmasq        
tcp6       0      0 ::1:53                  :::*                    LISTEN      2121/dnsmasq        
tcp6       0      0 fe80::a9fe:a9fe:53      :::*                    LISTEN      2121/dnsmasq        
tcp6       0      0 fe80::a9fe:a9fe:80      :::*                    LISTEN      2058/haproxy        
tcp6       0      0 fe80::f816:3eff:fe5b:53 :::*                    LISTEN      2121/dnsmasq        
root@controller:~# 

 tcp        0      0 169.254.169.254:80      0.0.0.0:*               LISTEN      2058/haproxy

✅ 意义分析:

这表示:

  • 在 DHCP 网络命名空间(qdhcp-...)中,

  • 存在一个 HAProxy 实例正在监听 169.254.169.254:80 —— 这是 云主机访问 metadata 的标准地址

因为你在 /etc/neutron/dhcp_agent.ini 中配置了:

enable_isolated_metadata = true

所以 Neutron 会自动为该网络中的 VM 启动 haproxy 来代理元数据请求,即使该网络没有 router。

✅ 结论:

现在可以确认两条元数据链路都已就绪:

网络类型元数据来源
有路由的网络(有 qrouter)qrouter 中的 haproxy ➝ namespace ➝ nova-metadata
无路由的隔离网络qdhcp 中的 haproxy ➝ namespace ➝ nova-metadata

这表明 Neutron 的元数据服务机制已全部工作正常

2.7 查看haproxy配置

Neutron 元数据代理为每个 qrouter/qdhcp 动态生成 haproxy 配置文件,位置在:

root@controller:~# ls /var/lib/neutron/ns-metadata-proxy/
48f2b88e-7740-4d94-a631-69e2abadf25b.conf  782e8b74-a13c-4e8c-83dd-066f49e55ac2.conf
root@controller:~#root@controller:~# ip netns
qrouter-782e8b74-a13c-4e8c-83dd-066f49e55ac2 (id: 2)  --> qrouter
qdhcp-28d343c8-1cbb-4d3a-b69c-7d9afe5840fa (id: 1)   --> selfservice network qdhcp
qdhcp-48f2b88e-7740-4d94-a631-69e2abadf25b (id: 0) --> provider network qdhcp
root@controller:~# 

48f2b88e-7740-4d94-a631-69e2abadf25b.conf为provider network上的qdhcp haproxy配置。

782e8b74-a13c-4e8c-83dd-066f49e55ac2.conf为selfservice network上的qrouter haproxy配置 

2.7.1 qrouter haproxy配置

查看对应 router 的配置:

root@controller:~# cat /var/lib/neutron/ns-metadata-proxy/782e8b74-a13c-4e8c-83dd-066f49e55ac2.confgloballog         /dev/log local0 infolog-tag     haproxy-metadata-proxy-782e8b74-a13c-4e8c-83dd-066f49e55ac2user        neutrongroup       neutronmaxconn     1024pidfile     /var/lib/neutron/external/pids/782e8b74-a13c-4e8c-83dd-066f49e55ac2.pid.haproxydaemondefaultslog globalmode httpoption httplogoption dontlognulloption http-server-closeoption forwardforretries                 3timeout http-request    30stimeout connect         30stimeout client          32stimeout server          32stimeout http-keep-alive 30slisten listenerbind :::9697server metadata /var/lib/neutron/metadata_proxyhttp-request del-header X-Neutron-Network-IDhttp-request set-header X-Neutron-Router-ID 782e8b74-a13c-4e8c-83dd-066f49e55ac2
root@controller:~# root@controller:~# brctl show

✅ 配置文件解读:

🔹 global 块:全局配置

  • 使用 syslog 记录日志,便于调试。

  • log-tag 带有 router 的 UUID,帮助你区分不同 router。

  • user/groupneutron,运行权限控制。

  • pidfile 用于记录进程 ID,便于管理。

  • daemon 表示以守护进程方式运行。


🔹 defaults 块:默认 HTTP 参数设置

  • 明确使用 HTTP 模式。

  • 开启日志选项、连接控制、超时设定等,保证元数据请求的可靠性。

  • option forwardfor:添加 X-Forwarded-For 头,用于传递原始 IP 地址。


🔹 listen listener 块:定义监听端口和代理行为

listen listener bind :::9697

  • 监听所有 IPv4/IPv6 地址的 9697 端口,这就是 iptables REDIRECT 转发进来的目的端口。


🔹 关键:代理转发逻辑

server metadata /var/lib/neutron/metadata_proxy

  • 这表示请求将被发送到一个 UNIX 域 socket,路径为:

    /var/lib/neutron/metadata_proxy

    它是 neutron-metadata-agent 在主机上创建的 socket,用于和 nova-metadata-api 服务通信。

http-request del-header X-Neutron-Network-ID

http-request set-header X-Neutron-Router-ID 782e8b74-a13c-4e8c-83dd-066f49e55ac2

  • 删除原有 X-Neutron-Network-ID 头。

  • 设置 X-Neutron-Router-ID 为此 router 的 UUID,用于 nova 端识别是哪台虚拟机发来的请求。


✅ 结论:元数据服务路径是否正常

根据你提供的配置,可以确认:

  • 元数据请求会被 NAT 到 9697

  • haproxy 在 router namespace 中监听 9697

  • 它把请求通过本地 UNIX socket 转发给 neutron-metadata-agent。

  • neutron-metadata-agent 再加上必要头部信息,转发给 nova-api 的 8775 端口。

🎯 所以:你的元数据服务链路是正常配置并处于运行状态的

2.7.1 qdhcp haproxy配置 

查看对应 qdhcp的配置:

root@controller:~# cat /var/lib/neutron/ns-metadata-proxy/48f2b88e-7740-4d94-a631-69e2abadf25b.confgloballog         /dev/log local0 infolog-tag     haproxy-metadata-proxy-48f2b88e-7740-4d94-a631-69e2abadf25buser        neutrongroup       neutronmaxconn     1024pidfile     /var/lib/neutron/external/pids/48f2b88e-7740-4d94-a631-69e2abadf25b.pid.haproxydaemondefaultslog globalmode httpoption httplogoption dontlognulloption http-server-closeoption forwardforretries                 3timeout http-request    30stimeout connect         30stimeout client          32stimeout server          32stimeout http-keep-alive 30slisten listenerbind 169.254.169.254:80bind fe80::a9fe:a9fe:80 interface ns-a51b2fe4-04server metadata /var/lib/neutron/metadata_proxyhttp-request del-header X-Neutron-Router-IDhttp-request set-header X-Neutron-Network-ID 48f2b88e-7740-4d94-a631-69e2abadf25b
root@controller:~# 

这份 haproxy 配置来自 DHCP 网络命名空间中,用于隔离网络(没有 router 连接)里的 VM 提供 metadata 服务:

listen listener 块:

listen listener bind 169.254.169.254:80

           bind fe80::a9fe:a9fe:80 interface ns-a51b2fe4-04

  • 169.254.169.254:80 是元数据服务标准地址。

  • 绑定了 IPv4 和 IPv6(link-local)地址。

  • interface ns-a51b2fe4-04 是 DHCP namespace 中虚拟接口名称。

server metadata /var/lib/neutron/metadata_proxy
    http-request del-header X-Neutron-Router-ID
    http-request set-header X-Neutron-Network-ID 48f2b88e-7740-4d94-a631-69e2abadf25b
metadata 请求最终转发到本地 Unix socket 文件:/var/lib/neutron/metadata_proxy

添加了 X-Neutron-Network-ID,删除了 router ID(因为隔离网络无 router)

隔离网络中的 VM 访问 http://169.254.169.254 时,会通过此 HAProxy 实例接入 Neutron 的 metadata 代理机制。

Neutron metadata agent 会从请求中读取 Network ID,然后向 nova-api 的 metadata 接口请求真实数据。

三、实例元数据通信过程测试

3.1 selfservice network场景测试

实例元数据通信过程(selfservice网络场景)

3.1.1 虚拟机启动

虚机启动后,开始初始化网络和系统配置。

启动selfservice-instance2虚机(位于compute1节点,属于selfservice network)。

root@osclient ~(myproject/myuser)# openstack server start selfservice-instance2         
root@osclient ~(myproject/myuser)#

3.1.2 通过 DHCP 获取 IP 和元数据路由

DHCP 服务由 neutron-dhcp-agent 提供,虚机获取到其私有 IP 地址,并添加了一条指向 169.254.169.254 的默认 metadata 路由。

此时,虚机将发送DHCP请求,qdhcp将发送dhcp offer。

对vmware workstation vmnet8抓包:

这段内容显示的是DHCP(动态主机配置协议)的通信过程,具体包括以下步骤:

DHCP Discover:虚机在这个阶段广播一个Discover消息,告知网络中的所有DHCP服务器它需要一个IP地址。 

DHCP Offer:DHCP服务器(qdhcp)收到Discover消息后,提供一个IP地址(172.16.1.152)给客户端,并发送一个Offer消息。

DHCP Request:客户端收到Offer消息后,广播一个Request消息,表示它接受服务器提供的IP地址。

DHCP ACK:DHCP服务器收到Request消息后,发送一个ACK消息,确认IP地址的分配。

这些报文用于 Controller 节点上的 qdhcp 与 compute1 节点上的虚拟机之间的通信。由于涉及跨节点传输,报文经过 VXLAN 封装,封装使用的 VXLAN VNI 为 649。

查看DHCP Offer报文内容:

在DHCP(动态主机配置协议)中,Option字段用于传递额外的配置信息给客户端。 

Option 3: Router (默认网关)

这个选项指定了客户端应该使用的默认网关(也称为路由器)的IP地址。

Option 121: Classless Static Route

提供了一个特定的路由信息,即元数据路由,指导客户端如何到达169.254.169.254这个特定的网络。

查看qrouter的IP地址信息:

root@controller:~# ip netns exec qrouter-782e8b74-a13c-4e8c-83dd-066f49e55ac2 ip add
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00inet 127.0.0.1/8 scope host lovalid_lft forever preferred_lft foreverinet6 ::1/128 scope host valid_lft forever preferred_lft forever
2: qr-fb68b947-33@if8: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1450 qdisc noqueue state UP group default qlen 1000link/ether fa:16:3e:33:b2:f8 brd ff:ff:ff:ff:ff:ff link-netnsid 0inet 172.16.1.1/24 brd 172.16.1.255 scope global qr-fb68b947-33valid_lft forever preferred_lft foreverinet6 fe80::f816:3eff:fe33:b2f8/64 scope link valid_lft forever preferred_lft forever
3: qg-02f3fada-b8@if9: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default qlen 1000link/ether fa:16:3e:bd:68:5a brd ff:ff:ff:ff:ff:ff link-netnsid 0inet 203.0.113.144/24 brd 203.0.113.255 scope global qg-02f3fada-b8valid_lft forever preferred_lft foreverinet 203.0.113.124/32 brd 203.0.113.124 scope global qg-02f3fada-b8valid_lft forever preferred_lft foreverinet 203.0.113.145/32 brd 203.0.113.145 scope global qg-02f3fada-b8valid_lft forever preferred_lft foreverinet6 fe80::f816:3eff:febd:685a/64 scope link valid_lft forever preferred_lft forever
root@controller:~# 

查看selfservice-instance2虚机(使用虚机对应的浮动地址203.0.113.124)

$ ip route
default via 172.16.1.1 dev eth0 
169.254.169.254 via 172.16.1.1 dev eth0 
172.16.1.0/24 dev eth0  src 172.16.1.152 
$ 

169.254.169.254 via 172.16.1.1 dev eth0

  • 这是访问元数据服务的特殊路由,明确告诉系统:去访问元数据服务时 也要经过网关(即通过 qrouter namespace)。

  • 这是 OpenStack 在 Self-service 网络中为了拦截元数据请求,特意配置的静态路由。

 3.1.3 虚拟机发起 metadata 请求

云初始化服务(如 cloud-init)尝试从 http://169.254.169.254:80 获取配置数据,例如 ssh 公钥、用户数据等。

登录selfservice-instance2虚机,发送元数据服务请求:

$ curl http://169.254.169.254/1.0/meta-data
(以下为返回结果)
ami-id
ami-launch-index
ami-manifest-path
hostname
instance-id
local-ipv4
public-keys/
reservation-id
security-groups
  • 169.254.169.254 是 OpenStack 中用于访问虚拟机元数据的 IP 地址。

  • /1.0/meta-data 是元数据服务的 URI。

此命令的目的是从虚拟机获取与实例相关的元数据,如实例 ID、AMI ID 等。

 对vmware workstation vmnet8抓包:

  • 2269请求帧:虚机发出一个HTTP GET请求,请求路径为 /1.0/meta-data,
  • 2272响应帧:169.254.169.254发回一个HTTP响应,状态码为200 OK,表示请求成功。响应内容类型为 text/plain

 查看2269 请求帧HTTP 报文内容:

字段含义
GET /1.0/meta-data HTTP/1.1表示请求的是元数据服务 API v1 的 meta-data 路径
Host: 169.254.169.254虽然是 link-local 地址,仍按 HTTP/1.1 规范需提供 Host 头
User-Agent: curl/7.42.1请求是通过 curl 命令发起的
Accept: */*接受任意类型的响应

 查看2272 响应帧内容:

这是虚拟机访问 OpenStack 元数据服务的 完整响应,且返回了 HTTP/1.1 200 OK,说明:

元数据服务可用,网络路径配置正常,元数据代理工作正常

响应内容解析:

HTTP 响应头:

  • Status Code: 200 OK:请求成功。

  • Content-Type: text/plain; charset=UTF-8:返回的是纯文本格式。

  • Content-Length: 117:正文长度为 117 字节。

  • Date::响应时间戳。

正文(元数据目录列表):

ami-id
ami-launch-index
ami-manifest-path
hostname
instance-id
local-ipv4
public-keys/
reservation-id
security-groups 

虚拟机可以进一步访问以下路径来获取具体信息,例如:

curl http://169.254.169.254/1.0/meta-data/hostname
curl http://169.254.169.254/1.0/meta-data/local-ipv4

3.1.4 qrouter 命名空间内 HAProxy 拦截请求

请求通过虚机网卡发送到 qrouter 命名空间中的 qr-* 接口。iptables 规则将所有目标为 169.254.169.254:80 的请求重定向到本地的 HAProxy(监听端口 9697)。HAProxy 会将请求通过 Unix domain socket /var/lib/neutron/metadata_proxy 转发给 neutron-metadata-agent

以下为查看步骤:

1、查看haproxy pid

root@controller:~# ip netns
qdhcp-48f2b88e-7740-4d94-a631-69e2abadf25b (id: 1)
qdhcp-28d343c8-1cbb-4d3a-b69c-7d9afe5840fa (id: 2)
qrouter-782e8b74-a13c-4e8c-83dd-066f49e55ac2 (id: 0)root@controller:~# ip netns pid qrouter-782e8b74-a13c-4e8c-83dd-066f49e55ac2
2045

pid: 这是 ip netns 子命令的一个选项,用于查找拥有特定网络命名空间的进程的 PID。

qrouter-782e8b74-a13c-4e8c-83dd-066f49e55ac2:这是 OpenStack Neutron 路由器的一个网络命名空间的名称。通常,每个 Neutron 路由器都会创建一个相应的网络命名空间。

该命令的作用是显示与指定进程 qrouter-782e8b74-a13c-4e8c-83dd-066f49e55ac2 相关的网络命名空间的进程 ID。 

该命令的输出显示,qrouter-782e8b74-a13c-4e8c-83dd-066f49e55ac2 网络命名空间当前与进程 ID 2045 相关联。这个进程 ID 对应的是某个在该命名空间内运行的进程(例如,haproxy)。

root@controller:~# ps fw -p 2045PID TTY      STAT   TIME COMMAND2045 ?        Ssl    0:00 haproxy -f /var/lib/neutron/ns-metadata-proxy/782e8b74-a13c-4e8c-83dd-066f49e55ac2.conf
root@controller:~# 

ps fw -p 2045

  • ps:是一个用于查看当前运行的进程状态的命令。

  • fw:是 ps 命令的选项,表示 "full width"。这个选项会提供进程的完整信息,包括每个进程的命令行参数、父进程 ID 等。

  • -p 2045:指定查看进程 ID 为 2045 的进程的信息。

输出信息:

  • PID:进程的 ID 号,表示进程的唯一标识符。这里的 PID2045,表示该进程的 ID 是 2045。

  • TTY:该进程所连接的终端(如果有的话)。? 表示该进程没有关联终端,即它是一个后台进程或守护进程。

  • STAT:进程的状态:

    • S:表示进程处于 "sleeping" 状态,意味着进程在等待某个事件(比如 I/O 操作)完成。

    • s:表示该进程是一个会话领导进程。

    • l:表示进程有多线程。

    • 所以 Ssl 表示该进程是一个会话领导进程,并且是一个多线程的睡眠状态进程。

  • TIME:进程使用的 CPU 时间。这里的 0:00 表示该进程并没有消耗大量的 CPU 时间,通常是因为它只是等待 I/O 操作。

  • COMMAND:启动进程的命令行及其参数。在这里,haproxy -f /var/lib/neutron/ns-metadata-proxy/782e8b74-a13c-4e8c-83dd-066f49e55ac2.conf 表示该进程是由 haproxy 启动的,并且使用了配置文件 /var/lib/neutron/ns-metadata-proxy/782e8b74-a13c-4e8c-83dd-066f49e55ac2.conf

总结:

  • 进程 2045 是由 haproxy 启动的,作为 Neutron metadata agent的一部分,正在处理与虚拟机元数据相关的请求。

  • 它正在后台运行,没有关联到任何终端(?),并且处于睡眠状态,等待事件(如网络连接)处理。

2、查看socket通信

 a. 在 Controller 节点执行 strace 命令:

strace 命令用于跟踪进程执行过程中发生的系统调用和信号。

首先,在 Controller 节点上使用 strace 命令来监控haproxy 进程的网络通信,特别是 recvfromsendto 系统调用。

root@controller:~# strace -f -e trace=recvfrom,sendto -p 2045
  • -f 选项表示追踪进程的所有子进程。

  • -e trace=recvfrom,sendto 指定只追踪 recvfromsendto 系统调用,通常用于网络通信。

  • -p 2045 表示监控进程 ID 为 2045 的进程(通常是 haproxy 或其他 Neutron 元数据代理进程)。

b. 在虚拟机中发送元数据服务请求:

接着,在虚拟机 selfservice-instance2 中,使用 curl 命令向元数据服务发送 HTTP 请求,查询元数据。

curl http://169.254.169.254/1.0/meta-data 

c. 在 Controller 节点终端显示 strace 输出:

当虚拟机发送请求后,Controller 节点上的 strace 命令会显示以下输出,这些信息展示了进程 2045 进行的网络操作:

root@controller:~# strace -f -e trace=recvfrom,sendto -p 2045                   
strace: Process 2045 attached with 4 threads
[pid  2045] recvfrom(16, "GET /1.0/meta-data HTTP/1.1\r\nHos"..., 16320, 0, NULL, NULL) = 92
[pid  2045] sendto(17, "GET /1.0/meta-data HTTP/1.1\r\nhos"..., 208, MSG_DONTWAIT|MSG_NOSIGNAL, NULL, 0) = 208
[pid  2045] recvfrom(17, 0x559769a4b8c0, 16320, 0, NULL, NULL) = -1 EAGAIN (Resource temporarily unavailable)
[pid  2045] recvfrom(17, "HTTP/1.1 200 OK\r\nContent-Type: t"..., 16320, 0, NULL, NULL) = 254
[pid  2045] sendto(16, "HTTP/1.1 200 OK\r\ncontent-type: t"..., 235, MSG_DONTWAIT|MSG_NOSIGNAL, NULL, 0) = 235
[pid  2045] recvfrom(16, "", 16320, 0, NULL, NULL) = 0
  • recvfrom(16, "GET /1.0/meta-data HTTP/1.1\r\nHos"..., 16320, 0, NULL, NULL) = 92进程 2045套接字 16 中接收到来自虚拟机的 HTTP 请求(GET 请求),长度为 92 字节。

  • sendto(17, "GET /1.0/meta-data HTTP/1.1\r\nhos"..., 208, MSG_DONTWAIT|MSG_NOSIGNAL, NULL, 0) = 208进程 2045 向套接字 17 发送一个请求,发送的数据大小为 208 字节。

  • recvfrom(17, 0x5635992018c0, 16320, 0, NULL, NULL) = -1 EAGAIN (Resource temporarily unavailable):尝试从套接字 17 接收数据,但资源暂时不可用(EAGAIN),表示没有数据可读。

  • recvfrom(17, "HTTP/1.1 200 OK\r\nContent-Type: t"..., 16320, 0, NULL, NULL) = 254:最终接收到来自元数据服务的响应,长度为 254 字节,响应状态为 HTTP/1.1 200 OK

  • sendto(16, "HTTP/1.1 200 OK\r\ncontent-type: t"..., 235, MSG_DONTWAIT|MSG_NOSIGNAL, NULL, 0) = 235进程 2045 向虚拟机返回 HTTP 响应,内容为元数据请求的结果,长度为 235 字节。

  • recvfrom(16, "", 16320, 0, NULL, NULL) = 0:接收到一个空响应,表示连接已关闭。

3.1.5 neutron-metadata-agent 请求 nova metadata API

neutron metadata agent 解包请求,并通过 HTTP 请求转发给运行在 controller 节点的 nova-api(nova-metadata-api)(默认监听 8775 端口),由 Nova 负责返回对应的 metadata。

1、controller节点运行wireshark。由于当前neutron metadata agent和nova api(nova metadata api)都安装在controller节点,他们之间可以通过controller loopback0进行抓包查看:

数据包编号4459:是一个HTTP请求,具体是“GET /1.0/meta-data HTTP/1.1”,这是一个元数据服务的请求。 

数据包编号5723:是一个HTTP响应数据包。状态码为200,表示请求成功,并且响应的内容类型是“text/plain”(纯文本)。

2、查看4459数据包报文内容: 

Frame 4459: 454 bytes on wire (3632 bits), 454 bytes captured (3632 bits) on interface lo, id 0
Ethernet II, Src: 00:00:00_00:00:00 (00:00:00:00:00:00), Dst: 00:00:00_00:00:00 (00:00:00:00:00:00)
Internet Protocol Version 4, Src: 10.0.20.11, Dst: 10.0.20.11
Transmission Control Protocol, Src Port: 41542, Dst Port: 8775, Seq: 1, Ack: 1, Len: 388
Hypertext Transfer ProtocolGET /1.0/meta-data HTTP/1.1\r\n[Expert Info (Chat/Sequence): GET /1.0/meta-data HTTP/1.1\r\n][GET /1.0/meta-data HTTP/1.1\r\n][Severity level: Chat][Group: Sequence]Request Method: GETRequest URI: /1.0/meta-dataRequest Version: HTTP/1.1Host: controller:8775\r\nUser-Agent: python-requests/2.25.1\r\nAccept-Encoding: gzip, deflate\r\nAccept: */*\r\nConnection: keep-alive\r\nX-Forwarded-For: ::ffff:172.16.1.152\r\nX-Instance-ID: 12faa86b-252a-4400-94d8-80dd4585b9d3\r\nX-Tenant-ID: f5e75a3f7cc347ad89d20dcfe70dae01\r\nX-Instance-ID-Signature: 5a0a5a4b322614e1a076f06166590421d8cc293624e90a20061350d5217742a3\r\n\r\n[Full request URI: http://controller:8775/1.0/meta-data][HTTP request 1/1][Response in frame: 5723]

这一帧(Frame 4459)正是从 Neutron Metadata Agent 发往 Nova Metadata API(端口 8775)HTTP 请求

包含的 Header:

  • X-Forwarded-For: ::ffff:172.16.1.152
    → 映射到 VM 的 IPv4 地址,标明 metadata 请求的源头;

  • X-Instance-ID: 12faa86b-252a-4400-94d8-80dd4585b9d3
    → VM 的 UUID;

  • X-Tenant-ID: f5e75a3f7cc347ad89d20dcfe70dae01
    → 所属项目/租户;

  • X-Instance-ID-Signature: 5a0a...742a3
    → 用于验证请求来源合法性的签名(由 metadata agent 用 shared secret 签名生成);

3、查看5723数据包报文内容: 

Frame 5723: 325 bytes on wire (2600 bits), 325 bytes captured (2600 bits) on interface lo, id 0
Ethernet II, Src: 00:00:00_00:00:00 (00:00:00:00:00:00), Dst: 00:00:00_00:00:00 (00:00:00:00:00:00)
Internet Protocol Version 4, Src: 10.0.20.11, Dst: 10.0.20.11
Transmission Control Protocol, Src Port: 8775, Dst Port: 41542, Seq: 1, Ack: 389, Len: 259
Hypertext Transfer ProtocolHTTP/1.1 200 OK\r\nContent-Length: 117\r\nContent-Type: text/plain; charset=UTF-8\r\nDate: Thu, 08 May 2025 01:03:23 GMT\r\nConnection: keep-alive\r\n\r\n[HTTP response 1/1][Time since request: 0.943338378 seconds][Request in frame: 4459][Request URI: http://controller:8775/1.0/meta-data]File Data: 117 bytes
Line-based text data: text/plain (9 lines)ami-id\nami-launch-index\nami-manifest-path\nhostname\ninstance-id\nlocal-ipv4\npublic-keys/\nreservation-id\nsecurity-groups

Nova Metadata API 的返回响应,状态码 HTTP/1.1 200 OK,返回了虚拟机的 metadata 信息。

这说明整条从 VM → HAProxy → Neutron Metadata Agent → Nova API 的 metadata 请求链路是通畅的,也进一步验证了你之前抓到的请求数据是完整的、正确的。 

3.1.6 结果返回虚拟机

Nova 返回的 metadata 经过 neutron-metadata-agent、HAProxy,最终返回给虚拟机的 cloud-init 使用。(返回结果已经在通信过程中说明)

3.2 Provider network场景测试

实例元数据通信过程(provider network场景)

3.2.1 虚拟机启动

虚机启动后,开始初始化网络和系统配置。

启动provider-instance虚机(位于compute1节点,属于provider network)。

root@osclient ~(myproject/myuser)# source myproject-admin-openrc 
root@osclient ~(myproject/admin)# openstack server show provider-instance
+-------------------------------------+----------------------------------------------------------+
| Field                               | Value                                                    |
+-------------------------------------+----------------------------------------------------------+
| OS-DCF:diskConfig                   | MANUAL                                                   |
| OS-EXT-AZ:availability_zone         | nova                                                     |
| OS-EXT-SRV-ATTR:host                | compute1                                                 |
| OS-EXT-SRV-ATTR:hypervisor_hostname | compute1                                                 |
| OS-EXT-SRV-ATTR:instance_name       | instance-00000009                                        |
| OS-EXT-STS:power_state              | Shutdown                                                 |
| OS-EXT-STS:task_state               | None                                                     |
| OS-EXT-STS:vm_state                 | stopped                                                  |
| OS-SRV-USG:launched_at              | 2025-04-27T15:30:56.000000                               |
| OS-SRV-USG:terminated_at            | None                                                     |
| accessIPv4                          |                                                          |
| accessIPv6                          |                                                          |
| addresses                           | provider=203.0.113.213                                   |
| config_drive                        |                                                          |
| created                             | 2025-04-27T15:30:53Z                                     |
| flavor                              | m1.nano (0)                                              |
| hostId                              | 892d1a79d804f6b0fbfb68938ec0df8a0abc8e3d52660529538123e4 |
| id                                  | 4dfb51e2-3b48-4cc7-b947-92d13500a8f9                     |
| image                               | cirros (429decdd-9230-49c0-b735-70364c226eb5)            |
| key_name                            | mykey                                                    |
| name                                | provider-instance                                        |
| project_id                          | f5e75a3f7cc347ad89d20dcfe70dae01                         |
| properties                          |                                                          |
| security_groups                     | name='default'                                           |
| status                              | SHUTOFF                                                  |
| updated                             | 2025-04-28T10:14:16Z                                     |
| user_id                             | 9382b59561c04dd1abf0a4cb7a8252ec                         |
| volumes_attached                    |                                                          |
+-------------------------------------+----------------------------------------------------------+root@osclient ~(myproject/admin)# source demo-openrc
root@osclient ~(myproject/myuser)# openstack server start provider-instance

3.2.2 通过 DHCP 获取 IP 和元数据路由

DHCP 服务由 neutron-dhcp-agent 提供,虚机获取到其私有 IP 地址,并添加了一条指向 169.254.169.254 的默认 metadata 路由,下一跳指向qdhcp。

此时,虚机将发送DHCP Discover,qdhcp将发送DHCP Offer。

对vmware workstation vmnet6抓包:

这段内容显示的是DHCP(动态主机配置协议)的通信过程,具体包括以下步骤:

DHCP Discover:虚机在这个阶段广播一个Discover消息,告知网络中的所有DHCP服务器它需要一个IP地址。 

DHCP Offer:DHCP服务器(qdhcp)收到Discover消息后,提供一个IP地址(203.0.113.213)给客户端,并发送一个Offer消息。

DHCP Request:客户端收到Offer消息后,广播一个Request消息,表示它接受服务器提供的IP地址。

DHCP ACK:DHCP服务器收到Request消息后,发送一个ACK消息,确认IP地址的分配。

这些报文用于 Controller 节点上的 qdhcp 与 compute1 节点上的虚拟机之间的通信。

查看DHCP Offer报文内容:

Frame 7: 370 bytes on wire (2960 bits), 370 bytes captured (2960 bits) on interface \Device\NPF_{EB0EAC8F-F071-4EC9-8E4B-BA92C6F6A612}, id 0
Ethernet II, Src: fa:16:3e:5b:d6:a5, Dst: fa:16:3e:17:9a:47
Internet Protocol Version 4, Src: 203.0.113.101, Dst: 203.0.113.213
User Datagram Protocol, Src Port: 67, Dst Port: 68
Dynamic Host Configuration Protocol (Offer)Message type: Boot Reply (2)Hardware type: Ethernet (0x01)Hardware address length: 6Hops: 0Transaction ID: 0xe2897a69Seconds elapsed: 0Bootp flags: 0x0000 (Unicast)Client IP address: 0.0.0.0Your (client) IP address: 203.0.113.213Next server IP address: 203.0.113.101Relay agent IP address: 0.0.0.0Client MAC address: fa:16:3e:17:9a:47Client hardware address padding: 00000000000000000000Server host name not givenBoot file name not givenMagic cookie: DHCPOption: (53) DHCP Message Type (Offer)Option: (54) DHCP Server Identifier (203.0.113.101)Option: (51) IP Address Lease TimeOption: (58) Renewal Time ValueOption: (59) Rebinding Time ValueOption: (1) Subnet Mask (255.255.255.0)Option: (28) Broadcast Address (203.0.113.255)Option: (15) Domain NameOption: (3) RouterLength: 4Router: 203.0.113.1Option: (121) Classless Static RouteLength: 14169.254.169.254/32-203.0.113.101default-203.0.113.1Option: (6) Domain Name ServerOption: (26) Interface MTUOption: (255) End

Classless Static Route (Option 121)

169.254.169.254/32 → 203.0.113.101
default → 203.0.113.1

这表示:

  • 当 VM 访问 169.254.169.254(即 metadata 服务地址)时,应当把数据包发送给 203.0.113.101(这是 qdhcp namespace 中的接口 IP)

  • 而默认路由仍然是 203.0.113.1(通常是外部网络的router gateway);

这是 Neutron DHCP agent 在向虚拟机分配地址时,添加的路由规则,确保:

  1. 虚拟机能通过 169.254.169.254 访问元数据;

  2. 实际是通过 qrouter namespace 中的 metadata proxy(绑定在 203.0.113.101)中转;

  3. 然后转发给 HAProxy,通过 unix socket 给 neutron-metadata-agent,最终到 nova-api。

查看qdhcp地址信息:

root@controller:~# ip netns exec qdhcp-48f2b88e-7740-4d94-a631-69e2abadf25b ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00inet 127.0.0.1/8 scope host lovalid_lft forever preferred_lft foreverinet6 ::1/128 scope host valid_lft forever preferred_lft forever
2: ns-a51b2fe4-04@if12: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default qlen 1000link/ether fa:16:3e:5b:d6:a5 brd ff:ff:ff:ff:ff:ff link-netnsid 0inet 203.0.113.101/24 brd 203.0.113.255 scope global ns-a51b2fe4-04valid_lft forever preferred_lft foreverinet 169.254.169.254/32 brd 169.254.169.254 scope global ns-a51b2fe4-04valid_lft forever preferred_lft foreverinet6 fe80::a9fe:a9fe/128 scope link valid_lft forever preferred_lft foreverinet6 fe80::f816:3eff:fe5b:d6a5/64 scope link valid_lft forever preferred_lft forever
root@controller:~# 

查看provider-instance虚机路由信息:

$ ip route
default via 203.0.113.1 dev eth0 
169.254.169.254 via 203.0.113.101 dev eth0 
203.0.113.0/24 dev eth0  src 203.0.113.213 
$ 

169.254.169.254 via 203.0.113.101 dev eth0

  • 这是访问元数据服务的特殊路由,明确告诉系统:去访问元数据服务时需要经过qdhcp(即通过 qdhcp namespace)。

  • 这是 OpenStack 在 provider  network中为了拦截元数据请求,特意配置的静态路由。

 3.2.3 虚拟机发起 metadata 请求

云初始化服务(如 cloud-init)尝试从 http://169.254.169.254:80 获取配置数据,例如 ssh 公钥、用户数据等。

登录provider-instance虚机,发送元数据服务请求:

$ curl http://169.254.169.254/1.0/meta-data
(以下为返回结果)
ami-id
ami-launch-index
ami-manifest-path
hostname
instance-id
local-ipv4
public-keys/
reservation-id
security-groups

对vmware workstation vmnet6抓包:

  • 73请求帧:虚机发出一个HTTP GET请求,请求路径为 /1.0/meta-data,
  • 76响应帧:169.254.169.254发回一个HTTP响应,状态码为200 OK,表示请求成功。响应内容类型为 text/plain

 查看编号为 73的请求帧HTTP 请求报文内容:

Frame 73: 158 bytes on wire (1264 bits), 158 bytes captured (1264 bits) on interface \Device\NPF_{EB0EAC8F-F071-4EC9-8E4B-BA92C6F6A612}, id 0
Ethernet II, Src: fa:16:3e:17:9a:47, Dst: fa:16:3e:5b:d6:a5
Internet Protocol Version 4, Src: 203.0.113.213, Dst: 169.254.169.254
Transmission Control Protocol, Src Port: 39822, Dst Port: 80, Seq: 1, Ack: 1, Len: 92
Hypertext Transfer ProtocolGET /1.0/meta-data HTTP/1.1\r\nHost: 169.254.169.254\r\nUser-Agent: curl/7.42.1\r\nAccept: */*\r\n\r\n[Response in frame: 76][Full request URI: http://169.254.169.254/1.0/meta-data]
字段含义
GET /1.0/meta-data HTTP/1.1表示请求的是元数据服务 API v1 的 meta-data 路径
Host: 169.254.169.254虽然是 link-local 地址,仍按 HTTP/1.1 规范需提供 Host 头
User-Agent: curl/7.42.1请求是通过 curl 命令发起的
Accept: */*接受任意类型的响应

 查看编号为 76 的响应帧内容:

Frame 76: 301 bytes on wire (2408 bits), 301 bytes captured (2408 bits) on interface \Device\NPF_{EB0EAC8F-F071-4EC9-8E4B-BA92C6F6A612}, id 0
Ethernet II, Src: fa:16:3e:5b:d6:a5, Dst: fa:16:3e:17:9a:47
Internet Protocol Version 4, Src: 169.254.169.254, Dst: 203.0.113.213
Transmission Control Protocol, Src Port: 80, Dst Port: 39822, Seq: 1, Ack: 93, Len: 235
Hypertext Transfer ProtocolHTTP/1.1 200 OK\r\ncontent-type: text/plain; charset=UTF-8\r\ncontent-length: 117\r\ndate: Thu, 08 May 2025 02:47:48 GMT\r\n\r\n[Request in frame: 73][Time since request: 0.391419000 seconds][Request URI: /1.0/meta-data][Full request URI: http://169.254.169.254/1.0/meta-data]File Data: 117 bytes
Line-based text data: text/plain (9 lines)ami-id\nami-launch-index\nami-manifest-path\nhostname\ninstance-id\nlocal-ipv4\npublic-keys/\nreservation-id\nsecurity-groups

这是虚拟机访问 OpenStack 元数据服务的 完整响应,且返回了 HTTP/1.1 200 OK,说明:

元数据服务可用,网络路径配置正常,元数据代理工作正常

响应内容解析:

HTTP 响应头:

  • Status Code: 200 OK:请求成功。

  • Content-Type: text/plain; charset=UTF-8:返回的是纯文本格式。

  • Content-Length: 117:正文长度为 117 字节。

  • Date::响应时间戳。

正文(元数据目录列表):

ami-id
ami-launch-index
ami-manifest-path
hostname
instance-id
local-ipv4
public-keys/
reservation-id
security-groups 

虚拟机可以进一步访问以下路径来获取具体信息,例如:

curl http://169.254.169.254/1.0/meta-data/hostname
curl http://169.254.169.254/1.0/meta-data/local-ipv4

3.2.4 qdhcp 命名空间内 HAProxy 拦截请求

请求通过虚机网卡发送到 qdhcp命名空间中的 qr-* 接口。HAProxy正在监听169.254.169.254:80端口,从而截获元数据请求。

root@controller:~# ip netns exec qdhcp-48f2b88e-7740-4d94-a631-69e2abadf25b netstat -tnlp | grep haproxy
tcp        0      0 169.254.169.254:80      0.0.0.0:*               LISTEN      2280/haproxy        
tcp6       0      0 fe80::a9fe:a9fe:80      :::*                    LISTEN      2280/haproxy        
root@controller:~# 

HAProxy 会将请求通过 Unix domain socket /var/lib/neutron/metadata_proxy 转发给 neutron-metadata-agent

以下为查看步骤:

1、查看haproxy pid

root@controller:~# ip netns
qdhcp-48f2b88e-7740-4d94-a631-69e2abadf25b (id: 1)
qdhcp-28d343c8-1cbb-4d3a-b69c-7d9afe5840fa (id: 2)
qrouter-782e8b74-a13c-4e8c-83dd-066f49e55ac2 (id: 0)root@controller:~# ip netns pid qdhcp-48f2b88e-7740-4d94-a631-69e2abadf25b
2280
10029

这个 qdhcp-... 网络命名空间中,有两个进程在运行:

  • 2280 是 HAProxy;

  • 10029 是另一个进程,dnsmasq,因为 DHCP agent 会在每个子网起一个 dnsmasq 用来给虚拟机分配 IP 地址。

root@controller:~# ps fw -p 2280PID TTY      STAT   TIME COMMAND2280 ?        Ssl    0:00 haproxy -f /var/lib/neutron/ns-metadata-proxy/48f2b88e-7740-4d94-a631-69e2abadf25b.conf
root@controller:~# root@controller:~# ps -fp 10029
UID          PID    PPID  C STIME TTY          TIME CMD
nobody     10029       1  0 01:41 ?        00:00:00 dnsmasq --no-hosts --no-resolv --pid-file=/var/lib/neutron/dhcp/48f2b88e-7740-4d94-a63

ps fw -p 2280

  • fw:是 ps 命令的选项,表示 "full width"。这个选项会提供进程的完整信息,包括每个进程的命令行参数、父进程 ID 等。

输出信息:

  • TTY:该进程所连接的终端(如果有的话)。? 表示该进程没有关联终端,即它是一个后台进程或守护进程。

  • STAT:进程的状态:

    • S:表示进程处于 "sleeping" 状态,意味着进程在等待某个事件(比如 I/O 操作)完成。

    • s:表示该进程是一个会话领导进程。

    • l:表示进程有多线程。

    • 所以 Ssl 表示该进程是一个会话领导进程,并且是一个多线程的睡眠状态进程。

  • TIME:进程使用的 CPU 时间。这里的 0:00 表示该进程并没有消耗大量的 CPU 时间,通常是因为它只是等待 I/O 操作。

  • COMMAND:启动进程的命令行及其参数。在这里,haproxy -f /var/lib/neutron/ns-metadata-proxy/48f2b88e-7740-4d94-a631-69e2abadf25b.conf 表示该进程是由 haproxy 启动的,并且使用了配置文件 /var/lib/neutron/ns-metadata-proxy/48f2b88e-7740-4d94-a631-69e2abadf25b.conf

总结:

  • 进程 2280 是由 haproxy 启动的,作为 Neutron metadata agent的一部分,正在处理与虚拟机元数据相关的请求。

  • 它正在后台运行,没有关联到任何终端(?),并且处于睡眠状态,等待事件(如网络连接)处理。

2、查看socket通信

 a. 在 Controller 节点执行 strace 命令:

strace 命令用于跟踪进程执行过程中发生的系统调用和信号。

首先,在 Controller 节点上使用 strace 命令来监控haproxy 进程的网络通信,特别是 recvfromsendto 系统调用。

root@controller:~# strace -f -e trace=recvfrom,sendto -p 2280
  • -f 选项表示追踪进程的所有子进程。

  • -e trace=recvfrom,sendto 指定只追踪 recvfromsendto 系统调用,通常用于网络通信。

  • -p 2280 表示监控进程 ID 为 2280 的进程(通常是 haproxy 或其他 Neutron 元数据代理进程)。

b. 在虚拟机中发送元数据服务请求:

接着,在虚拟机 provider-instance中,使用 curl 命令向元数据服务发送 HTTP 请求,查询元数据。

curl http://169.254.169.254/1.0/meta-data 

c. 在 Controller 节点终端显示 strace 输出:

当虚拟机发送请求后,Controller 节点上的 strace 命令会显示以下输出,这些信息展示了进程 2280进行的网络操作:

root@controller:~# strace -f -e trace=recvfrom,sendto -p 2280
strace: Process 2280 attached with 4 threads
[pid  2281] recvfrom(17, "GET /1.0/meta-data HTTP/1.1\r\nHos"..., 16320, 0, NULL, NULL) = 92
[pid  2281] sendto(18, "GET /1.0/meta-data HTTP/1.1\r\nhos"..., 203, MSG_DONTWAIT|MSG_NOSIGNAL, NULL, 0) = 203
[pid  2281] recvfrom(18, 0x7fe700029d10, 16320, 0, NULL, NULL) = -1 EAGAIN (Resource temporarily unavailable)
[pid  2281] recvfrom(18, "HTTP/1.1 200 OK\r\nContent-Type: t"..., 16320, 0, NULL, NULL) = 254
[pid  2281] sendto(17, "HTTP/1.1 200 OK\r\ncontent-type: t"..., 235, MSG_DONTWAIT|MSG_NOSIGNAL, NULL, 0) = 235
[pid  2281] recvfrom(17, "", 16320, 0, NULL, NULL) = 0

从 strace 输出可以非常明确地看出 HAProxy 是如何通过 Unix domain socket 把请求转发给 Neutron metadata agent 的。
HAProxy 的进程(PID 2280),它监听在 metadata 地址 169.254.169.254:80,通过 strace 看到了下面这些 syscall:
recvfrom(17, ...) = 92        ← 从网卡收到 VM 的 metadata 请求
sendto(18, ...) = 203         ← 把请求转发到 /var/lib/neutron/metadata_proxy(Unix socket)
recvfrom(18, ...) = 254       ← 从 metadata_agent 得到响应
sendto(17, ...) = 235         ← 把响应回给 VM

3.2.5 neutron-metadata-agent 请求 nova metadata API

neutron metadata agent 解包请求,并通过 HTTP 请求转发给运行在 controller 节点的 nova-api(nova-metadata-api)(默认监听 8775 端口),由 Nova 负责返回对应的 metadata。

1、controller节点运行wireshark。由于当前neutron metadata agent和nova api(nova metadata api)都安装在controller节点,他们之间可以通过controller loopback0进行抓包查看:

数据包编号7120:是一个HTTP请求,具体是“GET /1.0/meta-data HTTP/1.1”,这是一个元数据服务的请求。 

数据包编号8556:是一个HTTP响应数据包。状态码为200,表示请求成功,并且响应的内容类型是“text/plain”(纯文本)。

2、查看7120数据包报文内容: 

Frame 7120: 448 bytes on wire (3584 bits), 448 bytes captured (3584 bits) on interface lo, id 0
Ethernet II, Src: 00:00:00_00:00:00 (00:00:00:00:00:00), Dst: 00:00:00_00:00:00 (00:00:00:00:00:00)
Internet Protocol Version 4, Src: 10.0.20.11, Dst: 10.0.20.11
Transmission Control Protocol, Src Port: 48824, Dst Port: 8775, Seq: 1, Ack: 1, Len: 382
Hypertext Transfer ProtocolGET /1.0/meta-data HTTP/1.1\r\n[Expert Info (Chat/Sequence): GET /1.0/meta-data HTTP/1.1\r\n][GET /1.0/meta-data HTTP/1.1\r\n][Severity level: Chat][Group: Sequence]Request Method: GETRequest URI: /1.0/meta-dataRequest Version: HTTP/1.1Host: controller:8775\r\nUser-Agent: python-requests/2.25.1\r\nAccept-Encoding: gzip, deflate\r\nAccept: */*\r\nConnection: keep-alive\r\nX-Forwarded-For: 203.0.113.213\r\nX-Instance-ID: 4dfb51e2-3b48-4cc7-b947-92d13500a8f9\r\nX-Tenant-ID: f5e75a3f7cc347ad89d20dcfe70dae01\r\nX-Instance-ID-Signature: 9fc97b0600cd9896ba2b779546216e19d0b4bf2562cbad97d5ce090d44c9fddf\r\n\r\n[Full request URI: http://controller:8775/1.0/meta-data][HTTP request 1/1][Response in frame: 8556]

3、查看8556数据包报文内容: 

Frame 8556: 325 bytes on wire (2600 bits), 325 bytes captured (2600 bits) on interface lo, id 0
Ethernet II, Src: 00:00:00_00:00:00 (00:00:00:00:00:00), Dst: 00:00:00_00:00:00 (00:00:00:00:00:00)
Internet Protocol Version 4, Src: 10.0.20.11, Dst: 10.0.20.11
Transmission Control Protocol, Src Port: 8775, Dst Port: 48824, Seq: 1, Ack: 383, Len: 259
Hypertext Transfer ProtocolHTTP/1.1 200 OK\r\n[Expert Info (Chat/Sequence): HTTP/1.1 200 OK\r\n][HTTP/1.1 200 OK\r\n][Severity level: Chat][Group: Sequence]Response Version: HTTP/1.1Status Code: 200[Status Code Description: OK]Response Phrase: OKContent-Length: 117\r\nContent-Type: text/plain; charset=UTF-8\r\nDate: Thu, 08 May 2025 03:35:44 GMT\r\nConnection: keep-alive\r\n\r\n[HTTP response 1/1][Time since request: 1.277074807 seconds][Request in frame: 7120][Request URI: http://controller:8775/1.0/meta-data]File Data: 117 bytes
Line-based text data: text/plain (9 lines)ami-id\nami-launch-index\nami-manifest-path\nhostname\ninstance-id\nlocal-ipv4\npublic-keys/\nreservation-id\nsecurity-groups

Nova Metadata API 的返回响应,状态码 HTTP/1.1 200 OK,返回了虚拟机的 metadata 信息。

这说明整条从 VM → HAProxy → Neutron Metadata Agent → Nova API 的 metadata 请求链路是通畅的,也进一步验证了你之前抓到的请求数据是完整的、正确的。 

3.2.6 结果返回虚拟机

Nova 返回的 metadata 经过 neutron-metadata-agent、HAProxy,最终返回给虚拟机的 cloud-init 使用。(返回结果已经在通信过程中说明)

http://www.xdnf.cn/news/346609.html

相关文章:

  • docker mac m1 部署 doris
  • VR制作软件用途(VR制作软件概述)
  • 如何阅读、学习 Git 核心源代码 ?
  • Vue知识框架
  • 为什么用Maple教授微分方程
  • Oracle EBS AP发票被预付款核算创建会计科目时间超长
  • 1688代采系统:技术架构与应用实践
  • mac运行java文件提示 错误: 缺少 JavaFX 运行时组件, 需要使用该组件来运行此应用程序
  • nginx 配置后端健康检查模块
  • AMO数据集:解决运动模仿偏差的超灵巧人形机器人全身控制混合数据集。
  • 【使用switch结构输出季节】2021-11-23
  • bootstrap入门
  • 15:00面试,15:06就出来了,问的问题有点变态。。。
  • 私服与外挂:刑事法律风险的深度剖析
  • 存储器:DDR和独立显卡的GDDR有什么区别?
  • (十二)深入了解AVFoundation-采集:人脸识别与元数据处理
  • gitee推送更新失败问题记录:remote: error: hook declined to update refs/heads/master
  • 代码随想录第38天:动态规划11(编辑距离)
  • Babylon.js学习之路《一、初识 Babylon.js:什么是 3D 开发与 WebGL 的完美结合?》
  • JavaScript中数组和对象不同遍历方法的顺序规则
  • 使用chrome浏览器截长图
  • 端口转发与跨域处理
  • 电商平台的流量秘密:代理IP在用户行为分析中的角色
  • WordPress插件:WPJAM Basic优化设置
  • HPE Primera 600 全闪存阵列,添加控制器教程!
  • DBeaver查询PostgreSQL的只读模式
  • RocketMQ的事务消息机制
  • 云平台搭建
  • SATA SSD 与 NVMe PCIe SSD 性能差距有多大?
  • python中的数据封装