
1. 存储节点扩容前的整体思路与方案选型OpenStack增加存储节点这件事说白了就是给云平台“加硬盘”。很多刚接触OpenStack的运维兄弟一上来就急着装包、改配置结果部署完了发现卷创建失败、调度不上去最后才回头研究架构白白浪费半天时间。作为跑过生产环境的过来人我建议动手之前先把扩容的整体思路捋清楚知道自己加的是什么角色、加完有什么效果、会牵动哪些服务。1.1 搞清楚你要加的是哪类存储节点OpenStack里的存储角色其实分两种路线。一种是走Cinder块存储路线提供的是云硬盘类似云主机的系统盘和数据盘底层一般用LVM、Ceph这类方案通过iSCSI或RBD协议把存储资源暴露给计算节点。另一种是Swift对象存储路线提供的是桶和对象类似网盘接口底层是普通硬盘加Swift服务。绝大多数场景下我们说“增加一个存储节点”默认指的是Cinder的存储后端节点。因为Swift扩容更像“加服务器跑Swift服务”而Cinder扩容则是把一台物理机作为独立的Block Storage节点通过cinder-volume服务对外提供块存储能力。我这次要拆解的就是Cinder存储节点的扩容流程。你的架构里如果已经有一台控制节点、一台或几台计算节点现在需要把业务数据容量扩上去那新增的这台机器就是专门的存储节点。它不跑nova-compute不跑neutron-agent只负责承载cinder-volume以及底层的LVM卷组和iSCSI Target。1.2 为什么单独加存储节点而不是堆计算节点本地盘有一个常见误区既然计算节点的本地盘也能通过LVM配置成Cinder后端为什么不直接在每个计算节点上把本地剩余空间加入存储池理论上确实可以很多小型测试环境也就是这么干的。但在生产环境里我强烈不建议这么玩。原因有三个。第一计算节点本地盘扩容会导致存储资源分散你没法统一规划卷组容量而且某台计算节点宕机时它本地承载的Cinder卷可能无法被其他计算节点正常访问除非底层有分布式复制机制。第二计算节点本身的CPU、内存、网络要承担虚拟机业务再叠加cinder-volume的LVM快照、iSCSI export操作容易出现IO争抢。第三独立存储节点故障域更清晰。存储节点挂了只影响卷IO不影响计算节点上的虚拟机生命周期管理而计算节点挂了还得考虑HA迁移。所以在生产架构里存储节点独立化是标准做法。新增的这台存储节点本质上是把“容量”和“计算”解耦容量不够就横向加存储节点计算不够就纵向加计算节点互不干扰。这也是OpenStack横向扩展的精髓。1.3 存储后端方案选型LVM、NFS还是Ceph加存储节点之前还得先确定后端选型因为这决定了你后面要装的软件包、要做的配置完全不同。我见过不少团队在OpenStack部署时前期没定死后端结果扩容阶段才纠结临时改后端导致数据迁移惊心动魄。所以这里给个明确建议。后端方案主要有三种。第一种是LVM iSCSI方案也就是我本文要详细展开的。它适合起步阶段成本低、操作直观、易排查故障单个存储节点的数据可靠性依赖硬件RAID或上层备份。第二种是NFS后端适合已经有NAS存储阵列的团队配置相对简单但性能和并发能力依赖网络存储设备的规格。第三种是Ceph RBD后端适合大规模生产环境或对扩展性和数据副本有要求的场景它天然支持多副本、自我修复但部署复杂度高扩容时还要考虑Ceph集群自身的OSD扩容。如果你现在只是“增加一个存储节点”而且环境里其他节点走的是LVM方案那就继续走LVM不要在中途切换后端。存储最忌讳频繁更换底层技术方案数据迁移的代价远高于你省下的那点运维成本。2. 新增存储节点前的环境准备与磁盘规划想清楚架构和方案之后就可以开始准备“新兵上阵”了。这一步做扎实了后面安装配置就会很顺很多扩容失败案例都是因为前期环境没准备好配置到一半才发现缺依赖、缺时间同步、磁盘分区不对。2.1 硬件配置和系统版本要求一台Cinder存储节点需要什么样的硬件配置我直接给一个基准参考CPU建议8核及以上因为快照、克隆操作时会触发比较多的CPU计算内存建议不低于16GB虽然cinder-volume本身不算吃内存但Linux的文件缓存、iSCSI target的内部缓存都会占用内存硬盘上系统盘建议单独一块SSD或小容量SAS盘用于装系统另外至少准备一块独立数据盘机械盘或SSD盘均可取决于你的性能需求这块盘才是真正给云平台提供存储容量的。网络方面存储节点至少需要两个网口一个走管理网络用于API通信、OpenStack内部服务互访另一个走存储网络用于iSCSI数据传输。如果环境规模不大网络可以复用但生产环境一定建议物理隔离存储流量否则高峰期虚拟机的IO会把管理网络打爆。系统版本建议和现有OpenStack环境保持一致。比如你的控制节点是CentOS 7 OpenStack Queens版本那新存储节点也用同样的系统和版本别自己整个Ubuntu或者Rocky版本来混搭。OpenStack各服务间的版本兼容性最好保持齐平跨版本混用很容易出现API版本不匹配、消息队列协议不一致的怪问题。2.2 主机名、hosts解析与时区规划新节点加进来之前主机名必须规范。我遇到过因为主机名带下划线导致OpenStack服务注册异常的事所以这里强调一下主机名只能用字母、数字和连字符不能用下划线首尾也不能是连字符。比如你这台新存储节点可以命名为block-storage-01。设置完主机名后记得在所有节点的/etc/hosts里加上新存储节点的解析记录。OpenStack服务之间会通过主机名互相访问如果hosts文件不全控制节点上cinder-scheduler调度卷的时候根本不知道该往哪里发请求。时区同步同样不能偷懒。你可以在新节点上先把时间手动校准一遍再安装NTP客户端并指向已有的NTP服务器。如果控制节点自己就是NTP服务器那新存储节点直接配置为server controller_ip iburst即可。不要小看时间同步Cinder创建卷、删除卷都会有状态机流转时间偏差过大轻则日志时间线混乱重则影响消息队列的时序逻辑。2.3 新增节点前的软件源和基础依赖系统装好后先配好OpenStack软件源。以CentOS为例需要启用OpenStack对应版本的yum源和extras源然后执行系统更新。建议先把python3-openstackclient等基础客户端工具装上这样后面验证服务状态时可以直接在存储节点上执行OpenStack命令。基础依赖方面LVM后端方案需要安装lvm2、targetcli或scsi-target-utils、openstack-cinder这几个核心包。这里要提醒一点targetcli和tgtadm是两套不同的iSCSI target工具配置不能混用。OpenStack的LVM驱动默认支持tgtadm也可以通过配置使用targetcli的LIO模式。我这次踩过坑所以后面配置时会专门展开讲这个选择避免你重蹈覆辙。2.4 数据盘分区与LVM逻辑卷规划数据盘的处理是重头戏。假设你的存储节点有一块2TB的独立数据盘/dev/sdb操作步骤是这样的先用fdisk或parted对/dev/sdb做分区建议创建为Linux LVM分区类型8e也可以直接把整个盘建成PV。生产环境我一般建议做分区再建PV这样后续扩展维护更清晰。然后创建物理卷PV和卷组VGpvcreate /dev/sdb1 vgcreate cinder-volumes /dev/sdb1这里的关键点在于卷组名字。OpenStack的Cinder LVM驱动默认会找名为cinder-volumes的卷组虽然可以通过配置文件自定义卷组名但为了减少出错概率直接使用cinder-volumes最省事。另外卷组空间不要一次性全部分配给逻辑卷因为你还需要考虑为卷快照预留空间。通常的做法是创建一个thin pool后续所有云硬盘都从这个thin pool里分配逻辑卷。LVM精简配置Thin Provisioning在生产环境中确实很实用它实现了“超额分配”即多个逻辑卷可以共享同一个底层存储池只有真正写入数据时才占用实际物理空间。比如你创建一个1TB的thin pool可以在里面创建20个100GB的云硬盘只要实际写入总和不超过1TB就不会出问题。但这种模式需要监控到位一旦thin pool空间用完所有卷会同时变成只读状态这是生产事故级别的故障。所以我建议新手先把普通线性卷模式跑通后续熟悉了再尝试thin pool。3. cinder-volume服务安装与LVM后端配置实战前期规划和环境准备就绪接下来进入实操环节。这一章我会把从安装软件到完成iSCSI后端配置的完整过程拆开讲清楚每一步都配上说明和验证命令你照着操作基本不会跑偏。3.1 安装cinder相关软件包SSH登录到新存储节点执行以下安装命令yum install -y openstack-cinder targetcli lvm2安装过程中有一个容易被忽视的细节openstack-cinder这个包会同时把cinder-api、cinder-scheduler、cinder-volume等组件全部装到系统里。但作为专业存储节点只需要运行cinder-volume服务就够了其他组件应该保持关闭状态。有些人图省事会把openstack-cinder-api和openstack-cinder-scheduler也一并启动这虽然不至于立刻引发故障但会造成服务逻辑混乱而且在多存储节点环境中会造成多个scheduler并发调度出现不可预知的问题。安装完成后确认一下这些组件的状态systemctl list-unit-files | grep cinder systemctl list-unit-files | grep target你期望看到的是openstack-cinder-volume、target等服务的unit文件存在即可暂时不要启动它们等配置完成后再统一拉起。3.2 cinder.conf配置文件详解OpenStack服务的套路都是配置文件驱动一切。Cinder的配置文件位于/etc/cinder/cinder.conf它是INI格式的文本文件其中控制节点和存储节点的配置内容不完全一样。存储节点上的cinder.conf需要重点关注[DEFAULT]段、[database]段、[keystone_authtoken]段和自定义后端段。先看核心的[DEFAULT]段配置[DEFAULT] transport_url rabbit://openstack:rabbit_passcontroller_ip:5672/ auth_strategy keystone enabled_backends lvm-1 my_ip 10.0.0.21 glance_api_servers http://controller_ip:9292其中transport_url是消息队列的连接地址存储节点的cinder-volume服务需要通过消息队列和控制节点上的cinder-api、cinder-scheduler通信这里填RabbitMQ的连接信息。注意密码里的特殊符号如果RabbitMQ密码设的是Fusion2024这种带符的整个URL就会解析错误建议选择纯字母数字组合的密码作为服务账号密码。或者做URL编码处理。enabled_backends lvm-1是重中之重它声明了该存储节点启用的后端名称列表。如果有多个后端可以用逗号分隔如lvm-1, lvm-2。这个名称是一个逻辑标识后续配置其他段时引用它。my_ip是存储节点自身的管理IP地址我这里写的是10.0.0.21实际填你新节点的管理IP即可。Cinder在创建iSCSI target时会用这个IP去注册target的IP地址如果填错或填成不回环地址后面虚拟机挂载云硬盘时会发现target地址对不上导致连接超时。再看数据库和认证相关配置。存储节点上的cinder-volume也需要访问数据库因为创建卷时cinder-volume会更新数据库中的卷状态记录。它也需要通过Keystone做认证这样才能调用Glance获取镜像信息。[database] connection mysqlpymysql://cinder:cinder_passcontroller_ip/cinder [keystone_authtoken] www_authenticate_uri http://controller_ip:5000 auth_url http://controller_ip:5000 memcached_servers controller_ip:11211 auth_type password project_domain_name Default user_domain_name Default project_name service username cinder password cinder_pass这里不推荐在存储节点上单独配置[database]和[keystone_authtoken]更优雅的做法是直接复用控制节点生成的cinder.conf然后修改其中和本机相关的部分。很多生产团队的做法是先在控制节点上把cinder.conf配置好然后scp到存储节点再改my_ip、enabled_backends等关键项。这种方式能保证配置一致性减少手写错漏。不过有个地方必须手动加就是后端段的声明。在cinder.conf末尾追加[lvm-1] volume_driver cinder.volume.drivers.lvm.LVMVolumeDriver volume_group cinder-volumes target_protocol iscsi target_helper tgtadm target_ip_address 10.0.0.21 volume_backend_name LVM_iSCSI这段配置决定了Cinder如何与底层LVM和iSCSI交互。volume_driver指LVM驱动类volume_group使用我们在前文创建的cinder-volumes卷组target_helper选择tgtadmtarget_ip_address则是存储节点在存储网络中的IP地址。volume_backend_name是一个便于识别的后端名称它会作为该存储节点的唯一身份出现在调度结果中建议设置为和环境匹配的显眼名称比如LVM_STORAGE_01。3.3 iSCSI Target工具选型tgtadm还是targetcli这一节单独拎出来讲是因为它确实是个容易踩坑的点。OpenStack的LVM驱动支持两种iSCSI Target工具tgt和LIO通过targetcli管理。传统方案是用tgtadm配tgt它的优点是配置简单、和OpenStack的默认驱动配合最顺兼容性比较好。但tgt的bug也不少特别是高并发场景下可能出现target服务假死、连接中断的情况生产环境经过充分测试后使用还是能接受的。现代方案是用LIO内核级iSCSI Target也就是targetcli。它的性能更好因为是内核态实现数据路径更短。但OpenStack的LVM驱动要使用LIO时需要确保系统里安装的是targetcli包并在配置文件中把以下参数配好[lvm-1] target_helper lioadm target_protocol iscsi说实话我测试过两种方式在中小规模部署并发IO不算极端的场景下差距不大。如果你是新环境且没有历史包袱推荐直接用LIO模式也就是targetcli它有原生openstack兼容性管理工具也更现代。如果环境中已经存在基于tgt后端的存量卷那就要保持一致性别混用。混用target工具是我见过的最致命的坑之一。比如系统里tgt和targetcli的配置文件同时存在两个服务都在监听iSCSI端口3260创建卷时可能出现两个target daemon互相干扰。所以在配置之前检查一下系统里现有的iSCSI target工具只保留一种方式。3.4 启动服务并注册存储节点配置完成后就可以启动服务了。依次执行systemctl enable --now lvm2-lvmetad systemctl enable --now openstack-cinder-volume systemctl enable --now target等等这里有个先后顺序的问题。openstack-cinder-volume服务启动的时候会去检查卷组是否存在如果LVM卷组还没创建好服务会启动失败或无法正常初始化后端。所以务必保证cinder-volumes卷组已经存在再启动服务。LVM后端的Cinder驱动要求卷组里必须有空闲空间哪怕是1GB也好否则初始化时也可能报错。验证服务状态systemctl status openstack-cinder-volume tail -f /var/log/cinder/volume.log日志里看到类似successfully initialized或Driver init successful字样说明后端初始化成功。接下来在控制节点上验证存储节点是否成功注册。在控制节点执行openstack volume service list输出中应该能看到新存储节点对应的cinder-volume服务状态为up并且显示对应的host名称比如block-storage-01lvm-1。如果这里看不到新节点多半是配置文件有问题或者服务没注册消息队列排查顺序建议是先看存储节点的volume.log再看RabbitMQ中队列是否创建接着确认Keystone中cinder服务账号是否有效。4. 调度验证、连通性测试与日常监控服务启动成功只是第一步真正的好戏在于验证新存储节点能否正常接收卷创建请求、虚拟机能否成功挂载卷。这个阶段往往能暴露很多只有实际业务流量才会触发的问题。4.1 创建测试卷验证调度逻辑Cinder的调度器cinder-scheduler由一个称为FilterScheduler的组件实现。它通过过滤器Filter和权重Weigher两个阶段来选择最佳存储后端。常见的过滤器包括AvailabilityZoneFilter、CapacityFilter和BackendFilter它们从不同维度筛选出满足条件的候选节点。当控制节点接收到创建卷请求后scheduler会根据后端可用信息来评估最终把请求路由到合适的存储节点上。为了验证新存储节点是否真的被纳入调度我们在控制节点上创建一个测试卷openstack volume create --size 1 --availability-zone nova test_vol_001创建后用openstack volume list查看卷的Status和Attached to列。如果状态能从creating变为available说明整个链路正常。更具体的验证是查看卷被分配到了哪个主机上openstack volume show test_vol_001 | grep properties或者直接查数据库mysql -ucinder -pcinder_pass -e select id, host, status from cinder.volumes where display_nametest_vol_001;看到host字段里有block-storage-01lvm-1就说明新存储节点真正接入了业务。倘若卷一直在creating状态大概率是scheduler没选到新节点优先查cinder-scheduler日志、新节点的cinder-volume日志以及RabbitMQ连接状态。4.2 iSCSI挂载连通性测试卷创建成功以后还要验证计算节点到新存储节点的iSCSI链路是否畅通。在计算节点上安装iscsi-initiator-utils然后手动挂载这个卷测试连通性openstack volume list openstack volume show test_vol_001 | grep attachments把卷附加到虚拟机时OpenStack会通过nova-compute触发iSCSI discovery。如果手动做连通性测试可以先找到卷对应的iSCSI targetiscsiadm -m discovery -t sendtargets -p 10.0.0.21正常情况下能看到类似10.0.0.21:3260,1 iqn.2010-10.org.openstack:volume-...的target输出。如果没有显示检查存储节点上的target服务状态和防火墙设置。很多初装环境最后排查一圈发现是防火墙拦了3260端口所以直接先执行firewall-cmd --permanent --add-port3260/tcp firewall-cmd --reload或者干脆测试阶段先临时关闭防火墙验证通了再按生产需求配置精确放行策略。4.3 多存储节点环境下的后端权重调整如果你的环境里现在不止一台存储节点那就涉及后端权重分配的问题。Cinder的权重机制通过CapacityWeigher实现默认策略下剩余容量更大的节点会被优先选中。这个逻辑在大多数场景下没问题它能均衡各节点的容量消耗。但有一种情况需要手动调整当所有存储节点的硬件性能差异明显时比如一台是普通机械盘另一台是全闪存盘仅仅按容量加权轮询会把IO压力同时打到两台设备上导致性能定义混乱。这时你可以通过修改配置来调整后端权重[DEFAULT] weight_slopes -1.0需要注意的是这个参数设置的是可用容量权重斜率正值显示偏好大容量节点默认负值反之。它并不能完全做到“性能优先”更合理的做法是通过启用不同的存储后端类型来实现不同性能级别的卷服务。在实际生产环境里我更推荐按照业务范围划分存储后端。比如后端A定义为LVM_SATA专门给归档类业务提供大容量低成本存储后端B定义为LVM_SSD给核心数据库提供高性能存储。通过创建卷类型Volume Type来约束业务归属配合调度过滤器实现逻辑隔离。4.4 存储节点的日常巡检与容量监控新节点上线后日常运维不能只靠跑一次systemctl status就完事。存储节点的核心关注指标有三个卷组剩余空间、iSCSI target连接数、磁盘IO健康度。卷组剩余空间可以用以下命令快速检查vgs重点关注VFree列当剩余空间低于20%时就该规划扩容了。我经历过一次事故某存储节点的卷组剩余空间跌到5%当时还在大量创建卷结果某次快照写入直接导致thin pool空间耗尽所有卷瞬间不可写。所以至少在VG里预留20%以上的空间冗余有条件的直接上thin pool并使用容量告警阈值监控。iSCSI target连接数可以这样看targetcli ls tgtadm --op show --mode conn正常情况下target连接数应该和计算节点上附加到该存储节点的卷数量线性对应。如果连接数异常波动可能是网络不稳定或计算节点上的iscsi initiator服务异常循环重连这时需要查看计算节点上的/var/log/messages和iscsid日志。磁盘IO健康度建议用iostat、iotop组合重点看%util是否长期超过80%。机械盘长期满载会加速老化甚至导致IO timeout事件SSD盘则要看写入寿命。我再分享一个小经验。日常巡检时在存储节点配置一个cron脚本定期往一个非关键目录写入文件并校验内容比如每5分钟写入一个health_check文件然后读取确认一致。这个方案能快速暴露底层文件系统或LVM映射异常。相比单纯的systemctl status这个更贴近实际IO路径我曾经靠它提前发现过一次RAID卡固件异常导致的偶发读写错误。5. 常见问题与排查技巧实录加了这么多次存储节点我总结出几类高频故障和排查思路这里直接以表格加实例的方式整理出来建议你收藏备用。问题现象可能原因排查手段新节点在volume service list中显示downcinder-volume未启动或无法连接消息队列检查/var/log/cinder/volume.log确认transport_url配置正确用rabbitmqctl list_queues查看队列创建卷一直creating调度器未将请求发送到新节点或后端初始化失败查看cinder-scheduler日志了解调度决策确认新节点volume.log中是否有异常堆栈虚拟机挂载卷失败iSCSI target地址错误或防火墙未放行3260端口在计算节点执行iscsiadm discovery确认target_ip_address与实际网络匹配放行防火墙端口创建快照慢或失败卷组空间不足或LVM thin pool容量耗尽vgs查看剩余空间清理不用快照或扩展卷组容量存储节点重启后服务未恢复服务未设置开机启动或target配置未持久化执行systemctl enable --now确保服务自启检查/etc/tgt/conf.d/中配置文件是否导入卷创建成功但大小不对volume_group名称写错导致驱动找到另一个卷组检查cinder.conf中volume_group参数是否为cinder-volumes或实际创建的名字5.1 排查实例新节点状态down但服务进程正常有一次我加一台新存储节点cinder-volume进程在跑但控制节点上一直显示down。排查了很久最后发现问题出在/etc/hosts上。新存储节点没有把自己加进hosts文件hostname解析指向了回环地址导致服务注册时上报的主机名解析失败控制节点无法确认它的心跳。这个问题的解决很简单把主机名写进/etc/hosts并重启服务就恢复了。但教训很深刻OpenStack内部服务自检依赖完整的域名解析/etc/hosts哪怕漏了自己都可能导致看似正常的服务不正常注册。5.2 排查实例卷能够创建但下发到虚拟机后无法识别还有一种情况是卷创建成功附加到虚拟机后虚拟机操作系统里看不到新硬盘。这种问题通常是物理链路和协议层面的错误。先从计算节点检查iSCSI会话状态iscsiadm -m session -P 3如果session显示连接正常但LUN数量为0说明target导出有问题如果session都建立不了就要看存储节点上tgtadm --op show --mode target的输出的target配置是否完整。我记得有一次就是因为在多路径环境下没有安装multipathd导致一个卷被识别成多个异常路径虚拟机里看到的设备号错乱最终无法正常分区格式化。装上device-mapper-multipath并重启iscsi服务后问题解决。5.3 经验性建议扩容存储节点前应该先做什么结合我自己的经验扩容前还应该做三件不紧急但重要的事情。第一备份控制节点上的cinder.conf和nova.conf扩容过程中如果误改了配置可以快速回滚。第二标记现有卷的容量分布情况记录哪些存量卷已经占用了多少空间方便预估新节点加入后是否需要做容量均衡。第三制定回滚方案。虽然加存储节点不算高风险操作但如果你是在业务高峰期操作万一碰到预期之外的问题至少能快速回到扩容前的状态。有一说一LVM后端的扩容不是特别复杂但它非常考验对OpenStack内部机制的熟悉程度。你理解了调度器如何选后端、cinder-volume如何注册状态、iSCSI target如何暴露存储再遇到新场景就不会手足无措。最后再聊一个实用技巧。新节点加入到现有环境后建议先在控制节点上调整卷创建时默认的可用域Availability Zone。如果你创建卷时不指定可用域调度器会按照默认可用域过滤节点如果新节点没有归属到正确的可用域创建请求可能永远轮不到它。在生产环境中如果一个可用域里的存储节点数量较多合理划分可用域能显著减少调度压力。这里就涉及OpenStack的可用域机制了它本质上是一个逻辑分组需要保证每个存储节点至少归属于一个可用域并且该可用域下包含可用的存储容量。把一个新存储节点划归到承载核心业务的可用域时务必确认该可用域下的网络、计算节点等也配套到位否则卷创建成功却无法被虚拟机拉取时排查起来更加耗时。