1. 为什么手动装 Nova 之前,得先把 RabbitMQ 和 Keystone 这两块地基打牢
搞 OpenStack 的人多少都有个共识:Nova 是整个云平台的“调度大脑”,虚机的创建、迁移、销毁全靠它指挥。但很多人一上来就急着apt install nova-api nova-compute,结果服务起不来,日志里全是AMQP connection refused或者Unauthorized,然后开始满世界找答案。我踩过这个坑不止一次,后来才想明白一件事——Nova 本身不存状态,它所有的协调动作都依赖两个外部组件:一个是消息队列,一个是身份认证。这两样没配好,Nova 就是个空壳。
这篇内容就是围绕“手动安装 Nova 之前,RabbitMQ 和 Keystone 到底该怎么配”来展开的。适合谁看?如果你正在跟着官方文档一步步搭 OpenStack,或者想搞清楚 Nova 各服务之间到底怎么通信、怎么鉴权,那这篇就是给你准备的。我会把每个配置项背后的逻辑讲清楚,不只是告诉你“填这个值”,而是告诉你“为什么是这个值”。手动安装的好处就在于,每一步你都得自己动手,反而能把组件之间的依赖关系摸透,这比用自动化部署工具学到的多得多。
先说结论性的判断:RabbitMQ 负责 Nova 内部各服务之间的异步消息传递,Keystone 负责所有 API 请求的身份验证和服务目录注册。Nova 的nova-api、nova-scheduler、nova-conductor、nova-compute这几个服务,彼此之间不直接调用,全靠 RabbitMQ 中转;而任何外部请求进来,或者服务之间需要确认对方身份,都得走 Keystone。所以这两个组件配错了,后面所有步骤都是白费。
2. 整体设计思路:为什么是 RabbitMQ 加 Keystone 这个组合
2.1 Nova 的通信模型决定了消息队列的选型
Nova 的架构是典型的“去中心化协作”模式。你创建一个虚机,请求先到nova-api,它把任务丢进消息队列,nova-scheduler从队列里拿到任务去选计算节点,选完再丢回队列,nova-conductor负责数据库操作,最后nova-compute在目标节点上真正执行。这几个服务可能跑在不同机器上,它们之间没有直接的 RPC 调用,全靠消息队列做解耦。
那为什么选 RabbitMQ 而不是别的?OpenStack 社区早期确实支持过 Qpid 和 ZeroMQ,但 RabbitMQ 因为成熟度高、社区活跃、AMQP 协议标准化程度好,成了事实标准。手动安装场景下,RabbitMQ 的配置也相对直观——你只需要一个虚拟主机(vhost)、一个用户、一组权限,就能让 Nova 跑起来。我实测下来,RabbitMQ 3.x 系列配合 Nova 的兼容性最稳,建议用 3.8 以上的版本。
这里有个设计上的关键点:Nova 不同服务用的是同一个 RabbitMQ 用户,但通过不同的 exchange 和 queue 来区分消息类型。你不需要为每个服务单独建用户,但 vhost 要独立出来,避免和其他 OpenStack 组件(比如 Neutron、Cinder)的消息混在一起。这个隔离思路很重要,后面排查问题时你会感谢自己当初分了 vhost。
2.2 Keystone 的角色:不只是登录认证那么简单
很多人对 Keystone 的理解停留在“用户名密码验证”,其实它在 Nova 手动安装里承担了三件事。第一是服务注册,Nova 的每个服务(api、conductor、scheduler、compute)都要在 Keystone 里注册一个 service 和对应的 endpoint,否则其他组件找不到它。第二是用户与权限,Nova 各服务之间通信要用专门的 service 账号,不能用 admin 账号凑合。第三是令牌签发,所有 API 请求携带的 token 都由 Keystone 颁发和校验。
手动配置 Keystone 时最容易出错的地方是 endpoint 的 URL 格式。Nova 的 endpoint 分 public、internal、admin 三种类型,端口都是 8774,但 URL 里的 host 要根据你的网络规划来填。如果你所有服务都在一台机器上做实验,那三个 URL 可以一样;但如果是多节点部署,public 用对外 IP,internal 用管理网 IP,admin 用 localhost 或管理网 IP,这个区分必须提前想清楚。我见过有人三个都填了公网 IP,结果内部通信绕了一圈公网,延迟高得离谱。
2.3 两者的配置顺序有讲究
正确的顺序是先 Keystone 后 RabbitMQ,原因很实际:Keystone 装好后你可以立刻验证认证是否正常,而 RabbitMQ 的用户权限配置需要你确认服务账号已经存在。如果你先配 RabbitMQ 再装 Keystone,中间出了问题你分不清是消息队列的锅还是认证的锅。另外,Nova 的配置文件里[DEFAULT]段的transport_url和[keystone_authtoken]段是分开写的,但服务启动时会先连 Keystone 拿 token,再连 RabbitMQ 发消息,所以 Keystone 不通的话,RabbitMQ 配得再对也没用。
3. Keystone 依赖配置的完整实操
3.1 数据库与基础服务的准备
Keystone 自己也需要数据库。手动安装时,先在 MySQL 里建库建用户:
CREATE DATABASE keystone; GRANT ALL PRIVILEGES ON keystone.* TO 'keystone'@'localhost' IDENTIFIED BY '你的密码'; GRANT ALL PRIVILEGES ON keystone.* TO 'keystone'@'%' IDENTIFIED BY '你的密码';这里有个细节:'keystone'@'%'这条授权在多节点场景下必须加,否则其他节点上的服务连不上 Keystone 的数据库。但如果你只是单机实验,加localhost就够了。密码别用太简单的,后面 Keystone 的配置文件里要明文写进去,虽然可以加权限保护,但基础强度还是要保证。
装包的时候注意版本对齐。如果你用的是某个 Linux 发行版自带的 OpenStack 软件源,keystone包的版本要和后面装的nova包版本匹配。我一般会先apt policy keystone看一眼可用版本,确认和 Nova 是同一个 release(比如都是 Wallaby 或 Yoga)。版本错配是手动安装里最隐蔽的坑,症状往往是服务能启动但 API 返回 500,日志里报一些莫名其妙的字段缺失。
3.2 keystone.conf 的关键配置项拆解
配置文件在/etc/keystone/keystone.conf,手动改的话重点看三个段:
[database] connection = mysql+pymysql://keystone:你的密码@控制节点IP/keystone [token] provider = fernet [DEFAULT] log_dir = /var/log/keystone[token]段的provider = fernet是必须的。早期版本用过 UUID token,但 Fernet 是现在的默认推荐,它自带加密和过期机制,不需要每次验证都查数据库,性能好很多。配完这个之后要执行keystone-manage fernet_setup和keystone-manage credential_setup来生成密钥,这两个命令分别生成 token 加密密钥和 credential 密钥,缺一不可。
然后初始化数据库:
su -s /bin/sh -c "keystone-manage db_sync" keystone这条命令用keystone系统用户执行,避免权限问题。执行完你可以进 MySQL 看一眼keystone库里有没有生成一堆表,有就说明数据库连接配置对了。
3.3 引导 Keystone 服务与创建 Nova 所需账号
引导命令是手动安装里最关键的一步:
keystone-manage bootstrap --bootstrap-password 管理密码 \ --bootstrap-admin-url http://控制节点IP:5000/v3/ \ --bootstrap-internal-url http://控制节点IP:5000/v3/ \ --bootstrap-public-url http://控制节点IP:5000/v3/ \ --bootstrap-region-id RegionOne这条命令做了三件事:创建 admin 项目、创建 admin 用户、把 Keystone 自己注册为服务。RegionOne是区域名,单区域部署随便填,但多区域时要和后续 Nova 的配置对应上。
接下来创建 Nova 需要的项目和服务账号。Nova 各服务之间通信用的是nova用户,这个用户要有service项目的admin角色:
openstack project create --domain default --description "Service Project" service openstack user create --domain default --password nova服务密码 nova openstack role add --project service --user nova admin然后注册 Nova 的服务和 endpoint:
openstack service create --name nova --description "OpenStack Compute" compute openstack endpoint create --region RegionOne compute public http://控制节点IP:8774/v2.1 openstack endpoint create --region RegionOne compute internal http://控制节点IP:8774/v2.1 openstack endpoint create --region RegionOne compute admin http://控制节点IP:8774/v2.1注意:endpoint 的 URL 末尾是
/v2.1,不是/v2。Nova 的 API 版本是 2.1,填错了后面openstack命令行工具会报版本不匹配。
3.4 验证 Keystone 是否真的可用
配完别急着往下走,先验证。最直接的方式是设置环境变量然后查服务列表:
export OS_USERNAME=admin export OS_PASSWORD=管理密码 export OS_PROJECT_NAME=admin export OS_USER_DOMAIN_NAME=Default export OS_PROJECT_DOMAIN_NAME=Default export OS_AUTH_URL=http://控制节点IP:5000/v3 export OS_IDENTITY_API_VERSION=3 openstack token issue openstack service listtoken issue能返回一个 token 就说明认证链路通了。service list里应该能看到keystone和nova两个服务。如果token issue报 401,大概率是密码错了或者OS_AUTH_URL的版本路径不对;如果报连接拒绝,检查 Keystone 服务是否真的在 5000 端口监听,ss -tlnp | grep 5000看一眼。
4. RabbitMQ 的安装与 Nova 专用配置
4.1 安装与基础服务启动
RabbitMQ 的安装相对简单,但依赖 Erlang,包管理器一般会自动处理:
apt install rabbitmq-server systemctl enable rabbitmq-server systemctl start rabbitmq-server启动后默认监听 5672 端口(AMQP 协议)和 15672 端口(管理界面,需要单独启用插件)。手动安装场景下我强烈建议启用管理插件:
rabbitmq-plugins enable rabbitmq_management启用后你可以用浏览器访问http://控制节点IP:15672,默认账号密码都是guest。但guest账号只能从 localhost 登录,远程访问会被拒绝,这是 RabbitMQ 的安全默认值。所以下一步必须创建 Nova 专用账号。
4.2 创建 vhost、用户与权限的完整流程
先建 vhost,我习惯命名为nova,和组件对应:
rabbitmqctl add_vhost nova rabbitmqctl add_user nova nova消息队列密码 rabbitmqctl set_permissions -p nova nova ".*" ".*" ".*" rabbitmqctl set_user_tags nova administratorset_permissions的三个".*"分别对应 configure、write、read 权限。生产环境可以收紧,但手动安装初期用全权限能减少排查干扰,等跑通后再按需限制。set_user_tags给administrator标签是为了让这个用户能在管理界面看到所有队列状态,方便调试。
这里有个实操心得:vhost 名字和用户名可以一样,但密码一定要和 Keystone 里 nova 用户的密码区分开。我见过有人图省事全用同一个密码,结果后面排查问题时分不清是认证失败还是消息队列认证失败,日志里两种错误长得太像了。
4.3 Nova 配置文件里的 transport_url 怎么写
Nova 的主配置文件/etc/nova/nova.conf里,[DEFAULT]段需要写:
[DEFAULT] transport_url = rabbit://nova:nova消息队列密码@控制节点IP:5672/nova这个 URL 的结构是rabbit://用户名:密码@主机:端口/vhost。注意 vhost 是放在路径里的,不是查询参数。如果密码里有特殊字符(比如@、/),需要做 URL 编码,否则解析会出错。我一般建议密码只用字母数字,省得折腾编码。
[oslo_messaging_rabbit]段还有一些可选调优项,手动安装初期可以先不碰,但有两个值得关注:
[oslo_messaging_rabbit] rabbit_retry_interval = 1 rabbit_retry_backoff = 2 rabbit_max_retries = 0rabbit_max_retries = 0表示无限重试,配合前两个参数实现指数退避。这个配置在服务启动时 RabbitMQ 还没完全就绪的场景下很有用,能避免 Nova 服务因为连不上队列直接退出。默认值其实也够用,但如果你遇到服务启动顺序问题,调这三个参数比反复重启服务有效。
4.4 用命令行验证消息队列连通性
配完后别只看配置文件,实际验证一下。最直接的方式是用rabbitmqctl看连接:
rabbitmqctl list_connections rabbitmqctl list_queues -p nova name messages如果 Nova 服务还没启动,list_connections是空的,这正常。你可以先用一个简单脚本测试认证:
rabbitmqadmin -H 控制节点IP -u nova -p nova消息队列密码 -V nova list queuesrabbitmqadmin是管理插件提供的命令行工具,能列出队列就说明用户、密码、vhost、权限全对了。如果报ACCESS_REFUSED,回去检查set_permissions是不是漏了-p nova参数——这个参数指定 vhost,漏了就会配到默认的/vhost 上,而 Nova 连的是novavhost,自然对不上。
5. 两个组件联调时的常见问题与排查实录
5.1 服务启动顺序引发的连锁报错
手动安装时最容易遇到的问题是:Nova 服务启动了,但日志里反复报AMQP connection refused或者Unable to establish connection to Keystone。这通常不是配置错了,而是启动顺序问题。Keystone 和 RabbitMQ 必须先于所有 Nova 服务就绪。
我的做法是写一个简单的检查脚本,在启动 Nova 之前跑一遍:
#!/bin/bash # 检查 Keystone curl -s -o /dev/null -w "%{http_code}" http://控制节点IP:5000/v3 | grep -q 200 || echo "Keystone 未就绪" # 检查 RabbitMQ rabbitmqctl status > /dev/null 2>&1 || echo "RabbitMQ 未就绪"两个都返回正常再启动 Nova。这个习惯能省掉大量“服务起了又挂”的无效排查。
5.2 认证失败与消息队列失败的区分方法
这两种失败在 Nova 日志里都表现为服务起不来,但错误关键词不同。Keystone 相关的问题通常包含Unauthorized、401、Invalid token、Could not find service;RabbitMQ 相关的问题包含AMQP、Connection refused、ACCESS_REFUSED、NOT_ALLOWED。
我整理了一个速查表,实际排查时对着看能快速定位:
| 日志关键词 | 大概率原因 | 排查动作 |
|---|---|---|
Unauthorized/401 | Keystone 密码错或 token 过期 | 用openstack token issue验证账号密码 |
Could not find service | Nova 的 service/endpoint 没注册 | openstack service list确认 nova 存在 |
AMQP connection refused | RabbitMQ 没启动或端口不通 | ss -tlnp | grep 5672检查监听 |
ACCESS_REFUSED | RabbitMQ 用户权限或 vhost 不对 | rabbitmqctl list_permissions -p nova |
NOT_ALLOWED | 用户没有对应 vhost 的访问权限 | 重新执行set_permissions |
5.3 几个我踩过的坑和独家避坑技巧
第一个坑是Fernet 密钥没生成就启动 Keystone。症状是 Keystone 能启动但token issue报 500,日志里说找不到密钥文件。解决方法是回到keystone-manage fernet_setup那一步,确认/etc/keystone/fernet-keys/目录下有文件生成。这个目录的权限也要注意,必须是keystone用户可读。
第二个坑是RabbitMQ 的loopback_users配置。默认情况下guest用户只能本地登录,但如果你创建的新用户也遇到远程连不上,检查/etc/rabbitmq/rabbitmq.conf里有没有loopback_users相关配置。新版本 RabbitMQ 默认只限制guest,但老版本可能行为不同。我一般直接在新用户上测试,不依赖guest。
第三个坑比较隐蔽:Nova 配置文件的段名拼写。[keystone_authtoken]这个段名里是下划线,不是连字符,也不是驼峰。我见过有人写成[keystone-authtoken],服务启动不报错,但认证永远失败,因为配置根本没被读取。这种问题只能靠仔细核对官方文档的示例来避免。
提示:每次改完
nova.conf,启动服务前先用nova-api --config-file /etc/nova/nova.conf --debug前台跑一下,能看到配置解析的详细过程,比直接systemctl start然后翻日志高效得多。
6. 配置完成后的验收清单与后续衔接
6.1 一份可以直接照着勾的验收清单
在进入 Nova 实际安装之前,我建议按这个清单逐项确认,全部打勾再往下走:
- Keystone 的
token issue能正常返回 token openstack service list能看到keystone和novaopenstack endpoint list里 nova 的 public/internal/admin 三个 endpoint 都存在且 URL 正确- RabbitMQ 的
novavhost 存在,nova用户有全权限 rabbitmqadmin -V nova list queues能正常执行nova.conf里transport_url的 vhost 和 RabbitMQ 里建的一致nova.conf里[keystone_authtoken]段的用户名、密码、项目名和 Keystone 里创建的一致
这份清单看着简单,但每一条都对应一个实际会卡住人的点。尤其是 endpoint 的 URL 和transport_url的 vhost,这两个地方的手误率最高。
6.2 从依赖配置到 Nova 服务启动的衔接要点
这两个组件配好后,Nova 的安装其实就顺了。nova-api启动时会先向 Keystone 注册自己(如果配置了[service_user]段的话),然后连 RabbitMQ 开始监听消息。nova-compute启动时会通过 RabbitMQ 向nova-conductor报到,同时用 Keystone 的 service token 做身份确认。
这里有个衔接细节值得提前知道:Nova 的[keystone_authtoken]段里除了username、password、project_name,还需要auth_url、auth_type、memcached_servers等参数。memcached_servers指向的 memcached 服务如果没装,token 缓存会失效,虽然不影响功能但性能会差。手动安装时可以先不配 memcached,等基础跑通再补。
另外,[service_user]段是 Nova 服务之间互相认证用的,和[keystone_authtoken]是两套配置。前者用于服务间调用,后者用于接收外部请求时的 token 校验。手动安装初期可以只配[keystone_authtoken],等需要跨服务调用时再补[service_user]。这个区分在官方文档里写得比较分散,我第一次配的时候在这两个段之间来回折腾了很久。
我个人在实际操作中的体会是,手动装 OpenStack 最耗时的部分从来不是敲命令,而是理解每个配置项在组件协作中的位置。RabbitMQ 和 Keystone 这两块地基打好了,后面 Nova 的各个服务就像积木一样往上搭,出问题也容易定位——因为你知道消息从哪来、认证走哪条路。反过来,如果这两块是糊里糊涂配过去的,后面任何一个服务起不来你都得从头排查,那才是真正的噩梦。所以宁可在这两步多花半小时验证,也别急着往下冲。