OpenStack 2025.2 (Flamingo) 单节点一键部署

在 openEuler 25.09 上以源码方式一键部署 OpenStack 2025.2 (Flamingo) 单节点环境, 含 keystone / glance / placement / nova / neutron / horizon / cinder 七个服务, 支持单网卡环境下的实例流量出口(br0 + veth 打通物理局域网)。

本目录是从一台已实际验证通过的机器上整理出的可复现资产: 配置副本、systemd 单元、Apache vhost、部署脚本与验收脚本。


目录结构

deploy/
├── install/                    # 一键部署脚本(按阶段执行)
│   ├── install.sh              # 主控:全量 / 断点续装 / 干跑
│   ├── answers.conf            # ★ 应答文件:所有可调参数集中于此
│   ├── lib.sh                  # 公共函数库(日志/幂等/配置渲染/等待/校验)
│   ├── 00-prepare.sh           # 阶段0 基础环境(RPM、数据目录、venv)
│   ├── 10-keystone.sh          # 阶段1 身份服务
│   ├── 20-glance-placement.sh  # 阶段2 镜像 + 放置
│   ├── 30-nova.sh              # 阶段3 计算服务
│   ├── 40-neutron.sh           # 阶段4 网络服务
│   ├── 50-horizon-cinder.sh    # 阶段5 仪表板 + 块存储
│   ├── 60-network.sh           # 阶段6 虚拟网络 / 物理出口 / 规格 / 镜像
│   └── 90-verify.sh            # 一键验收(57 项检查)
├── etc/                        # 各服务配置副本(口令为占位符)
│   ├── keystone/glance/placement/nova/neutron/cinder/
│   ├── my.cnf                  # MariaDB 主配置(datadir → /data)
│   ├── rabbitmq/ sysconfig/ sysctl.d/
├── httpd/                      # Apache vhost(mod_wsgi 入口)
├── systemd/                    # 14 个自建 systemd 单元
└── scripts/                    # 运维脚本(出口切换/看门狗/开机自检)

前置条件

项 要求
操作系统 openEuler 25.09+(RHEL 系)
Python 3.11
数据盘 挂载到 /data,SSD 优先,可用空间 ≥ 20 GB
网卡 单网卡(本方案按单网卡设计;enp2s0 为例)
硬件虚拟化 支持 vmx/svm(否则须把 VIRT_TYPE 改为 qemu)
内存 ≥ 8 GB(跑 cirros 测试实例建议 ≥ 16 GB)
网络 可访问外网(下载源码包与 pip 依赖)
权限 root

网络要求:本方案要求数据盘在 /data,部署前请确认:

df -h /data                    # 应显示已挂载
lsblk -o NAME,SIZE,ROTA,MOUNTPOINT | grep data    # ROTA=0 表示 SSD

快速开始

1. 修改应答文件

cd deploy/install
vi answers.conf

必改项:

HOSTNAME_SHORT=open88                 # 主机名
MANAGE_IP=192.168.3.88                # ★ 管理 IP(填本机实际地址)
MANAGE_PREFIX=24
MANAGE_GW=192.168.3.1                 # ★ 网关
MANAGE_IF=enp2s0                      # ★ 物理网卡名(ip link 查看)

# 口令(生产务必替换)
ADMIN_PASS=...
RABBIT_PASS=...

# 网络规划(默认即真实网段,按需调整)
EXTERNAL_NET_CIDR=192.168.3.0/24      # 须与物理 LAN 一致
EXTERNAL_NET_GW=192.168.3.1
EXTERNAL_POOL_START=192.168.3.200     # 浮动 IP 池(确认该段空闲)
EXTERNAL_POOL_END=192.168.3.249
SELFSERVICE_CIDR=10.0.0.0/24          # 实例私有网段

⚠️ 浮动 IP 池不能包含网关本身,也不能包含已被占用的地址。 扫描确认:for i in $(seq 200 249); do ping -c1 -W1 192.168.3.$i & done; wait

可选开关:

WITH_EGRESS_SWITCH=no     # ★ 是否打通物理出口(会秒级断网,默认关闭)
WITH_IMAGE=yes            # 是否下载 cirros 镜像
WITH_FLOATING_IP=yes      # 是否为测试实例绑定浮动 IP
WITH_HORIZON=yes          # 是否部署仪表板
WITH_CINDER=yes           # 是否部署块存储

2. 全量部署

sudo ./install.sh

执行时会打印部署摘要并要求确认(输入 yes)。全程约 20–40 分钟 (其中 pip 安装编译组件耗时最长)。

3. 验收

sudo ./90-verify.sh            # 全部检查(含创建测试实例)
sudo ./90-verify.sh --quick    # 只查服务与端口,不创建实例

常用命令

# 列出所有阶段
./install.sh --list

# 断点续装:从阶段 3 开始(修好问题后继续,无需重头来)
sudo ./install.sh 3

# 只执行阶段 0 到 2
sudo ./install.sh 0 2

# 干跑:只打印将执行的步骤,不实际改动系统
./install.sh --dry-run

