1. 项目缘起:为什么选择Kolla-ansible部署单节点OpenStack?

如果你正在寻找一种能让你在单台物理机或虚拟机上,快速搭建一个功能完整、可用于学习、开发测试甚至小型生产环境的OpenStack云平台的方法,那么Kolla-ansible几乎是当前最主流、最“省心”的答案。我之所以用“省心”这个词,是因为在OpenStack漫长的部署史中,手动编译依赖、逐个服务配置、处理版本兼容性这些事,足以劝退大部分初学者和运维人员。Kolla项目通过将每个OpenStack服务及其依赖打包成独立的Docker容器,从根本上解决了环境一致性的噩梦;而Kolla-ansible则是在此基础上,用Ansible这个自动化利器,把上千个容器编排、网络配置、服务启动的复杂流程,变成了一条条可重复执行的剧本。

那么,为什么是“all-in-one”单节点部署?这绝不是为了追求极致的性能或高可用,它的核心价值在于 极致的便捷性和低成本 。你不需要准备三台甚至更多的服务器来划分控制、计算和网络节点,一台配置尚可的机器(比如32G内存、8核CPU、200G磁盘的虚拟机或老旧服务器)就能跑起来。这对于个人学习者来说,意味着零硬件门槛;对于开发者而言,它是一个完美的沙盒,可以随意测试新功能、调试代码而不用担心影响线上环境;对于小团队,它也能作为一个内部开发测试云,承载CI/CD流水线中的临时资源需求。

网络上关于“ollama本地部署”、“dify私有化部署”、“vllm部署大模型”的热度,其实反映了一个共同趋势:大家越来越倾向于在本地或可控环境中部署复杂的开源软件栈。OpenStack作为IaaS(基础设施即服务)的基石,其部署复杂度远高于单个应用。Kolla-ansible的“all-in-one”模式,正是将这种复杂性封装起来,让你能以接近部署一个“大模型”或“开发平台”的体验,来获得一整套云基础设施的控制权。接下来,我会带你走通从零开始,在一台干净的CentOS 7/8或Ubuntu 20.04/22.04系统上,完成Kolla-ansible部署OpenStack Yoga版本(一个长期稳定版本)的全过程,并分享那些官方文档可能不会细说的“坑”和技巧。

2. 部署前深度准备:不止是安装包

很多人部署失败,第一步就错了——他们以为准备环境就是照着文档敲几行 yum install 或 apt-get 命令。实际上,准备工作决定了整个部署过程的平滑度。我们需要从系统、网络、存储三个维度进行彻底检查。

2.1 系统环境与关键参数调优

首先,确认你的系统。这里我以CentOS 7.9为例,但原理相通。一个全新的最小化安装系统是最佳起点,避免残留服务造成端口冲突。

内核参数调整 :这是为了满足Docker和OpenStack Neutron(网络服务)的需求。编辑 /etc/sysctl.conf ,在文件末尾添加或修改以下参数:

net.ipv4.ip_forward=1
net.bridge.bridge-nf-call-iptables=1
net.bridge.bridge-nf-call-ip6tables=1

执行 sysctl -p 使配置生效。第一行开启IPv4转发,这是Linux作为路由器或网关(Neutron的虚拟路由器需要)的基础。后两行是针对Linux网桥的iptables过滤规则,让经过网桥的流量也能被iptables规则处理,这是Docker和OpenStack网络正常工作的关键。

关闭并禁用防火墙与SELinux :在实验环境,为了排除干扰,我们通常选择关闭。生产环境则需要精细配置策略。

systemctl stop firewalld
systemctl disable firewalld
setenforce 0
sed -i 's/SELINUX=enforcing/SELINUX=disabled/g' /etc/selinux/config

注意 : setenforce 0 是临时关闭,修改配置文件是永久生效。务必两者都做,否则重启后SELinux可能会再次阻断容器操作。

安装基础依赖与EPEL源 :

yum install -y epel-release
yum install -y python3-devel libffi-devel gcc openssl-devel python3-pip git

这里安装 python3-devel 和 libffi-devel 是为了后续编译安装某些Python包(如 cryptography )时不报错。

2.2 网络规划:单节点的“虚拟”多网卡

单节点部署,所有服务都挤在一台机器上,但OpenStack的架构设计默认需要多个网络平面(如管理网、业务网、外部网)。我们的策略是: 通过VLAN或Linux Bridge,在单张物理网卡上虚拟出多个逻辑接口 。

