RHEL 10 双节点 Pacemaker
高可用集群部署配置文档
从裸机到可用集群的完整落地路径。每一步都给出可直接复制执行的命令、执行位置、预期输出与验证方法,并针对双节点场景特有的脑裂与 fencing 竞态问题给出明确对策。
00文档说明与实施路线
0.1 命令执行位置约定
本文每段命令的标题栏右侧都标注了执行位置,务必按标注执行:
node1 和 node2 都要跑一遍。
集群配置类命令只需在任一节点执行一次,会自动同步全集群。
在 qnetd 第三方主机上执行。
0.2 实施路线总览
| 阶段 | 章节 | 产出 | 关卡(必须通过才进入下一步) |
|---|---|---|---|
| ① 规划 | 01 | IP 表、主机名表、fence 设备清单 | 网络互通、fence 设备凭据已确认可用 |
| ② 准备 | 02–03 | 软件安装完成、防火墙放行、pcsd 运行 | 两节点互相能解析主机名、时间同步 |
| ③ 建集群 | 04 | 集群创建并启动 | pcs status 显示两节点 Online |
| ④ 保完整性 | 05–07 | qdevice + fencing 就绪 | pcs stonith fence 测试成功 |
| ⑤ 上业务 | 08–09 | 存储、资源、约束配置完成 | 业务可通过 VIP 访问 |
| ⑥ 验收 | 10 | 故障演练报告 | 全部测试用例通过 |
| ⑦ 交接 | 11–13 | 运维手册、配置备份 | 交付检查表全绿 |
不要跳过第 ④ 阶段直接上业务。没有可用 fencing 的双节点集群在故障时不会切换(会一直等待 fence 结果),或者更糟 —— 发生脑裂损坏数据。Red Hat 对未配置 fencing 的集群不提供生产支持。
01规划:拓扑 / 网络 / 命名
1.1 参考拓扑
1.2 规划表(实施前填写)
| 项目 | node1 | node2 | 说明 |
|---|---|---|---|
| 主机名(FQDN) | node1.example.com | node2.example.com | 必须与 hostname -f 一致,且两边可互相解析 |
| 业务 IP | 192.168.10.11 | 192.168.10.12 | — |
| 心跳 link0 | 192.168.20.11 | 192.168.20.12 | 独立网卡/VLAN |
| 心跳 link1 | 192.168.30.11 | 192.168.30.12 | 强烈建议,避免单链路故障误判 |
| BMC / iDRAC / iLO | 10.10.10.11 | 10.10.10.12 | fencing 用;必须与集群心跳网物理隔离 |
| VIP(浮动 IP) | 192.168.10.100/24 | 不能与任何物理网卡 IP 冲突 | |
| 集群名 | my_cluster | — | |
| 仲裁主机 | 192.168.10.20 / qnetd.example.com | 第三方主机,不装 pacemaker | |
| 共享存储 | /dev/sdb(两节点看到同一 LUN) | 按需;无共享存储可跳过第 8 章 | |
1.3 硬件与环境前置条件
- 两台 RHEL 10 节点,配置尽量一致(CPU/内存/网卡),已完成基础安装
- 每个节点都有可用的 fence 设备(物理机:IPMI/iDRAC/iLO;虚机:vCenter/RHV API;无带外:SBD + watchdog + 共享块设备)
- 心跳网络与业务网分离,至少 2 条心跳链路(knet 最多支持 8 条)
- 时间同步:两节点 chrony 指向同一时间源,偏差 < 1s
- DNS 或 /etc/hosts 双向解析正常(包括仲裁主机)
- 有效订阅,可启用 HighAvailability 仓库
- SELinux 保持 enforcing(Red Hat 支持并推荐)
- 共享存储(如需)已在两节点识别为同一设备,且 multipath 配置一致
fence 设备的网络路径不能与心跳网共用。如果心跳网交换机故障导致节点失联,而 BMC 也走同一台交换机,那么 fence 也会失败 → 集群卡死。带外管理网必须独立。
02订阅与软件仓库
启用 High Availability 仓库
两个节点都要执行。x86_64 架构的仓库 id 如下;其他架构请替换。
# 确认已注册
subscription-manager status
# 启用高可用附加仓库(RHEL 10 / x86_64)
subscription-manager repos --enable=rhel-10-for-x86_64-highavailability-rpms
# 确认仓库已生效
dnf repolist | grep -i highavailability
若使用 GFS2 等共享集群文件系统,还需 Resilient Storage 仓库:rhel-10-for-x86_64-resilientstorage-rpms。本文的主备(active/passive)方案使用 HA-LVM,不需要该仓库。
安装集群软件
官方推荐一次性安装全部 fence agent,也可只装需要的型号以减小攻击面。
# 方式 A:安装全部 fence agents(官方默认建议)
dnf install -y pcs pacemaker fence-agents-all
# 方式 B:只装所需 fence agent(把 model 换成实际型号,如 ipmilan)
# dnf install -y pcs pacemaker fence-agents-ipmilan
# 可选:性能数据采集,便于事后分析集群抖动(官方建议)
dnf install -y pcp-zeroconf
# 查看已安装的 fence agents
rpm -q -a | grep fence
# 确认版本
rpm -q pcs pacemaker corosync
03系统准备(两节点)
主机名与解析
集群使用节点名进行通信与 fencing 映射,解析必须稳定可靠。
# 在 node1 上
hostnamectl set-hostname node1.example.com
# 在 node2 上
# hostnamectl set-hostname node2.example.com
# 两节点都写入 /etc/hosts(即使有 DNS 也建议写,避免 DNS 故障影响集群)
cat >> /etc/hosts <<'EOF'
192.168.10.11 node1.example.com node1
192.168.10.12 node2.example.com node2
192.168.10.20 qnetd.example.com qnetd
EOF
# 验证:两节点互 ping FQDN
ping -c2 node1.example.com
ping -c2 node2.example.com
hostname -f
时间同步
时间不一致会导致日志难以关联、部分资源代理行为异常。
dnf install -y chrony
systemctl enable --now chronyd
chronyc sources -v
chronyc tracking # 确认 System time 偏差很小
timedatectl # 确认时区一致、NTP 已同步
防火墙放行
firewalld 内置 high-availability 服务,一条命令覆盖所有必需端口。
firewall-cmd --permanent --add-service=high-availability
firewall-cmd --add-service=high-availability
firewall-cmd --list-services
# 如使用 qdevice,仲裁主机与节点间还需 5403/tcp(high-availability 已含)
# 如后续使用 Pacemaker Remote:3121/tcp;GFS2/DLM:21064/tcp;Booth:9929
| 端口 | 协议 | 用途 | 本方案是否需要 |
|---|---|---|---|
| 2224 | TCP | pcsd,节点间通信与认证 | 必需 |
| 5404–5412 | UDP | corosync 节点间通信 | 必需 |
| 5403 | TCP | corosync-qnetd 仲裁设备 | 使用 qdevice 时必需 |
| 3121 | TCP | Pacemaker Remote 节点 | 本方案不需要 |
| 21064 | TCP | DLM(GFS2) | 本方案不需要 |
| 9929 | TCP/UDP | Booth 多站点 | 本方案不需要 |
设置 hacluster 密码并启动 pcsd
hacluster 是安装 pcs 时自动创建的管理账户,两节点密码建议保持一致。
# 设置 hacluster 密码(两节点使用相同密码)
passwd hacluster
# 启动并设置开机自启
systemctl start pcsd.service
systemctl enable pcsd.service
# 验证
systemctl status pcsd.service --no-pager
ss -lntp | grep 2224
保持 enforcing。RHEL 的集群组件与常用资源代理均已适配 SELinux 策略。若某个自定义应用被拦截,正确做法是用 ausearch -m avc -ts recent 分析后添加策略模块,而不是关闭 SELinux。
04节点认证与集群创建
节点认证
RHEL 8 起使用 pcs host auth(取代了旧版的 pcs cluster auth)。只需在一个节点执行。
pcs host auth node1.example.com node2.example.com
# Username: hacluster
# Password: ********
# 预期输出:
# node1.example.com: Authorized
# node2.example.com: Authorized
# 非交互方式(脚本化部署时使用,注意密码会进 history)
# pcs host auth node1.example.com node2.example.com -u hacluster -p 'YourPassword'
创建集群
推荐直接使用双心跳链路创建。多个 addr= 按出现顺序对应 link0、link1。
# —— 推荐:双心跳链路 ——
pcs cluster setup my_cluster --start \
node1.example.com addr=192.168.20.11 addr=192.168.30.11 \
node2.example.com addr=192.168.20.12 addr=192.168.30.12
# —— 最简形式(单链路,仅实验用)——
# pcs cluster setup my_cluster --start node1.example.com node2.example.com
# 设置开机自启(否则节点重启后需手工 pcs cluster start)
pcs cluster enable --all
验证集群已就绪
这是第一个关卡,必须两节点均为 Online 才能继续。
pcs cluster status # 集群服务状态
pcs status # 总览:节点 / 资源 / 守护进程
pcs status --full # 含 failcount 等详细信息
pcs cluster config # 查看生成的 corosync 配置
pcs quorum status # 票数与 quorum
corosync-cfgtool -s # 两条 link 都应为 connected
# pcs status 期望输出(节选)
Cluster name: my_cluster
Cluster Summary:
* Stack: corosync
* Current DC: node1.example.com (version ...) - partition with quorum
* 2 nodes configured
* 0 resource instances configured
Node List:
* Online: [ node1.example.com node2.example.com ] <== 两节点均 Online
Daemon Status:
corosync: active/enabled
pacemaker: active/enabled
pcsd: active/enabled
确认 two_node 已自动写入
双节点集群,pcs cluster setup 会自动在 corosync 配置中写入 two_node: 1。
grep -A5 '^quorum' /etc/corosync/corosync.conf
# 期望看到:
# quorum {
# provider: corosync_votequorum
# two_node: 1
# }
pcs quorum config
corosync-quorumtool -s
05双节点特有风险与对策
双节点是最常见、也是最危险的集群规模。本章的内容决定了这套集群在真实故障中是"优雅切换"还是"数据损坏"。
5.1 two_node 与 wait_for_all
| 参数 | 行为 | 解决什么 | 引入什么风险 |
|---|---|---|---|
two_node: 1 | quorum 计算改为"有 1 票即算有 quorum" | 否则任一节点故障就整体停摆,HA 形同虚设 | 网络分区时两边都认为自己有 quorum → 脑裂 |
wait_for_all | 集群首次启动时必须看到全部节点才获得 quorum;two_node: 1 时自动隐式启用社区 votequorum(5) | 防止冷启动时两台机器各自成群 | 两台都断电后,必须两台都起来集群才恢复服务 |
two_node: 1 把"防脑裂"的责任全部转移给了 fencing。这就是为什么双节点集群必须配置可靠的 fencing,并且强烈建议再加一个 qdevice 把票数变成 3。
5.2 脑裂场景推演
5.3 Fencing 竞态的两种对策
# 负责打 node1 的设备立即动手;负责打 node2 的设备等 10 秒
# 结果:脑裂时 node2 总是先被打掉,node1 胜出(确定性)
pcs stonith update fence-node1 pcmk_delay_base=0s
pcs stonith update fence-node2 pcmk_delay_base=10s
# 或使用随机延迟打破对称(不确定谁赢,但一定不会互杀)
# pcs stonith update fence-node1 pcmk_delay_max=15s
# pcs stonith update fence-node2 pcmk_delay_max=15s
# 给重要资源设置 priority,集群会让"承载高优先级资源较少"的节点延迟 fence,
# 从而更可能被对方先干掉 —— 保住业务更重的一侧。
pcs resource update Website meta priority=10
pcs property set priority-fencing-delay=15s
pcs property config priority-fencing-delay
延迟必须大于 fence 操作本身的耗时,否则起不到错开作用。IPMI 通常 5–10 秒可完成,因此 priority-fencing-delay 建议设为 15s 或更高。可用 time pcs stonith fence <node> 实测再定。
06Quorum Device 配置
qdevice 让双节点集群拥有第 3 票,从根本上消除对半分裂的歧义。生产双节点集群强烈建议部署。RHEL10 官方 Ch.28
准备仲裁主机
一台独立的 RHEL 主机即可,不安装 pacemaker,不参与资源运行;可被多个集群共用。
dnf install -y pcs corosync-qnetd
systemctl start pcsd.service
systemctl enable pcsd.service
# 设置 hacluster 密码(与集群节点保持一致更便于管理)
passwd hacluster
# 初始化并启动 qnetd 服务
pcs qdevice setup model net --enable --start
# 放行端口
firewall-cmd --permanent --add-service=high-availability
firewall-cmd --add-service=high-availability
# 验证
pcs qdevice status net --full
ss -lntp | grep 5403
集群节点安装 qdevice 客户端
dnf install -y corosync-qdevice
认证仲裁主机并加入集群
# 先认证仲裁主机
pcs host auth qnetd.example.com
# Username: hacluster / Password: ********
# 加入 quorum device(ffsplit 为默认算法)
pcs quorum device add model net \
host=qnetd.example.com \
algorithm=ffsplit
# 验证
pcs quorum config
pcs quorum status
pcs quorum device status
# pcs quorum status 期望输出(节选)
Quorum information
------------------
Nodes: 2
Node ID: 1
Quorate: Yes
Votequorum information
----------------------
Expected votes: 3 <== 变成 3 票了
Highest expected: 3
Total votes: 3
Quorum: 2
Flags: Quorate Qdevice
Membership information
----------------------
Nodeid Votes Qdevice Name
1 1 A,V,NMW node1.example.com (local)
2 1 A,V,NMW node2.example.com
0 1 Qdevice
| 算法 | 行为 | 适用 |
|---|---|---|
ffsplit(默认) | 对半分裂时,qnetd 只把票投给一个分区(按启发式规则裁决) | 双节点标准选择 |
lms(last man standing) | 只要还能连上 qnetd,即使只剩最后一个节点也保持 quorum | 希望"最后一台也能撑住"的场景,但需确保 fencing 绝对可靠 |
pcs quorum device update model algorithm=lms
pcs quorum device remove # 从集群移除 qdevice
# 在仲裁主机上销毁:pcs qdevice destroy net
07Fencing / STONITH 实操
fencing 未验证通过之前,不要配置任何业务资源。
确认可用的 fence agent
pcs stonith list # 全部可用 agent
pcs stonith list ipmi # 关键字过滤
pcs stonith describe fence_ipmilan # 查看参数说明(配置前必看)
# 先用命令行直接测试 fence agent 能否连通设备(不经过集群)
fence_ipmilan -a 10.10.10.12 -l fenceuser -p 'FencePass' \
--lanplus -o status
7.1 方案 A:fence_ipmilan(物理服务器,最常见)
# 负责隔离 node1 的设备(指向 node1 的 BMC)
pcs stonith create fence-node1 fence_ipmilan \
ip=10.10.10.11 \
username=fenceuser password='FencePass' \
lanplus=1 \
pcmk_host_list="node1.example.com" \
pcmk_delay_base=0s \
op monitor interval=60s
# 负责隔离 node2 的设备(指向 node2 的 BMC)
pcs stonith create fence-node2 fence_ipmilan \
ip=10.10.10.12 \
username=fenceuser password='FencePass' \
lanplus=1 \
pcmk_host_list="node2.example.com" \
pcmk_delay_base=10s \
op monitor interval=60s
# 避免 fence 设备资源运行在它要隔离的那个节点上
pcs constraint location fence-node1 avoids node1.example.com=INFINITY
pcs constraint location fence-node2 avoids node2.example.com=INFINITY
pcs stonith config
pcs stonith status
7.2 方案 B:fence_vmware_rest(VMware 虚机)
# 先确认能列出虚机(验证凭据与连通性)
fence_vmware_rest -a vcenter.example.com \
-l 'fenceuser@vsphere.local' -p 'FencePass' \
--ssl-insecure -o list | grep -Ei 'node1|node2'
# 单个 stonith 资源即可管理两台虚机(用 pcmk_host_map 做映射)
pcs stonith create fence-vmware fence_vmware_rest \
ip=vcenter.example.com \
username='fenceuser@vsphere.local' password='FencePass' \
ssl=1 ssl_insecure=1 \
pcmk_host_map="node1.example.com:RHEL10-node1;node2.example.com:RHEL10-node2" \
pcmk_delay_max=15s \
op monitor interval=60s
格式为 集群节点名:设备上的标识,多个用分号分隔。VMware 场景里"设备上的标识"是 vCenter 中的虚机名称;APC PDU 场景里是插座编号;刀片场景里是槽位号。名字对不上是 fencing 失败最常见的原因。
7.3 方案 C:SBD + Watchdog(无带外管理时)
# ① 两节点安装
dnf install -y sbd fence-agents-sbd
# ② 确认 watchdog 设备存在(硬件 watchdog 优先;虚机可加载 softdog)
ls -l /dev/watchdog*
# modprobe softdog # 仅测试环境
# ③ 在共享存储上创建 SBD 分区(例如 /dev/sdc1,8MB 即可),仅需在一个节点初始化
sbd -d /dev/sdc1 create
sbd -d /dev/sdc1 dump
sbd -d /dev/sdc1 list
# ④ 两节点配置 /etc/sysconfig/sbd
# SBD_DEVICE="/dev/sdc1"
# SBD_WATCHDOG_DEV=/dev/watchdog
# SBD_STARTMODE=always
# ⑤ 启用(需要先停集群)
pcs cluster stop --all
pcs stonith sbd enable --device=/dev/sdc1
pcs cluster start --all
pcs stonith sbd status
# ⑥ 创建 fence_sbd 资源(poison-pill 模式需要)
pcs stonith create fence-sbd fence_sbd devices=/dev/sdc1
watchdog-only 模式(无共享存储)依赖节点在失去 quorum 时自我复位,因此必须配合 qdevice 或三节点才有意义 —— 双节点无仲裁时两边都不会主动认输。另外软件 watchdog(softdog)在内核 hang 死时可能失效,生产环境应使用硬件 watchdog。
启用 stonith 并测试(关键验收点)
# 确认已启用(默认即为 true)
pcs property set stonith-enabled=true
pcs property config stonith-enabled
# ⚠ 真实测试:这会真的重启 node2!请在业务上线前完成
pcs stonith fence node2.example.com
# 预期:node2 被重启,pcs status 中短暂显示 OFFLINE,随后自动恢复 Online
watch -n2 pcs status
# 查看 fencing 历史
pcs stonith history show
stonith_admin --history='*'
① pcs stonith fence node2.example.com 返回成功;② node2 确实被重启;③ 反向测试(从 node2 fence node1)同样成功;④ pcs stonith status 中两个 stonith 资源均为 Started。四条全部满足,才可进入下一章。
7.4 可选:多级 fencing
# 第 1 级 IPMI,失败后第 2 级切 PDU 电源
pcs stonith level add 1 node1.example.com fence-node1
pcs stonith level add 2 node1.example.com fence-pdu-node1
pcs stonith level add 1 node2.example.com fence-node2
pcs stonith level add 2 node2.example.com fence-pdu-node2
pcs stonith level config
08存储与 LVM 准备
本方案采用 HA-LVM(system_id 模式):同一时刻只有一个节点激活并挂载卷组。相比 GFS2 更简单、性能更好,是主备场景的标准做法。
下列命令会销毁磁盘数据。执行前务必确认 /dev/sdb 是规划中的共享盘,且两节点看到的是同一个 LUN(用 lsblk -o NAME,SIZE,WWN 或 multipath -ll 核对 WWN)。
配置 LVM system_id
让 VG 打上"归属节点"标记,防止另一节点误激活。
# 将 system_id_source 设为 uname
sed -i 's/^\s*#\?\s*system_id_source\s*=.*/\tsystem_id_source = "uname"/' /etc/lvm/lvm.conf
# 验证:应返回本机 hostname
lvm systemid
grep -E '^\s*system_id_source' /etc/lvm/lvm.conf
创建 VG / LV / 文件系统
只在 node1 执行一次。--setautoactivation n 关键:禁止开机自动激活,必须由集群控制。
# 分区(也可直接用整盘)
parted -s /dev/sdb mklabel gpt
parted -s /dev/sdb mkpart primary 0% 100%
partprobe /dev/sdb
# 加入 LVM devices 文件(RHEL 9+ 默认启用 devices file)
lvmdevices --adddev /dev/sdb1
# 创建 VG:禁止自动激活,交给集群管理
vgcreate --setautoactivation n my_vg /dev/sdb1
# 创建 LV 与文件系统
lvcreate -L 10G -n my_lv my_vg
mkfs.xfs /dev/my_vg/my_lv
# 确认 VG 的 system id 已打上 node1
vgs -o+systemid
lvmdevices --adddev /dev/sdb1
pvscan --cache
vgs -o+systemid # 应能看到 my_vg,system id 为 node1(当前归属)
不要把共享 LV 写入 /etc/fstab!挂载必须完全由集群的 Filesystem 资源控制。写入 fstab 会导致两节点开机同时挂载 → XFS 文件系统损坏。
09资源与约束配置
以官方的 Apache 主动/被动示例为模板。RHEL10 官方 Ch.4 其他业务(NFS、数据库、自研应用)可套用同样的结构。
准备 Apache
注意:不要 enable httpd,服务由集群拉起。
dnf install -y httpd wget
# apache 资源代理需要通过 server-status 探测健康,必须配置
cat > /etc/httpd/conf.d/status.conf <<'EOF'
<Location /server-status>
SetHandler server-status
Require local
</Location>
EOF
# ⚠ 关键:禁止 systemd 自启,避免与集群抢管理权
systemctl disable --now httpd
# 防火墙放行 http
firewall-cmd --permanent --add-service=http
firewall-cmd --add-service=http
# 临时激活并挂载(配置完资源后会由集群接管)
lvchange -ay my_vg/my_lv
mount /dev/my_vg/my_lv /var/www
mkdir -p /var/www/html /var/www/cgi-bin /var/www/error
restorecon -R /var/www
echo '<html><body>Hello from RHEL 10 HA Cluster</body></html>' \
> /var/www/html/index.html
umount /var/www
lvchange -an my_vg/my_lv
创建资源组(沙箱方式,推荐)
用 pcs -f 离线编辑再一次性提交,避免中间态引起资源抖动。
# ① 导出当前 CIB 到本地文件
pcs cluster cib my_cfg
# ② 在沙箱里创建资源(组内按声明顺序启动,逆序停止,且必定同节点)
pcs -f my_cfg resource create my_lvm ocf:heartbeat:LVM-activate \
vgname=my_vg vg_access_mode=system_id \
--group apachegroup
pcs -f my_cfg resource create my_fs ocf:heartbeat:Filesystem \
device="/dev/my_vg/my_lv" directory="/var/www" fstype="xfs" \
--group apachegroup
pcs -f my_cfg resource create VirtualIP ocf:heartbeat:IPaddr2 \
ip=192.168.10.100 cidr_netmask=24 \
op monitor interval=30s \
--group apachegroup
pcs -f my_cfg resource create Website ocf:heartbeat:apache \
configfile="/etc/httpd/conf/httpd.conf" \
statusurl="http://127.0.0.1/server-status" \
op monitor interval=1min \
--group apachegroup
# ③ 设置默认资源黏性,避免故障节点恢复后资源自动漂回(二次中断)
pcs -f my_cfg resource defaults update resource-stickiness=100
# ④ 校验后一次性提交
crm_verify -x my_cfg -V
pcs cluster cib-push my_cfg --config
# ⑤ 查看
pcs status
pcs resource config apachegroup
资源组自动等价于"组内所有资源 colocation INFINITY + 按顺序 order"。四个资源如果手写约束需要 3 条 order + 3 条 colocation,既繁琐又易错。凡是"必须在同一节点、有严格先后顺序"的一组资源,一律用 group。
9.1 如需手工约束(跨组场景)
# 位置倾向:正常情况下优先跑在 node1
pcs constraint location apachegroup prefers node1.example.com=100
# 共置:Website 必须和 VirtualIP 在一起(A 跟着 B 走)
pcs constraint colocation add Website with VirtualIP INFINITY
# 顺序:先起 VirtualIP 再起 Website
pcs constraint order start VirtualIP then start Website
# 查看 / 删除
pcs constraint --full
pcs constraint delete <constraint_id>
业务连通性验证
pcs status
ip a | grep 192.168.10.100 # VIP 应出现在承载资源的节点上
mount | grep /var/www # 文件系统已挂载
curl http://192.168.10.100 # 应返回 Hello from RHEL 10 HA Cluster
curl http://192.168.10.100/server-status | head
10验证与故障演练
上线前必须完成下列全部测试用例,并记录实际结果。建议在演练时开一个终端持续运行 watch -n1 pcs status 观察。
| # | 测试项 | 操作命令 | 预期结果 |
|---|---|---|---|
| T1 | 计划内切换 | pcs node standby node1.example.com | 资源组整体迁到 node2,curl VIP 中断 < 30s;pcs node unstandby 后因 stickiness=100 不自动漂回 |
| T2 | 手工迁移 | pcs resource move apachegroup node2.example.com | 迁移成功;随后必须执行 pcs resource clear apachegroup 清除临时约束 |
| T3 | 单资源故障 | killall httpd | monitor 检测到失败,集群在原节点重启 Website;pcs status --full 中 failcount +1 |
| T4 | 反复故障触发迁移 | 连续 kill 超过 migration-threshold | 资源被迁到另一节点;pcs resource cleanup 可清零计数 |
| T5 | 节点内核崩溃 | echo c > /proc/sysrq-trigger(在承载资源的节点) | 另一节点 fence 掉它并接管全部资源 |
| T6 | 强制 fencing | pcs stonith fence node2.example.com | node2 重启并自动重新加入集群 |
| T7 | 单心跳链路故障 | 断开 link0 网卡 | 集群不切换,link1 接管;corosync-cfgtool -s 显示 link0 faulty |
| T8 | 全部心跳断开(脑裂) | 同时断开 link0 与 link1 | 有 qdevice:一侧保留 quorum 并 fence 对方;无 qdevice:观察 delay 是否有效避免互杀 |
| T9 | 仲裁主机故障 | 停掉 qnetd | 集群退化为 two_node 模式仍可运行;pcs quorum status 显示 Qdevice 不可用 |
| T10 | 断电恢复 | 两节点同时断电后依次上电 | 因 wait_for_all,需两节点都启动后集群才恢复服务 —— 这是预期行为,需向业务方说明 |
| T11 | 集群整体重启 | pcs cluster stop --all → pcs cluster start --all | 资源自动恢复到正常状态 |
# 实时观察
watch -n1 'pcs status --full'
crm_mon -f # 交互式,含 failcount
# 客户端侧观察中断时长
while true; do curl -s -o /dev/null -w "%{http_code} " \
--max-time 2 http://192.168.10.100; sleep 1; done
# standby / unstandby
pcs node standby node1.example.com
pcs node unstandby node1.example.com
# 迁移后务必清理临时约束(否则资源被"钉死")
pcs resource move apachegroup node2.example.com
pcs constraint --full | grep -i "cli-"
pcs resource clear apachegroup
# 清理失败计数
pcs resource failcount show --full
pcs resource cleanup Website
pcs resource move 会创建一条 cli-prefer-* 的 -INFINITY location 约束把资源"钉"在目标节点。如果不执行 pcs resource clear,这条约束会永久存在,导致后续故障时资源无法回到原节点。每次 move 之后立刻 clear,养成习惯。
11日常运维与排错
11.1 巡检命令
pcs status --full # 总览 + failcount
pcs cluster status
pcs quorum status
pcs stonith status
pcs constraint --full
pcs config # 完整配置快照
crm_mon -1 -A # 含节点属性
crm_verify -L -V # 校验配置合法性(应无输出)
corosync-cfgtool -s # 心跳链路健康
11.2 计划内维护
# —— 单节点维护(打补丁、换硬件)——
pcs node standby node2.example.com # 资源迁走
# ... 维护操作、重启 ...
pcs node unstandby node2.example.com
pcs status # 确认重新 Online
# —— 全集群维护模式(集群只监控不动作)——
pcs property set maintenance-mode=true
# ... 手工操作资源 ...
pcs resource refresh # 重新探测真实状态
pcs property set maintenance-mode=false
# —— 单个资源不受管 ——
pcs resource unmanage Website
pcs resource manage Website
# —— 停用/启用资源 ——
pcs resource disable apachegroup
pcs resource enable apachegroup
11.3 配置备份与恢复
# 官方备份/恢复(打包 CIB + corosync 配置)
pcs config backup /root/cluster_backup_$(date +%F)
pcs config restore /root/cluster_backup_2026-08-09.tar.bz2
# 额外导出为可复现的命令脚本(做变更前强烈建议)
pcs cluster cib > /root/cib_$(date +%F).xml
pcs resource config --output-format=cmd > /root/resources.sh
pcs constraint config --output-format=cmd > /root/constraints.sh
11.4 排错决策树
| 现象 | 先查什么 | 常见根因 |
|---|---|---|
节点显示 UNCLEAN (offline),资源不切换 | pcs stonith status / pcs stonith history show | fencing 失败:BMC 不可达、凭据过期、pcmk_host_map 名字对不上 |
资源 Stopped 且不启动 | pcs status --full 看 Failed Actions;pcs resource debug-start <rsc> | RA 参数错误、依赖资源未起、存储不可用、SELinux 拦截 |
| 资源在两节点反复漂移 | pcs resource failcount show --full | monitor 超时太短、应用本身不稳定、resource-stickiness=0 |
| 资源被"钉"在某节点回不去 | pcs constraint --full | grep cli- | 之前 pcs resource move 后忘了 clear |
| 集群失去 quorum,资源全停 | pcs quorum status | 心跳全断、qdevice 不可达、no-quorum-policy=stop(默认行为) |
| 节点重启后不自动加入 | systemctl is-enabled corosync pacemaker | 忘了执行 pcs cluster enable --all |
| 两节点都挂载了共享 FS | 立即 umount 一侧并检查文件系统 | 写了 /etc/fstab、或 fencing 未生效导致脑裂 |
| 找不到原因 | pcs cluster report --from "YYYY-MM-DD H:M" /tmp/report | 打包全集群日志提交 Red Hat Support |
journalctl -u pacemaker -u corosync --since "30 min ago"
tail -f /var/log/pacemaker/pacemaker.log
tail -f /var/log/cluster/corosync.log
grep -Ei 'fence|stonith|error|Transition' /var/log/messages | tail -50
# 一键打包全集群日志与配置(提交支持时使用)
pcs cluster report --from "2026-08-09 08:00" /tmp/cluster_report
12避坑清单与最佳实践
生产环境关闭 fencing
stonith-enabled=false 意味着放弃数据完整性保护,Red Hat 不提供支持。只在无共享存储的纯功能演示环境临时使用。
共享 LV 写入 /etc/fstab
会导致开机双挂载,XFS 直接损坏。挂载必须由 Filesystem 资源独占控制。
集群管理的服务 systemctl enable
httpd、nfs-server 等交给集群后必须 systemctl disable,否则与集群抢管理权。
手工编辑 corosync.conf / cib.xml
官方明确要求通过 pcs / Web 控制台 / ha_cluster 系统角色修改,手改会被覆盖或造成不一致。
用 NetworkManager 配置 VIP
浮动 IP 必须由 IPaddr2 资源管理。静态配置会与集群冲突导致 IP 冲突。
每个资源都配 monitor
没有 monitor 操作 = 集群看不到故障 = 假 HA。op monitor interval=30s。
设置正的 resource-stickiness
建议 100。避免故障节点恢复后资源自动漂回造成二次中断。
双心跳链路 + 独立带外网
单链路故障不应触发切换;fence 路径不能与心跳共用交换机。
部署 qdevice
把双节点变成 3 票模型,彻底消除脑裂歧义。仲裁主机成本极低。
move 之后立刻 clear
pcs resource move 会留下 cli-prefer 约束,不清理会影响后续故障切换。
变更用 pcs -f 沙箱
多条命令的配置变更先导出 CIB 离线编辑,crm_verify 校验后一次性 cib-push。
上线前跑完全部演练用例
特别是 T5(内核崩溃)与 T8(脑裂)。没演练过的切换等于没有 HA。
12.1 关键参数推荐值
| 参数 | 推荐值 | 理由 |
|---|---|---|
stonith-enabled | true | 生产必须 |
no-quorum-policy | stop(默认) | 失去 quorum 时停资源最安全;GFS2 场景才用 freeze |
resource-stickiness(默认) | 100 | 避免资源自动漂回 |
priority-fencing-delay | 15s 起 | 必须大于一次 fence 操作耗时 |
pcmk_delay_base | node1=0s / node2=10s | 确定性打破 fencing 竞态 |
| qdevice algorithm | ffsplit | 双节点标准选择 |
| 心跳链路数 | 2 | knet 支持最多 8 条,2 条已能覆盖绝大多数故障 |
migration-threshold | 视应用而定,常用 3 | 避免单次抖动就迁移 |
13附录:全量命令 / 交付表
13.1 从零到可用 —— 完整命令序列
#=========== [两节点] 1. 仓库与安装 ===========
subscription-manager repos --enable=rhel-10-for-x86_64-highavailability-rpms
dnf install -y pcs pacemaker fence-agents-all pcp-zeroconf corosync-qdevice
#=========== [两节点] 2. 系统准备 ===========
hostnamectl set-hostname node1.example.com # node2 上改成 node2
cat >> /etc/hosts <<'EOF'
192.168.10.11 node1.example.com node1
192.168.10.12 node2.example.com node2
192.168.10.20 qnetd.example.com qnetd
EOF
dnf install -y chrony && systemctl enable --now chronyd
firewall-cmd --permanent --add-service=high-availability
firewall-cmd --add-service=high-availability
echo 'YourPassword' | passwd --stdin hacluster
systemctl enable --now pcsd.service
#=========== [node1] 3. 建集群 ===========
pcs host auth node1.example.com node2.example.com -u hacluster -p 'YourPassword'
pcs cluster setup my_cluster --start \
node1.example.com addr=192.168.20.11 addr=192.168.30.11 \
node2.example.com addr=192.168.20.12 addr=192.168.30.12
pcs cluster enable --all
pcs status
#=========== [仲裁主机] 4. qnetd ===========
# dnf install -y pcs corosync-qnetd
# systemctl enable --now pcsd.service; echo 'YourPassword' | passwd --stdin hacluster
# pcs qdevice setup model net --enable --start
# firewall-cmd --permanent --add-service=high-availability; firewall-cmd --reload
#=========== [node1] 5. 加入 qdevice ===========
pcs host auth qnetd.example.com -u hacluster -p 'YourPassword'
pcs quorum device add model net host=qnetd.example.com algorithm=ffsplit
pcs quorum status
#=========== [node1] 6. Fencing ===========
pcs stonith create fence-node1 fence_ipmilan ip=10.10.10.11 \
username=fenceuser password='FencePass' lanplus=1 \
pcmk_host_list="node1.example.com" pcmk_delay_base=0s op monitor interval=60s
pcs stonith create fence-node2 fence_ipmilan ip=10.10.10.12 \
username=fenceuser password='FencePass' lanplus=1 \
pcmk_host_list="node2.example.com" pcmk_delay_base=10s op monitor interval=60s
pcs constraint location fence-node1 avoids node1.example.com=INFINITY
pcs constraint location fence-node2 avoids node2.example.com=INFINITY
pcs property set stonith-enabled=true
pcs property set priority-fencing-delay=15s
pcs stonith fence node2.example.com # ⚠ 验收测试
#=========== [两节点] 7. LVM + Apache 准备 ===========
sed -i 's/^\s*#\?\s*system_id_source\s*=.*/\tsystem_id_source = "uname"/' /etc/lvm/lvm.conf
dnf install -y httpd
printf '<Location /server-status>\n SetHandler server-status\n Require local\n</Location>\n' \
> /etc/httpd/conf.d/status.conf
systemctl disable --now httpd
firewall-cmd --permanent --add-service=http && firewall-cmd --add-service=http
#=========== [node1] 8. 存储 ===========
lvmdevices --adddev /dev/sdb1
vgcreate --setautoactivation n my_vg /dev/sdb1
lvcreate -L 10G -n my_lv my_vg
mkfs.xfs /dev/my_vg/my_lv
#=========== [node1] 9. 资源 ===========
pcs cluster cib my_cfg
pcs -f my_cfg resource create my_lvm ocf:heartbeat:LVM-activate \
vgname=my_vg vg_access_mode=system_id --group apachegroup
pcs -f my_cfg resource create my_fs ocf:heartbeat:Filesystem \
device="/dev/my_vg/my_lv" directory="/var/www" fstype="xfs" --group apachegroup
pcs -f my_cfg resource create VirtualIP ocf:heartbeat:IPaddr2 \
ip=192.168.10.100 cidr_netmask=24 op monitor interval=30s --group apachegroup
pcs -f my_cfg resource create Website ocf:heartbeat:apache \
configfile="/etc/httpd/conf/httpd.conf" \
statusurl="http://127.0.0.1/server-status" op monitor interval=1min --group apachegroup
pcs -f my_cfg resource defaults update resource-stickiness=100
crm_verify -x my_cfg -V
pcs cluster cib-push my_cfg --config
#=========== [node1] 10. 验收 ===========
pcs status --full
curl http://192.168.10.100
pcs config backup /root/cluster_backup_initial
13.2 交付检查表
- 集群状态:
pcs status两节点 Online,无 Failed Actions - Quorum:
pcs quorum status显示 Expected votes = 3,Flags 含 Quorate Qdevice - 心跳链路:
corosync-cfgtool -s两条 link 均 connected - Fencing:两个方向的
pcs stonith fence测试均成功,stonith-enabled=true - 资源:资源组全部 Started,
curl VIP返回正常业务页面 - 黏性:
resource-stickiness已设为正值 - 开机自启:
pcs cluster enable --all已执行,节点重启后自动加入 - 无残留约束:
pcs constraint --full | grep cli-无输出 - 配置校验:
crm_verify -L -V无输出 - 演练:T1–T11 全部通过并记录
- 备份:
pcs config backup已生成并归档到集群外部 - 文档:IP 规划表、fence 凭据(安全保管)、运维手册已交接
13.3 参考资料
- RHEL 10《Configuring and managing high availability clusters》
- Ch.3 Creating a Red Hat High-Availability cluster with Pacemaker(安装 / 端口表 /
pcs cluster setup) - Ch.4 Configuring an active/passive Apache HTTP server(本文资源配置模板来源)
- Ch.9 Configuring fencing
- Ch.10 Configuring SBD fencing
- Ch.23 Controlling cluster behavior
- Ch.27 Configuring cluster quorum
- Ch.28 Configuring quorum devices
- Ch.32 Performing cluster maintenance
- RHEL 9 同名文档(单页版,用于语法对照)RHEL9 官方
man 5 votequorum/man 5 corosync.conf/man 8 pcs社区
如需理解各组件的内部原理(Corosync、CIB、各守护进程、调度决策流程),请参阅 《RHEL 10 Pacemaker 高可用集群 · 核心模块培训文档》(pacemaker-core-modules-training.html)。