k8s LB 只支持一个 v4 + 一个v6 IP

4 阅读4分钟

我已经拿到官方概念文档了,再补一下 API 字段层面的定义,避免只停留在概念说明。 是的,按 Kubernetes 原生 Service type=LoadBalancer 的设计,没有标准字段让你指定两个以上的 LB IP。更准确地说:

结论

  • 原生 API 里,用户可填写的只有 spec.loadBalancerIP 这个单数字段。
  • 这个字段从 Kubernetes v1.24 起已经被标记为 deprecated,官方理由是它“语义不明确、各实现不一致,而且无法支持 dual-stack”,官方建议改用 provider-specific annotations官方 Service 文档
  • 所以如果你问“原生设计能不能指定 2 个以上 IP”,答案是:不能
  • 甚至更严格一点说:原生标准设计连‘指定 2 个固定 IP’都没有通用方案

为什么会有这个结论

  • Kubernetes 原生 LoadBalancer 只定义了“我要一个外部负载均衡入口”,具体怎么分配地址主要交给云厂商或实现方。
  • Kubernetes 官方对双栈的支持,是通过 ipFamilyPolicy / ipFamilies 表达“这个 Service 需要 IPv4、IPv6 或双栈”,而不是通过原生字段让你枚举多个指定 IP。Dual-stack 文档
  • 官方双栈文档描述的也是“为 Service 分配 IPv4 和 IPv6 地址”,本质上还是 最多两个地址族,不是任意长度的 IP 列表。Dual-stack 文档

容易混淆的一点

  • status.loadBalancer.ingress 在状态上是个列表,这意味着某些实现可以上报多个 ingress 地址/hostname
  • 但这不代表 Kubernetes 原生 spec 提供了一个标准能力,让你主动指定多个固定 LB IP
  • 如果某个平台支持多个指定 IP,通常也是它自己的 annotation 或扩展能力,不是 Kubernetes 原生 Service 标准语义。

和 MetalLB 对照起来看

  • MetalLB 的 metallb.io/loadBalancerIPs 能接收多个 IP,这是 MetalLB 自己扩展出来的能力,不是 Kubernetes 原生 Service API 自带的。
  • MetalLB 代码里之所以最多只接受 2 个,而且要求不同 family,本质上是在贴合 Kubernetes 的双栈模型,而不是在扩展成“任意多个公网 IP”。

一句话版

  • Kubernetes 原生 LoadBalancer不能标准化地指定两个以上 IP
  • 严格说:原生连“指定两个固定 IP”都没有统一设计,只有单数的 spec.loadBalancerIP,而且已经废弃;双栈走的是地址族模型,不是多 IP 列表模型。

在 metal LB 的代码中,一个 LB 类型的 service 可以指定多个公网 IP 么?

我继续沿着控制器里分配 IP 的路径确认一下:重点看“多个公网 IP”是任何场景都支持,还是只在 loadBalancerIPs / 双栈场景下支持。

结论

  • 一个 LoadBalancer 类型的 Service 在 MetalLB 里可以拿到多个 IP。
  • 但不是“任意多个公网 IP”,而是最多 2 个,并且这 2 个必须分别属于不同地址族,也就是 1 个 IPv4 + 1 个 IPv6 的双栈场景。
  • 不能给同一个 Service 分配多个 IPv4 公网 IP,也不能分配 3 个及以上 IP。

代码依据

  • controller 里请求的 LB IP 是按 []net.IP 处理的,说明设计上支持多个 IP,见 service.go
  • metallb.io/loadBalancerIPs 明确支持逗号分隔列表,但文档写得很清楚,这个列表是“用于 Dual Stack services”,见 usage/_index.md
  • 分配器里直接限制了数量和地址族:
  • ipfamily 逻辑也只认 1 个地址是单栈,2 个不同 family 是双栈,超过 2 个就是非法,见 ipfamily.go

你这个问题对应到“公网 IP”

  • 如果你的“多个公网 IP”意思是:
    • 1.2.3.41.2.3.5 两个 IPv4 公网地址给同一个 Service
    • 结论:不支持
  • 如果你的意思是:
    • 一个公网 IPv4 + 一个公网 IPv6 给同一个 Service
    • 结论:支持,前提是 Service 和地址池都按双栈配置

怎么指定

  • 单个 IP:spec.loadBalancerIPmetallb.io/loadBalancerIPs: "192.0.2.10"
  • 双栈两个 IP:metallb.io/loadBalancerIPs: "192.0.2.10,2001:db8::10"

示例:

apiVersion: v1
kind: Service
metadata:
  name: my-app
  annotations:
    metallb.io/loadBalancerIPs: "192.0.2.10,2001:db8::10"
spec:
  type: LoadBalancer
  ipFamilyPolicy: PreferDualStack
  ipFamilies:
  - IPv4
  - IPv6

补一句容易混淆的点

  • metallb.io/allow-shared-ip 不是“给一个 Service 多个 IP”,而是“让多个 Service 共享同一个 IP”。