1. 为什么还要折腾 DevStack 单节点部署
先把话说在前头:如果你只是想快速体验一下 OpenStack 的界面长什么样,那用官方打包好的发行版或者容器化方案会省事得多。但如果你是真的想搞明白 OpenStack 各个组件之间到底怎么串起来的、Keystone 怎么发令牌、Nova 怎么调度虚拟机、Neutron 怎么把网络打通,那 DevStack 依然是目前最直接的一条路。它本质上就是一套 Shell 脚本集合,把 OpenStack 所有核心服务的源码从代码仓库拉下来,在本机直接跑起来,不走打包、不走容器,所有配置文件、日志、进程都摊在你面前,出问题了你能一层层扒开看。
我这次的环境是 Ubuntu 18.04 LTS,这个版本虽然不算新,但胜在稳定,社区里大量文档和踩坑记录都是基于它写的,遇到问题容易搜到答案。目标是在一台机器上把单节点 OpenStack 跑起来,版本走 master 分支,也就是所谓的"最新版本"。这里要提醒一句,DevStack 的 master 分支是跟着 OpenStack 开发节奏走的,今天能跑通不代表下周还能跑通,所以如果你追求可复现,最好在跑通之后把当时拉下来的各个仓库 commit 记录下来。
单节点部署意味着所有角色——控制节点、网络节点、计算节点——全部挤在一台机器上。好处是省资源、结构简单;坏处是资源竞争严重,尤其是内存和 CPU,配置不够的话跑起来会非常卡,甚至服务起不来。所以下面我会先讲清楚硬件和系统层面的准备,再进入具体的安装流程。
这篇文章适合两类人:一类是刚接触 OpenStack、想动手把整套东西跑起来看看的运维或开发;另一类是已经用过 OpenStack 但没自己从源码装过、想搞清楚底层细节的人。我会把每一步为什么这么做讲清楚,包括参数怎么算、坑在哪里,尽量让你照着做能复现出来。
2. 环境准备与系统层面的取舍
2.1 硬件资源的实际需求估算
DevStack 官方文档里给的最低配置看起来不高,但那是"能启动"的底线,不是"能用"的配置。我实测下来,单节点跑全套核心服务,比较舒服的配置是这样的:
| 资源项 | 最低能跑 | 推荐配置 | 说明 |
|---|---|---|---|
| CPU | 2 核 | 4 核及以上 | Nova 调度、Neutron 转发都吃 CPU |
| 内存 | 8 GB | 16 GB | 内存不足是最常见的失败原因 |
| 磁盘 | 40 GB | 60 GB 以上 | 镜像、实例、日志都占空间 |
| 网卡 | 1 张 | 2 张更佳 | 单网卡也能跑,但网络配置受限 |
为什么内存这么关键?因为 OpenStack 核心组件加起来,光是 Python 进程就有几十个,每个 MySQL 连接、每个 RabbitMQ 队列、每个 API 服务的 WSGI worker 都要占内存。8 GB 是勉强能起来的水平,一旦你创建实例,内存马上吃紧。16 GB 能让你在跑起来之后还有余量做实验。
磁盘方面,除了系统本身,DevStack 会把源码放在/opt/stack,Glance 镜像默认存在/opt/stack/data/glance,Nova 实例存在/opt/stack/data/nova。一个 Cirros 镜像才十几 MB,但你要是传个 Ubuntu 云镜像,动辄几百 MB 到 1 GB,再加上实例的磁盘文件,40 GB 很快就满了。
2.2 系统安装时的分区与网络建议
装 Ubuntu 18.04 的时候,我建议手动分区,给/opt单独留一块大空间,因为 DevStack 的东西基本都堆在/opt/stack。如果你用默认的 LVM 自动分区,根分区可能只有几十 GB,后面容易爆。
网络这块,单网卡也能跑,但你要接受一个现实:DevStack 默认会创建一个 Linux bridge,把物理网卡挂上去,然后给你的机器配一个浮动 IP 段。如果你只有一张网卡,而且是通过 SSH 远程连上去操作的,那在 DevStack 配置网络的过程中,你的 SSH 连接很可能会断掉。所以我的做法是:要么直接在虚拟机控制台里操作,要么配两张网卡,一张管理、一张给 OpenStack 用。
提示:如果你是在云主机或者虚拟化环境里装,务必确认你的环境支持嵌套虚拟化,否则 Nova 起不来 KVM 加速,实例只能用 QEMU 软件模拟,慢到怀疑人生。
2.3 系统更新与基础依赖
装完系统第一件事,更新软件源并升级:
sudo apt update sudo apt upgrade -y然后装一批基础工具,这些在后面排查问题时会用到:
sudo apt install -y git curl wget vim net-tools bridge-utils \ python3-pip python3-dev build-essential这里解释一下为什么装这些。git是拉源码用的,DevStack 本身就是从 git 仓库克隆下来的;bridge-utils用来查看和管理网桥,Neutron 会创建大量网桥,没这个工具你连brctl show都跑不了;python3-dev和build-essential是因为有些 Python 包需要编译 C 扩展,缺了编译工具会直接报错。
2.4 创建专用用户与免密 sudo
DevStack 强烈建议用一个非 root 的专用用户来跑,官方推荐叫stack。原因很简单:DevStack 会往这个用户的家目录写大量东西,而且很多操作需要 sudo 权限,用 root 跑反而容易出权限混乱的问题。
sudo useradd -s /bin/bash -d /opt/stack -m stack sudo passwd stack echo "stack ALL=(ALL) NOPASSWD: ALL" | sudo tee /etc/sudoers.d/stack sudo chmod 0440 /etc/sudoers.d/stackNOPASSWD这一行很关键,因为 DevStack 脚本里会频繁调用 sudo,如果每次都要求输密码,脚本会卡住。配好之后切换到 stack 用户:
sudo su - stack3. DevStack 的获取与核心配置解析
3.1 拉取 DevStack 源码
用 stack 用户操作,先克隆 DevStack 仓库:
git clone https://opendev.org/openstack/devstack cd devstack这里有个细节:默认克隆的是 master 分支,也就是最新开发版。如果你想用某个稳定版本,可以git checkout stable/xxx,但既然标题说的是"最新版本",我们就留在 master。克隆下来之后,你可以git log -1看一下当前是哪个 commit,记下来,方便以后复现。
3.2 local.conf 的编写逻辑
DevStack 的所有配置都集中在一个叫local.conf的文件里,放在 devstack 目录下。这个文件不写的话,DevStack 会用一堆默认值,但默认值往往不适合单节点实验环境,所以我们必须自己写一份。
先看一份我实测可用的配置:
[[local|localrc]] ADMIN_PASSWORD=secret DATABASE_PASSWORD=$ADMIN_PASSWORD RABBIT_PASSWORD=$ADMIN_PASSWORD SERVICE_PASSWORD=$ADMIN_PASSWORD HOST_IP=192.168.1.100 # 关闭不需要的服务,节省资源 disable_service tempest disable_service cinder disable_service swift # 启用核心服务 enable_service n-api,n-cpu,n-cond,n-sch,n-novnc,n-crt enable_service q-svc,q-agt,q-dhcp,q-l3,q-meta enable_service horizon # 日志 LOGFILE=$DEST/logs/stack.sh.log LOGDAYS=2逐条解释一下。最上面四个密码,DevStack 要求至少设置ADMIN_PASSWORD,其他几个如果引用它,就统一了,省得记一堆。HOST_IP必须写你本机实际的 IP,不能写 127.0.0.1,因为 OpenStack 各服务之间要通过这个 IP 通信,写回环地址会导致服务互相连不上。
disable_service这几行是资源优化的关键。Tempest 是测试套件,跑起来很吃资源,实验阶段可以先关掉;Cinder 是块存储,Swift 是对象存储,如果你不做存储相关实验,关掉能省下不少内存和端口。核心的 Nova、Neutron、Keystone、Glance、Horizon 保留。
enable_service里那些缩写对应的是各个服务的具体进程,比如n-api是 Nova API,q-svc是 Neutron Server,q-l3是三层代理。这些名字在 DevStack 的lib/目录下有定义,写错了会直接报"unknown service"。
3.3 网络配置的坑与选择
单节点网络是最容易出问题的地方。DevStack 默认会尝试用你的物理网卡做网桥,如果你的机器是远程 SSH 连着的,这一步会断网。有两种应对方式:
第一种是配一张不用的网卡专门给 OpenStack,在local.conf里指定:
PUBLIC_INTERFACE=eth1第二种是用NEUTRON_CREATE_INITIAL_NETWORKS=False先不让它自动建网络,等装完了手动配。我一般用第一种,前提是机器上确实有第二张网卡。
还有一个参数FLOATING_RANGE,默认是172.24.4.0/24,这是给实例分配浮动 IP 用的网段。如果你本机网络跟这个段冲突,要改掉,否则路由会乱。
4. 执行安装与过程监控
4.1 启动 stack.sh 与预期耗时
配置写好之后,直接跑:
./stack.sh这个过程第一次跑通常要 20 到 40 分钟,取决于网络速度和机器性能。它会依次做这些事:装系统依赖包、从 git 拉各个 OpenStack 组件的源码、装 Python 依赖、初始化数据库、启动各个服务、创建默认的网络和镜像。
我建议你开两个终端,一个跑stack.sh,另一个用tail -f /opt/stack/logs/stack.sh.log实时看日志。因为stack.sh的输出有时候会刷得很快,关键错误一闪而过,看日志文件更靠谱。
4.2 安装过程中的关键节点
整个安装过程有几个关键节点,你可以对照日志判断进度:
- 依赖安装阶段:会看到大量
apt install的输出,这一步慢是正常的,尤其是国内网络环境。 - 源码克隆阶段:会逐个克隆 Nova、Neutron、Keystone 等仓库,每个仓库几百 MB。
- 数据库初始化:会看到
keystone-manage db_sync之类的命令。 - 服务启动:会看到
systemctl start或者直接screen会话的创建。
DevStack 默认用screen来管理各个服务的进程,装完之后你可以screen -ls看到一堆会话,每个会话对应一个服务。想进某个服务的控制台看输出,就screen -r 会话名,退出用Ctrl+A然后按D。
4.3 安装成功的标志
当你在终端看到类似这样的输出,基本就成功了:
This is your host IP address: 192.168.1.100 This is your host IPv6 address: ::1 Horizon is now available at http://192.168.1.100/dashboard Keystone is serving at http://192.168.1.100/identity/ The default users are: admin and demo The password: secret这时候打开浏览器,访问那个 Horizon 地址,用 admin / secret 登录,能看到 OpenStack 的仪表盘,就说明整套东西跑起来了。
5. 安装后的验证与基本操作
5.1 用命令行验证各服务状态
光看界面还不够,我习惯用命令行确认一遍。先加载环境变量:
source /opt/stack/devstack/openrc admin admin然后逐个检查:
openstack service list openstack endpoint list openstack network agent list openstack compute service listservice list能看到所有注册的服务,endpoint list能看到各个服务的访问端点,network agent list里所有 agent 应该是Alive状态,compute service list里 nova-compute 应该是enabled且up。
5.2 创建第一个实例的完整流程
验证服务没问题后,走一遍创建实例的流程,这是检验整套系统是否真正可用的最好方式。
先下载一个测试镜像:
wget http://download.cirros-cloud.net/0.5.2/cirros-0.5.2-x86_64-disk.img openstack image create "cirros" \ --file cirros-0.5.2-x86_64-disk.img \ --disk-format qcow2 --container-format bare --public然后创建网络、子网、路由:
openstack network create demo-net openstack subnet create --network demo-net \ --subnet-range 10.0.0.0/24 demo-subnet openstack router create demo-router openstack router set demo-router --external-gateway public openstack router add subnet demo-router demo-subnet最后创建实例:
openstack flavor create --ram 512 --disk 1 --vcpus 1 m1.tiny openstack keypair create demo-key > demo-key.pem chmod 600 demo-key.pem openstack server create --flavor m1.tiny --image cirros \ --nic net-id=$(openstack network show demo-net -f value -c id) \ --key-name demo-key demo-instance创建完用openstack server list看状态,从BUILD变成ACTIVE就成功了。想 SSH 进去的话,先分配浮动 IP:
openstack floating ip create public openstack server add floating ip demo-instance <浮动IP>然后用ssh -i demo-key.pem cirros@<浮动IP>登录,密码是gocubsgo。
6. 常见问题与排查技巧实录
6.1 安装失败的典型原因速查
| 现象 | 可能原因 | 排查方向 |
|---|---|---|
| stack.sh 中途退出 | 依赖装不上 | 看日志里 apt 报错,检查网络源 |
| 服务起不来 | 端口被占 | netstat -tlnp看端口冲突 |
| 数据库连不上 | MySQL 没起来 | systemctl status mysql |
| 实例一直 BUILD | 计算节点异常 | 看 nova-compute 日志 |
| 网络不通 | 网桥配置错 | brctl show看网桥 |
6.2 几个我踩过的坑
第一个坑是HOST_IP写错。我有一次图省事写了127.0.0.1,结果 Keystone 能起来,但 Nova 连不上它,因为 Nova 拿到的 endpoint 是回环地址,跨进程通信就废了。这个错误很隐蔽,因为服务本身不报错,只是互相调不通。
第二个坑是内存不够导致 OOM。8 GB 的机器跑全套,创建实例的时候经常触发 OOM Killer,把 MySQL 或者 RabbitMQ 干掉。解决办法要么加内存,要么在local.conf里关掉更多服务,比如把 Horizon 也关了,纯命令行操作。
第三个坑是重装。DevStack 装失败之后,直接重跑stack.sh往往还是失败,因为残留的配置和数据库会干扰。正确做法是先./unstack.sh清理,再./clean.sh彻底清,然后重新跑。clean.sh会把/opt/stack下的数据都删掉,慎用但有效。
6.3 日志排查的通用思路
OpenStack 的日志分散在各个服务的目录下,比如/var/log/nova/、/var/log/neutron/、/var/log/keystone/。排查问题的通用思路是:先看 API 服务的日志,找到报错的请求 ID,然后拿这个 ID 去其他服务的日志里搜,就能串起整个调用链。
比如创建实例失败,先在/var/log/nova/nova-api.log里找到报错,记下 request-id,然后去nova-conductor.log、nova-scheduler.log、nova-compute.log里搜同一个 ID,就能看到请求在哪一步断掉的。
7. 资源优化与后续扩展方向
7.1 让单节点跑得更流畅的调整
跑起来之后,如果你觉得卡,可以做一些优化。首先是关掉不用的服务,前面已经关了 Cinder 和 Swift,如果还卡,可以把 Horizon 也关了,用命令行操作。其次是调整 MySQL 的配置,默认的innodb_buffer_pool_size很小,可以适当调大。还有就是限制 Nova 的并发,在nova.conf里把workers调小。
另外,DevStack 默认会创建一堆默认网络和路由,如果你不做网络实验,可以在local.conf里加NEUTRON_CREATE_INITIAL_NETWORKS=False,省掉这部分开销。
7.2 从单节点到多节点的思路
单节点跑通之后,如果你想扩展成多节点,核心思路是把计算节点拆出去。控制节点上跑 Keystone、Glance、Nova API、Neutron Server,计算节点上只跑 nova-compute 和 neutron-agent。两边通过local.conf里的HOST_IP和SERVICE_HOST参数关联。这个扩展过程本身就是一个很好的学习路径,能让你真正理解 OpenStack 的分布式架构。
7.3 版本升级与回滚的注意事项
DevStack 的 master 分支更新很频繁,如果你git pull之后重跑stack.sh,可能会因为代码变动导致失败。我的建议是,跑通一个版本之后,把 devstack 目录和/opt/stack下各个组件的 commit 都记录下来,需要升级的时候再整体更新。如果升级失败想回滚,就git checkout回原来的 commit,然后./unstack.sh && ./stack.sh重来。
我个人在实际操作中的体会是,DevStack 最大的价值不在于"装好了能用",而在于"装的过程逼着你去理解每个组件"。每次失败、每次看日志、每次改配置,都是在加深对 OpenStack 的理解。所以别怕它报错,报错才是学习的机会。最后再分享一个小技巧:把每次成功的local.conf和当时的 commit 记录存一份,下次重装直接抄,能省下大量试错时间。