1. 为什么你需要这份OpenStack部署操作手册
先说点实在话。OpenStack这套东西,名声很大,劝退率也极高。早些年我参与过几套云平台的交付,从几百台规模的实验环境到数千节点的生产集群都待过,一个特别深的感受是:网上找得到的OpenStack资料,要么是官方文档那种“把所有选项都列出来但不告诉你该选哪个”的参考手册,要么是培训机构那种“跟着敲命令就能装完但换一台机器就翻车”的速成教程,真正能拿来当作战手册用的东西太少。
所以我打算写的这一份部署操作手册,定位很明确:不是从零解释OpenStack是什么的科普,也不是纯命令堆积的操作列表,而是把一套可落地的部署路径、每个环节为什么要这么选、最容易出问题的点在哪里,完整地串起来。
这份手册适合谁来用?两类人。一类是正准备在公司内部落地一套云平台,需要自己完成从架构规划、环境初始化到组件部署的运维工程师;另一类是正在准备云计算运维相关岗位面试,想把OpenStack的部署链路和核心机制讲清楚的学习者。对于已经在用商业发行版、只关心界面操作的朋友,这份手册帮助有限,因为你们遇到的问题通常已经被厂商封装好了。
先亮一下手册的整体目录框架,后面所有内容都围绕这个骨架展开:
- OpenStack部署前的架构规划(硬件、网络、存储)
- 核心组件逐个拆解:Keystone、Glance、Nova、Neutron、Cinder
- 部署方式选型与自动化工具实践
- 部署完成后的初始化与连通性验证
- 日常运维监控、备份与故障排查
- 集群扩容、升级与高可用演进
这套框架背后有一个核心思路:OpenStack部署的难点从来不是某个组件的安装,而是组件之间如何正确通信、数据如何流转、故障时从哪里查起。如果只是按文档把服务装完,服务状态都是UP,但虚拟机就是起不来,这种场景我见过太多次了。所以手册里每个章节都不是孤立写部署步骤,而是把“部署”和“验证”绑在一起,装完一个模块就验证一个模块的连通性,这样到最后一步才不至于无从下手。
行业内有个经典说法:OpenStack部署最容易失败的地方,十个里有八个出在“准备阶段”——要么是网络规划漏了网段,要么是后端存储没想清楚,要么是操作系统版本和组件版本不匹配。准备工作做得越充分,后面真正执行部署命令的过程反而最轻松。
接下来的内容,就是把这些准备工作一一拆开细讲。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 部署前的架构规划:硬件、网络与后端存储选型
2.1 硬件资源配置的最低标准与扩容方向
OpenStack不像装个MySQL或者Redis,它是一组服务的集合,控制面本身就由十几个核心服务组成。硬件规划的第一原则是:控制节点要稳,计算节点要狠,网络节点要通。
控制节点上跑着Keystone、Glance、Nova的调度服务、Neutron的Server服务、Cinder的API服务,以及数据库、消息队列等基础依赖。我的经验是控制节点CPU不低于8核、内存不低于16GB,磁盘至少200GB且建议SSD。小规模环境可以把控制、网络、存储三个角色合在一台物理机上,但只要规模预期会超过50台计算节点,控制面服务就该拆开部署,尤其要把消息队列和数据库单独放,这两个服务是控制面的命脉,资源一旦被挤占,整个云平台的表现就是“所有虚拟机都卡在创建中”。
计算节点主要看CPU和内存的配比。行业里常用的超配比例是CPU 1:4到1:8、内存1:1到1:1.5,具体取决于线上负载类型——如果是跑高并发Web业务的,超配比例要保守;如果是离线任务、批处理场景,可以激进一些。计算节点的本地磁盘建议至少两块,一块装系统,一块做实例的本地存储临时空间,避免系统盘被实例I/O拖垮。
存储节点如果要接Ceph,最好单独规划。Ceph对网络要求很高,建议万兆网卡起步,而且OSD节点不要和计算节点混布,否则会出现“计算负载高的时候,整个存储集群跟着抖动”的情况。
2.2 网络规划:管理网、数据网、外部网与网卡bond策略
网络规划是整个部署中最容易出连环事故的地方。很多初学者把网络想简单了,以为一个网段搞定所有通信,结果装到Neutron那一步就卡住了,因为服务之间、服务与实例之间、实例与外部之间需要不同的网络平面。
一套规范的多平面网络规划建议如下:
| 网络平面 | 用途 | 网段示例 | 带宽要求 | 备注 |
|---|---|---|---|---|
| 管理网 | 组件API通信、SSH管理 | 10.0.0.0/24 | 千兆 | 全节点可达,禁止与数据网重叠 |
| 数据网(实例网络) | 虚机之间数据流量、VXLAN隧道 | 10.10.0.0/16 | 万兆 | 计算节点与网络节点必须打通 |
| 外部网 | Floating IP、路由器网关 | 192.168.100.0/24 | 千兆/万兆 | 承载业务对外流量 |
| 存储网(可选) | Ceph、NFS等后端存储流量 | 10.20.0.0/24 | 万兆 | 与业务网络物理隔离 |
生产环境中,我强烈建议给每台物理机至少配4块网卡:管理网、数据网、外部网各用一块,再留一块做管理网或数据网的bond备用。网卡bond的模式通常用mode 4(LACP),配合交换机的链路聚合配置。这里有个常见坑:如果交换机端没配LACP,linux bond在mode 4下会直接“假活”,表现为网卡状态是UP但ping不通,所以bond做完一定要做双向的连通性验证。
管理网和数据网如果只有一块物理网卡可用,可以退而求其次做VLAN子接口,把管理流量和数据流量通过802.1Q隔离,但这是妥协方案,生产上不建议,因为VXLAN隧道流量和API流量混在一起,出了问题很难定位是哪个平面的故障。
2.3 操作系统、Python版本与组件版本匹配
OpenStack社区每半年发一个大版本,版本命名按字母顺序走。目前常见的老牌稳定版包括Train、Ussuri、Wallaby、Yoga等。不同版本对操作系统和Python版本的要求差异很大,规划阶段就要锁定版本组合,否则到了部署后期会发现某个组件依赖的库版本和系统自带的冲突。
我的建议是:不要追求最新版本,选择当前生态里已经稳定运行过一段时间的版本组合。比如用Ubuntu 20.04搭配OpenStack Wallaby或Yoga,用CentOS Stream 8搭配Train或Ussuri,这些都是经过大量生产环境验证的组合。Rocky Linux 9搭配最新版本虽然新特性多,但社区的issue记录和踩坑资料相对少,遇到问题时要靠自己去翻源码,对新手不友好。
操作系统选型上,Ubuntu Server和Rocky Linux/CentOS Stream是两大主流。Ubuntu的优势是Python环境干净、OpenStack社区在Ubuntu上的测试覆盖最广;RHEL系的优势是SELinux体系完善,而且很多企业已有Red Hat运维基础。如果团队之前没有强SELinux经验,建议直接从Ubuntu起步,减少一道安全策略上的学习成本。
2.4 后端存储选型:本地目录、NFS、LVM还是Ceph
Glance镜像服务和Cinder块存储服务都需要后端存储,这个选择直接影响虚机启动速度和块设备性能。
| 后端方案 | 适用规模 | 优势 | 劣势 |
|---|---|---|---|
| 本地目录(file) | 实验环境、单节点 | 零配置、最简单 | 无共享能力,无法迁移实例 |
| NFS | 中小规模 | 配置简单、共享存储 | 性能一般、存在单点 |
| LVM(Cinder专用) | 单计算节点小规模 | 性能好、稳定 | 不支持跨节点,无法做快照高级功能 |
| Ceph | 生产环境、大规模 | 分布式、自愈、快照丰富 | 架构复杂、需要独立维护 |
实践中的选型逻辑很简单:先定Cinder的后端,再看Glance放哪里。如果Cinder后端选了Ceph,Glance也应该用Ceph的RBD驱动,让镜像数据和块设备数据在同一个存储池里流转,省去镜像从Glance复制到Cinder的等待时间;如果只是小规模环境,直接让Glance用本地目录、Cinder用LVM即可,不要为了“看起来专业”硬上一套Ceph,那是在给自己制造运维负担。
还要关注一个容易被忽略的点:Glance存放镜像的目录所在分区,剩余空间要预留足够。镜像文件默认是qcow2格式,但虚机启动时Glance需要把镜像转为raw格式再传给计算节点,这期间临时文件会占用额外空间。实测中遇到过一两次镜像目录被写满,导致所有新建虚机都失败的案例,排查了很久才发现是这个原因。
3. 核心组件逐个拆解:从身份认证到网络通路的完整链路
3.1 Keystone:项目、用户、角色与多项目归属
Keystone是整个OpenStack的身份认证中心,其他所有服务在收到请求时都会先拿Token找Keystone验明身份。部署Keystone本身不难,难点在于理解它的数据模型,尤其是“项目”和“用户”的关系。
OpenStack的权限模型里有几个核心概念:
- Domain(域):最顶层的容器,可以理解为一个企业或租户空间
- Project(项目):资源隔离的单位,虚机、网络、镜像等资源都归属于某个项目
- User(用户):登录实体,可以归属于一个或多个项目
- Role(角色):用户在某个项目内的权限等级
热搜词里有一个“openstack 一个用户属于多个项目”,这确实是实际使用中非常常见的问题。Keystone默认支持一个用户关联多个项目,但要注意:Token是绑定在“用户-项目”这一对关系上的。一个用户如果有三个项目的权限,登录时需要显式指定要进入哪个项目,切换项目时需要重新获取Token。具体的操作方式是用openstack login时选择项目,或者通过openstack token issue为指定项目重新签发Token。
命令行里最常见的操作是:
bash复制# 创建项目
openstack project create --domain default --description "研发部门项目" dev-project
# 创建用户并设置密码
openstack user create --domain default --password 'SecurePass123' zhangsan
# 将用户添加到多个项目并赋予不同角色
openstack role add --project dev-project --user zhangsan member
openstack role add --project test-project --user zhangsan member
部署Keystone时最容易踩的坑有两个。第一是endpoint的IP地址写错或写成了localhost,导致其他节点访问Keystone时连接被拒。第二是fernet key的备份问题,Keystone默认用fernet作为token格式,fernet key存放在/etc/keystone/fernet-keys/目录下,这个目录在Keystone节点挂了之后如果没有备份,所有存量用户的token都会失效,而且无法恢复。所以部署完第一件事就是把fernet keys备份到安全的地方。
3.2 Glance:镜像格式、后端驱动与上传激活流程
Glance负责管理云主机的镜像。部署Glance服务本身很快,就是配置数据库连接、注册endpoint、配置存储后端,然后启动服务。但它有几个细节决定后续使用是否顺畅。
镜像格式的选择上,qcow2是默认推荐格式,支持压缩、快照、稀疏文件,适合上传和存储;raw格式性能最好,但文件大、不支持压缩。上传到Glance之后,Nova在创建实例时会把镜像转成raw格式放到计算节点的本地存储或共享存储上,这个转换过程是自动的,但如果计算节点本地磁盘空间不足,就会直接报错。
一个经常被忽略的点是镜像的可见性和共享范围。Glance里的镜像默认只有创建者所属项目可见。通过openstack image set --shared可以把镜像共享给其他项目,或者设置--public让所有项目可见。在小团队环境里,建议把基础镜像都设为public,避免每个项目重复上传一份。
上传镜像的标准流程:
bash复制# 下载官方云镜像
wget https://cloud-images.ubuntu.com/focal/current/focal-server-cloudimg-amd64.img
# 上传到Glance
openstack image create "Ubuntu-20.04" \
--file focal-server-cloudimg-amd64.img \
--disk-format qcow2 \
--container-format bare \
--public
这里有个参数很多人不理解:--disk-format qcow2 --container-format bare。简单解释,disk-format是镜像内部磁盘的格式,container-format是镜像文件的封装格式,绝大多数场景都是bare,代表没有额外的容器封装。这两个参数一旦写错,镜像虽然能上传但虚机启动时会失败。
3.3 Nova:从调度到创建实例的完整流程与关键配置文件
Nova是整个OpenStack的计算核心,组件也最多:nova-api接收请求、nova-scheduler决定把虚机放到哪台计算节点、nova-conductor协调数据库操作、nova-compute在计算节点上真正拉起虚机。
部署Nova时,大多数文档会让你按顺序配置并启动这些服务,但很少解释清楚它们之间的调用链。我画一条直观的链路:
code复制用户请求创建虚机
-> nova-api 接收请求并校验Token
-> nova-conductor 写数据库,生成一个虚机记录
-> nova-scheduler 根据过滤器和权重选出计算节点
-> 选中的计算节点上的 nova-compute 执行创建动作
-> 从Glance拉镜像
-> 调用Neutron创建网络端口
-> 调用Cinder创建根磁盘
-> 通过libvirt/KVM启动虚机
这条链路里,任何一个环节失败,虚机都会卡在“创建中”状态。所以排查虚机创建问题时,应该沿着这条链路一层层查日志,而不是一上来就看nova-compute的日志。
生产环境里Nova配置的几个关键参数:
ini复制[DEFAULT]
# 控制CPU超配比例,默认为16.0,生产建议4.0-8.0
cpu_allocation_ratio = 4.0
# 控制内存超配比例,默认为1.5
ram_allocation_ratio = 1.2
# 磁盘超配,默认1.0即不超配
disk_allocation_ratio = 1.0
[libvirt]
# 虚拟机CPU模式,生产用host-passthrough性能最好
cpu_mode = host-passthrough
# 镜像缓存清理策略,避免磁盘被缓存镜像占满
disk_cachemodes = network=writeback
[vnc]
# VNC控制台监听地址,设为0.0.0.0才能从外部访问
novncproxy_host = 0.0.0.0
关于cpu_mode,如果计算节点的CPU型号不一致(比如一部分是Intel,一部分是AMD),host-passthrough会导致虚机在线迁移失败,因为目标宿主机不支持源宿主机透传的CPU特性。这种混用场景下应该改用custom,指定一个所有节点都兼容的CPU模型。
还有一个高频问题:计算节点上明明有充足资源,但虚机调度过去就是起不来。最常见的两个原因,一个是计算节点的时间不同步,导致Keystone验证Token时出现偏差,另一个是计算节点和网络节点之间的VXLAN隧道端口没放通。这两个问题看似是小细节,实际上我排查过的很多“调度失败”都跟它们有关。
3.4 Neutron:网络模型、Agent机制与创建网络的完整流程
Neutron可能是OpenStack里最复杂的组件。它的核心设计是:控制面负责管理网络资源的定义和状态,数据面由部署在各节点上的Agent负责实际执行。理解了“控制面与数据面分离”这个设计,Neutron的很多行为就说得通了。
先明确几个网络概念,这直接影响部署配置:
- Provider Network(提供商网络):直接映射到物理网络的网络,虚机的流量不做隧道封装,性能好,但网络隔离能力弱
- Self-service Network(自助网络):通过VXLAN或GRE封装实现多租户隔离,支持租户自助创建网络,是默认选择
- Router(路由器):连接自助网络和外部网络,实现虚机访问外网以及Floating IP映射
- Security Group(安全组):虚机级别的防火墙规则
部署时最常见的模式是:计算节点上配置一个网桥(Bridge)用于虚机流量接入,网络节点上运行DHCP Agent、L3 Agent和Metadata Agent,分别是给虚机分配IP、做路由转发和提供元数据服务。
以经典的自助网络创建流程为例:
bash复制# 1. 创建外部网络
openstack network create --external --provider-physical-network physnet1 --provider-network-type flat external-net
# 2. 在外部网络上创建子网
openstack subnet create --network external-net \
--subnet-range 192.168.100.0/24 \
--gateway 192.168.100.1 \
--allocation-pool start=192.168.100.100,end=192.168.100.200 \
--dns-nameserver 114.114.114.114 \
external-subnet
# 3. 创建租户内部网络
openstack network create --project dev-project selfservice-net
openstack subnet create --network selfservice-net --subnet-range 10.10.10.0/24 --dns-nameserver 114.114.114.114 selfservice-subnet
# 4. 创建路由器并连接两个网络
openstack router create dev-router
openstack router set --external-gateway external-net dev-router
openstack router add subnet --subnet selfservice-subnet dev-router
这里有一个初学者高频出错点:Floating IP只能从外部网络分配,而且一个Floating IP对应一个虚机端口。如果外部网络的--allocation-pool配置不对,比如池范围和实际物理网络冲突,Floating IP在外部就是不可达的。所以外部网络的规划要和实际物理网络设备同步,不能自己凭空造一个网段出来。
Neutron的Agent状态也是必检项:
bash复制openstack network agent list
正常情况下,dhcp-agent、l3-agent、metadata-agent的状态都应该是alive。如果某个agent显示dead,虚机创建能成功但是拿不到IP、或者无法访问外网、或者cloud-init无法注入元数据,问题基本都是从这里来的。处理方式通常不复杂,重启对应agent服务即可,但要先看日志找到agent为什么挂掉,否则会反复复发。
3.5 Cinder:卷组配置、创建卷与挂载链路
Cinder提供块存储服务,让虚机可以获得持久化的数据盘或独立的启动盘。小规模环境里最常见的后端就是LVM,部署时需要先在存储节点上准备好一个卷组。
LVM后端的配置要点:
bash复制# 在存储节点上创建卷组(假设有独立磁盘sdb)
pvcreate /dev/sdb
vgcreate cinder-volumes /dev/sdb
# 修改cinder.conf
[LVM]
volume_driver = cinder.volume.drivers.lvm.LVMVolumeDriver
volume_group = cinder-volumes
target_protocol = iscsi
target_helper = tgtadm
LVM后端有个必须注意的细节:Cinder的卷组不要和系统使用的卷组混用。操作系统安装时默认创建的卷组叫ubuntu-vg或centos-vg,如果Cinder也往这个卷组里创建逻辑卷,一旦卷组空间耗尽,整个系统都可能无法启动。生产上强烈建议用独立磁盘创建独立的Cinder卷组。
创建和挂载卷的操作:
bash复制# 创建5GB数据卷
openstack volume create --size 5 --type lvm data-volume
# 挂载到虚机
openstack server add volume my-instance data-volume --device /dev/vdb
# 在虚机内部查看并格式化
lsblk
mkfs.ext4 /dev/vdb
mount /dev/vdb /data
Cinder的问题排查核心在cinder-volume服务上。创建卷一直处于creating状态时,先到存储节点上看/var/log/cinder/cinder-volume.log,绝大多数情况是tgt或LVM的配置问题,特别是iscsi的target管理服务没启动。还有个操作习惯值得养成:删除卷之前先确认没有虚机正在使用它,否则数据库里会留下残留引用,导致卷处于“无法删除也无法挂载”的中间状态。
4. 部署方式选型:从手工部署到Kolla-Ansible自动化实践
4.1 四种主流部署方式定位对比
OpenStack的部署方式这些年沉淀下来主要有四类,各有明确的使用场景,不存在“谁完全替代谁”的结论。
| 部署方式 | 代表工具 | 适用场景 | 学习成本 | 生产可用性 |
|---|---|---|---|---|
| 脚本化快速部署 | DevStack | 开发测试、单机体验 | 低 | 不可用 |
| 手工部署 | 无(手动安装配置各组件) | 学习原理、定制架构 | 极高 | 低(团队无自动化能力时) |
| 容器化编排部署 | Kolla-Ansible | 生产环境主流选择 | 中 | 高 |
| 开源发行版部署 | OpenStack-Ansible、TripleO | 特定场景、大客户交付 | 中高 | 高 |
DevStack基本只用于开发环境,一条./stack.sh就能在当前机器上搭出一套完整环境。但它把所有服务都跑在同一台机器上,网络配置也是简化过的,生产不可用,只适合快速上手体验。
手工部署适合学习和深度定制,但生产上可以放弃这个选项。手工部署一套完整的OpenStack社区版,熟练工程师也需要大半天时间,而且升级和故障恢复全靠人肉运维。我自己学习时手工部署过五次,每次都至少踩一个之前没遇到过的新坑,但正是这个过程让我真正理解了组件之间的依赖关系。
生产环境里我最推荐的是Kolla-Ansible。它的核心思路是把所有OpenStack服务容器化,通过Ansible编排在目标节点上拉取镜像、生成配置、启动容器。这样做的好处有三个:一是部署环境与宿主机解耦,宿主机只要装好Docker和Python环境即可;二是升级时可替换镜像,服务无需重新配置;三是故障恢复时直接把容器重启就能恢复大部分问题,比手工部署时代方便太多。
4.2 Kolla-Ansible关键步骤与globals.yml配置要点
以Kolla-Ansible在Ubuntu 20.04上部署Wallaby版本为例,完整流程可以压缩成几个阶段。
第一步是准备部署节点。Kolla-Ansible的入口控制节点需要安装Python、Ansible和Kolla-Ansible:
bash复制sudo pip install -U pip
sudo pip install 'ansible<2.10' 'kolla-ansible==wallaby'
注意Ansible版本要匹配,Wallaby版本对应的是Ansible 4.x系列,直接装最新版Ansible往往会因为Playbook语法变更导致执行失败。
第二步是在/etc/kolla/globals.yml里配置核心参数。这个文件是整个部署的“总开关”,下面几个配置项特别关键:
yaml复制# 基础镜像版本
kolla_base_distro: "ubuntu"
openstack_release: "wallaby"
# 控制节点和网络节点网卡
network_interface: "eth0"
api_interface: "eth0"
tunnel_interface: "eth1"
external_interface: "eth2"
# Docker仓库地址,国内环境换成镜像源
docker_registry: "registry.cn-hangzhou.aliyuncs.com"
# Neutron网络模式
neutron_plugin_agent: "openvswitch"
neutron_plugin_type: "vxlan"
tunnel_interface是VXLAN隧道流量的承载网卡,必须指向数据网的网卡,如果这里配置错成管理网,实例之间的流量会走到管理网交换机上,既影响性能又可能触发管理网的安全策略限制。
第三步是初始化管理环境和执行部署:
bash复制# 生成密码文件并修改默认密码
kolla-genpwd
# 初始化节点
kolla-ansible bootstrap-servers
# 预检查,这一步会提前暴露大部分环境问题
kolla-ansible prechecks
# 正式部署,耗时长,建议用screen或tmux挂起
kolla-ansible deploy
预检查这一步强烈建议不要跳过。Kolla-Ansible会检查目标节点的网卡是否存在、SELinux状态、磁盘空间、Docker是否正常,等等。我见过有人跳过prechecks直接deploy,结果四个小时后才在某个组件的容器日志里发现基础环境问题,白白浪费时间。
部署完成后还需要生成admin-openrc文件:
bash复制kolla-ansible post-deploy
source /etc/kolla/admin-openrc.sh
然后按照第3章的验证流程,创建第一个项目、第一个网络、第一台虚机。Kolla-Ansible的成功部署标志不是所有容器都Running,而是你能用命令行完整跑通一次“创建虚机→绑定Floating IP→SSH登录”的链路。这个验证不通过,说明整体配置里还有不协调的地方。
4.3 为什么生产环境要拥抱容器化部署
我再展开说说为什么强烈建议生产环境用容器化部署而不是手工部署。
OpenStack服务多、依赖复杂、升级频繁(社区每半年一个大版本)。手工部署时,每个服务都直接装在宿主机上,彼此共享Python环境和系统库。某次升级一个服务时,它依赖的某个库升级了,另一个服务引用了旧版本的接口,整个控制面就崩了。这是我们早期用手工部署时真实经历过的场景:升级Neutron时把它的neutron-lib拉高了一个小版本,结果Nova的python-neutronclient调接口直接报错,所有依赖Neutron的操作都不可用。
容器化彻底规避了这个问题。每个服务独立容器、独立依赖,升级只是换镜像,服务之间的接口调用按API走,底层库的冲突被容器隔离了。Kolla-Ansible把这种隔离变成了标准化的模板和配置,团队里新来的同学照着文档就能完成一次部署,不需要理解每个服务的依赖关系。
当然,容器化也有代价——占用的磁盘和内存比裸装服务多。控制节点上几十个容器平均每个占几十到几百兆内存,加上镜像文件,20GB磁盘起步是必要的。但相比省下的维护和故障恢复成本,这点资源开销完全值得。
5. 部署完成后的初始化与连通性验证
5.1 创建项目、用户与多项目权限配置
部署完成的第一个动作,是初始化一个“日常使用”的租户体系。我的建议是按公司组织架构创建项目,每个项目对应一个部门或一条业务线,而不是所有人都塞进默认的admin项目里。
bash复制# 创建研发项目
openstack project create --domain default --description "研发部门" dev
# 创建运维项目和测试项目
openstack project create --domain default --description "运维部门" ops
openstack project create --domain default --description "测试环境" test
# 创建一个Jhon用户,同时加入多个项目
openstack user create --domain default --password 'ComplexPass123' jhon
openstack role add --project dev --user jhon member
openstack role add --project test --user jhon member
# 给运维创建带管理员权限的用户
openstack user create --domain default --password 'OpsPass456' opsadmin
openstack role add --project admin --user opsadmin admin
openstack role add --project ops --user opsadmin admin
多项目用户登录后,第一次执行命令时可能会发现看不到某个项目的资源。这时候要检查环境变量里OS_PROJECT_NAME设置的是哪个项目,切项目时重新source对应项目的rc文件即可。这里有个隐藏的权限细节:用户在非admin项目里即使有member权限,也无法创建外部网络,因为外部网络属于管理员级别资源。合理的授权规划是:普通用户只管自己的内部网络,外部网络和Floating IP地址池由管理员统一创建。
5.2 创建内外网、路由和安全组规则的完整演练
这是每次部署后必走的验证链路。我建议把这套操作固化成一张检查表,每次搭完环境按表过一遍,可以提前发现很多隐藏问题。
- 创建外部网络和子网,确认可以分配Floating IP。
- 创建租户内部网络和子网,确认DHCP状态正常。
- 创建路由器,把内部网络接入外部网络,确认路由器接口状态为ACTIVE。
- 上传一个测试镜像,确认glance可以正确读取。
- 创建Flavor(规格),注意磁盘和内存参数要和实际资源匹配。
- 创建安全组规则,放通SSH和ICMP。
- 创建虚机,等待状态变为ACTIVE。
- 给虚机绑定Floating IP,从外部ping通虚机。
每一步的验证命令如下:
bash复制openstack network list
openstack subnet list
openstack router list
openstack router show dev-router
openstack image list
openstack flavor list
openstack security group list
openstack server create --flavor m1.small --image Ubuntu-20.04 --network selfservice-net --key-name mykey test-vm
openstack server list
openstack floating ip create external-net
openstack server add floating ip test-vm 192.168.100.100
ping -c 4 192.168.100.100
安全组是新手最常忽略的环节。默认安全组只放通同组内互访,外部访问全部拒绝。创建虚机后如果ping不通、SSH连不上,先别怀疑网络配置,先检查安全组有没有放通规则。这里有个细节:放通SSH时源IP范围建议限定为实际管理网的IP段,而不是0.0.0.0/0全放通,否则虚机等于裸奔在公网上。
5.3 虚机控制台与日志验证,确保“真正可用”
虚机状态显示ACTIVE只代表它被KVM拉起来了,内部操作系统是否正常启动、cloud-init是否成功配置了网络和SSH密钥,需要进一步验证。
对于Ubuntu云镜像,默认用户是ubuntu,密码登录也被禁用,只能使用密钥登录。创建虚机时如果没有指定key-name,虚机的cloud-init又没配置密码,那么你通过VNC控制台也登录不进去——因为SSH密钥没注入,密码登录被禁用。这是初学者最容易卡住的地方。
我的建议是创建一个专门的测试镜像,在上传前用cloud-localds工具生成一个带密码或密钥的seed镜像,或者直接用--key-name指定已有的密钥对:
bash复制# 生成密钥对
openstack keypair create mykey > mykey.pem
chmod 600 mykey.pem
# 用密钥创建虚机
openstack server create --flavor m1.small --image Ubuntu-20.04 --network selfservice-net --key-name mykey test-vm
# 绑定Floating IP后通过密钥登录
ssh -i mykey.pem ubuntu@192.168.100.100
如果SSH始终不通,登录到计算节点上查看虚机的控制台日志:
bash复制# 在计算节点上
virsh list
virsh console <instance-id>
# 或者通过OpenStack命令查看日志
openstack console log show test-vm
从控制台日志里能看到cloud-init的执行情况,比如网络是否拿到IP、SSH服务是否正常启动。这套排查链路配合nova-compute日志,能解决90%的“虚机起不来”问题。
6. 日常运维:监控告警、备份恢复与故障排查链路
6.1 关键服务状态检查与日志目录速查
OpenStack运维的第一个习惯动作,是每天或至少在变更前检查一遍核心服务的状态。不必用其他监控系统,命令行就能完成:
bash复制# 检查各核心服务的进程状态(以Kolla-Ansible环境为例)
docker ps --format "table {{.Names}}\t{{.Status}}"
# 检查OpenStack服务列表
openstack service list
# 检查Neutron Agent状态
openstack network agent list
# 检查计算节点是否正常
openstack compute service list
openstack hypervisor list
通常需要重点关注的指标包括:nova-compute服务是否正常、cinder-volume是否在线、网络Agent的存活状态、消息队列和数据库的负载。
遇到故障时,日志是第一个突破口。各组件日志的位置在手工部署和容器化环境下有区别:
| 组件 | 手工部署日志路径 | Kolla-Ansible容器日志路径 |
|---|---|---|
| Nova | /var/log/nova/nova-conductor.log | docker logs nova_conductor |
| Neutron | /var/log/neutron/neutron-server.log | docker logs neutron_server |
| Cinder | /var/log/cinder/cinder-volume.log | docker logs cinder_volume |
| Keystone | /var/log/keystone/keystone.log | docker logs keystone |
容器化环境下查看日志更简单,docker logs直接看最近的输出,配合journalctl -u docker可以查容器本身的启停记录。有个实用技巧:出问题时先把最后50行日志拉出来看有没有traceback,绝大多数组件在异常时都会抛出python的堆栈信息,定位到抛异常的那一行,基本就能确定根因。
6.2 数据库、配置文件与密钥的备份策略
OpenStack的状态大部分存在数据库里:虚机定义、网络定义、镜像元数据、用户信息都在MySQL中。备份策略的核心是数据库优先。
我的备份方案分三层:
- 数据库每日全量备份。用mysqldump或xtrabackup,备份文件保留7天,同时同步到异地存储。
- 配置目录备份。手工部署时是
/etc/keystone、/etc/nova等目录,Kolla-Ansible环境下是/etc/kolla,这个目录里包含所有服务的配置和密码,每次变更后备份一次。 - 对象存储或镜像目录备份。Glance镜像在本地目录时注意同步,Ceph环境的备份策略和Ceph体系一起做。
恢复演练也不能省。我见过有团队备份做了三年,从没试过恢复,结果一次数据库机器故障,发现备份文件是坏的——因为备份脚本在某个版本升级后路径变了,后续的备份任务其实一直在报错但没注意。所以每隔半年要真正做一次恢复演练,至少恢复到一台新节点上,验证数据库能否正常拉起、服务能否注册成功。
6.3 一次真实故障排查:虚机创建超时的完整链路
最后分享一个我排查过的经典故障,链路比较完整,可以作为以后排查类似问题的模板。
症状:用户创建虚机,状态一直停留在“创建中”超过5分钟。
排查第一步:看nova-conductor的日志。发现有一行类似Timeout waiting for notification of instance ...的记录,这个信息说明conductor已经发出了创建指令但没收到计算节点的确认。
排查第二步:确认nova-compute服务状态。在计算节点上执行openstack compute service list,发现对应节点nova-compute状态为down。转到计算节点上查看服务日志,发现nova-compute在反复重启。
排查第三步:查看nova-compute的具体错误。日志里出现libvirt: XML-RPC error这样的字样。结合报错,用virsh list测试libvirt连接,结果是failed to connect to the hypervisor。
排查第四步:检查libvirtd服务。发现libvirtd没有运行,尝试启动时报错,原因指向/var/lib/libvirt/qemu目录权限异常。用ls -ld查看目录owner,发现问题出在之前手工迁移数据时,这个目录的属主被改成了root,libvirt用户无法访问。
处理方式:把目录属主改回libvirt用户(或kolla环境下的对应用户),重启libvirtd和nova-compute,虚机创建恢复正常。整个过程不到半小时,但如果一上来就去查虚机的网络配置或者镜像问题,方向就完全错了。
这个案例能反映OpenStack故障排查的一个通用方法论:从控制面一层层往数据面推,沿着请求的流转路径查日志,而不是凭感觉乱猜。虚机创建失败,先看调度层(nova-scheduler),再看执行层(nova-compute),再看底层虚拟化(libvirt),每一层都确认没问题再往下一层走,就不会绕远路。
6.4 时钟同步与消息队列:两个容易被轻视的基础依赖
再单独提两个基础依赖,它们在OpenStack部署和运维中的重要性不亚于任何一个核心组件。
第一个是时钟同步。OpenStack的Token有生命周期,组件间的API请求也有超时机制,节点间时间偏差超过一定范围,就会出现“Token有效但是服务认为过期”的诡异问题。我见过时间偏差5分钟导致的诡异现象:同一套环境里,一部分用户能创建虚机,另一部分一直报401认证失败,重启Keystone也解决不了,最后发现是其中一台计算节点的时钟慢了5分钟。解决办法很简单,所有节点统一配置NTP/chrony客户端,同步到同一台时间服务器。生产环境的chrony配置文件里建议配两到三个时间源,避免单一时间源故障后所有节点开始漂移。
第二个是消息队列(RabbitMQ)。Nova的conductor和compute之间的通信、Neutron Server和各Agent之间的通信,很多都走消息队列。消息队列一旦拥堵或挂掉,现象是虚机创建请求发出后完全无响应、CPU和内存使用率低但虚机就是不变状态。生产环境控制节点上RabbitMQ的磁盘和内存占用要重点监控,尤其是rabbitmqctl list_queues里如果有大量堆积的消息,基本可以断定某个消费者服务已经失联。这时候先找到失联的消费者服务并恢复它,比单纯重启RabbitMQ更有效——重启之后老的堆积消息还会回来,问题依旧。
这两个“配角”的问题,占了我实际运维中故障排查的相当比例。所以规划之初就把时间同步和消息队列的健康状态纳入监控范围,能给日常运维省很多事。
7. 集群扩容、升级与高可用演进的实战经验
7.1 新增计算节点的标准流程
OpenStack的扩展通常是从控制面往数据面加计算节点。Kolla-Ansible环境下,新增计算节点的操作非常标准化:新节点装好操作系统和基础网络配置后,把它加进Ansible的inventory文件,在/etc/kolla/multinode里追加[compute]主机组,然后重新执行:
bash复制kolla-ansible bootstrap-servers
kolla-ansible deploy --limit new-compute-node
执行完成后,在控制节点上确认新计算节点已注册:
bash复制openstack compute service list --host new-compute-node
openstack hypervisor list
手工部署环境下的计算节点加入流程也类似:安装nova-compute、neutron-openvswitch-agent等相关服务包,配置控制节点连接信息,设置好/etc/nova/nova.conf中RabbitMQ和数据库的连接,启动服务后检查注册状态。差异在于手工环境要自己确保版本一致——两边nova的版本不一致时,新节点注册后调度上去的虚机可能起不来。
新增计算节点前有个容易被忽略的检查项:新节点的CPU型号如果和控制面不一致,参考前面提到的cpu_mode设置。如果全局配置是host-passthrough,新老节点CPU型号不同时,从老节点迁移虚机到新节点会直接失败,最稳妥的做法是新增节点前用virsh cpu-models比较一下CPU特性集,或者干脆把cpu_mode统一调整为custom模式并指定兼容模型。
7.2 版本升级:从Wallaby到Xena的注意事项
OpenStack升级的生产纪律是:逐版本升级,不要跨大版本跳。社区支持从N-1升级到N,但从Wallaby直接跳到Zed基本等于重装。每次升级前做完整备份,升级过程中先升控制面,再升计算节点,最后升存储相关服务。
以Kolla-Ansible环境的Wallaby升Xena为例,核心步骤:
bash复制# 1. 安装新版的kolla-ansible
sudo pip install 'kolla-ansible==xena'
# 2. 升级控制面(在维护窗口执行)
kolla-ansible upgrade --tags control-plane
# 3. 升级计算节点(逐个节点升级,避免业务全断)
kolla-ansible upgrade --limit compute01
kolla-ansible upgrade --limit compute02
升级控制面时,所有API服务会短暂不可用,所以必须选在业务低峰期操作。升级计算节点的过程中,该节点上的虚机不会中断——因为nova-compute是支持滚动重启的,但该节点在重启期间无法被调度新虚机上去。升级前最好用openstack server migrate --live把手头不重要的虚机迁走,降低风险。
升级最大的隐性风险在数据库。OpenStack的数据库schema是随着版本演进的,升级顺序如果错乱,可能造成新旧数据不一致。Kolla-Ansible通常会在升级过程中自动执行数据库迁移(alembic upgrade head),但前提是升级前数据库有可用备份。万一升级中途失败,数据库能回滚到升级前的状态——这是保命的一步,绝不能省。
7.3 高可用演进的三个阶段
最后说说高可用。很多团队一上来就想用HAProxy+Keepalived把所有控制面服务都做成双活,我建议分阶段演进,先跑起来再逐步加固。
阶段一:单控制节点+多计算节点的可用性。这个阶段没有控制面HA,靠的是虚机层面的可用性(比如提前做好镜像备份、数据盘使用Cinder卷)。适合内部开发测试环境和小规模生产。
阶段二:控制面核心服务HA。在控制节点上部署HAProxy+Keepalived,给Keystone、Nova API、Neutron Server等无状态API服务提供浮动VIP。同时启用数据库主从和RabbitMQ镜像队列。这个阶段能够容忍单台控制节点故障,API不会中断。
阶段三:网络节点HA和存储高可用。Neutron的L3 Agent启用handle_internal_only_routers配合VRRP模式,让路由器在多个网络节点之间漂移;存储层面接Ceph,虚机支持热迁移和自动重建。
演进到这里,你的OpenStack环境才真正具备了生产级的高可用能力。在我的经验里,多数团队停在阶段二已经能满足99%的业务需求,阶段三要看实际业务SLA要求,不必为了“用分布式存储”而硬上Ceph。
我自己动手搭过太多次OpenStack环境,从最早的手工部署到后来的Kolla-Ansible,几乎每次都会在架构规划或者网络配置上找到新的优化空间。这正是这个系统有意思的地方——它永远在逼你把基本功学扎实。版本会一直迭代,但“先规划网络、再选存储后端、分层验证连通性、按链路排查故障”这套方法论是稳定的,吃透了它,不管哪个版本来了都不会慌。
