1. OpenStack Placement 服务:为什么它不是“可有可无”的配角,而是云平台调度的真正中枢
你有没有遇到过这样的情况:在 OpenStack 云平台上创建虚拟机时,明明计算节点还有大量空闲 CPU 和内存,nova-scheduler 却死活找不到合适的宿主机?或者,你给虚拟机指定了一个特定的 Cinder 存储卷,结果 nova 却把虚拟机调度到了完全不连通该存储后端的计算节点上,导致启动失败?又或者,你想把一批需要 SR-IOV 网卡的高性能虚拟机,只部署在配备了特定网卡型号的服务器上,但现有的过滤器(Filter)却束手无策?这些看似“玄学”的调度失败,其根源往往不在 Nova 本身,而在于一个被很多初学者和运维人员严重低估的服务——Placement。
Placement 不是 Nova 的一个子模块,也不是一个锦上添花的监控插件。它是从 OpenStack Pike 版本起就强制启用、并在 Stein 版本彻底独立出来的核心基础设施服务。它的存在,直接回答了云平台最根本的一个问题:“我的资源,到底在哪里?还剩多少?” 在 Placement 出现之前,Nova 的 Resource Tracker 只能“数自己家的米”——它只知道计算节点本地的 CPU、内存、磁盘,对于由 Cinder 提供的块存储、由 Neutron 提供的网络端口、甚至是由外部 SDS(软件定义存储)或 NFV(网络功能虚拟化)设备提供的资源,它一概不知。这就像一个只认识自家仓库管理员的采购经理,却要负责为整个集团的工厂调配所有原材料,其结果必然是混乱与低效。
Placement 的核心价值,就在于它构建了一个统一、抽象、可扩展的“资源账本”。它将一切可以被消费的实体——无论是物理服务器、GPU 卡、SR-IOV 虚拟功能(VF)、共享存储池,还是一个逻辑上的网络子网——都抽象为一个Resource Provider(资源提供者)。每个 Resource Provider 都拥有自己的Inventory(库存),即它能提供多少种资源(VCPU、MEMORY_MB、DISK_GB、SRIOV_NET_VF),每种资源的总容量和当前已用量是多少;同时,它还拥有自己的Traits(特征标签),用来描述其独一无二的属性(HW_CPU_X86_AVX2、CUSTOM_HIGH_PERF、MISC_SHARES_VIA_AGGREGATE)。当用户发起一个创建虚拟机的请求时,nova-scheduler 不再是凭经验“猜”,而是向 Placement API 发起一个精确的查询:“我需要 2 个 VCPU、4096MB 内存、50GB 磁盘,并且这个节点必须支持 AVX2 指令集和 SR-IOV 网络”,Placement 则会返回一份详尽的Allocation Candidates(分配候选人)清单,其中不仅列出了哪些资源提供者能满足要求,还精确地告诉你它们各自的资源使用率和特征。这才是现代云平台实现精细化、智能化、可编程化调度的基石。如果你正在部署一个生产级的 OpenStack 环境,尤其是涉及异构硬件、多后端存储或高级网络功能的场景,跳过 Placement 的部署,无异于在高速公路上只画了一条虚线,却指望所有车辆都能自动对齐行驶。它不是流程的一部分,它就是流程本身。
2. 核心设计与架构拆解:Placement 如何用三层模型重构资源管理范式
理解 Placement 的部署,绝不能停留在“照着文档敲几行命令”的层面。必须深入其背后的设计哲学,否则在后续的排错和调优中,你会陷入“知其然,不知其所以然”的困境。Placement 的整个架构,可以用一个清晰的三层模型来概括:Provider 层、Inventory/Traits 层、以及 Consumer/Allocation 层。这三层并非简单的堆叠,而是环环相扣、相互制约的有机整体。
2.1 Provider 层:一切资源的“身份证”与“户口本”
在 Placement 的世界里,“资源”没有高低贵贱之分,只有“提供者”(Resource Provider)这一种身份。一个计算节点(Compute Node)是一个 Provider,一台物理存储服务器(Cinder Backend)是一个 Provider,一个网络交换机上的一个端口池(Neutron Port Pool)同样是一个 Provider。甚至,一个逻辑概念,比如一个用于存放高安全级别虚拟机的“安全隔离区”(Security Zone),也可以被建模为一个 Provider。这种极致的抽象,是 Placement 能够统一纳管所有类型资源的根本原因。
每一个 Provider 都有一个全球唯一的 UUID,这是它的“身份证号”。更重要的是,它还有一个“户口本”,即root_provider_uuid和parent_provider_uuid构成的树状结构。例如,一台物理服务器(Root Provider)上可能插着一块 GPU 卡(Child Provider),而这块 GPU 卡上又划分出了多个 CUDA Core(Grandchild Provider)。通过这种父子关系,Placement 能够精确地追踪到一个资源请求最终消耗的是哪一块物理芯片上的哪一个计算单元。这解决了传统方案中“资源归属不清”的老大难问题。当你看到parent_provider_uuid字段为空时,就意味着这是一个顶级的、不可再分割的物理资源实体。部署时,我们首先要确保所有关键的 Provider(尤其是计算节点)都被正确地注册到 Placement 中,这是整个资源账本得以建立的第一步。
2.2 Inventory/Traits 层:资源的“数量”与“质量”双维度刻画
如果说 Provider 是资源的“人”,那么 Inventory 和 Traits 就是它的“简历”。Inventory 描述的是“数量”,即这个 Provider 能提供什么、能提供多少。它是一组键值对,Key 是标准化的Resource Class(资源类别),如VCPU、MEMORY_MB、DISK_GB、SRIOV_NET_VF;Value 则是一个包含total(总量)、reserved(预留量)、min_unit(最小分配单位)、max_unit(最大分配单位)和step_size(步长)的 JSON 对象。这里的关键在于,reserved字段的存在,使得 Placement 可以预留一部分资源给系统自身(如 Hypervisor 开销)或特定用途,避免资源被完全耗尽。
Traits 则描述的是“质量”,即这个 Provider 具备哪些独特的、非数值化的特征。它是一组字符串标签,分为两类:一类是社区预定义的、以HW_或CUSTOM_开头的标准 Trait(如HW_CPU_X86_AVX2),另一类则是用户自定义的、以CUSTOM_为前缀的业务标签(如CUSTOM_FINANCE_DEPT)。Traits 的强大之处在于其组合性。你可以用required=HW_CPU_X86_AVX2,CUSTOM_FINANCE_DEPT这样的查询条件,精准地筛选出既具备高性能计算能力,又归属于财务部门专属资源池的 Provider。这比传统的 Host Aggregate 更加灵活和强大,因为它不依赖于 Nova 的调度逻辑,而是直接作用于资源数据层。在部署配置中,placement.conf文件里的[api]和[keystone_authtoken]部分,本质上就是在为这个“简历”管理系统配置访问权限和认证方式,确保只有经过授权的服务(如 Nova)才能读写这份关键的“人才档案”。
2.3 Consumer/Allocation 层:资源的“消费者”与“占用凭证”
当一个虚拟机(VM)被创建时,它在 Placement 的世界里就变成了一个Consumer(消费者),并获得一个唯一的 UUID(通常就是 VM 的 instance_uuid)。Consumer 本身不拥有任何资源,它只是资源的“使用者”。真正的资源占用,体现在Allocation(分配)记录上。Allocation 表是 Placement 数据库的核心,它记录了每一次资源分配的“三方协议”:谁(consumer_id)向谁(resource_provider_id)申请了什么(resource_class_id)以及多少(used)。这个设计极其精妙。它意味着资源的占用状态是“事件驱动”的,而不是“状态轮询”的。Nova 在启动 VM 前,会先向 Placement 发起一个claim_resources请求,Placement 会在数据库中插入一条 Allocation 记录,并原子性地更新对应 Provider 的 Inventory 使用量。如果此时另一个并发请求也想占用同一份资源,Placement 会因为数据库的唯一约束或乐观锁机制而拒绝,从而保证了资源分配的强一致性。这正是 Placement 能够替代 Nova 旧有过滤器(CpuFilter 等)的根本技术保障——它把资源调度从一个基于“猜测”的概率游戏,变成了一个基于“事实”的确定性事务。部署完成后,检查allocations表是否为空,是验证 Placement 是否真正开始工作的第一个黄金指标。
3. 核心部署环节详解:从零开始构建 Placement 服务的完整实操链
部署 Placement 并非一个孤立的动作,它是一个嵌入在整个 OpenStack 控制节点初始化流程中的关键环节。下面我将基于 Rocky 或更高版本的 OpenStack(推荐使用 Ussuri 或 Wallaby),为你拆解每一个步骤背后的原理、参数选择的依据,以及那些文档里绝不会写的“潜规则”。
3.1 数据库准备:为什么必须用 MySQL/MariaDB,而非 SQLite?
Placement 服务对数据库的并发读写性能和事务一致性有极高要求。虽然官方文档有时会提到 SQLite 作为开发测试选项,但在任何生产环境,这都是一个危险的信号。SQLite 是一个文件级数据库,其锁粒度是整个数据库文件,在高并发的云环境中,这会导致严重的性能瓶颈和锁等待。因此,我们必须使用一个真正的客户端-服务器架构的数据库,如 MariaDB(MySQL 的一个主流分支)。
# 1. 登录数据库,创建专用数据库 $ mysql -u root -p MariaDB [(none)]> CREATE DATABASE placement CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci; # 2. 创建专用用户并授予权限 # 注意:这里我们使用 'placement'@'%' 而非 'placement'@'localhost' # 因为在分布式部署中,Placement API 可能运行在独立的控制节点上,需要从网络访问数据库 MariaDB [(none)]> GRANT ALL PRIVILEGES ON placement.* TO 'placement'@'%' IDENTIFIED BY 'YourStrongPassword123!'; MariaDB [(none)]> FLUSH PRIVILEGES;关键参数解析与避坑心得:
CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci:这是强制要求。Placement 的某些字段(如 Traits 名称)可能包含 emoji 或其他四字节 Unicode 字符,utf8编码(在 MySQL 中实际是utf8mb3)无法支持,会导致插入失败。'placement'@'%':这是生产环境的黄金配置。如果你错误地只授予了'placement'@'localhost'权限,那么当你的 OpenStack 环境是多节点(如 controller、compute 分离)时,Placement 服务将无法连接数据库,报错Access denied for user 'placement'@'controller'。这个错误非常隐蔽,因为controller主机名在数据库看来就是一个远程 IP 地址。- 密码强度:
YourStrongPassword123!仅作示例。生产环境必须使用符合复杂度要求的密码,且该密码将在后续的placement.conf配置文件中重复出现,务必妥善保管。
3.2 Keystone 服务注册:不只是“走个过场”,而是建立信任链
Placement 作为一个独立的 OpenStack 服务,它必须像 Nova、Glance 一样,在 Keystone 的服务目录(Service Catalog)中注册自己,以便其他服务能够发现并调用它。这个过程远不止是创建一个用户那么简单,它是在 Keystone 的身份认证体系中,为 Placement 建立一条完整的信任链。
# 1. 加载 admin 凭据 $ source admin-openrc # 2. 创建 placement 用户(注意:密码必须与 placement.conf 中的配置一致) $ openstack user create --domain default --password-prompt placement # 输入密码:YourPlacementPassword456! # 3. 将 placement 用户添加到 service 项目,并赋予 admin 角色 # 这一步至关重要!Placement API 需要 admin 权限来执行数据库同步等管理操作 $ openstack role add --project service --user placement admin # 4. 创建 Placement 服务实体 $ openstack service create --name placement --description "Placement API" placement # 5. 创建三个端点(public, internal, admin) # 这是 OpenStack 的标准实践,确保不同网络区域的服务都能访问 $ openstack endpoint create --region RegionOne placement public http://controller:8778 $ openstack endpoint create --region RegionOne placement internal http://controller:8778 $ openstack endpoint create --region RegionOne placement admin http://controller:8778为什么必须是admin角色?Placement 的placement-manage db sync命令,本质上是执行一系列 DDL(数据定义语言)操作,如创建表、添加索引、修改字段。这些操作在 Keystone 的 RBAC(基于角色的访问控制)模型下,只有admin角色才被授权。如果你错误地只给了member角色,那么在执行数据库同步时,你会收到HTTP 403 Forbidden错误,提示权限不足。这是一个新手最容易踩的坑,也是排查 Placement 启动失败的第一个检查点。
3.3 Placement 服务安装与配置:placement.conf文件的逐行精读
在控制节点上安装 Placement 服务包后,核心工作就是编辑/etc/placement/placement.conf文件。这个文件虽小,但每一行都牵一发而动全身。
[DEFAULT] # 日志级别,生产环境建议设为 WARNING 或 ERROR,避免日志爆炸 debug = false log_dir = /var/log/placement [api] # 这是 Placement API 的核心策略:必须启用 Keystone 认证 auth_strategy = keystone # 这个配置决定了 Placement API 的监听地址和端口 # 默认是 0.0.0.0:8778,即监听所有网卡的 8778 端口 # 如果你的控制节点有多个网卡,且只想让内部网络访问,可以改为 bind_host = 192.168.1.10 bind_host = 0.0.0.0 bind_port = 8778 [placement_database] # 数据库连接字符串,必须与前面创建的数据库信息完全一致 # 注意:connection 字符串中的密码,必须是 URL 编码后的形式 # 如果你的密码包含特殊字符(如 @, /, :),必须进行编码,否则连接会失败 connection = mysql+pymysql://placement:YourStrongPassword123%21@controller/placement [keystone_authtoken] # 这是 Placement 服务向 Keystone 自我证明身份的凭证 # 它告诉 Keystone:“我是 placement 服务,我属于 service 项目” auth_url = http://controller:5000/v3 memcached_servers = controller:11211 auth_type = password project_domain_name = default user_domain_name = default project_name = service username = placement password = YourPlacementPassword456! # 这个配置非常重要!它指定了 Placement 服务使用的认证域 # 必须与 Keystone 中创建的 placement 用户所在的 domain 一致 # 默认是 default,但如果你们的环境使用了自定义 domain,这里必须修改 domain_name = default最关键的配置项:connection字符串的 URL 编码这是我在无数个深夜排错后总结出的血泪教训。mysql+pymysql://连接字符串中的密码,如果包含@、/、:、?、#等 URL 保留字符,必须进行百分号编码(Percent-encoding)。例如,密码P@ssw0rd/123必须编码为P%40ssw0rd%2F123。否则,PyMySQL 会将@之后的内容误认为是主机名,导致连接controller失败。一个简单的方法是,在配置前,先用 Python 的urllib.parse.quote_plus()函数对密码进行编码:
>>> from urllib.parse import quote_plus >>> quote_plus("P@ssw0rd/123") 'P%40ssw0rd%2F123'把这个编码后的字符串填入connection配置项,就能彻底避免这个“幽灵错误”。
3.4 数据库初始化与服务启动:验证部署成功的“三板斧”
完成配置后,最后一步是初始化数据库并启动服务。但这一步的验证,不能只看systemctl status显示active (running)就万事大吉。
# 1. 初始化数据库(这一步会创建所有必需的表和索引) $ su -s /bin/sh -c "placement-manage db sync" placement # 2. 重启 Apache HTTPD 服务(Placement API 通常以 WSGI 应用的形式托管在 Apache 下) $ systemctl restart httpd # 3. 验证服务是否真正可用 # 第一板斧:检查 Apache 的 error_log,确认没有与 placement 相关的 ImportError 或 ConfigurationError $ tail -f /var/log/httpd/error_log | grep -i placement # 第二板斧:使用 curl 直接调用 Placement API 的健康检查端点 # 如果返回 HTTP 200,说明服务进程和 Web 服务器都正常 $ curl -i http://controller:8778/healthcheck HTTP/1.1 200 OK Content-Length: 2 Content-Type: application/json; charset=UTF-8 Date: Mon, 01 Jan 2024 00:00:00 GMT {} # 第三板斧:最关键的一步,检查数据库中的 allocations 表是否为空 # 这个表在初始化后应该是空的,因为还没有任何资源被分配 $ mysql -u placement -pYourStrongPassword123! placement -e "SELECT COUNT(*) FROM allocations;" +----------+ | COUNT(*) | +----------+ | 0 | +----------+为什么allocations表必须为空?因为allocations表是 Placement 的“心脏”。如果这个表在初始化后就有数据,那说明数据库被污染了,或者之前的部署残留了脏数据。一个健康的 Placement 服务,其allocations表应该从零开始,随着 Nova 的资源上报和虚拟机创建而自然增长。如果这里不为零,后续的资源调度一定会出错,必须清空该表(TRUNCATE TABLE allocations;)并重新检查。
4. 实操过程与核心环节实现:从服务启动到资源上报的全链路打通
部署完成只是万里长征第一步。真正的挑战在于,如何让 Placement 与 Nova 等上游服务无缝协同,形成一个闭环。这个过程充满了细节,任何一个环节的疏忽,都会导致整个资源调度链条断裂。
4.1 Nova 侧的配置联动:nova.conf中的 Placement 关键配置
Placement 服务本身是被动的,它只提供 API。真正驱动它运转的,是 Nova 的各个组件。因此,我们必须在 Nova 的配置文件/etc/nova/nova.conf中,进行精确的联动配置。
[placement] # 这是 Nova 与 Placement 通信的“地址簿” # 必须与 Keystone 中注册的 Placement public 端点完全一致 os_region_name = RegionOne auth_url = http://controller:5000/v3 auth_type = password project_domain_name = default user_domain_name = default project_name = service username = placement password = YourPlacementPassword456! # 这个配置决定了 Nova 如何缓存 Placement 的响应 # 在高并发环境下,合理的缓存可以极大减轻 Placement 的压力 # 但缓存时间过长,又会导致 Nova 获取到过期的资源信息 # 生产环境建议设置为 30 秒,这是一个平衡点 cache = oslo_cache.memcache memcache_servers = controller:11211cache配置的深度解析:Nova 的placement部分配置了一个缓存层,其目的是为了提升性能。然而,这个缓存是一把双刃剑。如果cache配置错误(例如,memcache_servers指向了一个不存在的 Memcached 服务),Nova 在启动时并不会报错,但它会默默地退回到无缓存模式,导致 Placement API 的请求量激增,拖垮整个控制平面。更隐蔽的问题是,如果缓存中的数据过期了,Nova 可能会基于一个已经失效的资源视图(例如,一个已经被删除的 Provider)做出错误的调度决策。因此,在生产环境中,我强烈建议在首次部署后,先将cache配置注释掉(# cache = ...),待整个系统稳定运行一周后,再逐步启用并调整缓存时间。这是一种“宁稳勿快”的务实策略。
4.2 资源上报机制:nova-compute如何成为 Placement 的“耳目”
Nova 的nova-compute服务,是 Placement 最重要的“数据采集员”。它会周期性地(默认每 30 秒)将自己的资源信息(CPU、内存、磁盘)上报给 Placement。这个过程的成败,直接决定了 Placement 的“账本”是否准确。
# 1. 确保 nova-compute 服务已启动 $ systemctl start openstack-nova-compute $ systemctl enable openstack-nova-compute # 2. 查看 nova-compute 的日志,寻找资源上报成功的标志 $ journalctl -u openstack-nova-compute -f | grep -i "reporting to placement" # 正常的日志输出应该类似于: # INFO nova.compute.resource_tracker [req-xxx] Successfully reported to placement for resource provider 5c5a578f-51b0-481c-b38c-7aaa3394e585上报失败的典型症状与根因分析:如果你在日志中看不到上述成功信息,或者看到Failed to report to placement的错误,那么问题一定出在nova.conf的[placement]配置上。最常见的根因有三个:
- 网络不通:
nova-compute所在的计算节点无法访问controller:8778。请在计算节点上执行curl -v http://controller:8778/healthcheck进行测试。 - 认证失败:
nova.conf中的username和password与 Keystone 中的placement用户不匹配。请再次核对。 - Provider 未注册:这是最隐蔽的错误。
nova-compute在第一次上报时,会尝试在 Placement 中注册自己作为一个 Resource Provider。如果这个注册失败(例如,Placement 数据库连接异常),后续的所有上报都会失败。此时,你需要手动检查 Placement 的日志/var/log/placement/placement.log,查找ResourceProviderNotFound或DatabaseError相关的错误。
4.3 验证与调试:用openstackCLI 和curl进行端到端的穿透测试
部署的最终目标,是让一个虚拟机能够被成功创建。我们可以用一组简洁的 CLI 命令,来模拟这个端到端的流程。
# 1. 列出所有已注册的 Resource Provider(即所有计算节点) $ openstack resource provider list +--------------------------------------+-----------+------------+--------------------------------------+----------------------+ | uuid | name | generation | root_provider_uuid | parent_provider_uuid | +--------------------------------------+-----------+------------+--------------------------------------+----------------------+ | 5c5a578f-51b0-481c-b38c-7aaa3394e585 | controller| 26 | 5c5a578f-51b0-481c-b38c-7aaa3394e585 | None | +--------------------------------------+-----------+------------+--------------------------------------+----------------------+ # 2. 查看某个 Provider 的详细 Inventory(资源库存) $ openstack resource provider inventory show 5c5a578f-51b0-481c-b38c-7aaa3394e585 +------------------+--------------------------------------+ | Field | Value | +------------------+--------------------------------------+ | DISK_GB | capacity='49', reserved='0', ... | | MEMORY_MB | capacity='60670', reserved='512', ... | | VCPU | capacity='512', reserved='0', ... | +------------------+--------------------------------------+ # 3. 查询满足特定资源需求的 Allocation Candidates(这是调度的核心) # 这个命令会触发 nova-scheduler 向 Placement 发起的第一次 API 调用 $ openstack allocation candidate list --resource VCPU=1,MEMORY_MB=2048,DISK_GB=10 +---+----------------------------------+--------------------------------------+----------------------------------------------+--------------------------------------------------------------+ | # | allocation | resource provider | inventory used/capacity | traits | +---+----------------------------------+--------------------------------------+----------------------------------------------+--------------------------------------------------------------+ | 1 | VCPU=1,MEMORY_MB=2048,DISK_GB=10 | 5c5a578f-51b0-481c-b38c-7aaa3394e585 | VCPU=5/512,MEMORY_MB=3648/60670,DISK_GB=7/49 | HW_CPU_X86_SSE2,HW_CPU_X86_SSE,HW_CPU_X86_MMX,HW_CPU_X86_SVM | +---+----------------------------------+--------------------------------------+----------------------------------------------+--------------------------------------------------------------+ # 4. (可选)手动触发一次虚拟机创建,观察整个流程 $ openstack server create --flavor m1.small --image cirros --network private test-vm # 如果创建成功,立刻去数据库检查 allocations 表 $ mysql -u placement -pYourStrongPassword123! placement -e "SELECT * FROM allocations;"allocation candidate list命令的实战意义:这个命令是 Placement 部署后最有力的“验金石”。它不依赖于 Nova 的任何调度逻辑,而是直接调用 Placement API。如果这个命令能成功返回结果,就证明 Placement 服务本身、数据库、Keystone 认证、以及 Nova 的配置全部是正确的。反之,如果这个命令失败,那么问题一定出在 Placement 的核心链路上,你可以立即聚焦于此,而无需在 Nova 的庞杂日志中大海捞针。
5. 常见问题与排查技巧实录:那些让你抓狂的“玄学”错误及独家解决方案
在无数次的 OpenStack 部署与维护中,我整理了一份 Placement 相关的“高频故障速查表”。这些问题,往往没有明确的错误信息,或者错误信息极具误导性,是新人最容易陷入的“黑洞”。
5.1 故障现象:openstack allocation candidate list命令返回HTTP 401 Unauthorized
表面症状:执行命令后,CLI 报错The request you have made requires authentication.,或者Authentication failed.。
深层根因与独家排查路径:这个问题的根源,99% 都在于 Keystone 的admin-openrc文件。请不要急于检查 Placement 的配置,而是按以下顺序逐一排查:
- 检查
OS_AUTH_URL:echo $OS_AUTH_URL,确认它指向的是http://controller:5000/v3,而不是http://controller:35357/v3(旧版 Keystone 管理端口,已废弃)。 - 检查
OS_IDENTITY_API_VERSION:echo $OS_IDENTITY_API_VERSION,必须是3。如果为空或为2,则 Keystone 会尝试用 v2 协议进行认证,而 Placement 只支持 v3。 - 检查
OS_PROJECT_NAME:echo $OS_PROJECT_NAME,必须是admin。openstackCLI 在执行allocation candidate list时,会使用当前 shell 环境中的项目(Project)进行认证。如果OS_PROJECT_NAME是service或其他项目,而该项目下的admin用户没有被授予 Placement 服务的访问权限,就会导致 401。 - 终极验证:绕过 CLI,直接用
curl模拟认证:
如果# 1. 先获取一个 admin token $ curl -i -X POST http://controller:5000/v3/auth/tokens \ -H "Content-Type: application/json" \ -d '{ "auth": { "identity": { "methods": ["password"], "password": { "user": { "name": "admin", "domain": {"name": "default"}, "password": "YourAdminPassword" } } }, "scope": { "project": { "name": "admin", "domain": {"name": "default"} } } } }' | grep -i "x-subject-token" # 2. 用获取到的 token 调用 Placement API $ curl -i -X GET http://controller:8778/allocation_candidates?resources=VCPU:1 \ -H "X-Auth-Token: gAAAAAB..." \ -H "OpenStack-API-Version: placement 1.21"curl成功而openstackCLI 失败,那问题 100% 出在你的admin-openrc环境变量上。
5.2 故障现象:nova-compute日志中反复出现Failed to report to placement,且placement.log中有ConnectionRefusedError
表面症状:nova-compute无法上报,Placement 服务看起来是“活”的(systemctl status正常),但curl http://controller:8778/healthcheck却超时。
深层根因与独家解决方案:这几乎可以断定是 Apache 的 WSGI 配置问题。Placement API 是通过 Apache 的mod_wsgi模块加载的,其配置文件通常位于/etc/httpd/conf.d/10-placement-api.conf。请检查该文件中WSGIScriptAlias指令的路径是否正确:
# 正确的配置(Rocky 及以后版本) WSGIScriptAlias / /usr/bin/placement-api # 错误的配置(Ocata/Pike 版本的遗留配置) WSGIScriptAlias / /usr/bin/placement-api.wsgi在较新版本的 OpenStack 中,placement-api已经是一个可执行的 Python 脚本,不再需要.wsgi后缀。如果你的配置文件中还保留着旧的.wsgi路径,Apache 就会找不到入口点,导致所有请求都被拒绝。解决方案是:备份原配置文件,然后用rpm -ql openstack-placement-api | grep conf命令找到 RPM 包自带的最新配置文件,将其覆盖到/etc/httpd/conf.d/目录下,再重启httpd。这是 RPM 包升级后最常被忽略的一步。
5.3 故障现象:openstack resource provider list返回空列表,但nova-compute日志显示上报成功
表面症状:一切看起来都正常,但 Placement 的“资源地图”上却一片空白。
深层根因与独家解决方案:这是一个经典的“时间差”问题。nova-compute的上报是周期性的(默认 30 秒),而openstackCLI 的查询是即时的。你可能恰好在两次上报的间隙执行了查询命令。但这只是表象,真正的根因在于nova-compute的resource_provider配置。
请检查/etc/nova/nova.conf文件的[DEFAULT]部分:
[DEFAULT] # 这个配置项必须存在,且值必须为 True # 它告诉 nova-compute:“请把我自己注册为一个 Resource Provider” # 如果这个配置项被注释掉或设为 False,nova-compute 就永远不会向 Placement 注册自己 enable_resource_provider_cache = true此外,还有一个更隐蔽的配置项:
[DEFAULT] # 这个配置项决定了 nova-compute 在上报时,是使用自己的主机名(hostname), # 还是使用一个固定的、由管理员指定的名称。 # 如果你的计算节点主机名是 `compute01.local`,但你在 Keystone 中注册的端点是 `http://compute01/`, # 那么 Placement 可能会因为域名解析问题而无法关联。 # 解决方案是显式指定一个简短、稳定的名称 host = compute01独家技巧:在nova-compute日志中,搜索Creating resource provider。如果看到了这条日志,说明注册请求已经发出;如果没看到,那问题就出在enable_resource_provider_cache配置上。如果看到了,但placement.log中没有对应的Created resource provider日志,那问题就出在网络或数据库连接上。
5.4 故障现象:openstack allocation candidate list返回结果,但nova-scheduler仍然找不到主机
表面症状:Placement 的 API 一切正常,但虚拟机创建依然失败,nova-scheduler日志中显示No valid host was found。
深层根因与独家解决方案:这说明问题已经从 Placement 层,转移到了 Nova 的调度器(Scheduler)层。Placement 只负责回答“有哪些资源可用”,而 Scheduler 还要回答“哪些资源最适合”。nova-scheduler的filter_scheduler会将 Placement 返回的Allocation Candidates,再经过一层过滤(Filter)和权衡(Weigher)。
请检查/etc/nova/nova.conf文件的[filter_scheduler]部分:
[filter_scheduler] # 这个配置项必须包含 'AggregateInstanceExtraSpecsFilter' 和 'AvailabilityZoneFilter' # 它们负责处理 Host Aggregate 和 Availability Zone 的逻辑 enabled_filters = RetryFilter, AvailabilityZoneFilter, ComputeFilter, ComputeCapabilitiesFilter, ImagePropertiesFilter, ServerGroupAntiAffinityFilter, ServerGroupAffinityFilter, AggregateInstanceExtraSpecsFilter, NUMATopologyFilter # 这个配置项必须包含 'RamWeigher' 和 'DiskWeigher' # 它们负责根据内存和磁盘的剩余量进行排序 weight_classes = nova.scheduler.weights.ram.RamWeigher,nova.scheduler.weights.disk.DiskWeigher最关键的一点:ComputeFilter是一个“兜底”过滤器,它会检查计算节点的state和status是否为up和enabled。如果nova-compute服务在某个节点上意外停止了