资讯详情

多master集群高可用:HAProxy+keepalived负载均衡实战部署

📅 2026/10/12 13:51:34 | 华诺云谱 👁 阅读
多master集群高可用:HAProxy+keepalived负载均衡实战部署
1. 多master架构里为什么必须有个像样的负载均衡搞过多master集群的人都知道单master的时候你只需要关心API Server能不能扛住一旦上了三个甚至五个master节点问题就完全变了。客户端拿着kubeconfig去连集群它到底该连哪个master如果写死了第一个master的IP那台机器一挂整个集群的管理入口就没了哪怕后面还有两台活得好好的也没用。所以多master部署里负载均衡这一层不是可选项而是决定整个控制平面高可用能不能真正落地的关键拼图。我这次要聊的就是多master部署的第二步——把负载均衡层搭起来。这里说的负载均衡核心目标是把客户端对API Server的访问请求均匀且可靠地分发到后端多个master节点上同时还要能感知后端节点的健康状态挂了就自动摘掉恢复了再自动加回来。听起来简单但实际做的时候选什么方案、怎么配健康检查、VIP怎么漂移、和keepalived怎么配合每一步都有坑。这篇文章适合正在搭多master集群、卡在负载均衡这一环的运维和平台工程师也适合那些单master跑久了想升级到高可用架构的朋友。我会从方案选型讲起把HAProxy加keepalived这套经典组合的配置细节、参数计算、健康检查逻辑、故障切换验证全部拆开讲清楚最后再把我踩过的坑和排查经验整理出来。你跟着走一遍基本能直接复现一套可用的高可用负载均衡层。2. 负载均衡方案选型为什么我最终选了HAProxy加keepalived2.1 几种常见方案的横向对比多master场景下的负载均衡市面上能用的方案其实不少但真正适合放在生产控制平面前面的需要同时满足几个条件支持TCP四层转发、能做主动健康检查、性能足够、配置可控、不引入额外复杂度。我先把常见的几种摆出来对比一下。方案工作层级健康检查高可用方式适用场景我的评价HAProxy keepalived四层/七层主动被动VIP漂移生产控制平面首选成熟稳定Nginx 四层stream四层被动为主需配合keepalived中小规模可用但健康检查弱LVS keepalived四层有限VIP漂移超大规模配置复杂杀鸡用牛刀云厂商负载均衡四层完善云平台托管云上环境省心但依赖云kube-vip四层完善ARP/BGP裸金属新选择轻量值得关注HAProxy在四层转发上的性能和稳定性是经过大规模验证的它的健康检查机制特别灵活可以针对后端每个master单独配置检查间隔、超时、失败阈值。keepalived负责VIP的漂移两者配合起来就是一套经典的高可用负载均衡组合。Nginx虽然也能做四层但它的健康检查偏被动后端挂了要等请求失败才发现对控制平面这种关键路径来说不够及时。LVS性能最强但配置和维护成本高多master这种规模用不上。云厂商的负载均衡在云上确实省事但很多自建机房或者混合环境用不了。kube-vip是近几年裸金属场景的新宠用ARP或者BGP宣告VIP确实轻量但生态和排错资料还不如HAProxy成熟。2.2 为什么是HAProxy而不是Nginx这里我单独说一下为什么在控制平面这个场景我更倾向HAProxy。API Server的流量是典型的TCP长连接加短请求混合客户端包括kubectl、kubelet、controller-manager、scheduler等等它们对连接建立的延迟很敏感。HAProxy在四层模式下用事件驱动模型连接建立和转发的开销极低而且它的option tcp-check配合自定义检查脚本可以精确判断后端API Server的/healthz或者/readyz端点是否返回200。Nginx的stream模块做四层转发没问题但它的健康检查要么靠max_fails和fail_timeout这种被动机制要么得上商业版或者第三方模块。被动检查意味着后端已经挂了还要等真实请求打过去失败几次才摘除这中间的时间窗口对控制平面来说就是风险。HAProxy的主动检查可以做到每2秒探测一次连续失败2次就摘除恢复后连续成功2次就加回整个切换过程在秒级完成。2.3 keepalived的角色和VIP规划keepalived在这套架构里负责两件事一是通过VRRP协议在多台负载均衡节点之间选举出master由它持有VIP二是当master故障时VIP能自动漂移到backup节点上。这样客户端只需要配置VIP这一个地址不用关心背后是哪台负载均衡器在干活。VIP的规划有个细节要注意它必须和负载均衡节点在同一网段因为VRRP是基于组播或者单播在二层网络里通信的。我一般会把VIP单独规划成一个不冲突的地址比如负载均衡节点是192.168.10.11和192.168.10.12VIP就用192.168.10.100。这个VIP后续会写进kubeconfig的server字段也会写进kubelet的配置里所以规划的时候要确保它不会被DHCP分配出去最好在交换机或者路由器上做好地址保留。提示VIP所在的网段如果有其他VRRP实例一定要确保virtual_router_id不冲突否则会出现两个master抢同一个VIP的诡异现象。3. 部署前的环境准备和参数规划3.1 节点角色和网络规划在动手之前先把整个拓扑理清楚。假设我们有三个master节点两台负载均衡节点。为什么负载均衡要两台而不是一台因为如果只有一台负载均衡器它本身就是单点VIP漂移没有意义。两台负载均衡器加keepalived才能实现负载均衡层自身的高可用。角色主机名IP地址说明Master1master-01192.168.10.21API Server 6443Master2master-02192.168.10.22API Server 6443Master3master-03192.168.10.23API Server 6443LB1lb-01192.168.10.11HAProxy keepalivedLB2lb-02192.168.10.12HAProxy keepalivedVIP-192.168.10.100客户端访问入口这里有个关键点HAProxy监听的端口要和API Server的端口对应。Kubernetes API Server默认监听6443所以HAProxy的frontend也监听6443backend指向三个master的6443。另外如果你还要转发其他端口比如etcd的2379可以再加frontend但控制平面高可用通常只需要6443。3.2 系统参数和内核调优负载均衡节点上有些内核参数需要调整否则在高并发下会出现连接被丢弃或者端口耗尽的问题。我一般会在/etc/sysctl.d/下加一个配置文件。# /etc/sysctl.d/99-haproxy.conf net.ipv4.ip_nonlocal_bind 1 net.ipv4.tcp_tw_reuse 1 net.ipv4.tcp_fin_timeout 30 net.ipv4.tcp_max_syn_backlog 8192 net.core.somaxconn 8192 net.ipv4.ip_local_port_range 1024 65000net.ipv4.ip_nonlocal_bind 1这个参数特别重要它允许HAProxy绑定到VIP上即使当前节点还没有持有VIP。如果没有这个参数keepalived还没把VIP漂过来的时候HAProxy启动会报错说地址不可用。tcp_tw_reuse让TIME_WAIT状态的连接可以复用对短连接频繁的场景很有帮助。somaxconn和tcp_max_syn_backlog调大可以避免高并发时SYN队列溢出。执行sysctl -p加载后可以用sysctl net.ipv4.ip_nonlocal_bind确认一下值是不是1。3.3 软件安装和版本选择HAProxy和keepalived的安装我建议直接用发行版自带的包管理器版本稳定且依赖处理好了。以常见的RPM系为例yum install -y haproxy keepalived装完之后确认版本HAProxy建议2.0以上keepalived建议2.0以上。这两个版本对四层转发和VRRP的支持都很成熟。如果你用的是DEB系把yum换成apt-get即可。注意不要为了追求最新版去编译安装除非你有明确的特性需求。发行版自带的版本经过了大量测试和系统其他组件的兼容性更好出问题的概率低得多。4. HAProxy配置详解与参数计算4.1 配置文件整体结构HAProxy的配置文件在/etc/haproxy/haproxy.cfg整体分成global、defaults、frontend、backend四大块。我先把完整的配置贴出来然后逐块解释。global log 127.0.0.1 local0 maxconn 40000 daemon nbthread 4 defaults log global mode tcp option tcplog option dontlognull retries 3 timeout connect 5s timeout client 1m timeout server 1m frontend k8s-api bind *:6443 mode tcp option tcplog default_backend k8s-masters backend k8s-masters mode tcp balance roundrobin option tcp-check tcp-check connect port 6443 tcp-check send GET\ /healthz\ HTTP/1.0\r\n\r\n tcp-check expect string ok server master-01 192.168.10.21:6443 check inter 2s fall 2 rise 2 server master-02 192.168.10.22:6443 check inter 2s fall 2 rise 2 server master-03 192.168.10.23:6443 check inter 2s fall 2 rise 24.2 global和defaults块的关键参数maxconn 40000是单个HAProxy进程允许的最大并发连接数。这个值怎么定我一般按每个master能承受的连接数乘以master数量再留点余量。API Server默认的--max-requests-inflight是400--max-mutating-requests-inflight是200但这是请求级别的限制连接级别可以更高。三个master加起来40000是个比较稳妥的值不会成为瓶颈也不会过度消耗文件描述符。nbthread 4指定工作线程数一般设成CPU核心数。如果你的负载均衡节点是4核就设48核就设8。线程数太少压不满CPU太多会有上下文切换开销。timeout connect 5s是HAProxy和后端建立连接的超时时间。API Server正常情况下响应很快5秒足够。timeout client和timeout server设成1分钟是因为kubectl的watch操作会保持长连接如果设太短watch会被频繁断开重连影响使用体验。4.3 健康检查机制的设计逻辑健康检查这块是HAProxy配置里最值得细说的。我用了option tcp-check配合自定义的HTTP检查而不是简单的TCP端口检查。为什么因为TCP端口检查只能判断6443端口是否listen如果API Server进程还在但已经无法正常处理请求比如etcd连接断了端口检查还是会认为它健康流量继续打过去就会失败。tcp-check connect port 6443先建立TCP连接然后tcp-check send发送一个HTTP GET请求到/healthztcp-check expect string ok期望返回内容里包含ok。API Server的/healthz端点在健康时返回ok这样检查才真正反映API Server的服务能力。inter 2s是检查间隔2秒fall 2是连续失败2次标记为downrise 2是连续成功2次标记为up。算一下最坏情况一个master挂了最多2秒后第一次检查失败再过2秒第二次失败总共4秒内被摘除。恢复时同样4秒内加回。这个时间窗口对控制平面来说是可以接受的。如果你想要更快可以把inter调到1s但会增加检查开销2s是个平衡点。4.4 负载均衡算法和会话保持balance roundrobin是轮询算法请求依次分发给三个master。对于API Server这种无状态的服务轮询是最合适的能均匀分散负载。有人会问要不要用leastconn理论上最少连接数算法在长连接场景下更优但API Server的请求处理很快连接数差异不大轮询足够。而且轮询的确定性更好排查问题时容易预测请求去了哪台。会话保持这块API Server本身是无状态的所有状态都在etcd里所以不需要会话保持。不要配stick相关的选项否则反而会导致负载不均。提示如果你在backend里加了option httpchk注意那是七层检查需要mode http。我们这里是mode tcp所以用tcp-check系列指令别搞混了。5. keepalived配置与VIP漂移实现5.1 主备节点的配置差异keepalived的配置文件在/etc/keepalived/keepalived.conf。两台负载均衡节点的配置大部分相同只有state、priority和unicast_src_ip不同。先看lb-01主的配置# lb-01 /etc/keepalived/keepalived.conf global_defs { router_id lb-01 enable_script_security script_user root } vrrp_script chk_haproxy { script /usr/bin/killall -0 haproxy interval 2 weight -20 fall 2 rise 2 } vrrp_instance VI_K8S { state MASTER interface eth0 virtual_router_id 51 priority 100 advert_int 1 unicast_src_ip 192.168.10.11 unicast_peer { 192.168.10.12 } authentication { auth_type PASS auth_pass K8sLb2024 } virtual_ipaddress { 192.168.10.100/24 } track_script { chk_haproxy } }lb-02备的配置只需要改三处router_id改成lb-02state改成BACKUPpriority改成90unicast_src_ip改成192.168.10.12unicast_peer改成192.168.10.11。5.2 VRRP参数的含义和取值virtual_router_id 51是VRRP组的标识同一个VRRP实例的所有节点必须一致不同实例之间必须不同。取值范围1到255我一般选个不常用的数字避免冲突。priority决定谁是master数值大的当选。主节点100备节点90差距10是为了让weight -20的脚本检查生效。当主节点的HAProxy挂掉时chk_haproxy脚本失败priority从100减20变成80低于备节点的90备节点就会抢占成为新的masterVIP漂移过去。这个设计比单纯靠节点宕机触发切换更灵敏因为HAProxy进程挂了但节点还活着的情况VRRP本身是感知不到的必须靠脚本检查。advert_int 1是VRRP通告间隔1秒。master每秒发一次通告backup如果3秒3倍间隔没收到就认为master挂了自己升为master。所以节点级故障的切换时间大约3秒。authentication是VRRP的认证防止其他VRRP实例误入。auth_pass最长8位我用的是一串自定义字符你部署的时候换成自己的。5.3 健康检查脚本的写法vrrp_script chk_haproxy里我用了/usr/bin/killall -0 haproxy这个命令的意思是发送信号0给haproxy进程信号0不实际发送信号只做权限和进程存在性检查。如果haproxy进程存在命令返回0不存在返回非0。keepalived根据返回值判断脚本成功还是失败。interval 2是每2秒执行一次脚本fall 2是连续失败2次算真正失败rise 2是连续成功2次算恢复。weight -20是失败时priority减20。注意script_user root和enable_script_security这两个配置在较新版本的keepalived里需要显式指定否则脚本可能因为权限问题执行失败。如果你发现脚本检查不生效先看keepalived日志里有没有脚本执行权限相关的报错。5.4 单播模式的优势我用了unicast_src_ip和unicast_peer配置单播而不是默认的组播。为什么组播在某些网络设备上会被过滤或者限制而且组播会把VRRP通告发给网段里所有设备不够干净。单播只发给指定的peer更可控也更容易在防火墙策略里放行。如果你的环境组播没问题用组播也行但单播是更稳妥的选择。6. 完整部署流程与故障切换验证6.1 分步部署操作先把两台负载均衡节点的系统参数调好然后按顺序操作。第一步在lb-01和lb-02上都安装软件并加载内核参数yum install -y haproxy keepalived sysctl -p /etc/sysctl.d/99-haproxy.conf第二步把HAProxy配置写到两台机器的/etc/haproxy/haproxy.cfg内容完全一致。然后启动HAProxysystemctl enable haproxy systemctl start haproxy systemctl status haproxy第三步把keepalived配置分别写到两台机器注意主备差异。然后启动systemctl enable keepalived systemctl start keepalived systemctl status keepalived第四步验证VIP是否在lb-01上ip addr show eth0 | grep 192.168.10.100正常情况下应该能在lb-01上看到VIPlb-02上看不到。6.2 验证负载均衡是否生效在任意一台能访问VIP的机器上用curl测试API Server的健康端点curl -k https://192.168.10.100:6443/healthz返回ok说明负载均衡转发正常。为了确认请求确实分发到了不同master可以多执行几次同时在三台master上用ss -tnp | grep 6443观察连接来源。不过因为HAProxy是四层转发源IP是HAProxy的IP你看到的是HAProxy和master之间的连接。更直接的验证方式是临时停掉一台master的API Server然后持续curl VIP观察是否仍然返回ok。如果HAProxy健康检查配置正确停掉的那台会在几秒内被摘除请求继续由剩余两台处理。6.3 模拟故障切换验证keepalived的VIP漂移最直接的方法是在lb-01上停掉keepalivedsystemctl stop keepalived然后在lb-02上查看VIP是否漂移过来ip addr show eth0 | grep 192.168.10.100同时从客户端持续ping VIP观察丢包情况。正常情况下会有1到3个ping包丢失然后恢复。这是因为VRRP切换需要重新选举和ARP更新秒级完成。再验证HAProxy故障触发的切换在lb-01上停掉HAProxy但保持keepalived运行systemctl stop haproxy由于chk_haproxy脚本检测到haproxy进程不存在priority减20lb-02的priority更高会抢占VIP。这个切换同样在几秒内完成。恢复时把haproxy重新启动priority恢复但VIP不会自动抢回来因为keepalived默认是非抢占模式除非配置了nopreempt的反面。如果你希望主节点恢复后自动抢回VIP需要确保没有配nopreempt并且priority确实更高。6.4 把VIP接入Kubernetes配置负载均衡层验证通过后集群的kubeconfig里server字段要指向VIPapiVersion: v1 kind: Config clusters: - cluster: server: https://192.168.10.100:6443 certificate-authority-data: CA证书 name: kuberneteskubelet的配置里server也要指向VIP。这样所有组件都通过VIP访问API Server背后master的增减对它们透明。7. 常见问题排查与避坑经验7.1 问题速查表现象可能原因排查方法解决方式VIP不漂移VRRP认证不一致检查auth_pass统一认证密码VIP不漂移virtual_router_id冲突检查同网段其他VRRP改idHAProxy启动报错ip_nonlocal_bind未开sysctl查看设为1健康检查不生效脚本权限问题看keepalived日志配script_user后端全部被摘除检查字符串不匹配手动curl /healthz调整expect切换后连接失败ARP缓存未更新客户端arp -n等待或清缓存长连接频繁断timeout太短看HAProxy日志调大timeout7.2 几个我踩过的坑第一个坑是ip_nonlocal_bind没开。当时HAProxy配置里bind了VIP但keepalived还没启动VIP不在本机HAProxy直接启动失败。日志里报cannot bind socket。加上net.ipv4.ip_nonlocal_bind 1后解决。这个参数一定要在HAProxy启动前就设好。第二个坑是健康检查的expect字符串。我一开始写的是tcp-check expect string ok但API Server的/healthz返回的是ok后面跟换行string匹配是子串匹配所以没问题。但如果你检查的是/readyz返回可能是ok或者具体的错误信息expect要相应调整。建议先用curl手动确认返回内容再配。第三个坑是VRRP的单播peer配置。有一次我只配了unicast_src_ip忘了配unicast_peer结果keepalived还是走组播而网络里组播被禁了导致备节点收不到通告一直以为主节点挂了频繁切换。单播模式下unicast_peer必须配全所有对端地址。第四个坑是防火墙。HAProxy的6443端口、VRRP的协议号112、keepalived之间的通信都需要在防火墙放行。我遇到过防火墙把VRRP包拦了导致VIP漂移失败的情况。建议在负载均衡节点之间完全放行或者至少放行VRRP和6443。7.3 性能和安全方面的注意事项性能上HAProxy的maxconn不要设得超过系统文件描述符限制。用ulimit -n看一下如果默认是1024需要调大可以在systemd的service文件里加LimitNOFILE65536。另外nbthread不要超过CPU核心数否则线程争抢反而降低性能。安全上HAProxy的stats页面如果开启一定要加认证和访问控制不要暴露在公网。我一般只在需要的时候临时开平时关掉。keepalived的auth_pass虽然简单但能防止误配置的VRRP实例加入还是要设。VIP所在的网络要确保只有可信设备能访问因为VIP是控制平面的入口。提示生产环境建议把HAProxy的日志单独输出到文件方便排查。在global块配log 127.0.0.1 local0然后在rsyslog里配一个规则把local0的日志写到/var/log/haproxy.log。8. 关于这套方案的一些延伸思考HAProxy加keepalived这套组合我在多个多master集群里用过稳定性没得说。但它也不是没有局限。比如keepalived的VIP漂移依赖二层网络如果负载均衡节点跨网段部署就用不了这时候得考虑用BGP宣告VIP的方案比如kube-vip的BGP模式或者ECMP。另外HAProxy是单进程多线程模型虽然性能很强但单机总有上限如果集群规模特别大可能需要在前面再加一层四层负载均衡。还有一个点是健康检查的粒度。目前我们检查的是/healthz它反映的是API Server进程本身的健康。但有时候API Server进程健康它和etcd之间的连接却有问题这时候/healthz可能还是返回ok。更严格的检查可以用/readyz它会检查更多依赖项。你可以根据实际需求选择/readyz更严格但可能因为某个非关键依赖抖动导致误摘除/healthz宽松一些。我一般用/healthz配合监控告警来发现更深层的问题。最后说个实操小技巧部署完成后写一个简单的巡检脚本定期curl VIP的/healthz同时检查两台负载均衡节点上VIP的位置和HAProxy进程状态输出到一个日志里。这样出问题的时候有历史数据可查比事后登机器翻日志高效得多。这个脚本用bash几十行就能搞定值得花时间做。
📝

华诺云谱内容团队

资深建站顾问 · 行业研究员

10年+企业数字化服务经验,专注智能建站、SEO优化与品牌营销,持续输出建站技巧、行业洞察与营销干货,已帮助5000+企业实现数字化增长。

你可能需要的服务

订阅华诺云谱资讯周报

每周一封,精选建站技巧、SEO与营销干货,直达邮箱。已有 8,000+ 企业主订阅,助你少走弯路。

↑