假设你的服务器只有一个物理网卡 eth0 ,IP是 192.168.1.100 。我们计划:

  • 管理网络 :用于OpenStack各服务内部通信,如MariaDB、RabbitMQ。我们使用一个虚拟网桥 br-mgmt ,并给它分配一个与管理网段不同的IP,例如 10.0.0.100 。实际上,在all-in-one中,管理流量很多走的是容器间的内部网络,这个桥主要用于宿主机与容器管理网络的互通。
  • 业务网络(租户网络) :虚拟机之间的通信网络。我们创建网桥 br-vlan 。
  • 外部网络 :虚拟机访问外网(互联网)的通道。这是最关键的一步。我们创建网桥 br-ex ,并将物理网卡 eth0 作为它的一个端口。这意味着 br-ex 将接管 eth0 的IP地址和路由。

具体操作 :

  1. 安装网桥工具: yum install -y bridge-utils
  2. 备份原网络配置,然后修改 /etc/sysconfig/network-scripts/ifcfg-eth0 ,将其从普通接口改为 br-ex 的端口:
    TYPE=Ethernet
    BOOTPROTO=none
    DEVICE=eth0
    ONBOOT=yes
    BRIDGE=br-ex # 关键:指定该接口属于br-ex网桥
    
  3. 创建 /etc/sysconfig/network-scripts/ifcfg-br-ex :
    TYPE=Bridge
    BOOTPROTO=static
    DEVICE=br-ex
    ONBOOT=yes
    IPADDR=192.168.1.100 # 使用原eth0的IP
    NETMASK=255.255.255.0
    GATEWAY=192.168.1.1
    DNS1=8.8.8.8
    
  4. 重启网络服务: systemctl restart network 。现在,你的默认网关和IP地址已经绑定在 br-ex 上了, eth0 变成了一个单纯的物理端口。

为什么这么做?因为OpenStack Neutron的“外部网络”需要绑定到一个存在于宿主机的、有IP地址的网桥或接口上,这样才能为虚拟机做SNAT(源地址转换),让虚拟机通过宿主机的IP访问外网。 br-ex 就是这个桥梁。

2.3 存储准备:Ceph还是LVM?单节点的务实之选

OpenStack的块存储服务(Cinder)需要后端存储。在生产多节点环境中,Ceph是明星选择。但在单节点,为了简化,我们通常使用LVM(Logical Volume Manager)作为Cinder的后端,这已经足够支持创建、挂载云硬盘等基本操作。

准备工作 :

  1. 确保有一块独立的磁盘(如 /dev/sdb )或足够大的磁盘分区未被使用。如果只有一块系统盘,可以创建一个大的文件作为回环设备模拟磁盘,但性能很差,仅用于测试。
  2. 安装LVM工具: yum install -y lvm2
  3. 假设使用 /dev/sdb :
    pvcreate /dev/sdb # 创建物理卷
    vgcreate cinder-volumes /dev/sdb # 创建卷组,名字必须是`cinder-volumes`,这是Kolla-ansible的默认配置
    
    创建完成后,可以用 vgs 命令查看卷组信息。

踩坑记录 :务必确保 /dev/sdb 上没有重要数据, pvcreate 操作会抹掉磁盘上的所有分区表。另外,如果使用虚拟机,确保磁盘是“厚置备”或已预先分配空间,避免动态扩展时空间不足。

3. Kolla-ansible核心组件安装与配置详解

环境准备好后,我们进入正题。Kolla-ansible的安装本质上是准备Python虚拟环境和配置两个关键的配置文件。

3.1 创建虚拟环境与安装Kolla-ansible

使用虚拟环境能将Kolla-ansible的依赖与系统Python环境隔离,避免版本冲突。

pip3 install -U pip # 升级pip
pip3 install virtualenv
virtualenv /opt/kolla-ansible-venv # 创建虚拟环境目录
source /opt/kolla-ansible-venv/bin/activate # 激活虚拟环境

激活后,命令行提示符前会出现 (kolla-ansible-venv) 字样。

安装Kolla-ansible :我们需要同时安装 kolla-ansible 和 ansible 。指定版本可以确保稳定性,这里使用较新的稳定版本。

pip install 'ansible>=4.0.0, <5.0.0'
pip install 'kolla-ansible==11.0.0' # 以Yoga版本为例

复制配置文件 :Kolla-ansible提供了全局配置和库存清单文件的样例。

