k3s高可用实现
对K3s 集群来说,最佳方案就是:MetalLB (Layer2) + 内置 Traefik,可替换传统的nginx+keepalived
注:MetalLB还支持L3模式,也就是BGP,此模式需要路由器或交换机支持
为什么 K3s 适合这个组合?
- Traefik 是 K3s 默认内置 Ingress
- 安装 K3s 时自动装上,不用额外部署
- 轻量、自动发现服务、动态配置、不用 reload
- 支持 HTTP/HTTPS、TCP/UDP、gRPC、websocket 等
K3s 自带的 ServiceLB(Klipper LB)很弱:
- 只能用节点 IP,没有真正 VIP
- 所有节点 80/443 被占用
- 高可用差、不能优雅切换
- 生产环境不推荐
kube-system命令空间下的svclb-traefik就是自带的servicelb,如图:

MetalLB L2 + Traefik = 完美搭配:
- MetalLB 给 Traefik 一个稳定 VIP(比如 192.168.1.200), Metallb就负责分配IP,其余不管
- VIP 高可用自动漂移
- Traefik 做 7 层网关(域名、HTTPS、路由、限流)
- 完全 K8s 原生、声明式、零维护
搭建
1、在三个Master节点禁用自带的servicelb,如下:
#servicelb 是 K3s 的控制平面组件,只运行在 master 节点,k3s server(master):负责启动servicelb、traefik、coredns 等核心插件
vim /etc/systemd/system/k3s.service
--disable=servicelb #添加的参数

禁用后已经看不到svclb-traefik开头的Pod,如图:

2、安装 MetalLB,如下:
kubectl apply -f https://raw.githubusercontent.com/metallb/metallb/main/config/manifests/metallb-native.yaml
有两个镜像需要先下载回来到本地,导入到各个节点上,否则可能不成功,如下:
quay.io/metallb/controller:main
quay.io/metallb/speaker:main

controller只在一个节点上有,speaker在每个节点上都有部署,contoller负责分配IP,speaker负责广播IP,controller是Deployment管理,speaker通过DaemonSet管理
controller是MetalLB 的总指挥,管分配、管调度、当 “大脑”,主要功能:
- 管理你配置的 IP 地址池,比如你配置了 192.168.1.200-210,controller 知道这段 IP 归 MetalLB 管
- 监听所有 LoadBalancer 类型 Service,比如 traefik 这个 Service 一创建,controller 就会看到
- 给 Service 分配一个外部 IP(VIP),从地址池里拿一个 IP 给 Service
- 记录哪个 IP 分给了哪个服务,防止 IP 冲突
- 控制整个 MetalLB 的状态
speaker(发言人),每个节点都跑一个(master + worker),对外喊话、告诉网络 “这个 IP 是我的”、高可用切换,主要功能:
- 对外发送 ARP 广播,告诉整个局域网:“192.168.1.200 这个 VIP 在我这台机器!”
- 同一时间只有一个 speaker 是 leader,只有一个节点负责响应 ARP → 这个节点就是流量入口
- 高可用自动切换,如果当前 leader 节点挂了,另一个节点的 speaker 立刻顶上,告诉网络:“VIP 飘到我这了!”
- 确保流量能进入集群
注:查看当前哪个节点是speaker的leader,如下:
curl -s http://<节点IP>:7472/metrics | grep -i metallb_speaker_announced
#输出中看到metallb_speaker_announced{ip="192.168.51.72",node="k3s-master01",protocol="layer2",说明此时k3s-master01就是leader节点
在metallb-system命名空间下还有一个service,名字为metallb-webhook-service,类型为ClusterIP,此service是 MetalLB 的准入控制 Webhook 服务,核心作用是校验、修改你提交的 MetalLB 自定义资源(CRD),保证配置合法、集群安全,主要功能如下:
- 检查你配置的 IP 地址池是否合法(比如 IP 段格式、是否重叠、是否超出网段)
- 检查 BGP 配置是否正确(ASN、邻居地址、路由规则)
- 检查 L2 宣告配置是否符合规范
- 拦截非法配置,避免错误配置导致 MetalLB 崩溃、IP 冲突、网络故障
- 给你没写全的配置自动补全默认值(比如自动设置合理的 ARP 宣告间隔)
- 统一配置规范,减少人为失误
3、配置 MetalLB L2 地址池,如下:
# metallb-config.yaml
apiVersion: metallb.io/v1beta1
kind: IPAddressPool
metadata:
name: default
namespace: metallb-system
spec:
addresses:
- 192.168.51.72-192.168.51.75 # 你的内网VIP段
---
apiVersion: metallb.io/v1beta1
kind: L2Advertisement
metadata:
name: default
namespace: metallb-system
kubectl apply -f metallb-config.yaml
执行后可以看到traefik已经拿到了VIP地址,如图:

通过describe可以看到VIP已经写入到status.loadBalancer.ingress 字段,如图:

有了VIP后,完整的用户流量请求流程是:
- 浏览器 / 客户端访问域名 → DNS 解析到 MetalLB 分配的 VIP
- MetalLB 负责 “引流到集群”,把流量发到 某一台 Node(Leader 节点)
- 进入 Node 后:到达raefik 的 LoadBalancer 类型 Service,kube-proxy / CNI(iptables/IPVS/eBPF)做 DNAT:Traefik Service 的 ClusterIP + port(VIP流量映射到上图中10.43.71.195中)
- Traefik 处理七层路由:Traefik Pod 收到请求,看 Host/Path 等规则,转发到 对应业务的 ClusterIP Service
- 最后到 Pod:业务 Service 再通过 kube-proxy/CNI 负载均衡到 某一个后端 Pod
简化版就是:
用户 → VIP → (DNAT: VIP → Traefik ClusterIP) → Traefik Pod → 业务 Service (ClusterIP) → 业务 Pod
注:这里的VIP和Traefik ClusterIP都在traefik这个LoadBalancer类型的svc上



