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 通过 元数据机制 提供这些信息。
元数据机制
元数据的作用
元数据就是一些关于实例的信息,这些信息对于实例的启动、配置、以及后续管理非常重要。它通常包括:
实例的唯一标识符(例如,UUID)
网络配置(如 IP 地址、网络掩码等)
用户数据(自定义脚本、配置等)
SSH 公钥和其他认证信息
实例的安全设置(如 root 密码)
传递方式:配置驱动 vs. 元数据服务
Nova 提供了两种主要方式来将元数据传递给实例:
配置驱动(Config Drive):配置驱动是一种将元数据嵌入到实例的磁盘中,并在实例启动时通过虚拟磁盘读取的方式。它通常用于没有网络连接的情况下,或者在一些特殊场景下。
元数据服务(Metadata Service):元数据服务是一种通过网络连接提供元数据的机制。实例启动后,它可以通过 HTTP 请求从 OpenStack 的元数据服务获取这些信息。它是一个动态的、可以随时更新的服务,实例通过访问它来获取各种配置信息。
用户数据(User Data)
用户数据是元数据的一部分,允许用户在实例启动时传递自定义的配置或脚本。这些数据通常以脚本的形式传递,实例在启动时执行这些脚本。这对自动化配置非常有用。例如,用户可以通过用户数据设置实例的主机名、安装软件包、配置防火墙规则等。cloud-init 是一个广泛使用的工具,它帮助实例处理这些用户数据。它能够解析用户传递的脚本,并执行相应的配置步骤。
元数据的类型
元数据可以根据不同的需求进行自定义,通常包含以下几种类型:
系统信息
包括实例的 ID、镜像 ID、主机名等。通常由 OpenStack 管理,并且对于实例的管理和调度很重要。网络信息
包括实例的 IP 地址、子网掩码、网关等。这些信息由 OpenStack 的网络服务提供。用户数据
自定义的配置或脚本数据,通常由用户指定,在实例启动时由 cloud-init 或其他类似工具执行。SSH 公钥
这通常用于实例的 SSH 认证,用户可以在启动实例时提供 SSH 公钥,实例会自动配置该公钥以便用户可以通过 SSH 访问。安全信息
包括实例的安全组、密码等敏感信息。用户可以通过元数据服务来访问这些信息。总结
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.254
或 fe80::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 后端,其流程大致如下:
-
实例发送 HTTP 请求以获取元数据,目标地址为 169.254.169.254。
-
该请求会根据实例中的路由表,要么进入路由器命名空间(router namespace),要么进入 DHCP 命名空间。
-
命名空间内的元数据代理服务(metadata proxy)会将以下信息添加到请求头中:
-
实例的 IP 地址(添加
X-Forwarded-For
头) -
路由器或网络的 ID(添加
X-Neutron-Network-Id
或X-Neutron-Router-Id
头)
-
-
元数据代理服务通过 UNIX 域套接字(UNIX domain socket)将该请求发送到命名空间外部的元数据代理(metadata agent)。
-
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-Id
或X-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 中,实例访问元数据服务的请求路径取决于该实例所连接的网络类型,主要分为两类: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安装信息
Nova和Neutron相关服务安装信息:
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/group
是neutron
,运行权限控制。
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场景测试

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
网络命名空间当前与进程 ID2045
相关联。这个进程 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 号,表示进程的唯一标识符。这里的
PID
是2045
,表示该进程的 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
进程的网络通信,特别是 recvfrom
和 sendto
系统调用。
root@controller:~# strace -f -e trace=recvfrom,sendto -p 2045
-f
选项表示追踪进程的所有子进程。
-e trace=recvfrom,sendto
指定只追踪recvfrom
和sendto
系统调用,通常用于网络通信。
-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场景测试

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 在向虚拟机分配地址时,添加的路由规则,确保:
虚拟机能通过
169.254.169.254
访问元数据;实际是通过 qrouter namespace 中的 metadata proxy(绑定在
203.0.113.101
)中转;然后转发给 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
进程的网络通信,特别是 recvfrom
和 sendto
系统调用。
root@controller:~# strace -f -e trace=recvfrom,sendto -p 2280
-f
选项表示追踪进程的所有子进程。
-e trace=recvfrom,sendto
指定只追踪recvfrom
和sendto
系统调用,通常用于网络通信。
-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 使用。(返回结果已经在通信过程中说明)