1. 项目概述:这不是一次普通的服务部署,而是一次对 OpenStack 身份认证体系的“解剖式”实操
Keystone 是 OpenStack 的核心服务之一,它不直接处理计算、存储或网络资源,却像城市交通指挥中心一样,掌控着所有用户、角色、项目、服务和端点的访问权限。你无法绕过它去启动一台虚拟机,也无法跳过它去创建一个对象存储容器——它就是整个云平台的“门禁系统”与“身份档案馆”。标题里写的“6.2 实训项目3 Keystone 的手动安装与配置”,表面看是教学大纲里的一个编号任务,但背后藏着的是对云基础设施底层逻辑的一次真实触达。我带过十几期 OpenStack 运维实训班,发现一个普遍现象:90% 的学员能用自动化脚本一键部署全套 OpenStack,但一旦 Keystone 报错“Invalid token”或“Service not found”,立刻陷入茫然。为什么?因为脚本把所有依赖、证书、数据库初始化、服务注册这些“脏活累活”全包圆了,你只看到一个绿色的 SUCCESS,却不知道绿色背后哪一行 SQL 插入失败、哪个环境变量漏写了、哪条 endpoint URL 少了个斜杠。这次手动安装,就是要亲手拧紧每一颗螺丝——从 MySQL 创建 keystone 数据库开始,到生成 Fernet 密钥、初始化数据库表结构、配置 Apache 模块、注册 admin 用户与 service project,再到最后用 curl 验证 token 获取是否成功。它适合三类人:正在备考 OpenStack 认证(如 COA)的工程师、需要在生产环境中做 Keystone 故障深度排查的运维人员,以及想真正理解“为什么 OpenStack 必须先配 Keystone”的云计算初学者。你不需要提前掌握 Python 编程,但必须熟悉 Linux 基础命令、HTTP 状态码含义、以及如何阅读日志文件。这不是教你怎么“点下一步”,而是带你回到 2012 年 OpenStack 社区刚起步时,开发者们最原始、最扎实的部署方式。
2. 整体设计思路与方案选型解析:为什么坚持“手动”,而不是用 DevStack 或 Kolla?
2.1 手动安装不是复古情怀,而是为了暴露关键决策点
很多人看到“手动安装”第一反应是:“太老土了,现在谁还这么干?”这种看法恰恰暴露了对云平台本质理解的偏差。DevStack 是个极好的开发测试工具,但它把所有服务都塞进一个本地用户目录下,用 screen 启一堆进程,数据库用 SQLite,证书全自签且路径混乱;Kolla 则是面向生产环境的容器化部署,但它的抽象层级太高——你改一个 keystone.conf 变量,得先理解 kolla-ansible 的 role 结构、jinja2 模板继承关系、以及 Ansible 的 facts 注入机制。而手动安装,是唯一一种能让你在每一步都停下来问“为什么必须这样”的方式。比如,为什么 Keystone 默认用 Apache + mod_wsgi 而不是自带的 eventlet 服务器?因为 eventlet 是单线程异步模型,在高并发 token 校验场景下容易成为瓶颈,而 Apache 的 prefork 或 worker 模型能更好利用多核 CPU;为什么数据库表初始化要用 keystone-manage db_sync 而不是直接执行 SQL 脚本?因为 Keystone 的 migration 机制是基于 Alembic 的,它会自动记录当前数据库版本,并在升级时只执行增量变更,避免手动 SQL 漏掉某张审计表;为什么 Fernet 密钥要分组管理(key_repository),且必须设置轮转策略?因为 Fernet 是对称加密,密钥一旦泄露,所有已签发的 token 都可被伪造,而轮转机制确保旧密钥只用于解密历史 token,新 token 全部用新密钥签名,形成时间隔离。这些不是文档里一句带过的“最佳实践”,而是你在手动执行keystone-manage fernet_setup --keystone-user keystone --keystone-group keystone这条命令时,必须思考的底层逻辑。
2.2 环境选型:Ubuntu 22.04 LTS + MySQL 8.0 + Apache 2.4 是当前最稳妥的组合
我们不选 CentOS Stream 或 Rocky Linux,是因为 Ubuntu 22.04 的 APT 源对 OpenStack Yoga/Zed 版本支持最成熟,Python 3.10 环境开箱即用,且社区文档覆盖最全。MySQL 8.0 是硬性要求——Keystone 从 Queens 版本起就废弃了对 MySQL 5.7 以下版本的支持,主要原因是其 JSON 数据类型和窗口函数被大量用于 policy 规则引擎与审计日志分析。你可能会看到网上有教程用 SQLite 做演示,那纯粹是教学简化,生产环境绝对禁止:SQLite 是文件级锁,当多个服务(如 Nova、Cinder)同时向 Keystone 请求 token 时,会因锁竞争导致严重延迟。Apache 2.4 也是经过验证的选择,它比 Nginx 更早原生支持 WSGI 协议,mod_wsgi 模块与 Keystone 的集成度更高,错误日志中能直接打印出 Python traceback,这对排错至关重要。至于 Python 版本,OpenStack 官方已全面转向 Python 3,Python 2.7 在 2020 年就停止维护,任何还在用 py2 的教程都是过期信息。我们不会去折腾源码编译,而是严格使用 Ubuntu 官方仓库提供的 python3-keystone 包,因为它已经过 Canonical 工程师的兼容性测试,避免了 pip install keystone==xx 可能引入的依赖冲突(比如某个旧版 oslo.config 与新版本不兼容)。
2.3 架构精简:只部署 Keystone 核心组件,剥离无关服务干扰
这个实训项目明确限定为“Keystone 的手动安装与配置”,因此我们必须主动做减法。不安装 Glance(镜像服务)、不部署 Nova(计算服务)、不配置 Horizon(Web 控制台)。很多初学者一上来就想搭个“完整云”,结果 Keystone 还没跑通,就被 Glance 的 registry 服务报错拖垮了注意力。我们要构建一个最小可行环境(MVP):仅包含 MySQL(数据存储)、Apache(Web 服务器)、Keystone(WSGI 应用)、以及用于验证的 curl 和 openstack client。所有服务都运行在同一台物理机或虚拟机上,IP 地址固定为 192.168.100.10(这个地址会在后续配置中反复出现,务必记牢)。这种“单点聚焦”不是偷懒,而是工程思维的体现——当你连最简单的单节点 Keystone 都无法稳定运行时,加再多节点也只会放大问题。就像修车师傅不会一边换火花塞一边调刹车片,我们必须把身份认证这条链路彻底跑通,再考虑与其他服务对接。
3. 核心细节解析与实操要点:从系统准备到服务启动的 12 个关键动作
3.1 系统初始化:时间同步、防火墙与主机名是隐形地雷
在敲下第一条 apt 命令前,有三件事必须做完,它们不出现在任何 Keystone 官方文档的“第一步”,却是我踩过最多坑的环节。第一是时间同步。OpenStack 对时间精度要求极高,所有服务间的 token 签名都带时间戳,如果 Keystone 服务器与客户端时间相差超过 5 分钟,token 会被直接拒绝。不要用 systemd-timesyncd 这种轻量级服务,它默认只做单向时间校准,稳定性不足。必须安装 chrony:sudo apt install chrony -y,然后编辑/etc/chrony/chrony.conf,注释掉所有 pool 行,添加server ntp.aliyun.com iburst(阿里云 NTP 服务器在国内延迟低、可用性高),最后重启服务sudo systemctl restart chrony。第二是防火墙。Ubuntu 默认启用 ufw,它会拦截 5000 端口(Keystone 默认 API 端口)。很多人部署完发现 curl http://192.168.100.10:5000/v3 失败,查半天以为是 Apache 没配好,其实是 ufw 在作祟。执行sudo ufw allow 5000即可放行。第三是主机名解析。Keystone 内部服务注册、endpoint URL 生成都依赖主机名。必须确保hostname -f返回的是一个完整的 FQDN(如 controller.example.com),而不是单纯的 controller。编辑/etc/hosts,添加一行192.168.100.10 controller.example.com controller,然后执行sudo hostnamectl set-hostname controller.example.com。这三步看似琐碎,但任何一个遗漏,都会导致后续步骤中出现“Connection refused”、“Invalid endpoint”等让人抓狂的错误,而且日志里找不到直接线索。
3.2 数据库准备:MySQL 8.0 的密码策略与字符集是两大陷阱
Keystone 需要一个独立的数据库来存储用户、角色、项目等元数据。创建过程远不止CREATE DATABASE keystone;这么简单。首先,MySQL 8.0 默认启用了caching_sha2_password认证插件,而 Keystone 的 Python MySQL 驱动(PyMySQL)在较老版本中不支持它,会导致连接数据库时报错Authentication plugin 'caching_sha2_password' cannot be loaded。解决方案是在创建用户时强制指定mysql_native_password插件:CREATE USER 'keystone'@'localhost' IDENTIFIED WITH mysql_native_password BY 'KEYSTONE_DBPASS';。其次,字符集必须设为 utf8mb4。Keystone 的 user_name、project_name 等字段允许 Unicode 字符(比如中文用户名),如果数据库用默认的 latin1,插入中文时会变成乱码,后续用 openstack user list 查看就是一堆问号。所以建库语句必须是:CREATE DATABASE keystone CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;。最后,授权语句不能只写GRANT ALL PRIVILEGES ON keystone.* TO 'keystone'@'localhost',因为 Keystone 服务可能从其他节点(比如未来要加的 compute 节点)连接数据库,所以必须加上远程访问权限:GRANT ALL PRIVILEGES ON keystone.* TO 'keystone'@'%' IDENTIFIED WITH mysql_native_password BY 'KEYSTONE_DBPASS';。执行完别忘了FLUSH PRIVILEGES;。这三处细节,网上 70% 的 MySQL 安装教程都会漏掉其中至少一项,导致 Keystone 启动后日志里疯狂刷pymysql.err.OperationalError: (1045, "Access denied for user...")。
3.3 用户与组创建:系统级隔离是安全基线,不是形式主义
Keystone 服务进程不应该以 root 用户运行,这是最基本的安全原则。我们必须创建一个专用的系统用户和组。执行sudo useradd -r -s /bin/false keystone,其中-r表示创建系统用户(UID < 1000),-s /bin/false表示该用户无法登录 shell,彻底杜绝了通过该账户提权的可能性。接着创建组sudo groupadd keystone,并将用户加入组sudo usermod -a -G keystone keystone。这步的意义远超“按规范办事”。当你后续配置 Apache 的 WSGI 进程时,会用到WSGIDaemonProcess指令,其中user=keystone group=keystone参数就依赖于此。如果这里用户不存在,Apache 启动会失败,错误日志里只显示Permission denied,根本看不出是用户问题。更隐蔽的坑在于 Fernet 密钥目录的权限。Keystone 要求密钥文件只能被 keystone 用户读写,其他用户不可访问。如果你跳过这步,直接用 root 创建/etc/keystone/fernet-keys目录,那么keystone-manage fernet_setup命令会成功,但 Apache 进程(以 www-data 用户运行)在尝试读取密钥时会因权限不足而崩溃。所以,创建用户和组,是为后续所有权限控制打下的第一根桩。
3.4 配置文件结构解析:keystone.conf 不是参数列表,而是一张服务关系图谱
/etc/keystone/keystone.conf是 Keystone 的心脏,但它的结构常被误解为“一堆 key=value 的集合”。实际上,它是一个分层的、模块化的配置图谱。最顶层是[DEFAULT],它定义全局行为,比如log_dir = /var/log/keystone指定了所有日志的根目录,transport_url = rabbit://openstack:RABBIT_PASS@controller则指向消息队列(虽然本实训暂不启用,但必须存在,否则启动报错)。往下是[database],这里填的是刚才创建的 MySQL 连接字符串:connection = mysql+pymysql://keystone:KEYSTONE_DBPASS@controller/keystone。注意,这里的controller是我们之前在/etc/hosts里配置的主机名,不是 IP 地址,这是为了将来扩展成多节点时方便 DNS 切换。最关键的是[identity]和[assignment]模块。[identity]指定用户、域、组的后端存储,默认是sql,意味着所有用户信息都存 MySQL;[assignment]则管理角色、项目、域分配关系,同样用sql。很多人会忽略[token]模块,但它决定了 token 的生成方式。我们用provider = fernet,而不是过时的uuid或pki,因为 Fernet 性能高、无需 CA 证书、且支持密钥轮转。而[cache]模块则启用了 memcache 作为 token 缓存,backend = dogpile.cache.memcached,这能极大减轻数据库压力——每次 token 校验先查缓存,命中则秒回,未命中才查 DB。理解每个 section 的职责,比死记硬背参数值重要十倍。
3.5 Fernet 密钥初始化:不是“运行命令就行”,而是理解密钥生命周期
Fernet 是 Keystone 的 token 加密标准,它要求一组密钥协同工作,而非单一密钥。keystone-manage fernet_setup命令会创建两个子目录:0/(主密钥)和1/(备用密钥)。但很多人不知道,0/目录下的密钥文件(如0000000000000000000000000000000000000000000000000000000000000000)并不是随机生成的,而是由keystone-manage fernet_rotate命令根据一个种子(seed)和轮转计数器动态派生的。这意味着,如果你备份了/etc/keystone/fernet-keys目录,恢复时必须保证 seed 文件(/etc/keystone/fernet-keys/0/0000000000000000000000000000000000000000000000000000000000000000)与原始环境完全一致,否则所有已签发的 token 都无法解密。所以,fernet_setup后的第一件事,不是启动服务,而是执行sudo chown -R keystone:keystone /etc/keystone/fernet-keys,确保只有 keystone 用户能读写。第二件事,是立即备份这个目录:sudo cp -r /etc/keystone/fernet-keys /root/keystone-fernet-backup-$(date +%F)。第三件事,是理解轮转机制。keystone-manage fernet_rotate默认会将0/的密钥移到1/,并生成新的0/,但旧密钥仍保留在1/中用于解密历史 token。生产环境建议每周轮转一次,并保留至少 3 个历史密钥(通过max_active_keys = 3参数配置),以防 token 有效期(默认 24 小时)跨越轮转周期。
3.6 Apache 配置:WSGI 是桥梁,不是装饰,每一个参数都有血泪教训
Keystone 不是独立 Web 服务,它必须寄生在 Apache 下,通过 WSGI 协议与之通信。/etc/apache2/sites-available/wsgi-keystone.conf这个文件,就是这座桥梁的设计蓝图。WSGIScriptAlias / /usr/bin/keystone-wsgi-admin这行告诉 Apache,所有以/开头的请求,都交给/usr/bin/keystone-wsgi-admin这个 Python 脚本处理。但关键在后面:WSGIDaemonProcess keystone-admin processes=5 threads=1 user=keystone group=keystone display-name=%{GROUP}。processes=5表示启动 5 个独立的 Python 进程,每个进程处理一个请求,避免单进程阻塞;threads=1是硬性要求,因为 Keystone 的某些内部锁(如数据库连接池)不是线程安全的,开多线程反而会死锁;user/group必须与前面创建的系统用户一致。最容易被忽略的是<Directory /usr/bin>块里的Require all granted,它允许 Apache 从任意路径加载 WSGI 脚本。如果没有这一行,Apache 会返回 403 Forbidden 错误,而日志里只显示client denied by server configuration,让人误以为是网络问题。最后,启用站点sudo a2ensite wsgi-keystone.conf和sudo a2enmod wsgi是必须的,前者激活配置,后者加载 WSGI 模块。很多人漏掉a2enmod wsgi,结果 Apache 启动成功,但访问 5000 端口时返回 503 Service Unavailable,查日志才发现Invalid command 'WSGIScriptAlias'—— 因为模块根本没加载。
3.7 数据库同步与初始数据注入:db_sync 是骨架,bootstrap 是血肉
keystone-manage db_sync命令的作用,是让 Keystone 的数据库模型(SQLAlchemy 定义)与实际的 MySQL 表结构保持一致。它会自动执行所有未应用的 Alembic migration 脚本,创建user,role,project,domain,credential等核心表。但这只是“骨架”,没有数据,Keystone 就是个空壳。keystone-manage bootstrap才是注入“血肉”的关键。它会一次性完成五件事:1) 创建admin用户,密码为你指定的ADMIN_PASS;2) 创建admin角色;3) 创建admin项目(也叫 tenant);4) 将admin用户在admin项目中赋予admin角色;5) 创建service项目,用于存放所有 OpenStack 服务(如 nova、glance)的注册信息。这个命令必须在db_sync之后执行,否则会报Table 'keystone.user' doesn't exist。而且,bootstrap命令会自动创建admin用户的servicetoken,这个 token 存储在/var/keystone/admin-token文件中,是后续所有服务注册的“万能钥匙”。所以,执行完bootstrap,一定要记住这个 token 值(或者直接 cat 一下文件),因为接下来注册 service 和 endpoint 时,它就是你的“身份证”。
3.8 服务与端点注册:Endpoint 不是 URL,而是 Keystone 的“服务地图”
OpenStack 的所有服务(Nova、Glance、Cinder)都必须向 Keystone “报备”,这个过程叫 service registration。openstack service create --name keystone --description "OpenStack Identity" identity这条命令,就是在 Keystone 的数据库里插入一条记录,表示“这里有一个名为 keystone 的 identity 类型服务”。但光有服务名还不够,其他服务怎么找到它?这就靠 endpoint(端点)。openstack endpoint create --region RegionOne identity public http://controller:5000/v3这条命令,是在service表和endpoint表之间建立关联,并指明:在RegionOne这个地理区域,identity服务的公开访问地址是http://controller:5000/v3。注意,这里有三个关键点:第一,--region参数必须是RegionOne,这是 OpenStack 的默认区域名,几乎所有客户端都硬编码了它,改了会导致后续所有服务无法通信;第二,URL 中的controller必须与/etc/hosts里配置的主机名完全一致,大小写都不能错;第三,/v3是 Keystone v3 API 的路径,v2 API 已废弃,绝不能写成/v2.0。注册完成后,你可以用openstack endpoint list查看所有端点,输出应该包含public,internal,admin三种接口类型,分别对应外部用户、内部服务、管理员的访问入口。对于 Keystone 自身,public和admin接口通常指向同一个 URL,但internal接口应指向http://127.0.0.1:5000/v3,因为内部服务(如 Nova)与 Keystone 在同一台机器上,走 localhost 更高效、更安全。
3.9 环境变量与 OpenStack Client 配置:OS_* 变量是客户端的“DNA”
openstack命令行工具本身不存储任何认证信息,它完全依赖环境变量。export OS_AUTH_URL=http://controller:5000/v3这行,告诉客户端:“我的 Keystone 服务在哪儿”;export OS_IDENTITY_API_VERSION=3指定用 v3 API;export OS_PROJECT_NAME=admin和export OS_USER_DOMAIN_NAME=Default定义了你要以哪个项目、哪个域的身份登录;export OS_USERNAME=admin和export OS_PASSWORD=ADMIN_PASS则是你的账号密码。最关键的export OS_PROJECT_DOMAIN_NAME=Default和export OS_USER_DOMAIN_NAME=Default,这两个变量在 Keystone v3 的多域(domain)模型中至关重要。OpenStack v3 引入了 domain 概念,把用户、项目、角色都划分到不同的域下,实现租户隔离。Default是系统内置的根域,所有初始资源都在这里。如果漏掉这两个变量,openstack user list会报错The request you have made requires authentication.,因为 Keystone 不知道你要在哪个域里找用户。把这些 export 命令写进~/.bashrc并source ~/.bashrc,是为了让每次打开终端都自动加载,避免重复输入。但要注意,~/.bashrc只对交互式 shell 生效,如果你用 crontab 或 systemd service 运行脚本,必须在脚本开头显式 source 它,否则环境变量不生效。
3.10 Token 获取与验证:curl 是终极检验,不是花架子
一切配置完成后,最激动人心的时刻,是亲手用最原始的 HTTP 工具验证。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": "ADMIN_PASS"}}}, "scope": {"project": {"name": "admin", "domain": {"name": "Default"}}}}}'这条命令,模拟了客户端向 Keystone 发起认证请求的全过程。-i参数显示响应头,你最关心的是X-Subject-Token这个 header,它的值就是本次认证生成的 token。把这个 token 复制下来,再执行curl -H "X-Auth-Token: $TOKEN" http://controller:5000/v3/projects,如果返回一个包含admin项目的 JSON 数组,恭喜你,Keystone 已经活了。这个过程的价值,在于它剥离了所有封装。openstack project list命令背后,就是做了这两步:先发 auth 请求拿 token,再带着 token 去查项目。当你遇到openstack命令报错时,第一反应不应该是重装客户端,而是用 curl 重走一遍,看是第一步(认证失败)还是第二步(token 无效)出了问题。这是所有资深 OpenStack 工程师的排错本能。
3.11 日志分析:/var/log/keystone/keystone.log 是你的“黑匣子”
Keystone 启动失败,90% 的原因都能在/var/log/keystone/keystone.log里找到答案。但日志不是从头读到尾,而是要有目标地扫描。第一,搜索ERROR和CRITICAL,这是最高优先级的错误。第二,搜索Traceback,它后面跟着的就是 Python 异常的完整堆栈,能精准定位到哪一行代码出错。第三,搜索Connection refused,这通常指向数据库或 memcache 连接失败。第四,搜索No module named,说明 Python 包缺失,比如No module named 'pymysql',就要sudo apt install python3-pymysql。第五,搜索Permission denied,这基本可以断定是 Fernet 密钥目录或配置文件的权限问题。一个实用技巧:用tail -f /var/log/keystone/keystone.log实时跟踪日志,然后在另一个终端执行sudo systemctl restart apache2,观察日志里是否有Starting Keystone、Loaded app keystone这样的成功提示。如果只有Stopping...没有Starting...,说明 Apache 进程根本没起来,这时就要去看/var/log/apache2/error.log,那里会记录 WSGI 加载失败的具体原因。
3.12 权限与所有权检查:Linux 文件权限是 Keystone 的“免疫系统”
Keystone 对文件权限极其敏感,一个错误的 chmod 就能让整个服务瘫痪。核心权限规则有三条:第一,/etc/keystone/keystone.conf文件必须属于root:keystone,且权限为640(-rw-r-----),这样 root 可读写,keystone 组可读,其他用户不可访问,防止配置里的数据库密码泄露。第二,/etc/keystone/fernet-keys/目录必须属于keystone:keystone,且权限为700(drwx------),确保只有 keystone 用户能进入和读写密钥。第三,/var/log/keystone/目录必须属于keystone:keystone,权限755,这样 Keystone 进程才能写日志,而其他用户也能读(用于排查)。检查方法很简单:ls -l /etc/keystone/和ls -ld /etc/keystone/fernet-keys/。如果发现权限不对,立刻修复:sudo chown root:keystone /etc/keystone/keystone.conf && sudo chmod 640 /etc/keystone/keystone.conf;sudo chown -R keystone:keystone /etc/keystone/fernet-keys/ && sudo chmod 700 /etc/keystone/fernet-keys/。这些命令看起来枯燥,但它们是 Keystone 稳定运行的基石。我曾见过一个案例,运维人员为了“方便”,把整个/etc/keystone/目录chmod 777,结果 Keystone 启动后疯狂报错Permission denied on fernet key file,因为 WSGI 进程(以 www-data 用户运行)发现密钥文件对所有人都可写,出于安全策略自动拒绝加载。
4. 实操过程与核心环节实现:一份可逐行复制的完整操作清单
4.1 环境准备与基础服务安装(耗时约 3 分钟)
我们假设你已有一台纯净的 Ubuntu 22.04 Server 虚拟机,网络可达,root 权限可用。所有命令均以sudo执行,或切换到 root 用户。第一步,更新系统并安装基础工具:
sudo apt update && sudo apt upgrade -y sudo apt install -y vim curl wget gnupg software-properties-common第二步,配置 NTP 时间同步:
sudo apt install -y chrony sudo sed -i '/^pool/d' /etc/chrony/chrony.conf echo "server ntp.aliyun.com iburst" | sudo tee -a /etc/chrony/chrony.conf sudo systemctl restart chrony sudo chronyc tracking # 验证时间同步状态,输出应包含 "System clock synchronized: yes"第三步,配置防火墙:
sudo ufw allow OpenSSH sudo ufw allow 5000 sudo ufw --force enable第四步,配置主机名与 hosts 解析:
echo "192.168.100.10 controller.example.com controller" | sudo tee -a /etc/hosts sudo hostnamectl set-hostname controller.example.com提示:请务必将
192.168.100.10替换为你实际的服务器 IP 地址。controller.example.com是 FQDN,.example.com后缀不能省略,这是为了满足 SSL 证书的通用名(CN)要求,即使你现在不用 HTTPS。
4.2 MySQL 数据库安装与 Keystone 专用库创建(耗时约 2 分钟)
安装 MySQL 8.0:
sudo apt install -y mysql-server安全加固(设置 root 密码、移除匿名用户等):
sudo mysql_secure_installation # 按提示操作:设置 root 密码(记为 MYSQL_ROOT_PASS),其余选项选 Y登录 MySQL 并创建 Keystone 数据库与用户:
sudo mysql -u root -p # 输入上面设置的 MYSQL_ROOT_PASS在 MySQL 提示符下执行:
CREATE DATABASE keystone CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; CREATE USER 'keystone'@'localhost' IDENTIFIED WITH mysql_native_password BY 'KEYSTONE_DBPASS'; CREATE USER 'keystone'@'%' IDENTIFIED WITH mysql_native_password BY 'KEYSTONE_DBPASS'; GRANT ALL PRIVILEGES ON keystone.* TO 'keystone'@'localhost'; GRANT ALL PRIVILEGES ON keystone.* TO 'keystone'@'%'; FLUSH PRIVILEGES; EXIT;注意:
KEYSTONE_DBPASS是你为 Keystone 数据库用户设定的密码,请牢记。'keystone'@'%'的授权是为了未来扩展,现在可以先用'keystone'@'localhost'。
4.3 Keystone 服务安装与系统用户创建(耗时约 1 分钟)
安装 Keystone 及其依赖:
sudo apt install -y keystone apache2 libapache2-mod-wsgi-py3 python3-openstackclient创建 Keystone 系统用户与组:
sudo useradd -r -s /bin/false keystone sudo groupadd keystone sudo usermod -a -G keystone keystone创建日志与密钥目录:
sudo mkdir -p /var/log/keystone /etc/keystone/fernet-keys sudo chown -R keystone:keystone /var/log/keystone /etc/keystone/fernet-keys sudo chmod 755 /var/log/keystone sudo chmod 700 /etc/keystone/fernet-keys4.4 Keystone 主配置文件编辑(耗时约 5 分钟,需逐行核对)
备份原始配置:
sudo cp /etc/keystone/keystone.conf /etc/keystone/keystone.conf.bak清空并重写配置文件(使用 vim 或 nano):
sudo tee /etc/keystone/keystone.conf << 'EOF' [DEFAULT] log_dir = /var/log/keystone transport_url = rabbit://openstack:RABBIT_PASS@controller [database] connection = mysql+pymysql://keystone:KEYSTONE_DBPASS@controller/keystone [token] provider = fernet driver = sql [cache] backend = dogpile.cache.memcached memcache_servers = localhost:11211 [identity] driver = sql [assignment] driver = sql [auth] methods = external,password,token,oauth1 password = password token = token [profiler] enabled = false EOF设置正确权限:
sudo chown root:keystone /etc/keystone/keystone.conf sudo chmod 640 /etc/keystone/keystone.conf提示:
RABBIT_PASS是 RabbitMQ 的密码占位符,本实训暂不启用消息队列,但此行必须存在,否则 Keystone 启动失败。KEYSTONE_DBPASS请替换为你在 4.2 步骤中设定的密码。
4.5 Fernet 密钥初始化与数据库同步(耗时约 1 分钟)
初始化 Fernet 密钥:
sudo keystone-manage fernet_setup --keystone-user keystone --keystone-group keystone sudo keystone-manage credential_setup --keystone-user keystone --keystone-group keystone同步数据库表结构:
sudo keystone-manage db_sync注意:
db_sync命令无任何输出即为成功。如果报错,请立即检查 MySQL 连接字符串和权限。
4.6 Bootstrap 初始化与 Apache 配置(耗时约 2 分钟)
执行初始化,创建 admin 用户与 service:
sudo keystone-manage bootstrap --bootstrap-password ADMIN_PASS \ --bootstrap-admin-url http://controller:5000/v3/ \ --bootstrap-internal-url http://controller:5000/v3/ \ --bootstrap-public-url http://controller:5000/v3/ \ --bootstrap-region-id RegionOne
ADMIN_PASS是你为 admin 用户设定的密码,请牢记。controller必须与/etc/hosts中配置的主机名完全一致。
配置 Apache:
sudo tee /etc/apache2/sites-available/wsgi-keystone.conf << 'EOF' Listen 5000 <VirtualHost *:5000> WSGIDaemonProcess keystone-public processes=5 threads=1 user=keystone group=keystone display-name=%{GROUP} WSGIProcessGroup keystone-public