# 单独重跑某阶段(等价于 ./install.sh <n> <n>)
sudo ./install.sh 6 6

部署阶段说明

阶段 脚本 内容 耗时
0 00-prepare.sh 环境检查、10 个基础 RPM、数据目录指向 /data、MariaDB/RabbitMQ/memcached、venv 与公共依赖、内核参数 5–10 min
1 10-keystone.sh 建库、装包、fernet 密钥、schema、bootstrap、mod_wsgi vhost 3–5 min
2 20-glance-placement.sh glance(镜像存储 → /data)+ placement(含 oslo.policy 兼容补丁) 3–5 min
3 30-nova.sh 三库同步、cell 规划、API vhost、计算节点(rootwrap/privsep/libvirt)、3 个单元 5–10 min
4 40-neutron.sh ML2+OVS、5 个 agent、service 角色、rootwrap、OVS 网桥 5–10 min
5 50-horizon-cinder.sh horizon(静态文件收集)+ cinder(loop 卷组于 /data) 5–10 min
6 60-network.sh 物理出口打通(可选)、外部/私有网络、router、安全组、规格、镜像、端到端 3–8 min

幂等性

所有脚本可重复执行:

  • 建库建用户用 CREATE ... IF NOT EXISTS
  • 配置用 set_opt() 按 section 精确改写(不会重复追加)
  • 服务注册失败时忽略(已存在)
  • 源码包已下载/已安装则跳过

因此部署中断后直接重跑该阶段即可。


关键设计

1. 全部数据落 /data

组件 路径
Python 运行时 /data/openstack/venv
MariaDB datadir /data/openstack/mysql
RabbitMQ mnesia /data/openstack/rabbitmq
镜像文件 /data/openstack/glance/images
实例磁盘 /data/openstack/nova/instances
cinder 卷组后端 /data/openstack/cinder/volumes.img(loop 文件)
源码包 /data/src

2. 服务由 systemd 托管(14 个单元)

不使用 nohup 裸进程(宿主会话结束会被回收,重启也不会自启)。14 个单元全部 enable:

单元 作用
glance-api.service 镜像 API
nova-conductor.service nova 数据库代理
nova-scheduler.service nova 调度器
nova-compute.service nova 计算节点
nova-novncproxy.service noVNC 控制台代理(:6080)
neutron-rpc-server.service neutron RPC 服务(2025.2 新增,缺失会导致 agent 不注册)
neutron-openvswitch-agent.service OVS agent
neutron-dhcp-agent.service DHCP agent
neutron-l3-agent.service L3 agent(实例出网必需)
neutron-metadata-agent.service metadata agent
cinder-scheduler.service 卷调度器
cinder-volume.service 卷服务
cinder-volumes-loop.service loop 设备 + LVM 卷组(Type=oneshot,开机自愈)
br0-provider-veth.service veth 打通 br0 ↔ br-provider(开机自愈)

单元模板要点:

[Service]
Type=simple
User=root
# venv 里的二进制要在 PATH 中(如 cinder-volume 需 cinder-rtstool)
Environment=PATH=/data/openstack/venv/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
ExecStart=/data/openstack/venv/bin/<service> --config-file /etc/<svc>/<svc>.conf
Restart=on-failure
RestartSec=5

keystone / placement / horizon / nova-api / neutron-api / cinder-api 不由独立单元承载, 它们经 mod_wsgi 挂在 httpd 下(vhost 见 httpd/ 目录)。

3. 版本锁定(2025.2 实测必需)

包 版本 原因
neutron-lib 3.21.1 新版 neutron_lib.constants 缺少 ATTR_*,neutron API 500
XStatic-Font-Awesome 4.7.0.0 horizon scss 找不到 font-awesome.scss
eventlet 0.41.2 降到 0.36.x 报 'HubThread' object has no attribute 'kill'

4. 已内置的兼容补丁

脚本会自动应用以下补丁(幂等,重复执行不会重复打):

位置 补丁 原因
placement/deploy.py getattr(conf.oslo_policy, 'enforce_scope', True) 新版 oslo.policy 已移除该选项,直接访问抛 NoSuchOptError
horizon local_settings.py SESSION_SERIALIZER = JSONSerializer 新版 Django 移除 PickleSerializer

单网卡出口方案(br0 + veth)

        物理交换机 / 局域网
               │
            enp2s0(纯 L2 桥端口)
               │
   ┌──────── br0 (Linux 网桥, NM) ────────┐
   │  管理 IP + 默认路由                    │
   │        veth-br0 ●~~~● veth-brex       │
   └────────────────┬──────────────────────┘
                    │
        ┌─── br-provider (OVS, neutron) ───┐
        │   phy-br-provider ↔ br-int        │
        └───────────────┬──────────────────┘
                        │
              qrouter(qg/qr) → 实例浮动 IP / SNAT

为什么这样设计:enp2s0 是唯一网卡,直接把它挂进 OVS 网桥会让管理 IP 无处安放。 方案是先用 br0 承接管理 IP(enp2s0 降为桥端口),再用一对 veth 把 br0(NM 管理)与 br-provider(neutron 管理)在 L2 上连通, 两类流量各走各的网桥,只在 L2 交汇。

