
做Linux运维的早晚都得碰高可用。刚入行那会儿我第一反应也是Keepalived两台机器配个VIP脚本挂上看起来挺省事。等业务多了才发现Keepalived那套在几十个资源、跨多节点的场景下根本转不动——脚本越堆越长脑裂问题全靠玄学处理。后来被生产环境逼着去啃Pacemaker才意识到Linux高可用的正确打开方式其实是PCS命令。PCSPacemaker Configuration System是红帽系Linux发行版管理高可用集群的标准命令行工具它是一套通过pcs统一管理Corosync和Pacemaker的接口覆盖了集群初始认证、配置下发、资源定义、约束管理、节点隔离、故障转移全流程。这篇文章我会从一个实际落地的角度把PCS命令的底层逻辑、核心操作和我在真实环境里踩过的坑完整过一遍适合正在从Keepalived往专业HA方案迁移的兄弟也适合备考RHCA、或者打算在公司搭一套正经集群的同学参考。1. PCS到底是什么高可用集群命令行工具的定位1.1 Pacemaker、Corosync、PCS三者关系很多刚接触PCS的人第一反应是这个东西到底负责哪一层。我一开始也糊里糊涂直到把三者的分工理清了才明白整个工具链的设计逻辑。底层是Corosync它负责集群的成员管理和消息通信。每台节点启动后通过心跳报文互相同步状态谁在线谁离线、投票数够不够、消息怎么广播这是Corosync管的。中间层是Pacemaker它是一个集群资源管理器Cluster Resource Manager真正决定这个VIP该放在哪台机器这个服务挂了之后要不要重启节点掉线后资源往哪儿迁移的是Pacemaker。最上层才是PCS——一个命令行配置前端它把Pacemaker内部纷繁复杂的CIBCluster Information Base配置以及Corosync那堆难读的配置文件翻译成一条条简单直观的pcs命令。打个比方Corosync是人的神经系统负责感知身体各部分的状态Pacemaker是大脑负责做决策PCS就是你和大脑对话时用的语言。过去老版本里配置集群要分别操作crm_configure、crm_resource、crm_mon这些分散工具PCS把这些全部收编成了一个统一入口。RHEL 7之后红帽正式把pcs作为标准HA管理接口一直延续到现在。底层Corosync —— 成员关系/心跳/投票 中层Pacemaker —— 资源调度/决策/执行 上层PCS —— 命令行配置接口操作Corosync Pacemaker1.2 为什么不用Keepalived而选PCS这个我很有发言权因为我是从Keepalived迁过来的。Keepalived的优势是上手快、配置简单两台机器一个VRRP实例就能跑。但它有几个绕不开的短板第一Keepalived本质上只在IP层做VIP漂移它不太关心业务进程的真实状态。虽然可以通过自定义脚本做健康检查但脚本逻辑一复杂维护成本就上去了。第二脑裂问题难解。Keepalived依赖组播心跳交换机配置、网络抖动、二层风暴都可能导致两台机器同时认为自己是主节点双主写数据这种事故处理起来真的头疼。第三扩展性差。十几台机器、几十个资源需要编排时Keepalived这种每个节点各自为战的模式很难形成统一调度。PCS/Pacemaker这套组合解决的就是这些问题。Corosync层有明确的quorum投票机制节点故障时先通过STONITH机制把故障节点隔离fencing再从剩余节点中选出新的资源承载者从机制上避免双主。资源类型的支持也很丰富VIPIPaddr2、systemd服务、Docker容器、文件系统挂载、LVM激活等都可以作为受管资源PCS只需要通过统一的pcs resource create语法来声明。所以我的结论是两台机器跑个简单服务Keepalived够用但一旦涉及多节点、多资源、需要可预测的故障转移行为直接上PCS才是正确选择。2. 环境准备安装与初始配置里最容易翻车的三个环节2.1 主机名、时间同步和解析的底层逻辑在敲第一条pcs命令之前环境准备决定了你后面是顺畅还是反复折腾。我先说最容易翻车的主机名问题。PCS集群的所有节点必须能通过主机名互相解析而且解析必须指向真实IP不能指向127.0.0.1。Corosync在启动时会通过/etc/hosts或DNS解析对端节点如果解析到loopback地址节点之间永远无法建立通信。我见过有人装完系统默认hostnamectl set-hostname之后/etc/hosts里还留着127.0.0.1 localhost 主机名这种初始配置结果pcs cluster start之后节点状态始终是OFFLINE查了半天才发现是解析问题。正确的做法是在每台节点的/etc/hosts中明确写入所有集群节点的hostname与IP对应关系192.168.56.11 node1 192.168.56.12 node2 192.168.56.13 node3然后是时间同步。Corosync内部对节点间的时钟偏差非常敏感如果时间不一致轻则token超时日志刷屏重则节点被判定为故障而踢出集群。生产环境建议用chronyd对接内网NTP服务器实验环境也至少确保所有节点对同一时间源同步dnf install -y chrony systemctl enable --now chronyd chronyc sources -v还有防火墙。Corosync的通信默认使用UDP 5405端口PCS自己的Web管理接口pcsd使用TCP 2224端口Pacemaker Remote使用TCP 3121端口。在RHEL系发行版上最简单的方式是直接放行high-availability服务firewall-cmd --permanent --add-servicehigh-availability firewall-cmd --reload提示high-availability这个firewalld服务定义里包含了corosync、pcsd、pacemaker需要的全部端口比自己一条条加靠谱得多。2.2 安装组件和PCS认证的细节RHEL 9 / Rocky Linux 9上安装PCS依赖的组件很简单dnf install -y pcs pacemaker resource-agents fence-agents-all systemctl enable --now pcsdfence-agents-all这一条经常被忽略。实验环境里如果确定不配置STONITH可以不装但如果要上生产fence agent就是生命线。装完之后还需要为hacluster用户设置密码PCS的所有节点认证都基于这个系统账号passwd hacluster这里的逻辑是PCS通过hacluster用户在节点间做相互认证pcs cluster auth命令本质上是让每个节点在本地验证对方的hacluster凭证验证通过后会在节点间建立互信后续的配置下发就基于这个信任关系。所以每一台节点的hacluster密码必须一致不然认证会失败。认证的具体命令pcs host auth node1 node2 -u hacluster注意在pcs 0.10及以上版本对应RHEL 8/9集群认证已经用pcs host auth代替了老版本的pcs cluster auth。如果网上搜到老教程让你敲pcs cluster auth在RHEL 9上是会报错的。3. 核心命令拆解从初始化到资源管理的完整语法3.1 集群生命周期管理命令环境就绪之后第一步是创建集群。PCS的集群初始化命令会自动生成Corosync配置和认证密钥不需要你手动编写corosync.confpcs cluster setup --name ha-cluster node1 node2其中--name指定集群名称后续跟所有节点的主机名。执行完后可以用pcs cluster status确认配置状态。启动集群和设置开机自启pcs cluster start --all pcs cluster enable --all这里有个实用技巧--all是对配置中所有节点执行操作。如果只想操作某个节点直接指定主机名即可。日常管理最常用的生命周期命令我整理成了一张表操作命令说明查看集群状态pcs cluster status显示corosync和pacemaker运行状态查看节点在线情况pcs status nodes列出所有节点在线/离线/待命状态停止整个集群pcs cluster stop --all停止所有节点的集群服务单独停止某节点pcs cluster stop node1让节点退出集群但不影响其他节点重启集群pcs cluster restart --all先停全部再启动全部3.2 资源与约束配置集群本身的创建只是第一步真正体现PCS威力的是资源定义和约束编排。创建一个VIP资源语法是pcs resource create cluster_vip ocf:heartbeat:IPaddr2 \ ip192.168.56.100 cidr_netmask24 \ op monitor interval10s我来拆解一下这段语法cluster_vip是资源名称ocf:heartbeat:IPaddr2是资源代理类型ocf是代理标准heartbeat是代理提供的厂商/命名空间IPaddr2是具体代理脚本ip和cidr_netmask是传给代理的参数op monitor interval10s定义监控操作Pacemaker每10秒检查一次VIP是否在线。创建一个systemd服务资源比如Nginxpcs resource create nginx_svc systemd:nginx \ op monitor interval10ssystemd:nginx表示通过systemd管理nginx.service单元。PCS几乎把Linux服务管理的所有常用入口都封装成了资源代理包括systemd、serviceSysV脚本、docker容器、Filesystem文件系统等。有了资源之后还需要定义它们之间的启动顺序和位置关系这就是约束Constraint。常用的是两种# 顺序约束先启动nginx_svc再启动cluster_vip pcs constraint order start nginx_svc then start cluster_vip # 位置约束cluster_vip必须和nginx_svc运行在同一节点 pcs constraint colocation add cluster_vip with nginx_svc INFINITY这样配置的逻辑在于如果服务没起来VIP漂过去也没有意义反过来只要服务在节点A上运行VIP就必须跟着在节点A上实现对外入口和业务进程的绑定。3.3 状态查询和故障排查常用命令PCS的命令体系里pcs status系列是我用得最频繁的覆盖了从宏观到微观的状态视角命令返回值含义pcs status总览集群、节点、资源、约束的整体运行状态pcs status resources只查看资源状态pcs resource show nginx_svc查看单个资源的详细定义和参数pcs constraint list查看所有约束规则pcs property list查看集群全局属性pcs quorum status查看投票仲裁状态pcs node status查看节点状态属性设置里最常被提起的是stonith-enabledpcs property set stonith-enabledfalse实验环境下我建议直接关掉STONITH因为默认情况下Pacemaker要求配置fence设备否则不会启动任何资源。生产环境则恰恰相反必须配置真实的fence动作这个后面第6章我会细讲。4. 实战用PCS从零搭建一个Nginx高可用集群4.1 实验拓扑与资源规划理论讲再多不如动手跑一遍。我用两台Rocky Linux 9虚拟机做演示规划如下节点IP角色node1192.168.56.11集群节点1node2192.168.56.12集群节点2虚拟VIP192.168.56.100对外提供服务的漂移地址规划两个资源VIP资源负责IP漂移Nginx服务资源负责业务进程二者通过约束绑定。Nginx在两台节点上都要安装dnf install -y nginx systemctl disable nginx注意这里只执行disable不要stop也不要start。因为Pacemaker接管后服务的启停应该由集群调度手动启动会干扰Pacemaker的状态判断。4.2 完整配置流程在node1上执行以下所有操作PCS支持任意节点作为管理端配置会自动同步到其他节点。第一步节点认证pcs host auth node1 node2 -u hacluster按提示输入hacluster密码。此时如果报错99%是前面提到的hacluster密码不一致或/etc/hosts解析没配好。第二步创建集群pcs cluster setup --name nginx-ha node1 node2 pcs cluster start --all pcs cluster enable --all pcs status执行pcs status时注意看Online节点列表里是否有node1和node2。然后设置全局属性pcs property set stonith-enabledfalse第三步创建资源pcs resource create nginx_svc systemd:nginx op monitor interval10s pcs resource create cluster_vip ocf:heartbeat:IPaddr2 \ ip192.168.56.100 cidr_netmask24 \ op monitor interval10s第四步添加约束pcs constraint order start nginx_svc then start cluster_vip pcs constraint colocation add cluster_vip with nginx_svc INFINITY到这里整套配置已经完成。用pcs status resources看一下[rootnode1 ~]# pcs status resources * nginx_svc (systemd:nginx): Started node1 * cluster_vip (ocf:heartbeat:IPaddr2): Started node1两个资源都运行在node1上。在node1上执行ip addr show能看到192.168.56.100已经绑定。4.3 资源组的便捷用法上面用约束实现资源编排是标准做法。PCS还提供了一种更简化的模型叫资源组Group组内资源按声明顺序启动、按逆序停止并且天然运行在同一节点上pcs resource group add nginx_group nginx_svc cluster_vip执行这条命令后之前定义的order和colocation约束会被PCS自动转换合并到组定义里pcs constraint list会看到PCS自动生成的组内约束。如果你的资源比较多、依赖关系简单清晰用组比手写一堆约束高效得多。这也是很多生产配置的实际选择。5. 故障转移测试验证集群到底高可用在哪5.1 节点级故障模拟资源都正常后就该验证故障转移行为是否符合预期。先测试手动迁移让node1进入standby待命状态pcs node standby node1执行后立即观察资源位置[rootnode1 ~]# pcs status resources * nginx_svc (systemd:nginx): Started node2 * cluster_vip (ocf:heartbeat:IPaddr2): Started node2两个资源在一两秒内漂移到了node2VIP 192.168.56.100在node2上正常绑定。这个过程中用户侧的TCP连接会中断但VIP恢复时间通常在秒级这是正常现象。恢复节点pcs node unstandby node1注意unstandby后资源不会自动迁回node1。Pacemaker的原则是资源当前运行正常就不必挪动只有当node2故障或资源再次失败时node1才会重新承担资源。这个设计是为了避免资源抖动对业务造成不必要的干扰。5.2 资源级故障模拟与服务恢复逻辑节点故障是最粗粒度的场景但如果只是服务进程自身崩溃呢更精细的测试是只停掉进程systemctl stop nginx这里的细节值得多说一句。因为nginx资源是由Pacemaker通过systemd代理监控的systemctl stop nginx触发systemd单元状态变化后Pacemaker会检测到监控失败然后执行资源重启。几秒后你会发现nginx服务又被启动资源状态恢复为Started。这就是op monitor的完整逻辑——Pacemaker不仅是检查节点活着更重要的是保证受管资源始终处于可用状态。再测试强制关机poweroff在实验环境未配fence且关闭STONITH的情况下node1直接断电后node2的Corosync会经过token超时默认约15秒后判定node1离线然后接管资源。但这里有一个两节点集群特有的坑我在第6章专门讲。5.3 实时监控视图在验证过程中开一个实时监控窗口是非常有用的crm_mon -Ar它会动态刷新集群状态-A显示详细的资源属性-r显示资源在失败后的操作历史。每次故障注入后观察监控面板的变化你对Pacemaker调度逻辑的理解会比看十篇文档都深。生产环境建议常驻运行故障发生时能第一时间看到资源在哪个节点、经历了什么操作。6. 踩坑实录我在PCS使用中遇到的几个典型问题和排查思路6.1 两节点集群在节点宕机后不接管资源这是最经典、也最坑的一个问题。按照上面实验环境配置如果你直接poweroff node1很多时候会发现node2并不接管资源甚至node2上原本正常的资源也会被冻结。原因在于两节点集群默认每个节点各持有1票quorum阈值是50%以上节点在线也就是至少需要2票。当node1离线后node2只剩1票不满足quorum条件集群进入无仲裁状态所有资源都会被置为停止状态。这个设计是为了防止脑裂——在没有仲裁的情况下宁可停服务也不能出现双主机。解决方式有三种第一种配置fence设备。节点被fence后故障节点的票数会从quorum中移除剩余节点恢复仲裁能力这也是生产环境最标准的做法。第二种用仲裁设备qdevice让第三方设备参与投票。第三种实验环境下直接设置pcs property set no-quorum-policyignore这里我要强调ignore只适合实验室验证生产环境千万不要用。两节点集群生产部署时要么配fence要么配qdevice否则就是拿业务稳定性开玩笑。6.2 STONITH误报导致的资源反复重启提到fence就不得不说我踩过的另一个坑在一台旧服务器上配好了IPMI的fence设备测试时发现资源一切正常但运行一段时间后偶发资源重启。查日志发现是fence设备超时导致的误判——BMC的IPMI端口响应慢Pacemaker认为fence执行失败反过来又把节点踢出集群。排查路径是journalctl -u pacemaker -u corosync看节点状态切换记录pcs stonith list看fence设备定义再用fence设备自带的测试命令手动执行一遍比如fence_ipmilan -a 172.16.1.10 -l admin -p password -o status如果手动执行就慢说明是设备本身响应延迟需要在fence配置里调大pcmk_delay_max等参数或者换用更快的fence方式比如虚拟机场景用fence_virsh。这个坑提醒我fence设备本身也是单点配置完之后一定要做故障演练不能配完就不管。6.3 systemd资源与手动启停的冲突还有一个常见误操作有人习惯在节点上手动执行systemctl restart nginx。这在普通服务器上没问题但在Pacemaker管理下这样做可能引发状态不一致。具体表现是手动重启后nginx服务确实起来了但Pacemaker的资源状态可能仍然显示上一次监控失败或者反过来Pacemaker认为资源已停止而再次拉起服务导致短时间内的双重重启。正确的操作方式是所有启停操作都通过PCS接口让Pacemaker去执行后端动作。pcs resource disable nginx_svc pcs resource enable nginx_svc如果确实需要手动干预去排查问题用pcs resource debug-start nginx_svc在前台执行资源代理脚本观察输出这在定位资源代理脚本失败原因时非常有用。6.4 pcsd服务端口连不上PCS的Web UI和节点间认证依赖pcsd服务端口是2224/tcp。有一次配置环境时pcs host auth一直提示连接被拒绝排查下来是因为pcsd服务没起来。systemctl status pcsd systemctl restart pcsd另一类情况是SELinux拦截表现为端口明明在监听但外部连不上。查看SELinux端口上下文semanage port -l | grep 2224如果在SELinux enforcing模式下端口上下文不对pcsd的监听会被拦截。生产环境不要图省事直接setenforce 0而是用semanage port -a -t http_port_t -p tcp 2224来修正上下文或者放行对应的SELinux布尔值。我记得自己在CentOS 7时代因为这台机器的SELinux策略模板被改动过pcsd怎么都起不来最后查日志看见AVC denial才定位到问题。6.5 资源启动失败却查不到原因最后一个典型的排错场景是pcs resource create执行成功但资源状态一直报Failedpcs status里只看得到resource不是Running却不知道具体原因。我的排查顺序如下首先用debug-start直接看代理脚本的输出pcs resource debug-start nginx_svc这会以交互方式执行资源代理的start方法任何脚本报错都会直接打在终端上。比如IPaddr2资源获取不到IP、nginx的binary路径不对这类原因此时一目了然。其次查看集群的详细日志journalctl -u pacemaker -u corosync --since 10 minutes agoPacemaker在资源操作失败时会把资源代理返回的错误码和标准输出记录在日志里。配合pcs resource history nginx_svc查看该资源的操作历史能看清失败的阶段是start还是monitor。排查思路再补充一点pcs resource refresh nginx_svc是清除失败状态的操作。很多资源虽然已经恢复但失败计数还在会干扰后续调度决策。清掉历史失败状态后再看pcs status有时候问题其实已经自己恢复了只是状态展示滞后。写在最后的一些体会PCS命令的系统性很强但真正上手之后会发现核心套路并不复杂pcs cluster管集群本身pcs resource管资源pcs constraint管编排pcs property管策略另外加一个pcs stonith管隔离。把这几组命令吃透大部分场景都能覆盖。我自己的经验是学习PCS一定要在实验环境里把两种故障都真实演练一遍——节点宕机和资源崩溃。前者测quorum和fence后者测monitor和restart。演练得越多对集群各种状态的判断就越有把握真正上了生产心里也不慌。如果你正准备在公司搭建高可用方案建议先拿虚拟机跑通这套流程再决定怎么落地。集群这玩意动手验证永远比看文档靠谱。