1. 多Master架构里为什么必须有个LoadBalancer
搞过单Master集群的人都清楚那个痛点:API Server一挂,整个集群的管理入口就没了,kubectl敲下去跟石沉大海一样。所以但凡对可用性有点追求的生产环境,多Master是标配。但多Master带来一个很现实的问题——客户端到底该连哪个Master?
你可能会想,kubeconfig里不是可以配多个server地址吗?确实可以,但那个机制本质上是客户端侧的轮询,健康检查能力很弱,而且像kubelet、kube-proxy这些组件连API Server的方式跟kubectl不一样,它们不会去读你的kubeconfig做负载均衡。更关键的是,集群内部组件之间的通信、证书SAN的配置、以及后续要做的HA拓扑,都要求有一个统一的、稳定的VIP(Virtual IP)入口。
这就是LoadBalancer要解决的核心问题:在多个Master节点的API Server前面放一个统一的访问入口,对外只暴露一个地址,后端自动做健康检查和流量分发。客户端只需要记住这一个地址,哪个Master挂了就自动摘掉,恢复了自己加回来,整个过程对使用者透明。
我这次做的部署方案,用的是HAProxy + Keepalived这套经典组合。HAProxy负责四层TCP负载均衡,Keepalived负责VIP的漂移和HAProxy自身的健康检查。为什么不用Nginx?Nginx做四层转发也可以,但HAProxy在TCP模式的健康检查粒度更细,配置也更直观,而且Keepalived跟HAProxy的配合方案非常成熟,社区资料多,踩坑成本低。
这套方案适合谁参考?如果你正在搭建或准备搭建多Master的K8S集群,已经完成了基础环境准备(系统初始化、容器运行时安装、kubeadm等工具就位),现在卡在LoadBalancer这一层,那这篇内容就是给你写的。如果你还在单Master阶段,也可以先了解一下整体架构,为后续扩展做准备。
2. 整体架构设计与方案选型拆解
2.1 部署拓扑长什么样
先把整体架构说清楚。假设我们有三台Master节点,IP分别是192.168.1.11、192.168.1.12、192.168.1.13,另外规划一个VIP 192.168.1.100作为统一入口。HAProxy和Keepalived装在哪?有两种常见做法:
第一种是独立部署,单独找两台机器专门跑HAProxy+Keepalived,跟Master节点分开。好处是职责清晰,负载均衡层不占用Master资源,坏处是多两台机器,成本上去了。
第二种是复用Master节点,直接在每台Master上装HAProxy和Keepalived。这是更常见的做法,三台Master上各跑一个HAProxy实例,Keepalived负责VIP漂移。我这次选的就是这种方案,原因很简单:资源利用率高,而且Master节点本身通常配置不低,多跑一个HAProxy和Keepalived几乎感觉不到额外开销。
拓扑逻辑是这样的:VIP 192.168.1.100绑定在某一台Master的网卡上(由Keepalived决定),所有客户端请求先到VIP,然后HAProxy把TCP 6443端口的流量转发到后端三个Master的6443端口。HAProxy自己会做健康检查,哪个后端API Server不健康就自动剔除。
2.2 为什么是HAProxy而不是LVS或Nginx
这里展开说一下选型逻辑。LVS(Linux Virtual Server)性能确实强,工作在四层,内核态转发,吞吐量天花板很高。但LVS的配置相对复杂,健康检查能力偏弱,而且跟Keepalived的配合虽然经典,但调试起来不如HAProxy直观。对于K8S API Server这种场景,流量规模通常不会大到需要LVS的程度,HAProxy完全扛得住。
Nginx大家最熟悉,但Nginx做TCP负载均衡需要stream模块,健康检查的配置粒度不如HAProxy灵活。HAProxy专门为负载均衡而生,TCP模式的健康检查支持多种探测方式,比如检查后端端口是否可连、发送特定请求判断响应等。而且HAProxy的统计页面非常实用,能看到每个后端的实时状态、连接数、流量等,排查问题的时候特别方便。
Keepalived的作用是管理VIP。它通过VRRP协议在多台机器之间选举出一个Master,VIP就绑在这台机器上。如果这台机器挂了,VRRP重新选举,VIP漂移到另一台机器。Keepalived还可以配置track script来监控HAProxy进程,如果HAProxy挂了,主动降级让出VIP,避免VIP在一台HAProxy已经挂掉的机器上。
2.3 关键参数规划
在动手之前,有几个参数需要提前定好:
| 参数项 | 值 | 说明 |
|---|---|---|
| VIP | 192.168.1.100 | 统一访问入口 |
| HAProxy端口 | 6443 | 跟API Server默认端口一致,也可以自定义 |
| 后端Master | 192.168.1.11/12/13 | 三台Master的IP |
| 后端端口 | 6443 | API Server监听端口 |
| Keepalived模式 | 主备(非抢占) | 避免VIP频繁漂移 |
| 虚拟路由ID | 51 | 同一VRRP组内必须一致 |
注意:VIP必须是一个跟Master节点同网段的空闲IP,不能跟任何现有设备冲突。部署前先在网络里ping一下确认没人用。
3. 核心细节解析与实操要点
3.1 HAProxy配置的关键细节
HAProxy的配置文件通常在/etc/haproxy/haproxy.cfg。针对K8S API Server的场景,核心配置段如下:
global log /dev/log local0 maxconn 2000 daemon defaults log global mode tcp option tcplog timeout connect 5000ms timeout client 50000ms timeout server 50000ms frontend k8s-api bind *:6443 mode tcp default_backend k8s-api-servers backend k8s-api-servers mode tcp balance roundrobin option tcp-check server master1 192.168.1.11:6443 check fall 3 rise 2 server master2 192.168.1.12:6443 check fall 3 rise 2 server master3 192.168.1.13:6443 check fall 3 rise 2这里有几个点值得展开说。mode tcp是必须的,因为API Server走的是HTTPS,但HAProxy不需要解密,直接做四层转发就行,证书由API Server自己处理。option tcp-check启用TCP层健康检查,HAProxy会定期尝试跟后端建立TCP连接,连不上就标记为不健康。
fall 3 rise 2这两个参数很关键。fall 3表示连续3次检查失败才标记后端不可用,rise 2表示连续2次成功才恢复。这个设置是为了避免网络抖动导致误判,如果设成fall 1,稍微有点网络波动后端就被踢了,反而影响稳定性。
balance roundrobin是轮询算法,也可以用leastconn(最少连接数)。对于API Server这种请求,轮询就够了,因为每个请求的处理时间差异不大。
3.2 Keepalived配置的核心逻辑
Keepalived的配置文件在/etc/keepalived/keepalived.conf。主备模式的配置如下:
global_defs { router_id k8s-master-1 } vrrp_script check_haproxy { script "/etc/keepalived/check_haproxy.sh" interval 3 weight -20 fall 2 rise 2 } vrrp_instance VI_K8S { state MASTER interface ens33 virtual_router_id 51 priority 100 advert_int 1 authentication { auth_type PASS auth_pass k8s123 } virtual_ipaddress { 192.168.1.100/24 } track_script { check_haproxy } }state MASTER和priority 100配合决定初始状态。三台机器上priority分别设为100、90、80,优先级最高的成为Master,VIP绑在它上面。nopreempt这个选项建议加上,作用是当原Master恢复后不主动抢回VIP,避免VIP来回漂移。这个在K8S场景下很重要,因为VIP漂移会导致API Server的客户端短暂断连。
track_script引用了一个检查脚本,这个脚本的作用是检测HAProxy进程是否存活。如果HAProxy挂了,脚本返回非零值,Keepalived会根据weight降低优先级,触发VIP漂移。
3.3 健康检查脚本怎么写
check_haproxy.sh的内容很简单:
#!/bin/bash if killall -0 haproxy; then exit 0 else exit 1 fikillall -0不发送任何信号,只检查进程是否存在。如果HAProxy进程在,返回0,Keepalived认为健康;如果不在,返回1,触发降级。这个脚本要加执行权限:chmod +x /etc/keepalived/check_haproxy.sh。
实操心得:脚本里不要用
ps aux | grep haproxy这种方式判断,因为grep本身也会出现在进程列表里,容易误判。killall -0或者pidof haproxy更可靠。
4. 实操过程与核心环节实现
4.1 安装与基础配置
三台Master上都要执行相同的安装步骤。以CentOS系为例:
yum install -y haproxy keepalived systemctl enable haproxy systemctl enable keepalived安装完成后先别急着启动,把配置文件写好。HAProxy的配置文件三台机器完全一样,可以直接scp分发。Keepalived的配置文件只有router_id、state、priority这三项不同,需要分别修改。
配置完成后,先启动HAProxy:
systemctl start haproxy systemctl status haproxy确认HAProxy正常运行后,再启动Keepalived:
systemctl start keepalived systemctl status keepalived4.2 验证VIP绑定情况
在优先级最高的那台机器上执行:
ip addr show ens33应该能看到192.168.1.100绑定在网卡上。另外两台机器上执行同样的命令,看不到VIP,说明主备关系正常。
然后验证HAProxy的负载均衡是否生效:
curl -k https://192.168.1.100:6443/healthz如果返回ok,说明通过VIP能正常访问到API Server。多执行几次,观察请求是否被分发到不同的后端。可以临时停掉一台Master的API Server(或者直接关机),再执行curl,应该仍然能返回ok,说明健康检查生效了。
4.3 模拟故障切换
这是最关键的验证环节。先确认当前VIP在哪台机器上,然后手动停掉那台机器的Keepalived:
systemctl stop keepalived在另外两台机器上观察VIP是否漂移过来。正常情况下,1-3秒内VIP就会转移到优先级次高的机器上。然后恢复刚才停掉的Keepalived,由于配置了nopreempt,VIP不会漂回去,保持现状。
再测试HAProxy的故障切换:停掉某台Master上的HAProxy,观察HAProxy的统计页面(如果开了的话),对应的后端应该被标记为DOWN。通过VIP访问API Server应该仍然正常,因为HAProxy会把请求转发到其他健康的后端。
4.4 与K8S集群的对接
LoadBalancer部署好之后,kubeadm初始化集群时就可以用VIP了。kubeadm-config.yaml里这样写:
apiVersion: kubeadm.k8s.io/v1beta3 kind: ClusterConfiguration controlPlaneEndpoint: "192.168.1.100:6443"controlPlaneEndpoint指向VIP,这样生成的证书SAN里会包含VIP地址,kubeconfig里也会用VIP作为server地址。后续加入新的Master节点时,也是通过这个VIP跟现有集群通信。
注意:如果集群已经初始化过了,再改controlPlaneEndpoint会比较麻烦,需要重新生成证书和更新kubeconfig。所以最好在初始化之前就把LoadBalancer规划好。
5. 常见问题与排查技巧实录
5.1 VIP不漂移或漂移异常
这是最常见的问题。排查思路分几步走:
第一,检查Keepalived是否正常运行。systemctl status keepalived看状态,journalctl -u keepalived -f看日志。日志里通常会明确显示VRRP状态切换的原因。
第二,检查防火墙。VRRP协议用的是IP协议号112,不是TCP也不是UDP。如果防火墙规则把VRRP拦了,Keepalived之间就通信不了。CentOS上可以用firewall-cmd --add-rich-rule='rule protocol value="vrrp" accept' --permanent放行。
第三,检查virtual_router_id是否冲突。同一网段内如果有其他Keepalived组用了相同的router_id,会互相干扰。换一个不常用的ID试试。
第四,检查网卡名称。配置里的interface必须跟实际网卡名称一致,用ip addr确认。
5.2 HAProxy后端全部显示DOWN
如果HAProxy启动后,所有后端都显示DOWN,但手动curl后端API Server是通的,那大概率是健康检查配置有问题。检查option tcp-check是否配置正确,以及后端端口是否写对。另外确认HAProxy所在机器到后端Master的网络是否通,telnet 192.168.1.11 6443测试一下。
还有一种可能是SELinux在捣乱。CentOS默认开启SELinux,可能会阻止HAProxy绑定端口或发起连接。临时用setenforce 0测试,如果问题消失,就需要配置SELinux策略或者直接关闭。
5.3 通过VIP访问API Server超时
如果VIP能ping通,但curl 6443端口超时,先检查HAProxy是否在监听:
ss -tlnp | grep 6443如果HAProxy没监听,看配置文件里frontend的bind是否正确。如果HAProxy在监听但请求超时,检查后端API Server是否正常,以及HAProxy到后端的网络是否通。
还有一个容易忽略的点:如果Master节点上开了iptables或firewalld,可能会拦截转发的流量。确保6443端口在防火墙里放行了。
5.4 常见问题速查表
| 现象 | 可能原因 | 排查命令 |
|---|---|---|
| VIP不漂移 | VRRP被防火墙拦截 | firewall-cmd --list-all |
| VIP不漂移 | router_id冲突 | 检查同网段其他Keepalived |
| 后端全DOWN | 健康检查配置错误 | haproxy -c -f /etc/haproxy/haproxy.cfg |
| 后端全DOWN | SELinux拦截 | getenforce |
| VIP通但6443不通 | HAProxy未监听 | ss -tlnp | grep 6443 |
| VIP通但6443不通 | 后端API Server异常 | systemctl status kube-apiserver |
| VIP频繁漂移 | 网络抖动或fall值太小 | 调大fall和rise |
5.5 几个踩过的坑
第一个坑:Keepalived的state和priority要配合使用。如果两台机器都配了state MASTER且priority相同,会出现双Master抢VIP的情况。正确做法是一台MASTER高优先级,其余BACKUP低优先级。
第二个坑:HAProxy的日志默认走local0,但rsyslog可能没配置接收。需要在/etc/rsyslog.conf里加一行local0.* /var/log/haproxy.log,然后重启rsyslog,否则HAProxy的日志看不到,排查问题很痛苦。
第三个坑:如果Master节点重启后VIP没有正确绑定,检查Keepalived是否设置了开机自启。systemctl is-enabled keepalived确认一下。
第四个坑:HAProxy的timeout client和timeout server不要设得太短。API Server有些操作(比如大规模list)响应时间较长,如果超时设成5秒,可能会被HAProxy主动断开。建议至少30秒以上。
6. 性能调优与高可用加固
6.1 HAProxy参数调优
默认配置下HAProxy能扛住不少流量,但如果集群规模大、客户端多,可以调几个参数。maxconn控制最大并发连接数,默认2000,可以调到10000甚至更高,取决于机器配置。nbproc可以设置多进程,利用多核CPU,但要注意HAProxy 2.x之后推荐用多线程(nbthread)而不是多进程。
global maxconn 10000 nbthread 4nbthread 4表示用4个线程处理请求,适合4核以上的机器。这个参数在HAProxy 1.8之后支持,比nbproc更推荐,因为多线程共享内存,统计信息更准确。
6.2 Keepalived的抢占模式选择
前面提到了nopreempt,这里再展开说一下。默认情况下Keepalived是抢占模式,原Master恢复后会抢回VIP。但在K8S场景下,VIP漂移会导致所有客户端短暂断连,所以建议用非抢占模式。配置方法是在vrrp_instance里加nopreempt,同时把state都设成BACKUP(或者一台MASTER其余BACKUP),让优先级决定初始Master。
非抢占模式下,如果Master挂了,VIP漂到BACKUP上,原Master恢复后不会抢回,VIP就留在BACKUP上。这样减少了不必要的漂移,稳定性更好。
6.3 监控与告警
LoadBalancer本身也需要监控。HAProxy提供了统计页面,可以在配置里加一段:
listen stats bind *:9000 mode http stats enable stats uri /stats stats refresh 10s访问http://192.168.1.100:9000/stats就能看到实时状态。不过这个页面没有认证,生产环境建议加stats auth admin:password做基础认证,或者只监听内网地址。
Keepalived的状态可以通过检查VIP在不在本机来判断。写个简单的脚本定期检查,如果VIP不在预期机器上就告警。这个可以配合现有的监控系统来做。
7. 一些个人体会
这套HAProxy+Keepalived的方案我用了挺久,整体稳定性很好,配置也不复杂。最关键的一点是:部署顺序很重要。一定要先把LoadBalancer搭好并验证通过,再去初始化K8S集群。如果集群已经跑起来了再补LoadBalancer,证书和kubeconfig的调整会比较折腾。
另外,VIP的选择要慎重。最好选一个跟Master同网段但不会被DHCP分配出去的IP,或者在路由器上把这个IP排除掉。我遇到过VIP跟其他设备冲突导致集群访问时好时坏的情况,排查了半天才发现是IP冲突。
最后分享一个小技巧:如果三台Master的HAProxy配置完全一样,可以用Ansible或者简单的shell脚本批量分发,避免手动改三遍配置文件出错。Keepalived的配置文件可以用模板生成,把router_id、priority、state这三个变量抽出来,其余部分共用。这样后续加节点或者改配置都方便很多。