ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

离线部署OpenStack高可用集群:基于Kolla-Ansible的分层实践

2026/9/26 4:46:48 拓冰建站 浏览量
离线部署OpenStack高可用集群:基于Kolla-Ansible的分层实践 搞离线部署 OpenStack 的人大概都有同感最难的不是 OpenStack 本身而是把整套依赖在一个没有互联网的环境里闭环转起来。我最近刚完成一套基于 CentOS Stream 9 的 OpenStack 2024.1 Caracal 高可用集群用的是离线分层部署的思路从操作系统源、容器镜像源、到 Kolla-Ansible 编排一层一层向下铺。这套方案不一定是最快的但一定是最稳的尤其适合机房网络隔离、不能访问外网、又必须上生产集群的场景。这篇文章把整个过程按层拆开讲包含我实际踩过的坑和最终保留的运维动作给准备在同类型环境里做 OpenStack 的人一个可以照着走的参考。1. 为什么离线部署要划分层次而不是直接一键装1.1 离线环境的真实难点我见过不少人拿到 OpenStack 部署任务后第一反应是找一台能联网的机器装个 kolla-ansible然后把kolla-ansible deploy一行命令写完就算完事。这个思路在能上网的环境里没问题但在离线内网里会碰上一连串连锁反应系统基础包装不全、容器镜像拉不到、pip 包没地方下载甚至连时间同步都做不了最终常常卡在一些莫名其妙的基础环境错误上。真正的离线部署难点不只是“没有网络”这一个事实而是整个部署过程被切成了多个独立闭环操作系统层需要本地 Yum 源否则节点初始化都做不完容器运行时层需要本地 Docker 源否则 bootstrap-servers 根本装不上 dockerOpenStack 容器镜像需要本地 Registry否则所有服务镜像拉取失败Kolla-Ansible 和 Ansible 的 Python 依赖需要离线包否则控制节点连编排工具都起不来。这些问题互相纠缠如果你一次性全部铺开处理任何一个环节出错排查范围都会变得非常大。所以我在这次部署里采用了分层推进的方式每一层独立验证通过之后再进下一层。这样出了问题问题基本能定界在某一层里不会出现“明明镜像没问题却在找 Yum 源”这种离谱的排查方向。1.2 我理解的“分层”其实是三层含义“离线分层部署”这个说法我在这次项目里把它拆成了三个层次第一层是软件栈分层。物理机装完 CentOS Stream 9 后往上依次是内核和驱动、容器运行时、Kolla-Ansible 编排层、再到 OpenStack 各服务容器每一层都有明确的依赖关系不能跳着装。第二层是控制面与数据面分层。控制节点承担 API、调度、数据库、消息队列计算节点只承担虚拟化计算和网络数据面。高可用集群如果控制面和数据面混在一起后续维护会非常痛苦节点发生抖动时影响面也会被放大。第三层才是部署动作分层。也就是先把离线基础设施全部准备到位再启动 OpenStack 服务的编排最后按服务依赖关系逐个补齐。这一层更多是项目管理上的“阶段划分”对离线项目来说尤其重要因为离线项目的返工成本远高于在线项目一旦中间发现底层源有问题前面所有部署动作都要推倒重来。把这三层含义理清楚后面每一步怎么做就比较自然了。1.3 为什么选择 OpenStack 2024.1 CaracalOpenStack 2024.1 的版本代号是 Caracal属于 2024 年上半年发布的版本。对这个版本我的整体评价是功能上比之前稳定配置上比之前严苛。Caracal 比较大的变化是安全策略收紧服务间默认启用 secure RBAC对权限模型要求更规范。这对生产集群是好事但如果你手上的客户端、SDK 版本太老或者镜像里自带的配置不是新版本的默认值很容易在创建用户、分配角色这些基础操作里遇到奇怪的 403 权限报错。离线部署时这个问题会被放大因为镜像一旦锁定改权限模型的成本比在线环境高得多。另外Caracal 在 CentOS Stream 9 上走 Kolla-Ansible 部署时基础镜像一般选 Rocky Linux 9 系列两者同属 RHEL 系兼容风险最小。这一点在准备容器镜像时就要想清楚后面第 3 部分会细讲。2. 动手前的环境盘点硬件、网络平面和系统底线2.1 控制节点与计算节点的硬件基线离线部署的一个好处是通常在规划阶段就能拿到明确的硬件清单不用像云上环境那样弹性伸缩。但这也意味着硬件规划一旦失误后面很难临时扩容。我这次的高可用集群采用 3 控制节点 N 计算节点的结构控制节点规格如下CPU 不低于 32 线程内存 64 GB 起步系统盘 RAID1 做冗余数据盘独立挂载建议至少 500 GB 空间因为 Glance 镜像、Cinder 后端缓存、日志都要落盘。计算节点则根据业务虚拟机密度来定我这边单台计算节点是 48 线程、256 GB 内存系统盘 RAID1另有 2 TB 本地数据盘用于 Nova 临时存储。如果你的环境里计划用 Ceph 或独立存储阵列计算节点本地盘要求可以低一些但网卡要求不能低。控制节点的内存是个很容易被低估的点。很多人觉得 64 GB 已经很多了但 Kolla-Ansible 会把 MariaDB、RabbitMQ、HAProxy、Keystone、Nova 控制器、Neutron Server、Glance 等将近二十个容器压在三个控制节点上。每个容器看似只占几百 MB叠加起来加上页缓存内存消耗非常可观。如果还要部署 Octavia、Manila 等扩展组件控制节点内存建议直接提到 128 GB。2.2 网络平面怎么划OpenStack 高可用集群最少需要四个网络平面我在这次项目里是严格分开的网络平面网段示例VLAN主要用途管理网192.168.10.0/24100控制节点内部通信、API 访问、Kolla 容器间通信业务网192.168.20.0/24200虚拟机业务流量、Neutron 内部网络外部网192.168.30.0/24300浮动 IP、外部访问存储网192.168.40.0/24400Glance 镜像上传、Cinder/存储后端流量管理网是集群的命脉。VIP、MariaDB 同步、RabbitMQ 集群通信、Kolla-Ansible 的 SSH 管理都走这个网络建议至少万兆并且做好网卡 bond。存储网很多人会忽略但如果后面接独立存储或者 Ceph存储流量和数据面流量混在一起网络拥塞时首先要怀疑的就是这里。业务网和外部网要分开不然浮动 IP 和内部业务网段冲突时路由规则会调到怀疑人生。网卡数量方面每台控制节点至少 4 个物理网口两个做管理网 bond两个做业务/外部网计算节点建议 4 到 6 个口业务网最好也做 bond避免单点链路故障导致虚拟机网络中断。2.3 CentOS Stream 9 初始化容易忽略的几个点系统装完后初始化阶段有几个让我吃过亏的细节。第一个是 SELinux。Kolla-Ansible 官方文档写得比较保守但实际部署中 SELinux 开启状态下容器挂载卷和网络命名空间经常会触发权限拦截报错还很隐晦。我这边直接设置为 Permissive生产环境如果有合规要求至少也要保持 Permissive不要强行 Enforcing否则排查容器权限问题会耗掉大量时间。第二个是防火墙。Kolla 自己的 HAProxy 和 Keepalived 会管理大量端口如果节点上的 firewalld 规则没放行VIP 看起来是通的实际访问 API 就是超时。离线内网环境如果物理隔离足够安全我建议先禁用 firewalld靠交换机 ACL 做访问控制如果必须开启至少放行管理网段的全部端口和业务网的关键端口段。第三个是网卡固件和驱动。CentOS Stream 9 内核比较新但新不一定等于兼容性好。有些万兆网卡需要额外的 linux-firmware 包不然链路协商不稳定会出现“通一通断一断”的现象。这个在系统装好后必须用ethtool -i和ethtool eth1检查驱动版本和链路速率不要等到部署 OpenStack 之后再去排查物理层问题。第四个是虚拟化支持。计算节点上要确认/dev/kvm存在lsmod | grep kvm能看到 kvm_intel 或 kvm_amd 模块。如果连嵌套虚拟化都要支持还得确认 BIOS 里 VT-x/AMD-V 已经打开。3. 离线源层Yum 仓库、容器镜像仓库、时钟与 DNS3.1 用 dnf reposync 把 CentOS Stream 9 Yum 源搬进内网离线环境的第一步是搭好 Yum 源。CentOS Stream 9 的核心仓库主要是 BaseOS、AppStream 和 CRB另外部署 Docker 还需要 docker-ce-stable 源部分组件可能用到 EPEL。我的做法是找一台与内网同 CPU 架构、且能临时联网的机器把仓库全部拉下来再通过移动介质拷进内网放到一台源服务器上。拉取命令大致如下dnf reposync --repoidbaseos --repoidappstream --repoidcrb -p /data/repo --download-metadata dnf reposync --repoidepel -p /data/repo dnf reposync --repoiddocker-ce-stable -p /data/reporeposync 会同步 RPM 包和仓库元数据但为了保险我建议每个仓库目录都再跑一次 createrepo_c避免某些仓库的元数据文件不完整导致客户端 makecache 失败for d in baseos appstream crb epel docker-ce-stable; do createrepo_c /data/repo/$d done然后在内网源服务器上把这些目录通过 Nginx 暴露出来配置里打开 autoindex。客户端节点上写好本地 repo 文件[local-baseos] nameLocal BaseOS baseurlhttp://192.168.10.10/repo/baseos/ enabled1 gpgcheck0 [local-appstream] nameLocal AppStream baseurlhttp://192.168.10.10/repo/appstream/ enabled1 gpgcheck0每台节点执行dnf clean all dnf makecache验证仓库可用。关于 gpgcheck 有一个取舍。完全离线内网里RPM 包在联网同步阶段已经被原始仓库的签名校验过了进入内网后再开 gpgcheck 意义不大反而要额外导入一堆 GPG Key增加出错的概率。我这边是 gpgcheck0但前提是源服务器物理可控且拷入内网的过程有严格校验。3.2 容器镜像从打包到内网 RegistryYum 源只是第一步OpenStack 本身是以容器方式运行的所以容器镜像仓库才是核心。Kolla-Ansible 部署时每个控制节点上会拉起二十多个容器计算节点上也有十几个这些镜像缺一不可。镜像来源有两个选择一是直接用官方构建好的镜像从 Quay 等镜像仓库拉取二是在联网机器上用 kolla-build 自己构建。对离线场景我推荐前者镜像版本和 OpenStack 版本的对应关系已经被官方验证过省去很多兼容性排查。拉取完成后把镜像导成 tar 包docker pull quay.io/openstack.kolla/centos-source-keystone:2024.1 docker save quay.io/openstack.kolla/centos-source-keystone:2024.1 -o keystone.tar更频繁的做法是用 skopeo 直接复制skopeo 不需要本地 Docker 守护进程导出导入速度更快。不管用哪种方式最终目的都是把镜像包送进内网然后 push 到内网 Registry。我这边内网 Registry 用的是 Harbor部署在内网一台单独的机器上承担所有 OpenStack 镜像的存储和分发。Kolla-Ansible 里要指定docker_registry: 192.168.10.10指向内网 Harbordocker_registry_insecure: yes允许 HTTP 协议拉取openstack_release: 2024.1确保拉取的镜像 tag 是 2024.1 而不是默认的其他版本。这里要特别强调镜像 tag 和 Kolla-Ansible 版本必须严格对应。Caracal 对应的是 Kolla-Ansible 的 17.x 系列如果用旧版 Kolla-Ansible 去拉新版镜像部署时可能连容器启动参数都对不上。3.3 Kolla-Ansible 的 Python 离线依赖Yum 源和容器镜像都解决了还有一个容易被忽视的依赖来源Kolla-Ansible 本身的 Python 包。控制节点上要安装 ansible-core、kolla-ansible 以及相关依赖这些包通常来自 PyPI。离线环境下需要在联网机器上预先把 wheel 包下载好pip download kolla-ansible17.0.0 ansible-core -d /data/wheels进入内网后用本地目录安装pip install --no-index --find-links/data/wheels kolla-ansible17.0.0 ansible-core这里有个血泪教训有人在离线节点上直接用yum install ansible结果装的是系统自带的旧版 ansible-core和 Kolla-Ansible 要求的版本差了一大截部署时各种模块找不到。记住Kolla-Ansible 的 Python 依赖一定走 pip wheelhouse不要混用系统 RPM 包。3.4 时间同步和 DNS 在离线环境的特殊处理时间同步在离线环境里比在线环境更容易被忽略因为大家默认“集群里各节点开机时间差不多应该不会差太多”。但 OpenStack 对时间非常敏感Keystone 的 Fernet token、Nova 的迁移任务、Cinder 的卷状态同步都依赖节点间时钟一致性差几秒可能问题不大差几十秒就会出现各种随机故障。离线环境没有外网 NTP 可用我的做法是在管理网里指定一台控制节点做内部 Chrony 服务器配置文件大致如下# 服务端 server 192.168.10.10 iburst allow 192.168.10.0/24 local stratum 10其他节点指向这台服务器并使用chronyc sources -v验证同步状态。DNS 同样重要。所有节点的主机名解析必须保持一致建议内网 DNS 直接解析控制节点主机名和管理网 VIP。Kolla-Ansible 在 HAProxy 后端配置里会使用主机名如果各节点 hosts 文件不一致会出现后端服务器时通时不通的现象。4. Kolla-Ansible 分层推进的实操序列4.1 先初始化所有节点的 Docker 运行时离线源层就绪后才正式进入 Kolla-Ansible 的部署阶段。第一步不是 deploy而是先把所有节点的容器运行时装好。Kolla-Ansible 的bootstrap-servers命令会帮助完成 Docker 安装、配置 daemon、拉起基础容器等动作。在控制节点上先把 multinode 模板复制出来cp /usr/share/kolla-ansible/ansible/inventory/multinode ./multinode修改 inventory 文件把三个控制节点、计算节点分别填入。控制机到所有节点要配好 SSH 免密登录否则 Ansible 连不上。然后执行kolla-ansible -i multinode bootstrap-servers这一步依赖前面准备的 docker-ce Yum 源如果 docker 源没配好这里会直接报错。所以说分层部署的“层”不是理论概念每层都支撑着下一层的实际动作。4.2 globals.yml 和 passwords.yml 的准备bootstrap 完成后修改 Kolla 的全局配置。Kolla-Ansible 的配置模板一般在/etc/kolla/globals.yml和/etc/kolla/passwords.yml如果没有就自己创建。globals.yml 里我这次用到的关键项kolla_base_distro: rocky kolla_install_type: source openstack_release: 2024.1 kolla_internal_vip_address: 192.168.10.250 network_interface: eth1 neutron_external_interface: eth3 docker_registry: 192.168.10.10 docker_registry_insecure: yes enable_haproxy: yes enable_keepalived: yes enable_mariadb: yes enable_rabbitmq: yes其中kolla_base_distro用 rocky 是因为 Kolla 对 Rocky Linux 9 的支持最成熟而 CentOS Stream 9 与 Rocky 9 底层兼容很好这样基础镜像的选择面更广。kolla_install_type用 source 表示从源码构建的镜像功能更全排错时报错信息也更明确。kolla_internal_vip_address是高可用集群的虚拟 IP必须和管理网在同一网段。密码文件直接用工具生成kolla-genpwd生成之后不要再去手工改密码除非你确实知道自己在改什么。RabbitMQ、MariaDB 的密码如果改得不一致集群根本起不来。4.3 分段部署与整体收敛的组合策略首次部署我最推荐的方式是先跑一次完整预检再按需分段定位最后用一次完整 deploy 收敛。先预检kolla-ansible -i multinode prechecks预检会检查磁盘空间、内存、网络连通性、Docker 状态等基础条件。但预检通过不代表部署一定成功它只是把最明显的资源问题挡在门外。预检之后我通常会先只部署基础设施服务kolla-ansible -i multinode deploy --tags mariadb,rabbitmq,memcached这里用--tags做局部部署不是官方推荐的首次部署方式但非常适合离线环境下的问题定位。如果 MariaDB 容器起不来你只需要看数据库这一层的日志不需要被 Nova、Neutron 同时报错把脑子搞乱。基础服务验证正常后再跑完整部署kolla-ansible -i multinode deploy完整部署会把所有服务全部拉起并自动补上之前按 tag 部署时没有覆盖的部分。Kolla-Ansible 的 playbook 本身是幂等的重复执行不会有副作用。所以我把它当作“分层定位 整体收敛”的组合拳既有分层的排查效率又有整体部署的完整性。最后生成 admin openrckolla-ansible -i multinode post-deploy执行后控制节点上会生成/etc/kolla/admin-openrc.sh后面所有 OpenStack CLI 操作都要先 source 这个文件。4.4 计算节点扩容的独立操作集群跑起来之后扩容计算节点是常见需求。这一步相对来说更独立但也需要按层来。新计算节点先要完成系统初始化、加入 Yum 源、容器镜像预先 warm up然后把它加入 multinode inventory 的计算节点组。回到控制机执行kolla-ansible -i multinode bootstrap-servers --limit new-compute kolla-ansible -i multinode deploy --limit new-compute--limit可以限定 Ansible 只在目标节点上执行避免整个集群被重新触发一遍。部署完成后在控制节点上确认 Nova 计算服务已经注册openstack compute service list如果新节点状态是 down先检查该节点上的 nova-compute 容器是否正常再看管理网到控制节点的连通性。5. 高可用集群运行中的踩坑记录5.1 MariaDB Galera 集群分裂的一次恢复高可用集群里MariaDB 的 Galera 多主复制是事故高发区。我遇到过机柜断电后三个控制节点的 mariadb 容器没能同时恢复两个节点的wsrep_cluster_size显示只有自己一个节点彼此之间无法同步。排查时先看每个节点上的集群状态SHOW STATUS LIKE wsrep_cluster_size; SHOW STATUS LIKE wsrep_local_state_comment;关键思路是找到数据最完整、seqno最大的节点作为引导节点让它单独启动成一个新集群再逐个拉起其他节点加入。在 Kolla 环境里推荐优先使用官方自带的恢复工具kolla-ansible -i multinode mariadb_recovery如果恢复工具失败再手工介入。我个人的建议是控制节点重启要滚动进行不要三个节点同时重启。Galera 对同时重启非常敏感一旦所有节点丢失了彼此的状态恢复起来相当麻烦。5.2 RabbitMQ 在内存紧张时的节点分区还有一次 RabbitMQ 集群出现了网络分区提示控制节点上rabbitmqctl cluster_status显示节点状态异常。查下来发现根因不是网络而是某个控制节点内存不足导致 RabbitMQ 频繁触发内存高水位保护暂停接收消息其他节点认为它失联了。RabbitMQ 的内存高水位默认是总内存的 0.4在控制节点内存本就不宽裕的情况下这个阈值很容易触发。我调整了 RabbitMQ 配置里的vm_memory_high_watermark适当提高了可用内存比例同时清理了控制节点上不必要的容器和服务把内存压力降下来。这个案例反映了一个问题高可用不等于可以低配。三个控制节点看起来是冗余但如果每个节点资源都卡在临界值任何一个节点抖动都会波及整个集群。5.3 VIP “看起来在实际访问不了”HAProxy Keepalived 是高可用入口问题表象通常是VIP 明明显示在其中一台控制节点上但访问 Horizon 或 Keystone API 就是超时。我的排查顺序是ip addr show dev eth1先确认 VIP 漂移到了哪个节点docker exec -it haproxy haproxy -c -f /etc/haproxy/haproxy.cfg验证 HAProxy 配置语法docker logs keepalived看健康检查日志确认当前节点防火墙是否放行了 VIP 端口。碰到过一次是 network_interface 配置错了Keepalived 把 VIP 绑定到了错误的网卡上导致 VIP 虽然在节点上但网络路径根本不通。这种问题从日志上看不出来只能逐个检查网络层配置。5.4 时间误差引发的花式故障时间不同步是我遇到过的最隐蔽的问题。现象包括Keystone token 刚创建就过期、Nova 冷迁移超时、镜像上传后状态一直 pending。这些故障看起来毫无关联最后定位到管理网节点的时钟偏了快 40 秒。解决方式不复杂所有节点统一指向内网 Chrony 服务器然后强制校准chronyc makestep但关键不是这一次校准而是要把时间同步作为集群巡检的固定项。离线环境没有外部时钟源内部时钟服务器也可能缓慢漂移必须定期和硬件 RTC 或可信时钟源对比。6. 部署验收、预演和后续维护6.1 部署后的健康检查清单集群部署完成后不要急着往里面灌业务先做一轮基础验收。我常用的命令有source /etc/kolla/admin-openrc.sh openstack service list openstack endpoint list openstack compute service list openstack network agent list openstack volume service list这几个命令能快速暴露控制面服务是否全部正常注册。接着我会上传一个测试镜像创建测试网络和一台测试虚拟机完整走一遍“镜像上传—网络创建—虚拟机创建—绑定浮动 IP—SSH 登录”的流程。测试镜像建议提前就准备好比如 Cirros 这种小镜像离线环境下也要放在内网 HTTP 服务器上方便随时下载。高可用验收更重要。我会在业务低峰期手动重启一个控制节点观察 VIP 是否漂移、服务是否中断再恢复该节点。这种演练第一次做的时候心里会慌但做过一次之后对整个集群的信任度会明显提升。6.2 用 QEMU 嵌套虚拟化做离线预演如果硬件还没到位或者不想在真实物理机上一遍遍试错可以用 QEMU/KVM 做小规模预演。宿主机开启嵌套虚拟化后虚拟机里再启动 OpenStack 计算节点是完全可行的。我这里用的是三层结构物理宿主机原生 KVM中间虚拟机充当 OpenStack 控制节点和计算节点计算节点里的虚拟机再启动业务虚机。这个环境非常适合验证离线源的一致性、镜像版本匹配这类问题。但要注意QEMU 嵌套虚拟化的性能折扣很大而且无法模拟真实网卡的 SR-IOV、DPDK 这类硬件特性。预演只能验证软件栈逻辑不能替代物理机上的性能测试和驱动兼容性测试。如果你想验证多架构支持比如后续要跑 ARM64 虚拟机也可以在这个环境里提前做功能验证。6.3 后续维护里最值得养成的几个习惯集群上线后维护阶段的“分层思维”依然有用只是层级变成了日常运维动作分层。第一层是定期巡检重点看时钟同步、磁盘空间、容器健康状态。Kolla 容器如果异常退出第一时间docker logs看日志不要盲目重启。第二层是备份策略/etc/kolla下的 globals.yml、passwords.yml 是核心资产必须异地备份。控制节点的容器数据目录也要定期备份尤其是 MariaDB 的数据目录。离线环境没有在线恢复的捷径备份就是最后的防线。第三层是升级策略。离线环境升级 OpenStack 前先把新版本的容器镜像全部拉到内网 Registry再执行kolla-ansible upgrade。不要直接拿在线环境那套“边下边升”的思路来套离线环境镜像没就位就升级大概率升到一半卡死。我自己的体会是离线高可用集群最怕的不是技术难度而是“想当然”。Yum 源版本不匹配、容器镜像 tag 不一致、时间不同步这些坑都是因为想当然地认为“应该没问题”才踩进去的。分层部署的核心价值就是逼着你在每一层都验证一次“确实没问题”层与层之间留好检查点后面整个集群才敢放心交付。