启用方式:

# answers.conf 中置 yes,然后重跑阶段 6
WITH_EGRESS_SWITCH=yes
sudo ./install.sh 6

⚠️ 会造成的秒级断网(管理 IP 从网卡迁移到网桥)。执行前必须:

  1. 确认有带外/现场操作条件(IPMI/iKVM/串口)
  2. 另开一个 SSH 窗口守候
  3. 脚本内置自检与失败自动回滚(/root/phase1-br0.sh 自带)

回滚:

ovs-vsctl --if-exists del-port br-provider veth-brex
ip link del veth-br0
systemctl disable --now br0-provider-veth
nmcli con down br0 && nmcli con delete br0-slave-enp2s0 && nmcli con delete br0
nmcli con mod enp2s0 connection.autoconnect yes && nmcli con up enp2s0

运维脚本

脚本 用途
scripts/br0-provider-veth.sh veth 打通(幂等,由 systemd 单元调用)
scripts/phase1-br0.sh 管理 IP 迁移(含自检+自动回滚)
scripts/net-watchdog.sh 通用回滚看门狗(N 秒未确认自动还原)
scripts/net-switch-egress.sh 出口切换一站式脚本(备选路径)
scripts/boot-verify.sh 开机后自检网络与服务

服务清单

服务 端口 systemd 单元
keystone 5000 (mod_wsgi,随 httpd)
glance 9292 glance-api
placement 8778 (mod_wsgi,随 httpd)
nova 8774 / 8775 nova-compute nova-conductor nova-scheduler
neutron 9696 neutron-rpc-server neutron-openvswitch-agent neutron-dhcp-agent neutron-l3-agent neutron-metadata-agent
horizon 80 (mod_wsgi,随 httpd)
cinder 8776 cinder-scheduler cinder-volume cinder-volumes-loop
网络出口 — br0-provider-veth

故障排查

部署日志

tail -100 /var/log/openstack-deploy.log      # 部署全过程

服务日志

/data/openstack/nova/*.log
/data/openstack/neutron/*.log
/data/openstack/cinder/*.log
/data/openstack/glance/glance-api.log
/var/log/httpd/error_log                     # mod_wsgi 层

常见问题

实例一直 BUILD 然后 ERROR

openstack server show <实例> -f value -c fault
fault 关键字 原因
Failed to allocate the network(s) neutron 未发 network-vif-plugged(检查 neutron.conf 的 [nova] 段与通知开关)
Exhausted all hosts / PortBindingFailed neutron-rpc-server 启动时漏了 --config-file ml2_conf.ini,导致 ML2 驱动未加载
Compute driver option required nova.conf 缺 compute_driver

实例 ACTIVE 但 ping 不通

# 1) 检查是否安全组拦了 ICMP(默认组只放行同组入向)
openstack security group rule list default
openstack security group rule create --ingress --proto icmp default

# 2) 检查实例是否真的起来了(内存是否足够)
virsh list --all
openstack flavor show <规格> -f value -c ram     # cirros 需 >= 128MB

# 3) 检查 DHCP 是否发到地址
cat /var/lib/neutron/dhcp/*/leases

浮动 IP 不通

# 内网是否通(先排除实例自身问题)
ip netns exec qrouter-<id> ping -c2 <实例私有IP>

# 上游常过滤 ICMP,用 TCP 验证
bash -c 'exec 3<>/dev/tcp/<浮动IP>/22'

# 物理出口是否已打通
ovs-vsctl list-ports br-provider     # 应含 veth-brex

重启后实例未自动拉起

# 现象:宿主机重启后实例为 SHUTOFF(libvirt 无 autostart)
openstack server start <实例>

# 永久启用(二选一)
virsh autostart instance-00000004
# 或 nova.conf: resume_guests_state_on_host_boot = True

已知限制

项 说明
单节点 未验证多计算节点、cell 扩容、HA
存储非冗余 cinder 用单机 loop 文件做卷组,无副本
cinder-backup 未部署(需对象存储后端)
实例自启 宿主机重启后实例需手动启动(见上)
出口切换有断网 WITH_EGRESS_SWITCH=yes 时管理 IP 迁移会秒级断网
源码版本 依赖上游 stable-2025.2 分支的 tarball,上游变动可能影响

安全提示

  1. answers.conf 中的口令为文档一致占位值,生产环境务必替换为强口令。
  2. 本方案不导出密钥材料:fernet-keys/、credential-keys/、RabbitMQ cookie、 Horizon SECRET_KEY 均不在仓库中,由部署脚本在目标机现场生成。
  3. 浮动 IP 直接暴露在物理局域网,安全组是唯一防线。
  4. 建议部署完成后限制 :5000、:9292 等管理端口的来源(本方案为简化未做)。

版本信息

项 值
OpenStack 2025.2 (Flamingo)
实测 OS openEuler 25.09(内核 7.2.0)
Python 3.11.13
MariaDB 11.8.3
RabbitMQ 3.12.10
OVS 3.3.1
libvirt / QEMU 9.10.0 / 8.2.0