虚拟机里那两块网卡,说断就断——去年帮一个做测试环境的朋友收拾残局,他在 ESXi 上跑一台 CentOS 中间件机器,某天在 vCenter 里调整虚拟交换机,误操作把虚拟网卡摘了一下,机器当场失联,重启后 SSH 连不上,业务也起不来,硬是折腾到半夜。后来复盘,问题不在于误操作本身,而在于这台机器从头到尾只有一块虚拟网卡,没有任何链路冗余可言。这次之后我们决定回炉重做:在 VMware 里给 CentOS 加第二块虚拟网卡,用 Linux Bonding 把两块卡绑成一个逻辑接口 bond0,做一份虚拟机内部的链路冗余。这篇文章就把整个配置过程、模式选型的逻辑、以及一路踩过的坑完整摊开讲一遍。网卡绑定(Bonding,也叫链路聚合、网卡 Team)本身不复杂,但放到虚拟化环境里,VMware 侧的端口组策略、虚拟网卡类型、CentOS 版本之间用 ifcfg 还是 nmcli,这几件事交织在一起,坑就多了。无论你是刚接触 Linux 网络配置的新手,还是想把虚机冗余做扎实的老手,下面这些内容都可以直接照着复现。
1. 先把需求掰开:虚拟化环境里为什么还要做网卡绑定
1.1 虚拟机里断一根"网线"到底会发生什么
很多人第一反应是:虚机里的网卡又不是真的网线,怎么可能断?实际上断的场景比想象中多。VMware 里给虚机做虚拟网卡的热添加、热移除、vMotion 迁移过程中的网络重连、ESXi 主机网卡故障后上行链路切换、甚至有人在 vCenter 里手动把虚拟网卡的"已连接"勾掉,对虚机内部来说都等同于物理机上被人拔了一根网线。单网卡机器遇到这种情况,轻则 SSH 会话僵死需要等超时,重则依赖长连接的中间件直接报错。
CentOS 内核默认对单网卡的感知是很快的,物理链路 down 之后接口状态会立刻变成 DOWN,路由表里的直连路由随之失效。但如果这台机器跑的是数据库、消息队列这类需要稳定长连接的服务,一次十几秒的断链就足以触发客户端重连风暴。Bonding 的价值就在于把两块网卡的链路状态合并成一个逻辑设备的链路状态:任意一块 down,bond0 依然 UP,IP 地址和路由不动,上层应用几乎无感知。这是最朴素、也最核心的诉求。
1.2 Bonding 在虚机里能救什么、救不了什么
这里必须先把话说明白,否则很容易做出一个"看起来做了冗余、实际上没冗余"的架构。
在 VMware 虚拟化环境下,虚机内部的 bonding 真正能覆盖的是虚机内部可见的链路事件:虚拟网卡被断开连接、虚拟网卡对应的虚拟端口异常、guest 内核层面某块网卡的驱动异常。这些场景下 bond0 会触发主备切换,IP 不受影响。
它不能替代的,是 ESXi 主机层面的物理链路冗余。如果你的两台物理交换机之间没有做堆叠,ESXi 的两块物理网卡分别接到不同交换机上,那么物理链路故障的切换逻辑应该做在 vSphere 的虚拟交换机上行链路 Teaming 上,而不是指望虚机内部的两块虚拟网卡去兜底。因为两块虚拟网卡很可能挂在同一个虚拟交换机、走同一条上行链路,物理链路一断,两块 vNIC 一起失联,bond0 也无能为力。
所以正确的理解是:虚机内 bonding 是一层补充,不是一层替代。它解决的是"虚拟网卡这一层"的可用性,物理层的冗余仍然要在 ESXi 上做。把这两层分清楚,后面所有配置决策都会变得顺理成章。我在实际项目里见过把虚机内 bonding 当成物理冗余、结果 ESXi 上一根上联线一拔整机失联的案例,问题就出在没分清层次。
1.3 七种模式怎么挑:从 VMware 标准交换机的限制倒推
Linux Bonding 官方有 0 到 6 共七种模式,每种模式对交换机的要求、对网卡的要求都不一样。放在 VMware 环境里,选择范围会被进一步压缩,因为vSphere 标准交换机(vSwitch)不支持 LACP,只有分布式交换机(vDS)才支持链路聚合组(LAG)。
| 模式 | 名称 | 是否需要交换机配合 | VMware 标准交换机可用性 | 典型适用场景 |
|---|---|---|---|---|
| mode=0 | balance-rr 轮询 | 通常需要 | 需要端口组开启混杂模式等策略 | 对吞吐要求高、能控制交换机侧的实验环境 |
| mode=1 | active-backup 主备 | 不需要 | 完全可用,最稳 | 绝大多数虚机冗余场景 |
| mode=2 | balance-xor | 需要 | 需交换机侧配合 | 特定哈希分流需求 |
| mode=3 | broadcast 广播 | 不需要 | 可用但少见 | 极特殊的高可靠场景 |
| mode=4 | 802.3ad 动态聚合 | 必须支持 LACP | 标准交换机不支持,vDS 可用 | 有 vDS 且交换机侧能配 LACP |
| mode=5 | balance-tlb 自适应发送 | 不需要 | 依赖网卡特性,虚机内支持一般 | 少见 |
| mode=6 | balance-alb 自适应负载 | 不需要 | 需网卡支持改 MAC,虚机内支持一般 | 无需交换机配置的负载均衡尝试 |
我的建议很直接:在 VMware 标准交换机环境下,优先选 mode=1。原因有三条。第一,它不需要交换机侧任何配合,配置完后立刻生效,排障路径最短。第二,它不改变 bond0 的 MAC 地址策略,切换时 MAC 会跟着走,对上层影响最小。第三,虚拟化环境下虚机的东西向流量通常走虚拟交换机内部,本就不过物理网卡,做负载均衡的收益远没有物理机那么大,用主备模式换取确定性更划算。
如果你手上确实有 vDS,并且交换机侧能配 LACP,那么 mode=4 是可以考虑的,吞吐和冗余都能兼顾。但一定要先确认链路两端都配好,否则会出现"bond0 起来了但一直是 DOWN、slave 全是 BACKUP"的典型现象,后面第 5 章会专门讲这个坑。
2. 实验环境搭建与前置检查
2.1 给虚机加第二块网卡:E1000e 还是 VMXNET3
先在 vCenter(或 ESXi 主机客户端)里把虚机关机,进入"编辑设置",添加一个新的网络适配器。这里有三个选项要慎重。
适配器类型:优先选VMXNET3。它是 VMware 的半虚拟化网卡,驱动在内核里是原生支持的,中断处理效率高,而且对 bonding 的各种模式兼容性最好。E1000e 是模拟的 Intel 千兆卡,兼容性没问题但性能一般,在极端情况下某些队列特性表现不如 VMXNET3。只有在客户机系统非常老、没有 VMXNET3 驱动时才退回 E1000e。
网络连接:两块虚拟网卡建议挂到同一个端口组上。因为要绑成同一个 bond0,两块卡必须在同一个二层广播域里,否则 bond0 的 IP 和网关根本对不上。有人会想着"挂两个不同端口组更冗余",那是另一套思路,前提是两个端口组背后是同一个二层网络,并且交换机侧配置好了对应关系,普通环境别这么折腾。
MAC 地址:保持自动分配,不要手动固定。bond0 的 MAC 默认会继承第一个 slave 的 MAC,手动固定容易在切换时出乱子。
加完之后开机,ip -br link应该能看到两块网卡,名字通常是 ens33 / ens37,或者 ens192 / ens224,取决于虚机硬件版本和 systemd 的可预测命名规则。记住这两个名字,后面所有配置都要用它们。
2.2 vSphere 端口组上那两个容易被忽略的开关
这一步是九成以上的人第一次做虚机内 bonding 会翻车的地方,必须单独拎出来讲。
vSphere 标准交换机的端口组有三项安全策略,默认值全部是"拒绝"(Reject):
- 混杂模式(Promiscuous Mode)
- MAC 地址更改(MAC Address Changes)
- 伪造传输(Forged Transmits)
虚机内部做 bonding 之后,bond0 发出的报文源 MAC 可能是 bond0 自己的 MAC,也可能在切换后变成另一块 slave 的 MAC,这与 ESXi 分配给该虚拟网卡的 MAC 不一定一致。ESXi 的虚拟交换机在默认策略下会直接丢弃这类"源 MAC 与分配 MAC 不符"的帧。表现出来的现象非常迷惑:/proc/net/bonding/bond0显示一切正常,slave 都是 UP,bond0 也是 UP,IP 也配上了,但就是 ping 不通网关,或者只能通一小会儿。
解决方法是把该端口组(或者更细粒度地,该虚机所在端口)的三项安全策略全部改为"接受"(Accept)。在 vSphere Client 里进入该端口组的"编辑设置" → "安全",三项都改成接受,保存即可。
注意:这三项策略是虚拟交换机层面的,改的是 vSphere,不是 CentOS。很多人反复在 guest 里改 bonding 参数,改到最后发现是 ESXi 侧在丢包。
改完之后如果还是不通,别急着重启虚机,先把虚机的虚拟网卡"断开再连接"一次,让 ARP 表重新学习,通常就能恢复。
2.3 CentOS 侧的四个前置检查项
环境准备好之后,在 guest 里做四件事,能把后面一半的问题提前排掉。
第一,确认 bonding 内核模块存在。执行modinfo bonding | head -5,如果有输出就说明模块可用。CentOS 7 及以后默认都带,极少出现缺失。顺带执行lsmod | grep bonding看是否已加载,没加载也没关系,配置好之后会自动加载。
第二,确认 NetworkManager 的状态。执行systemctl status NetworkManager。这一步很关键,因为 CentOS 7 之后网络管理有两条路子:NetworkManager 和传统的 network-scripts,两者混用会导致配置被覆盖、重启后配置丢失。原则是只用一套,不要混。CentOS 7 两种都支持,我建议统一用 nmcli;CentOS 8 / Stream 之后 network-scripts 已经被标记为废弃(虽然还能装),更是只能用 nmcli。
第三,确认两块网卡上没有残留配置。执行nmcli connection show,看看有没有之前给 ens33、ens37 建过的连接,有的话用nmcli connection delete <名字>删掉,或者直接把/etc/sysconfig/network-scripts/ifcfg-ens33里多余的 IP 配置清理掉。残留的 IP 配置会和 bond0 抢路由,造成"能通但走错网卡"的怪现象。
第四,确认 IP 规划。因为 bond0 会接管原来那块网卡的全部 IP,改配置的过程中 SSH 会断。稳妥做法是通过 vCenter 的 Web 控制台(或者直接在 ESXi 上开虚机控制台)操作,别指望 SSH 全程不断。这一点听着像废话,但确实有人改到一半连接断了,然后就再也没有然后了。
3. 两种落地方式:ifcfg 与 nmcli 全流程
3.1 传统 network-scripts 方式(CentOS 7)
先讲传统方式,因为它的配置文件直观,出问题容易定位,也是很多老环境的现状。假设两块网卡是ens33和ens37,bond0 规划地址为192.168.10.50/24,网关192.168.10.1,采用 mode=1 主备。
第一步,创建 bond0 的配置文件/etc/sysconfig/network-scripts/ifcfg-bond0:
DEVICE=bond0 NAME=bond0 TYPE=Bond BONDING_MASTER=yes BOOTPROTO=none IPADDR=192.168.10.50 PREFIX=24 GATEWAY=192.168.10.1 DNS1=192.168.10.2 ONBOOT=yes NM_CONTROLLED=no BONDING_OPTS="mode=active-backup miimon=100 primary=ens33 updelay=200 downdelay=200"这里几个字段值得单独解释。TYPE=Bond明确告诉系统这是一个 bonding 主设备,不能省。BONDING_MASTER=yes是配套标记,缺了它某些版本下 bond0 不会自动拉起。NM_CONTROLLED=no表示这个接口不受 NetworkManager 管辖,走传统脚本——但如果你打算整套都用传统方式,那两块 slave 卡也必须写NM_CONTROLLED=no,否则会出现"master 归传统管、slave 归 NM 管"的撕扯。BONDING_OPTS是核心,里面用空格分隔各个参数,后面 3.3 节会逐个算清楚。
第二步,改两块 slave 卡的配置。/etc/sysconfig/network-scripts/ifcfg-ens33:
TYPE=Ethernet NAME=ens33 DEVICE=ens33 BOOTPROTO=none ONBOOT=yes MASTER=bond0 SLAVE=yes NM_CONTROLLED=noens37同理,只改NAME和DEVICE。注意 slave 卡里绝对不能有 IPADDR、GATEWAY、DNS,这些全部归 bond0。留着的话,开机时两个接口抢同一网段的路由,会出现"时通时不通"。
第三步,可选但推荐,创建/etc/modprobe.d/bonding.conf:
alias bond0 bonding options bonding max_bonds=1现代 systemd 环境下这一步不是必需的,ifcfg 里的TYPE=Bond已经能触发模块加载和接口创建。但加上没坏处,尤其在老版本内核上能规避"bond0 不存在"的报错。
第四步,重启网络。CentOS 7 上执行systemctl restart network,或者更稳妥地先ifdown ens33再ifup bond0(顺序很重要,先下后上)。如果 systemctl 走的还是 NetworkManager,可能会报冲突,那就用nmcli connection reload加systemctl restart network组合。这也是为什么我更推荐下面这套 nmcli 方案。
3.2 NetworkManager nmcli 方式(CentOS 8 / Stream)
nmcli 的好处是配置集中、命令可追溯、不会出现"改完文件忘记 reload"的问题。整套流程四到五条命令就能拿下,而且 CentOS 7/8/Stream 通用。
第一条,创建 bond 主连接:
nmcli connection add type bond con-name bond0 ifname bond0 \ bond.options "mode=active-backup,miimon=100,primary=ens33,updelay=200,downdelay=200"注意这里的参数分隔符是逗号,跟 ifcfg 里的空格不一样,这是很多人复制粘贴出错的地方。
第二条,把两块物理网卡加成 slave:
nmcli connection add type ethernet con-name bond0-slave1 ifname ens33 master bond0 nmcli connection add type ethernet con-name bond0-slave2 ifname ens37 master bond0master bond0这个参数是关键,它会在 slave 的连接配置里自动写入master=bond0和slave-type=bond,不用手工去改文件。
第三条,给 bond0 配 IP:
nmcli connection modify bond0 \ ipv4.method manual \ ipv4.addresses 192.168.10.50/24 \ ipv4.gateway 192.168.10.1 \ ipv4.dns 192.168.10.2 \ connection.autoconnect yes第四条,拉起连接。顺序是先 slave 后 master,虽然 nmcli 一般能自动处理依赖,但显式激活更稳:
nmcli connection up bond0-slave1 nmcli connection up bond0-slave2 nmcli connection up bond0如果需要清理残留,用nmcli connection delete "Wired connection 1"这类命令把自动生成的默认连接删掉,避免它们开机抢跑。
提示:CentOS 8 之后配置文件位置从
/etc/sysconfig/network-scripts/挪到了/etc/NetworkManager/system-connections/,文件名形如bond0.nmconnection。想备份配置的话去这个目录拷,别再去老路径找。
3.3 关键参数怎么算:miimon、updelay、downdelay、xmit_hash_policy
BONDING_OPTS里那一串参数不是随便填的,每一个都影响故障检测的灵敏度和稳定性。我按重要性挨个说。
miimon=100:链路监测间隔,单位毫秒。100 表示每 100ms 用 MII 机制查询一次 slave 的物理链路状态。这个值不能太小,太小会频繁轮询增加开销;也不能太大,太大故障发现变慢。100ms 是业界默认值,对应最快 100ms 内发现链路 down。如果你的业务对中断极其敏感,可以调到 50;如果虚机 CPU 紧张,调到 200 也完全可以。
updelay / downdelay:单位毫秒,分别表示"链路恢复后延迟多久才把 slave 加回 bond"和"链路断开后延迟多久才把 slave 移出 bond"。它们是 miimon 的整数倍才生效。设为 200 意味着要连续两个监测周期都判定异常才动作,目的是防止链路抖动导致频繁切换。虚拟化环境里链路状态偶尔抖一下很常见(比如 vMotion 过程中的瞬间重连),加了延迟能避免"刚切过去又切回来"的来回横跳。建议 updelay 和 downdelay 都设成 miimon 的 2 到 5 倍。
primary=ens33:指定主用网卡。mode=1 下不加这个参数,系统会选第一个 UP 的 slave 当主用;加了之后会优先用 ens33,只有当 ens33 彻底不可用时才切到 ens37,切回来时也会优先回到 ens33。这个参数的价值在于避免"谁先起来谁当主"的随机性,让流量走向可预期,排查问题时心里有数。
xmit_hash_policy:只有 mode=2、4 这类需要哈希分流的模式才用得上,mode=1 下无效。可选 layer2、layer3+4、layer2+3 等。layer3+4 会按源/目的 IP 加端口做哈希,分流更均匀;layer2 只看 MAC。如果做 mode=4,我一般用xmit_hash_policy=layer3+4,因为虚机之间的流量端口变化多,按四层哈希分布更均衡。
arp_interval / arp_ip_target:这是另一套链路检测机制,用 ARP 请求探测对端是否可达,能发现"链路 UP 但对端不通"的情况。miimon 和 arp_interval 只能二选一,不能同时开,同时开的话内核会直接拒绝加载 bonding 参数。绝大多数场景用 miimon 就够了,只有在链路状态正常但实际已经黑洞的场景才考虑 ARP 检测。
3.4 上线后的验证动作清单
配置完不能只看ip a显示 bond0 有 IP 就完事,得逐层验证。我习惯按下面这个顺序走一遍,五分钟能全部跑完。
第一层,看接口状态:
ip -br addr show期望输出里 bond0 是 UP 并且带规划好的 IP,ens33 和 ens37 也是 UP 但没有 IP。如果 slave 上还挂着 IP,说明 3.1 或 3.2 里某一步没清干净。
第二层,看 bonding 详细状态:
cat /proc/net/bonding/bond0这是最重要的一条命令,输出里会明确列出 Bonding Mode、Currently Active Slave、MII Status,以及每个 slave 的 MII Status 和 State。mode=1 正常情况下应该是:一块State: ACTIVE,另一块State: BACKUP,两块 MII Status 都是 up。
第三层,看链路速率和双工:
ethtool bond0关注 Speed 和 Duplex 两行。虚机里通常是 10000Mb/s 全双工,如果显示 Unknown 或者 0,说明链路协商有问题,得回头查 vSphere 侧的端口组配置。
第四层,验证实际连通性:
ping -c 4 192.168.10.1 ping -c 4 -I bond0 192.168.10.2第二条命令强制从 bond0 发包,能验证源地址选择是否正确。有些环境里默认路由走的是另一块网卡,不加-I测不出 bond0 的真实状态。
第五层,看 bonding 模块参数是否真的生效:
cat /sys/class/net/bond0/bonding/mode cat /sys/class/net/bond0/bonding/miimon这里的值是内核实际在用的,跟配置文件里的对比一下,能发现"配置文件写了但没生效"的问题。这种情况在 nmcli 和 ifcfg 混用时特别常见。
4. 故障切换实测:把网卡真拔了看它扛不扛
4.1 三种模拟断链的手法与差异
配置完必须做切换测试,不然你永远不知道它是不是真的能扛。测试手段有三种,效果和真实性差别很大。
第一种,软件层 down 接口:ip link set ens33 down。这是最轻量的方式,直接在 guest 内核里把接口置为 down。bond0 会立刻通过 miimon 检测到,触发切换。优点是不用碰 vSphere,随时可做;缺点是它测的是 guest 内核的检测逻辑,绕过了虚拟网卡和虚拟交换机这一层。
第二种,nmcli 断开连接:nmcli device disconnect ens33。这个更接近"虚拟网卡被断开"的真实场景,因为 NetworkManager 会真正去操作设备状态,效果接近在 vCenter 里把网卡的"已连接"勾掉。我一般用这个做主力测试。
第三种,vCenter 里操作:在虚机设置里把某块网络适配器的"已连接"取消勾选。这是最贴近真实故障的模拟,因为它连虚拟交换机那一层的连接都断开了。缺点是要切界面,操作慢,而且如果操作失误(比如把两块都断了)会直接失联。
我的建议是三种都跑一遍,至少跑第一种和第三种。第一种验证配置逻辑,第三种验证真实链路。
4.2 观察 /proc/net/bonding/bond0 的状态跃迁
测试的时候要一边操作一边刷这个文件,才能看到状态变化的过程。开两个终端,一个挂着:
watch -n 0.5 'cat /proc/net/bonding/bond0'另一个终端执行ip link set ens33 down。正常情况下你会看到这样一段跃迁:先是 ens33 的MII Status从 up 变成 down,但因为设了downdelay=200,它会保持 ACTIVE 状态约 200ms;然后Currently Active Slave从 ens33 变成 ens37,ens33 的 State 变成 DOWN,ens37 从 BACKUP 变成 ACTIVE。整个过程应该在 300ms 到 500ms 内完成。
与此同时,另一个终端保持一个持续的 ping:
ping 192.168.10.1你会看到丢 1 到 3 个包然后恢复。如果丢包超过 5 个,说明 updelay/downdelay 设得太保守,或者 miimon 间隔太大,可以把 miimon 降到 50 再测。
再执行ip link set ens33 up,观察回切。因为设了primary=ens33,bond0 会重新把 ens33 切回 ACTIVE,ens37 退回 BACKUP。回切过程同样会丢一两个包,这属于正常现象,主备模式做不到零丢包。
4.3 回切测试与 ARP 缓存问题
回切测试里有一个特别隐蔽的问题:对端设备的 ARP 缓存。bond0 切换 slave 的时候,如果两块网卡的 MAC 不一样(mode=1 下 bond0 的 MAC 会跟着走,但某些配置下可能不一致),对端的 ARP 表里还记着旧 MAC,切换后对端仍然往旧 MAC 发包,结果就是"本地看状态一切正常,但业务不通,要等 ARP 老化之后才恢复"。
判断方法很简单:切换后立刻在本地arp -n看网关的 MAC,再在网关上查对应 ARP 记录,两边对不上就是这个问题。处理方式有两个:一是在交换机或网关上清一下 ARP 表;二是等它自然老化(通常 300 秒以内)。
这也是我坚持在虚机环境用 mode=1 而不是 mode=0 的原因之一。mode=1 下 bond0 的 MAC 是固定的(继承第一个 slave),切换时不会变;mode=0 下不同 slave 各自用自己的 MAC 发包,对端 ARP 表会频繁更新,问题更多。
5. 常见问题排查实录与避坑清单
5.1 bond0 起不来的五步定位法
bond0 起不来是最常见的问题,症状五花八门:nmcli connection up bond0报错、bond0 根本没有出现在ip link里、bond0 有了但一直是 DOWN。我总结了一套固定的五步定位法,按顺序走,基本都能定位。
第一步,看内核模块状态。lsmod | grep bonding。如果没有输出,执行modprobe bonding手动加载,再试。模块加载失败通常是内核版本不匹配或者被其他模块占用,看dmesg | tail -30里的报错。
第二步,看 systemd 日志。journalctl -u NetworkManager -n 50 --no-pager。这里面会明确写出 NetworkManager 拒绝激活该连接的原因,比如 "bond.options contains invalid value" 这类参数格式错误,一眼就能看出来。
第三步,看 slave 连接是否已经绑到 master 上。nmcli -f NAME,DEVICE,TYPE,MASTER connection show。如果 MASTER 列是空的,说明 slave 没挂上,回到 3.2 第二条命令重新执行。
第四步,看参数拼写。尤其是bond.options里的逗号分隔符。写成空格的话 nmcli 会把整串当做一个 option 名,直接报错。这个错误我见过不止一次,都是复制 ifcfg 的写法直接粘到 nmcli 里。
第五步,看是否有残留连接抢占。nmcli connection show里如果有两个连接都绑定了同一块物理网卡,NetworkManager 会拒绝激活新的。把旧的删掉,nmcli connection delete <名字>。
5.2 重启后配置被打回原形的几类原因
"配好了能用,一重启就没了"是第二高频的问题。根因基本跑不出下面几类。
ifcfg 和 nmcli 混用。手工写了ifcfg-bond0又用 nmcli 建了bond0连接,重启时 NetworkManager 读到的是 nmconnection 文件,把手工写的配置覆盖了。解决办法是确定一套管理方式,另一套的配置文件全部删掉。CentOS 7 上我还见过NM_CONTROLLED=no写在 bond0 上但 fork 写在 slave 上没写,重启后 slave 被 NM 接管,bond0 散架。
忘了 autoconnect。nmcli 建的连接默认connection.autoconnect是 yes,但如果你建的时候显式设过 no,或者从别处导入的配置,可能不会自动拉起。用nmcli connection modify bond0 connection.autoconnect yes补上。
ONBOOT=no。ifcfg 方式里ONBOOT=yes是必须的,漏了就开机不启动。这个错太低级但确实常见,检查的时候顺手看一眼。
NetworkManager 服务被禁用。systemctl is-enabled NetworkManager,如果是 disabled,nmcli 配的再好也不会生效。CentOS 7 最小化安装有时候默认就是 disabled(因为默认用 network 服务),得手动 enable。
5.3 模式 4 协商不上的真实原因
前面提过 mode=4 在标准交换机上用不了,这里展开说清楚,因为踩这个坑的人太多了。
现象是这样的:配置里写了mode=802.3ad,bond0 能起来,但/proc/net/bonding/bond0里两块 slave 全是MII Status: up而State: BACKUP,一块 ACTIVE 都没有,Aggregator ID是 0,业务完全不通。
根本原因在于 mode=4 要求链路两端通过 LACPDU 报文协商,本端发出去,交换机得回。vSphere 标准交换机会把 LACPDU 当普通组播帧丢弃(它根本不认识这个协议),所以收不到对端回应,协商永远不完成,bond0 就永远处于"没聚合"的状态。
解决方案只有两条:要么换成 vDS 并在 vDS 上配 LAG,交换机侧配动态链路聚合;要么放弃 mode=4,退回 mode=1。没有第三条路。
还有一种迷惑情况:交换机侧确实配了 LACP,但配的是 active 模式而 vDS 侧配的是 passive,或者两边端口数量对不上(一边配了两个口聚合,另一边只有一块网卡参与),也会协商失败。这种情况看交换机侧的 LACP 状态页面,一般能看到 "individual" 而不是 "bundled",就能确认。
5.4 常见问题速查表
| 现象 | 最可能原因 | 快速验证 | 处理方式 |
|---|---|---|---|
| bond0 UP 但 ping 不通网关 | vSphere 端口组安全策略 | 查端口组三项策略 | 三项全部改为"接受" |
| slave 显示 UP 但 State 是 BACKUP 或不显示 | mode=4 协商失败 | 看 Aggregator ID 是否为 0 | 改 mode=1,或换 vDS + LACP |
| 重启后 bond0 消失 | 连接未设 autoconnect 或 NM 未启用 | nmcli connection show看 autoconnect | 设 autoconnect yes,enable NM |
| slave 上有 IP 地址 | 残留 IP 配置未清 | ip -br addr看 slave 是否有 IP | 清掉 slave 连接里的 ipv4.addresses |
| 切换后业务不通但本地正常 | 对端 ARP 缓存陈旧 | 两边比对 ARP 表 MAC | 清对端 ARP 或等老化 |
nmcli connection up报参数错误 | bond.options 用了空格分隔 | 检查命令原文 | 改成逗号分隔 |
| 切换丢包超过 5 个 | miimon 或 updelay 设得过大 | 看bonding/miimon实际值 | miimon 降到 50,updelay 降到 100 |
| 只有一块 slave 生效 | primary 指定的网卡一直是 UP | cat /proc/net/bonding/bond0看 primary | 这是 mode=1 的正常行为,不是故障 |
6. 一些踩过坑之后才明白的事
6.1 虚拟化层与 guest 层的职责边界
做了这么多次,我最大的体会是:别把虚机内 bonding 当成万能药。它解决的是"虚机内部看到的链路可用性",物理链路、ESXi 主机的上联冗余,那是 vSphere 层面该干的事。这两层各干各的,不要互相指望。
具体到实践上,我在 vSphere 侧一般只做两件事:端口组安全策略全开、虚机网卡用 VMXNET3 挂同一端口组。至于 ESXi 的上行链路 Teaming,保持默认的"基于源虚拟端口 ID 的路由"就行,不要在 ESXi 侧也做一套 active/standby,两套切换机制叠在一起,出了故障根本没人能说清楚是哪一层切的。这一点在排障时特别重要——层级越少,定位越快。
6.2 什么时候别用 bonding
最后说点反向的经验。不是所有虚机都值得做 bonding。如果这台机器只是跑个临时测试、做个构建节点、或者业务本身允许多分钟的中断,那折腾这一套的投入产出比并不高,加一块网卡、配一堆参数、还要改 vSphere 策略,出问题排查的时间可能比省下来的还多。
我在实际项目里的判断标准是看两件事:这台机器上有没有长连接类的服务(数据库、消息队列、长轮询接口),以及它断了之后有没有人能立刻感知并处理。两个都是"是",那就老老实实做 bonding;两个都是"否",那就把精力放到别的地方去,比如把备份和监控做扎实,收益更大。
另外提一个实操细节:bonding 配置做完后,记得把/etc/NetworkManager/system-connections/或者/etc/sysconfig/network-scripts/下的相关文件用tar打个包存到别处。虚拟化环境里虚机重装、克隆、迁移都很频繁,下一次遇到同样需求时,直接解压覆盖、改个 IP 和网卡名就能用,比从头再配一遍省一个小时。这个习惯我保持了两年多,救过至少三次场。