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上

标签