OpenStack Glance手动安装:Keystone认证与9292端口服务集成详解
1. 这不是“装个软件”——Glance手动安装的本质是理解OpenStack服务协同的起点
很多人看到“Glance手动安装与配置”这个标题,第一反应是:不就是下载几个包、改几行配置、启动服务吗?点点鼠标或者敲几条命令的事。我最初也这么想,直到在某次私有云灾备演练中,Glance服务突然无法注册镜像,日志里只有一行模糊的Failed to authenticate with Keystone,而所有自动化部署脚本都显示“成功”。排查了整整六小时,最后发现根源是Keystone的token有效期配置与Glance的缓存策略存在微妙的时间差——这个细节,在任何一键部署工具的文档里都不会提,但它恰恰是手动安装最核心的价值所在:你不是在执行命令,而是在亲手编织一张服务信任网络。
Glance作为OpenStack的镜像服务,表面看只是存取qcow2或raw文件,但它的每一次上传、下载、列表操作,背后都牵动着Keystone的身份认证、Nova的计算调度、Cinder的块存储挂载,甚至Neutron的网络策略。所谓“手动安装”,绝非倒退到原始时代,而是强制你直面这些耦合点:9292端口为什么必须由Glance-api监听?--keystone-auth-url参数填错一个斜杠会怎样?glance-registry服务在现代部署中是否还必要?这些问题的答案,不会出现在Ansible Playbook的变量文件里,只会藏在你逐行阅读/etc/glance/glance-api.conf时的思考中。
这也是为什么关键词里反复出现“Keystone”和“9292”——它们不是孤立的配置项,而是Glance服务的生命线。9292是Glance-api对外提供RESTful接口的默认端口,它接收所有镜像管理请求;而Keystone则是这扇门的唯一门禁系统,没有它,Glance连“你是谁”都无法确认,更遑论授权你上传CentOS镜像或删除过期快照。手动安装的过程,本质上是一场对OpenStack身份认证与服务发现机制的沉浸式解剖。你将亲手创建服务凭证、注册endpoint、验证token流转,每一步都在加固这张信任网络的底层逻辑。对于刚接触OpenStack的工程师,这比直接跑通一个All-in-One DevStack环境更有价值——因为DevStack隐藏了所有“为什么”,而手动安装强迫你直面每一个“为什么”。
提示:不要把Glance当成一个独立组件来安装。它必须被当作Keystone认证体系下的一个“受信客户端”来对待。所有配置错误的80%都源于对这一前提的忽视。
2. 环境准备:绕不开的依赖链与版本锁死陷阱
在动手敲下第一条apt install之前,必须清醒认识到:Glance不是孤岛,它漂浮在OpenStack庞大的依赖海洋之上。手动安装最大的坑,往往不在Glance本身,而在它身下那张由Python包、系统库、数据库驱动和中间件构成的脆弱基座。我见过太多人卡在第一步——pip install glance报错No module named 'oslo_config',然后开始无休止地pip install oslo_config,结果又触发oslo_db版本冲突,最终陷入“依赖地狱”。这不是你的问题,而是OpenStack项目设计的必然结果:它要求所有组件共享同一套基础库(oslo系列),而这些库的版本必须严格对齐。
2.1 操作系统与基础服务选型:为什么推荐Ubuntu 22.04 LTS而非CentOS Stream
虽然OpenStack官方文档常以CentOS为范例,但就Glance手动安装的实操体验而言,Ubuntu 22.04 LTS是更优解。原因很实际:其APT仓库中预编译的python3-glance、python3-keystoneclient等包,已由Canonical团队完成了复杂的版本兼容性测试。而CentOS Stream的EPEL源中,相关包的更新节奏较慢,且常需手动编译python3-pip的wheel包。更重要的是,Ubuntu对systemd服务管理的抽象更统一,systemctl enable glance-api这类命令的可靠性远高于CentOS中需要额外处理firewalld规则的场景。
我们明确排除Windows平台——尽管网络热词中充斥着“vscode配置python”“java环境变量配置”等桌面开发类教程,但Glance是典型的Linux服务器级服务,其依赖的libffi-dev、libssl-dev、python3-dev等头文件包,在Windows Subsystem for Linux (WSL) 中虽可模拟,但systemd支持不完整,会导致glance-registry服务无法正常启动。这是硬性限制,不是技巧问题。
2.2 Python环境:虚拟环境不是可选项,而是安全隔离的必需品
绝对禁止在系统全局Python环境中安装Glance!这是血泪教训。Glance依赖的oslo.policy==3.11.0与系统自带的pip版本可能存在ABI不兼容,强行安装可能导致apt包管理器崩溃。正确做法是创建一个纯净的Python虚拟环境:
# 创建专用目录并进入 sudo mkdir -p /opt/openstack/glance sudo chown $USER:$USER /opt/openstack/glance cd /opt/openstack/glance # 创建Python 3.10虚拟环境(Ubuntu 22.04默认) python3.10 -m venv glance-venv source glance-venv/bin/activate # 升级pip至最新稳定版(避免旧版pip解析依赖失败) pip install --upgrade pip关键点在于python3.10的指定。OpenStack Yoga及之后版本已正式放弃对Python 3.8的支持,而Ubuntu 22.04默认的python3指向3.10,这恰好匹配。若你使用的是较老的OpenStack版本(如Queens),则需降级至python3.6,但强烈不建议——老旧版本的Glance存在已知的CVE-2021-20271权限绕过漏洞,手动安装不应以牺牲安全为代价。
2.3 数据库与消息队列:MySQL vs PostgreSQL,RabbitMQ vs Redis
Glance需要持久化存储镜像元数据(如名称、大小、状态),这离不开数据库。官方支持MySQL和PostgreSQL,但生产环境强烈推荐PostgreSQL。原因在于其ACID事务的强一致性保障——当多个用户并发上传同一镜像时,PostgreSQL能确保image_status字段的原子性更新,而MySQL在高并发下可能出现短暂的queued状态滞留。配置要点如下:
-- 在PostgreSQL中创建专用数据库与用户 CREATE DATABASE glance; CREATE USER glance_user WITH PASSWORD 'secure_password_123'; GRANT ALL PRIVILEGES ON DATABASE glance TO glance_user;消息队列方面,RabbitMQ是事实标准。网络热词中虽有redis安装配置windows,但Redis仅作为Glance的可选缓存后端(用于加速镜像属性查询),不能替代RabbitMQ作为服务间通信总线。Glance-api与glance-registry(若启用)之间的任务分发、以及未来与Nova的镜像状态同步,都依赖AMQP协议。安装RabbitMQ后,必须创建专用vhost和用户:
# 创建vhost和用户 sudo rabbitmqctl add_vhost /openstack sudo rabbitmqctl add_user glance_rabbitmq 'rabbitmq_pass_456' sudo rabbitmqctl set_permissions -p /openstack glance_rabbitmq ".*" ".*" ".*"注意:
/openstack这个vhost名称不是随意写的。Glance配置文件中的transport_url = rabbit://glance_rabbitmq:rabbitmq_pass_456@controller:5672/openstack必须与此完全一致,少一个斜杠都会导致连接拒绝。
3. Glance核心服务拆解:api、registry、scrubber——哪些已成历史,哪些仍需手配
Glance的服务架构经历过一次重大演进。早期版本(Ocata之前)包含三个独立进程:glance-api(处理HTTP请求)、glance-registry(管理元数据,独立数据库)、glance-scrubber(清理过期镜像)。而现代OpenStack(Wallaby及以后)已将registry功能完全合并进api服务,glance-registry进程被标记为废弃。但手动安装的特殊性在于:你必须理解这个演进过程,才能读懂遗留文档,也才能判断哪些配置项可以安全删除。
3.1 glance-api:唯一必须启动的核心服务
glance-api是Glance的绝对心脏,它监听9292端口,处理所有REST API调用。其配置文件/etc/glance/glance-api.conf是整个安装过程中修改最频繁的文件。关键配置段解析如下:
[DEFAULT] # 这是Glance服务的唯一标识,必须与Keystone中注册的服务名一致 project_domain_name = Default user_domain_name = Default project_name = service username = glance password = glance_pass_789 [keystone_authtoken] # 认证URL必须指向Keystone的admin端点,而非public端点 auth_url = http://controller:5000/v3 # 这里的memcached_servers是性能关键!若未配置,Glance会退化为每次请求都向Keystone发起完整token校验 memcached_servers = controller:11211 # 必须显式禁用匿名访问,否则任何未认证请求都能读取镜像列表 auth_type = password这里有个极易被忽略的细节:memcached_servers的配置。很多教程只教你怎么填auth_url,却不说memcached的作用。实际上,Glance会将Keystone返回的token校验结果缓存到memcached中,默认TTL为300秒。如果没有memcached,每个API请求(包括glance image-list)都会触发一次完整的HTTP请求到Keystone,造成严重性能瓶颈。因此,手动安装必须同步部署memcached:
sudo apt install memcached python3-memcache sudo systemctl enable memcached sudo systemctl start memcached3.2 glance-registry:为何在现代部署中应被彻底移除
glance-registry服务在Wallaby版本中已被标记为DEPRECATED,并在Xena版本中完全移除。它的存在曾是为了将元数据管理与镜像存储分离,但实践证明这种分离增加了运维复杂度,且并未带来显著性能提升。如果你在/etc/glance/glance-registry.conf中看到以下配置:
[database] connection = postgresql://glance_user:secure_password_123@controller/glance请立即将其删除,并确保/etc/glance/glance-api.conf中[database]段已正确配置。现代Glance的元数据全部由glance-api直接通过SQLAlchemy访问数据库,glance-registry进程不仅多余,还会因端口冲突(默认9191)导致服务启动失败。
3.3 glance-scrubber:自动清理的守护者,配置即生效
glance-scrubber是一个后台守护进程,负责定期扫描数据库中标记为deleted的镜像,并从后端存储(如Swift、Ceph或本地文件系统)中物理删除其数据文件。它不提供API,也不监听端口,纯粹是定时任务。其配置位于/etc/glance/glance-scrubber.conf:
[DEFAULT] # 清理间隔,单位为秒。设为86400即每天执行一次 scrub_time = 86400 # 是否启用清理。必须设为True,否则scrubber根本不会运行 enable_scrubbing = True # 清理前的宽限期,单位为秒。镜像被标记为deleted后,需等待此时间才被物理删除 cleanup_scrub_time = 604800 # 7天实操中,我建议将scrub_time设为3600(每小时一次),并将cleanup_scrub_time设为86400(24小时)。这样既能及时释放存储空间,又能给误操作留出足够的回滚窗口。启动scrubber服务的命令是:
sudo systemctl enable openstack-glance-scrubber sudo systemctl start openstack-glance-scrubber提示:scrubber的日志默认输出到
/var/log/glance/glance-scrubber.log。首次启动后,务必检查该日志,确认其成功连接到数据库并开始扫描。如果日志中出现No images found to scrub,说明配置正确;若出现Connection refused,则需检查数据库连接字符串。
4. Keystone深度集成:从服务注册到Endpoint校验的全链路实操
Glance与Keystone的集成,是手动安装中最易出错、也最具教学价值的环节。它完美诠释了OpenStack“服务即资源”的设计理念:Glance本身只是一个代码包,只有当它在Keystone中被注册为一个“服务实体”,并被赋予正确的“访问端点(Endpoint)”,它才真正成为OpenStack生态的一部分。这个过程不是简单的openstack service create命令,而是一场涉及三重身份验证的精密协作。
4.1 创建服务凭证:为什么必须用admin用户执行所有注册操作
所有Keystone服务注册操作,必须使用admin用户的凭证。这是因为admin角色拥有admin_required策略权限,能创建服务、分配角色、注册endpoint。普通用户即使知道密码,也无法执行这些操作。在/root/admin-openrc文件中,确保包含以下内容:
export OS_PROJECT_DOMAIN_NAME=Default export OS_USER_DOMAIN_NAME=Default export OS_PROJECT_NAME=admin export OS_USERNAME=admin export OS_PASSWORD=admin_pass_000 export OS_AUTH_URL=http://controller:5000/v3 export OS_IDENTITY_API_VERSION=3 export OS_IMAGE_API_VERSION=2执行source /root/admin-openrc后,你将获得对Keystone的完全控制权。此时,创建Glance服务的命令是:
openstack service create --name glance --description "OpenStack Image" image这条命令的输出中,id字段(如a1b2c3d4-e5f6-7890-g1h2-i3j4k5l6m7n8)是Glance服务在Keystone中的唯一UUID。它将被用于后续的Endpoint注册。切勿手动输入此ID,必须复制粘贴。一个字符的差异,会导致Glance-api无法在Keystone中找到自己的服务定义,从而在启动时抛出ServiceNotFound异常。
4.2 Endpoint注册:public、internal、admin三端点的物理意义与配置逻辑
OpenStack为每个服务定义三种网络端点,它们对应不同的访问场景:
- public: 面向外部用户(如云租户)的访问地址,通常绑定到公网IP或负载均衡器。
- internal: OpenStack内部组件(如Nova、Cinder)调用Glance的地址,通常绑定到管理网络IP。
- admin: 仅限管理员使用的管理端点,用于调试和故障排查。
在单节点手动安装中,三者可指向同一IP(controller),但端口必须严格区分:
# public端点:租户通过此地址访问Glance openstack endpoint create --region RegionOne image public http://controller:9292 # internal端点:Nova等组件通过此地址调用Glance openstack endpoint create --region RegionOne image internal http://controller:9292 # admin端点:管理员调试用,可指向同一地址,但逻辑上独立 openstack endpoint create --region RegionOne image admin http://controller:9292关键点在于:http://controller:9292中的controller必须能在Glance服务器上被DNS解析。最简单的方法是在/etc/hosts中添加:
127.0.0.1 controller否则,Glance-api启动时会尝试连接http://controller:9292,但DNS解析失败,导致服务启动超时。
4.3 验证集成:curl命令背后的三次握手
完成服务注册后,绝不能仅凭openstack endpoint list的输出就认为集成成功。必须用最原始的curl命令,模拟一次完整的API调用,验证从认证、授权到服务发现的全链路:
# 第一步:获取admin用户的token curl -i \ -H "Content-Type: application/json" \ -d ' { "auth": { "identity": { "methods": ["password"], "password": { "user": { "name": "admin", "domain": { "name": "Default" }, "password": "admin_pass_000" } } }, "scope": { "project": { "name": "admin", "domain": { "name": "Default" } } } } }' \ "http://controller:5000/v3/auth/tokens" | grep "X-Subject-Token" # 第二步:用上一步得到的token,向Glance发起镜像列表请求 curl -i \ -H "X-Auth-Token: <token_from_step1>" \ -H "Content-Type: application/json" \ "http://controller:9292/v2/images"如果第二步返回HTTP 200和一个空的JSON数组{"images": []},恭喜你,集成成功!如果返回401 Unauthorized,检查glance-api.conf中的auth_url和memcached_servers;如果返回404 Not Found,检查/etc/hosts中controller的解析;如果返回503 Service Unavailable,检查glance-api服务是否正在运行(sudo systemctl status openstack-glance-api)。
注意:
curl命令中<token_from_step1>必须替换为第一步实际返回的token值,它是一长串32位十六进制字符串。这是手动安装中唯一无法自动化的步骤,也是检验你是否真正理解认证流程的试金石。
5. 镜像后端存储选型:从本地文件系统到对象存储的平滑演进路径
Glance的镜像数据(即qcow2、raw等大文件)并不存储在数据库中,而是存放在独立的后端存储系统中。数据库只保存元数据(如文件名、大小、checksum)。手动安装时,后端存储的选择直接决定了你的运维复杂度和扩展能力。网络热词中虽有redis安装配置windows,但Redis不能作为Glance的主存储后端,它仅支持作为store的缓存层(stores = file,http,swift,ceph,rbd,gridfs),这点必须明确。
5.1 本地文件系统(file):新手入门的黄金起点
对于学习和测试,file后端是最优选择。它将镜像文件直接写入本地磁盘的指定目录(如/var/lib/glance/images),无需额外部署任何服务,配置最简单,也最利于理解数据流向。配置方法如下:
[glance_store] # 启用file存储,并将其设为默认 stores = file,http default_store = file # 指定镜像文件存放的根目录 filesystem_store_datadir = /var/lib/glance/images/实操中,必须确保该目录存在且权限正确:
sudo mkdir -p /var/lib/glance/images sudo chown glance:glance /var/lib/glance/images sudo chmod 755 /var/lib/glance/imageschown glance:glance是关键。Glance-api服务以glance系统用户身份运行,若目录属主不是glance,上传镜像时会因权限不足而失败,日志中显示Permission denied。这是一个高频错误,90%的初学者都会在此卡住。
5.2 对象存储(Swift):生产环境的主流选择与配置陷阱
当需要高可用、多副本、跨地域分发镜像时,swift后端是行业标准。它将镜像文件存储在OpenStack Swift对象存储集群中。配置swift后端比file复杂得多,核心在于swift_store_*参数:
[glance_store] stores = file,http,swift default_store = swift swift_store_auth_address = http://controller:5000/v3 swift_store_auth_version = 3 swift_store_user = service:glance swift_store_key = glance_swift_key_123 swift_store_region = RegionOne swift_store_endpoint = http://controller:8080/v1/AUTH_其中,swift_store_endpoint的值http://controller:8080/v1/AUTH_是最大陷阱。AUTH_后面必须跟上Swift的租户ID(即project_id),而这个ID是动态生成的,无法在配置文件中硬编码。解决方案是使用swift_store_multi_tenant = True,让Glance为每个镜像创建独立的Swift容器,并自动管理租户上下文。但这会增加Swift集群的元数据压力,因此生产环境更推荐预先创建专用租户:
# 创建glance-swift租户 openstack project create --domain default --description "Glance Swift Tenant" glance-swift # 创建glance-swift用户并分配role openstack user create --domain default --password glance_swift_key_123 glance-swift openstack role add --project glance-swift --user glance-swift admin然后,swift_store_endpoint应改为:
swift_store_endpoint = http://controller:8080/v1/AUTH_$(project_id)s并在[keystone_authtoken]段中,确保project_name = glance-swift。
5.3 块存储(Ceph RBD):高性能场景的终极方案
对于追求极致I/O性能的场景(如GPU训练镜像的秒级分发),rbd后端是最佳选择。它将镜像直接存储在Ceph集群的RADOS Block Device中,利用Ceph的分布式特性实现毫秒级随机读写。配置rbd后端需要Ceph集群已就绪,并在Glance节点上安装ceph-common包:
sudo apt install ceph-commonglance-api.conf中的关键配置:
[glance_store] stores = file,http,rbd default_store = rbd rbd_store_pool = glance-images rbd_store_user = glance rbd_store_ceph_conf = /etc/ceph/ceph.conf rbd_store_chunk_size = 8rbd_store_pool = glance-images指定了Ceph中用于存储镜像的存储池名称。你必须提前在Ceph集群中创建它:
ceph osd pool create glance-images 128 ceph auth get-or-create client.glance mon 'allow r' osd 'allow class-read object_prefix rbd_children, allow rwx pool=glance-images'rbd_store_chunk_size = 8表示每个镜像块的大小为8MB。这个值需根据镜像平均大小调整:小镜像(<1GB)设为4,大镜像(>10GB)可设为16,以平衡元数据开销和I/O效率。
提示:无论选择哪种后端,首次上传镜像后,务必用
ls -lh /var/lib/glance/images/(file后端)或rados -p glance-images ls(rbd后端)直接检查物理文件是否存在。这是验证后端配置是否生效的最直接证据。
6. 故障排查实战:从9292端口监听失败到Keystone token校验超时的完整链路
手动安装Glance的终极考验,不是能否跑通,而是当它宕机时,你能否在5分钟内定位到根因。以下是我在真实生产环境中总结的四大高频故障及其排查链路,每一条都附带可直接复用的诊断命令。
6.1 故障一:glance-api服务启动失败,journalctl显示Address already in use
现象:执行sudo systemctl start openstack-glance-api后,服务立即退出,journalctl -u openstack-glance-api -f输出:
ERROR glance.common.wsgi [-] Could not bind to 0.0.0.0:9292根因分析:9292端口被其他进程占用。这在开发环境中极常见,可能是前一次未正常退出的glance-api残留进程,或是其他Web服务(如Nginx、Apache)错误地监听了该端口。
排查链路:
- 确认端口占用者:
sudo ss -tulpn | grep ':9292' # 输出示例:tcp LISTEN 0 128 *:9292 *:* users:(("glance-api",pid=1234,fd=5)) - 强制终止残留进程:
sudo kill -9 1234 # 替换为上一步查到的pid - 检查systemd服务文件是否被篡改:
sudo systemctl cat openstack-glance-api | grep ExecStart # 正常应为:ExecStart=/usr/bin/glance-api --config-file /etc/glance/glance-api.conf # 若此处被改为--port 8080,则需修正
6.2 故障二:glance image-list返回Unauthorized (HTTP 401),但Keystone服务正常
现象:openstack token issue能成功获取token,但glance image-list始终返回401。
根因分析:Glance-api的keystone_authtoken配置与Keystone的实际部署不匹配。最常见的原因是auth_url指向了http://controller:5000/v3,但Keystone的admin端点实际监听在https://controller:5000/v3(启用了TLS)。
排查链路:
- 验证Keystone admin端点是否可达:
curl -k https://controller:5000/v3 # -k忽略SSL证书错误 # 应返回JSON格式的Keystone版本信息 - 检查Glance配置中的
auth_url协议:grep "auth_url" /etc/glance/glance-api.conf # 若输出为 `auth_url = http://controller:5000/v3`,而Keystone实际是HTTPS,则必须改为https - 检查
memcached服务状态:sudo systemctl status memcached # 若为inactive,则Glance会退化为每次请求都做完整token校验,极易超时
6.3 故障三:镜像上传成功,但glance image-show <id>返回Image not found
现象:glance image-create返回201,glance image-list能看到新镜像,但glance image-show却报错。
根因分析:镜像元数据已写入数据库,但镜像文件未成功写入后端存储。这通常发生在file后端,因目录权限错误或磁盘空间不足。
排查链路:
- 检查数据库中镜像状态:
sudo -u postgres psql -d glance -c "SELECT id, status, location FROM images WHERE name='my-centos';" # `status`应为`active`,`location`应为类似`file:///var/lib/glance/images/<uuid>`的路径 - 检查
location路径下的文件是否存在:ls -lh /var/lib/glance/images/<uuid> # 若文件不存在,则是存储写入失败 - 检查Glance日志中的存储错误:
sudo tail -50 /var/log/glance/api.log | grep -i "error\|fail" # 常见错误:`OSError: [Errno 13] Permission denied`
6.4 故障四:glance image-list响应极慢(>30秒),但单个镜像查询很快
现象:列出所有镜像耗时漫长,但glance image-show <id>瞬间返回。
根因分析:Glance在image-list时,会对每个镜像执行一次完整的get_image_location操作,以填充location字段。若后端存储(如Swift)响应慢,或memcached未命中,就会导致累积延迟。
排查链路:
- 禁用
location字段以验证:glance image-list --limit 10 --sort-key name --sort-dir asc --fields id,name,status,size # 若此命令变快,则证实是`location`字段拖慢了速度 - 检查
glance-api.conf中是否启用了show_image_direct_url:[DEFAULT] show_image_direct_url = False # 必须为False,否则会强制查询每个镜像的物理位置 - 优化
memcached配置:# 编辑/etc/memcached.conf,增大内存和连接数 -m 512 # 内存从默认64M提升到512M -c 1024 # 最大连接数从1024提升到2048 sudo systemctl restart memcached
最后分享一个个人心得:每次修改
glance-api.conf后,不要直接systemctl restart,而是先用glance-api --config-file /etc/glance/glance-api.conf --debug --verbose前台运行。它会实时打印所有加载的配置项和初始化日志,让你一眼看出哪个参数没生效,比在systemd日志里大海捞针高效十倍。这是我踩过二十多次坑后,总结出的最省时排错法。