mkdir -p /etc/kolla
cp -r /opt/kolla-ansible-venv/share/kolla-ansible/etc_examples/kolla/* /etc/kolla/
cp /opt/kolla-ansible-venv/share/kolla-ansible/ansible/inventory/* .

这里会复制两个重要的样本文件: /etc/kolla/globals.yml 和当前目录下的 all-in-one 库存文件。

3.2 灵魂文件:globals.yml 配置精讲

/etc/kolla/globals.yml 是部署的总开关,每一个参数都直接影响最终生成的OpenStack形态。下面我挑出最核心且容易出错的几个进行说明:

kolla_base_distro: "centos"
kolla_install_type: "binary"
openstack_release: "yoga"

这三行定义了基础:使用CentOS作为容器基础镜像,安装二进制包(而非源码),部署Yoga版本。

kolla_internal_vip_address: "10.0.0.100"
network_interface: "eth0"
neutron_external_interface: "br-ex"
  • kolla_internal_vip_address : 内部VIP地址。在单节点部署中,它就是一个固定的IP,用于一些高可用服务的访问端点。我们将其设置为之前规划的 br-mgmt 网桥所在的网段中的一个IP(例如 10.0.0.100 ),但 这个IP必须未被占用,且宿主机能路由到 。在单节点中,简单起见,你可以直接设置为宿主机 br-mgmt 的IP,或者同一个网段内一个不冲突的IP。
  • network_interface : 这是OpenStack管理网络绑定的物理接口。填写你的物理网卡名,如 eth0 。管理网络的流量会通过这个接口。
  • neutron_external_interface : 这是最关键的一项!填写我们之前创建的 外部网络网桥 br-ex 。Neutron会在这个网桥上创建虚拟机的虚拟网卡(tap设备),从而实现虚拟机与外部的通信。
enable_cinder: "yes"
enable_cinder_backend_lvm: "yes"

启用Cinder块存储服务,并使用LVM作为其后端。这和我们之前准备的 cinder-volumes 卷组对应。

nova_compute_virt_type: "qemu"

如果你的环境是纯虚拟化(VMware里再开虚拟机),或者没有硬件虚拟化支持( /proc/cpuinfo 里没有 vmx 或 svm 标志),这里必须设为 qemu ,即使用软件模拟的CPU。如果有Intel VT-x或AMD-V支持,可以设为 kvm 以获得近乎原生的性能。

3.3 库存文件:告诉Ansible目标在哪

库存文件 all-in-one 定义了Ansible操作的主机。对于单节点,它非常简单:

[control]
localhost ansible_connection=local

[network]
localhost ansible_connection=local

[compute]
localhost ansible_connection=local

[monitoring]
localhost ansible_connection=local

[storage]
localhost ansible_connection=local

[deployment]
localhost ansible_connection=local

所有组都指向 localhost ,并且 ansible_connection=local 表示在本地执行,不需要SSH。这完美契合了all-in-one的场景。

4. 部署执行与关键环节监控

配置完成后,部署过程几乎是自动化的,但你需要理解每个步骤在做什么,并在关键点进行监控。

4.1 预部署检查:抓住早期错误

运行预检查命令,它会验证你的环境是否满足所有要求(如Docker版本、内核参数、目录权限等)。

kolla-ansible -i ./all-in-one prechecks

这是最重要的排错阶段! 如果这里报错,必须解决后才能继续。常见错误:

  • SELinux未禁用 :检查 /etc/selinux/config 和 getenforce 命令输出。
  • 内核参数未生效 :确认 sysctl -p 已执行,并用 sysctl net.ipv4.ip_forward 查看值是否为1。
  • 网桥配置错误 :用 brctl show 检查 br-ex 网桥是否存在,且 eth0 是否在其 interfaces 列表中。
  • LVM卷组不存在 :用 vgs 确认 cinder-volumes 卷组已创建。

4.2 拉取容器镜像:漫长的等待与加速

执行拉取镜像命令,这会从Docker Hub等仓库下载所有需要的容器镜像,大小约10GB。

kolla-ansible -i ./all-in-one pull

这个过程耗时很长,且容易因网络问题失败。 强烈建议配置国内镜像加速器 。编辑 /etc/docker/daemon.json (不存在则创建):

{
  "registry-mirrors": [
    "https://docker.mirrors.ustc.edu.cn",
    "https://hub-mirror.c.163.com"
  ]
}

然后重启Docker服务: systemctl restart docker 。之后再执行 pull 命令。

4.3 核心部署:一键生成云平台

这是最核心的一步,Ansible剧本会完成所有容器的创建、配置和启动。

kolla-ansible -i ./all-in-one deploy

这个过程会持续20分钟到1小时不等,取决于机器性能。 请务必在稳定的网络环境下执行,并保持终端连接 。你可以打开另一个终端,用 docker ps 观察容器被陆续创建和启动的状态。

部署过程中的典型问题排查 :

  • 容器启动失败 :使用 docker logs <container_id> 查看具体容器的日志。常见原因是配置文件错误(如 globals.yml 中IP地址写错)、端口冲突(如某个服务端口被系统占用)、或者存储路径权限问题。
  • 数据库初始化失败 :MariaDB容器可能因为 /etc/kolla 目录下的配置文件权限问题而无法启动。确保 /etc/kolla 目录及其子目录对容器用户是可读的。
  • 长时间卡在某个任务 :可能是Ansible在等待某个服务(如RabbitMQ)就绪超时。可以尝试中断命令(Ctrl+C),解决可能的问题(如查看对应容器日志),然后 重新运行 deploy 命令 。Kolla-ansible具有幂等性,重新运行通常会跳过已成功的任务,从失败点继续。

4.4 部署后配置:生成管理员密码与安装客户端

部署完成后,OpenStack服务都在容器里跑起来了,但我们需要拿到访问凭证。

kolla-ansible post-deploy

这个命令会生成管理员账户的密码文件,默认位于 /etc/kolla/admin-openrc.sh 。这个文件里包含了用于认证的环境变量。

安装OpenStack命令行客户端 :

pip install python-openstackclient python-glanceclient python-neutronclient python-cinderclient

你也可以在虚拟环境外系统级安装,但为了环境纯净,建议在虚拟环境内安装。

载入环境变量并验证 :

source /etc/kolla/admin-openrc.sh
openstack token issue

如果成功,你会看到一个长长的Token信息。这说明你的OpenStack核心服务(Keystone)已经正常工作,并且命令行客户端可以成功认证。

5. 初始化OpenStack基础资源与创建第一台云主机

服务跑起来不等于云平台就能用了。我们还需要创建一些基础资源:外部网络、镜像、规格(Flavor)等。

5.1 创建外部网络与子网

这是让虚拟机连接外网的关键一步。我们通过命令行操作:

# 创建外部网络(provider network),指定网络类型为flat,并绑定到我们配置的物理网络(provider:physical_network)
openstack network create --external --provider-network-type flat --provider-physical-network physnet1 public1

# 为外部网络创建子网。这里的网关和DNS需要根据你实际的网络环境填写。
openstack subnet create --network public1 --subnet-range 192.168.1.0/24 --gateway 192.168.1.1 --dns-nameserver 8.8.8.8 --allocation-pool start=192.168.1.200,end=192.168.1.250 subnet-public1

参数解释 :

  • --provider-physical-network physnet1 :这个 physnet1 是一个标签,它必须与Neutron的配置对应。在Kolla-ansible默认的 globals.yml 中, neutron_plugin_agent 设置为 openvswitch ,并且会默认映射 physnet1 到我们配置的 neutron_external_interface (即 br-ex )。所以这里使用 physnet1 。
  • --subnet-range :这个网段必须与你宿主机 br-ex 接口的IP( 192.168.1.100 )在同一个局域网内。
  • --allocation-pool :定义了从这个子网中分配给虚拟机的IP地址池范围。

5.2 下载并上传云镜像

虚拟机需要操作系统镜像。我们以CirrOS(一个极小的Linux测试镜像)为例。

wget http://download.cirros-cloud.net/0.5.2/cirros-0.5.2-x86_64-disk.img
openstack image create --file cirros-0.5.2-x86_64-disk.img --disk-format qcow2 --container-format bare --public cirros

--public 参数使得所有项目(租户)都能看到和使用这个镜像。

5.3 创建安全组、密钥对和虚拟机规格

  1. 创建安全组规则 :默认的安全组拒绝所有入站流量。我们需要添加规则允许SSH和ICMP(ping)。
    openstack security group rule create --protocol tcp --dst-port 22:22 --ingress default
    openstack security group rule create --protocol icmp --ingress default
    
  2. 创建密钥对 :用于SSH登录虚拟机。
    openstack keypair create --public-key ~/.ssh/id_rsa.pub mykey
    
    如果你没有SSH密钥,先用 ssh-keygen 生成。
  3. 创建虚拟机规格(Flavor) :定义虚拟机的CPU、内存、磁盘大小。
    openstack flavor create --vcpus 1 --ram 512 --disk 2 m1.tiny
    

5.4 启动第一台虚拟机并验证网络

现在,万事俱备,可以创建虚拟机了。

openstack server create --flavor m1.tiny --image cirros --nic net-id=$(openstack network show public1 -f value -c id) --key-name mykey vm1
  • --nic net-id :指定虚拟机连接到我们刚创建的 public1 外部网络。这里用了命令替换 $() 来获取网络的ID。

使用 openstack server list 查看虚拟机状态,直到变为 ACTIVE 。然后获取它的IP地址:

openstack server show vm1 -f value -c addresses

你应该能看到一个类似于 public1=192.168.1.200 的输出。

最终验证 :

  1. 从宿主机ping虚拟机的IP: ping 192.168.1.200 。应该能通。
  2. 如果宿主机所在网络有其他机器,尝试从其他机器ping这个虚拟机的IP。 这很可能不通! 为什么?因为虚拟机的流量需要经过宿主机的 br-ex 网桥和物理网卡 eth0 出去,默认情况下,外部网络交换机可能不允许这个“凭空出现”的MAC地址通过(这是一个安全特性,称为“端口安全”或“MAC地址过滤”)。你需要在你物理交换机的 eth0 所连接的端口上,启用“端口快速”(PortFast, Cisco术语)或禁用“STP”(生成树协议),并可能需要在OpenStack Neutron中配置允许MAC地址欺骗。对于家庭路由器或简单交换机,可能没有这个问题。这是单节点部署网络中最常见的一个“坑”。
  3. 如果ping通,可以尝试SSH登录: ssh cirros@192.168.1.200 。密码通常是 cubswin:) 。登录成功,恭喜你,一个全功能的OpenStack单节点云平台已经部署完成!

6. 日常运维、问题排查与进阶思考

部署成功只是开始,稳定运行和问题排查才是日常。

6.1 基础运维命令

  • 查看所有容器状态 : docker ps 或 kolla-ansible -i ./all-in-one check
  • 重启所有OpenStack服务 : kolla-ansible -i ./all-in-one reconfigure (这比重启单个容器更安全,它会根据配置文件重新生成容器)
  • 停止整个OpenStack环境 : kolla-ansible -i ./all-in-one stop
  • 启动整个OpenStack环境 : kolla-ansible -i ./all-in-one start
  • 查看某个服务的日志 : docker logs <container_name> ,例如 docker logs nova_compute
  • 进入容器内部调试 : docker exec -it <container_name> /bin/bash

6.2 常见问题与排查思路

  1. 虚拟机无法获取IP(处于 BUILD 或 ERROR 状态) :

    • 检查Neutron的DHCP Agent容器是否正常运行: docker logs neutron_dhcp_agent 。
    • 检查 br-ex 网桥上是否有虚拟机的tap设备( ovs-vsctl show )。
    • 检查Neutron的命名空间: ip netns list ,应该能看到 qdhcp- 开头的命名空间。进入命名空间查看: ip netns exec qdhcp-<id> ip addr ,看是否有IP地址。
  2. 虚拟机无法访问外网 :

    • 首先确认宿主机本身能访问外网。
    • 在宿主机上,检查 iptables -t nat -L -n -v ,查看 neutron-l3-agent 容器是否添加了正确的SNAT规则(将虚拟机子网 192.168.1.0/24 的源地址转换为宿主机 br-ex 的IP)。
    • 检查虚拟机的默认网关是否指向了Neutron的虚拟路由器IP(在 qrouter 命名空间内查看)。
  3. Cinder卷创建失败 :

    • 检查 cinder-volume 容器日志: docker logs cinder_volume 。
    • 确认LVM卷组 cinder-volumes 存在且有空间( vgs )。
    • 检查 /etc/kolla/cinder-volume/cinder.conf 中LVM后端配置是否正确。
  4. Web界面(Horizon)无法访问 :

    • 默认Horizon监听在宿主机IP的80端口。确认 horizon 容器正在运行。
    • 检查防火墙是否关闭或放行了80端口。
    • 查看Horizon日志: docker logs horizon 。

6.3 从单节点到多节点的思考

虽然本文聚焦单节点,但理解其部署为未来扩展打下了基础。从单节点扩展到多节点,核心变化在于:

  1. 库存文件 :需要明确指定哪些主机是控制节点、网络节点、计算节点、存储节点。
  2. 网络架构 :需要规划并实际部署多个物理网卡,分别用于管理网络、业务网络、存储网络(如Ceph集群通信)、外部网络等。
  3. 共享存储 :如果使用Cinder LVM后端,需要配置共享存储(如NFS、iSCSI)使得所有计算节点都能访问卷组;更常见的做法是部署Ceph分布式存储集群。
  4. 高可用 :控制节点需要部署多个,并通过HAProxy和Keepalived实现负载均衡和高可用。

Kolla-ansible的多节点部署剧本已经内置了这些复杂拓扑的编排能力,你只需要在 globals.yml 和库存文件中进行正确的配置即可。本次单节点部署的实践,让你熟悉了Kolla-ansible的核心工作流程和配置方法,这正是迈向更复杂生产部署的坚实第一步。

更多推荐