Skip to content

Coordinator

简体中文 | English

Spiderpool 内置一个叫 coordinator 的 CNI meta-plugin, 它在 Main CNI 被调用之后再工作,它主要提供以下几个主要功能:

  • 解决 underlay Pod 无法访问 ClusterIP 的问题
  • 在 Pod 多网卡时,调谐 Pod 的路由,确保数据包来回路径一致
  • 支持检测 Pod 的 IP 是否冲突(遗弃,现在由 IPAM 完成)
  • 支持检测 Pod 的网关是否可达 (遗弃,现在由 IPAM 完成)
  • 支持固定 Pod 的 Mac 地址前缀

注意: 如果您的操作系统是使用 NetworkManager 的 OS,比如 Fedora、Centos等,强烈建议配置 NetworkManager 的配置文件(/etc/NetworkManager/conf.d/spidernet.conf),避免 NetworkManager 干扰 coordinator 创建的 Veth 虚拟接口,影响通信:

~# cat > /etc/NetworkManager/conf.d/spidernet.conf <<EOF
[keyfile]
unmanaged-devices=interface-name:^veth*;interface-name:${IFACER_INTERFACE}
EOF
~# systemctl restart NetworkManager

下面我们将详细的介绍 coordinator 如何解决或实现这些功能。

CNI 配置字段说明

Field Description Schema Validation Default
type CNI 的类型 字符串 required coordinator
mode coordinator 运行的模式. "auto": coordinator 自动判断运行在 Underlay 或者 Overlay; "underlay": 为 Pod 创建一对 Veth 设备,用于转发集群东西向流量。由 Pod 的 Underlay 网卡转发南北向流量; "overlay": 不额外创建 veth 设备,运行在多网卡模式。由 overlay 类型的 CNI(calico,cilium) 转发集群东西向流量,由 underlay 网卡转发南北向流量; "disable": 禁用 coordinator 字符串 optional auto
tunePodRoutes Pod 多网卡模式下,是否调协 Pod 的路由,解决访问来回路径不一致的问题 布尔型 optional true
podDefaultRouteNic Pod 多网卡时,配置 Pod 的默认路由网卡。默认为 "", 其 value 实际为 Pod 第一张拥有默认路由的网卡 字符串 optional ""
podDefaultCniNic K8s 中 Pod 默认的第一张网卡 布尔型 optional eth0
detectGateway 遗弃,创建 Pod 时是否检查网关是否可达 布尔型 optional false
detectIPConflict 遗弃,创建 Pod 时是否检查 Pod 的 IP 是否冲突 布尔型 optional false
podMACPrefix 是否固定 Pod 的 Mac 地址前缀, 前缀长度为两个字节, 由":"拼接。注意:首字节的最低位必须是 "0"。比如 "0a:1b"。 字符串 optional ""
overlayPodCIDR 默认的集群 Pod 的子网,会注入到 Pod 中。不需要配置,自动从 Spidercoordinator default 中获取 []stirng optional 默认从 Spidercoordinator default 中获取
serviceCIDR 默认的集群 Service 子网, 会注入到 Pod 中。不需要配置,自动从 Spidercoordinator default 中获取 []stirng optional 默认从 Spidercoordinator default 中获取
hijackCIDR 额外的需要从主机转发的子网路由。比如nodelocaldns 的地址: 169.254.20.10/32 []stirng optional 空
policyRoutes 下发到 coordinator 当前运行网卡对应策略路由表中的静态路由。每个条目包含 dst 和 gw,并且两者必须属于同一个 IP family。 []object optional 空
hostRuleTable 策略路由表号,同主机与 Pod 通信的路由将会存放于这个表号 整数型 optional 500
podRPFilter 设置 Pod 的 sysctl 参数 rp_filter 整数型 optional 0
txQueueLen 设置 Pod 的网卡传输队列 整数型 optional 0
detectOptions 检测地址冲突和网关可达性的高级配置项: 包括发送探测报文次数(retries: 默认为 3 次), 和响应的超时时间(timeout: 默认为 100ms),还有发送报文的间隔(interval:默认为 10ms, 将会在未来版本中移除) 对象类型 optional 空
logOptions 日志配置,包括 logLevel(默认为 debug) 和 logFile(默认为 /var/log/spidernet/coordinator.log) 对象类型 optional -

如果您通过 SpinderMultusConfig CR 帮助创建 NetworkAttachmentDefinition CR,您可以在 SpinderMultusConfig 中配置 coordinator (所有字段)。参考: SpinderMultusConfig。

Spidercoordinators CR 作为 coordinator 插件的全局缺省配置(所有字段),其优先级低于 NetworkAttachmentDefinition CR 中的配置。 如果在 NetworkAttachmentDefinition CR 未配置, 将使用 Spidercoordinator CR 作为缺省值。更多详情参考: Spidercoordinator。

配置下发到 coordinator 策略路由表的静态路由

coordinator.policyRoutes 用于配置静态路由,coordinator 会把这些路由下发到当前运行网卡对应的策略路由表中。它与 hijackCIDR 不同:hijackCIDR 用于把匹配流量转发到主机网络栈,而 policyRoutes 是给当前 coordinator 网卡的策略路由表增加路由。

可以在全局 SpiderCoordinator 中配置默认路由:

apiVersion: spiderpool.spidernet.io/v2beta1
kind: SpiderCoordinator
metadata:
  name: default
spec:
  policyRoutes:
  - dst: 10.10.0.0/16
    gw: 172.18.0.1

也可以在某个 SpiderMultusConfig 中覆盖全局默认值。SpiderMultusConfig controller 会把该配置写入自动生成的 NetworkAttachmentDefinition coordinator 插件配置中:

apiVersion: spiderpool.spidernet.io/v2beta1
kind: SpiderMultusConfig
metadata:
  name: macvlan-ens192
  namespace: kube-system
spec:
  cniType: macvlan
  enableCoordinator: true
  macvlan:
    master:
    - ens192
  coordinator:
    policyRoutes:
    - dst: 10.10.0.0/16
      gw: 172.18.0.1

每条路由中,dst 可以是 IP 或 CIDR,webhook 会将其标准化为 CIDR 格式。gw 必须是 IP 地址。dst 和 gw 必须使用相同的 IP family。

Pod 创建完成后,Coordinator 会把配置的路由下发到当前运行网卡对应的策略路由表中。下面示例使用 macvlan underlay 网卡,并配置类似 10.10.0.0/16 via 172.100.0.1 和 10.20.0.0/16 via 172.200.0.1 的自定义路由。

underlay 单网卡 Pod:

/# ip rule
1000: from all fwmark 0x1 lookup 100

/# ip route
default via 172.100.0.1 dev eth0
10.233.0.0/18 via 172.100.0.2 dev veth0 src 172.100.0.210
10.233.64.0/18 via 172.100.0.2 dev veth0 src 172.100.0.210
169.254.0.0/16 via 172.100.0.2 dev veth0 src 172.100.0.210
172.100.0.0/16 dev eth0 proto kernel scope link src 172.100.0.210

/# ip route show table 100
default via 172.100.0.2 dev veth0 src 172.100.0.210

/# ip route show table 101
10.10.0.0/16 via 172.100.0.1 dev eth0

main 表保留 eth0 上的 underlay 默认路由。fwmark 0x1 lookup 100 规则会让被 Coordinator 标记的报文查询 table 100,使 underlay 路由调协需要时可以通过 veth0 回复。自定义 coordinator.policyRoutes 路由会写入当前网卡对应的 table 101。普通流量仍会走 main 表,除非有其他 ip rule 选中 table 101。

underlay 双网卡 Pod:

/# ip rule
999: from 172.200.0.201 lookup 101
1000: from all fwmark 0x1 lookup 100

/# ip route
default via 172.100.0.1 dev eth0
172.100.0.0/16 dev eth0 proto kernel scope link src 172.100.0.211
172.200.0.0/16 dev net1 proto kernel scope link src 172.200.0.201

/# ip route show table 100
default via 172.100.0.2 dev veth0 src 172.100.0.211

/# ip route show table 101
default via 172.200.0.1 dev net1
10.10.0.0/16 via 172.100.0.1 dev eth0
10.20.0.0/16 via 172.200.0.1 dev net1
172.200.0.0/16 dev net1 scope link src 172.200.0.201

源地址来自第一张 underlay 网卡的流量默认使用 main 表。from 172.200.0.201 lookup 101 规则会让源地址来自 net1 的流量查询 table 101,Coordinator 在该表中保存 net1 的默认路由、直连路由以及自定义路由。fwmark 0x1 lookup 100 规则独立处理被标记报文的回复路径,不受源地址策略路由表影响。

解决 underlay Pod 无法访问 ClusterIP 的问题

我们在使用一些如 Macvlan、IPvlan、SR-IOV 等 Underlay CNI时,会遇到其 Pod 无法访问 ClusterIP 的问题,这常常是因为 underlay Pod 访问 CLusterIP 需要经过在交换机的网关,但网关上并没有去往 ClusterIP 的路由,导致无法访问。

在 underlay 模式下,coordinator 会在 main 路由表中通过 veth0 写入 overlay Pod CIDR、Service CIDR 和 hijackCIDR 对应的 hijack 路由。对于 underlay 多网卡 Pod,underlay 策略路由表只保留对应 underlay 网卡自身的路由,不会复制这些同步的 Kubernetes 路由或 hijack 路由。

关于 Underlay Pod 无法访问 ClusterIP 的问题,请参考 Underlay-CNI访问 Service

支持检测 Pod 的 IP 是否冲突( alpha 阶段)

对于 Underlay 网络,IP 冲突是无法接受的,这可能会造成严重的问题。在创建 Pod 时,我们可借助 coordinator 检测 Pod 的 IP 是否冲突,支持同时检测 IPv4 和 IPv6 地址。通过发送 ARP 或 NDP 探测报文, 如果发现回复报文的 Mac 地址不是来自 Pod 本身的网卡,那我们认为这个 IP 是冲突的,并拒绝 IP 冲突的 Pod 被创建。 此外,我们默认还会对发生 IP 冲突的**无状态**的 Pod 释放所有的已分配的 IP 使其重新分配,使得 Pod 在下一次重新调用 CNI 时能够尝试分配到其它非冲突的 IP。对于发生 IP 冲突的**有状态**的 Pod,为了保持 IP 地址也是有状态设计,我们不会对其释放。您可通过 spiderpool-agent 环境变量 SPIDERPOOL_ENABLED_RELEASE_CONFLICT_IPS 来控制此功能。

我们可以通过 Spidermultusconfig 配置它:

apiVersion: spiderpool.spidernet.io/v2beta1
kind: SpiderMultusConfig
metadata:
  name: detect-ip
  namespace: default
spec:
  cniType: macvlan
  macvlan:
    master: ["eth0"]
  coordinator:
    detectIPConflict: true    # Enable detectIPConflict

若 IP 冲突检查发现某 IP 已被占用,请检查是否被集群中其他处于 Terminating 阶段的 无状态 Pod 所占用,并配合 IP 回收机制 相关参数进行配置。

支持固定 Pod 的 Mac 地址前缀(alpha)

有一些传统应用可能需要通过固定的 Mac 地址或者 IP 地址来耦合应用的行为。比如 License Server 可能需要应用固定的 Mac 地址或 IP 地址为应用颁发 License。如果 Pod 的 Mac 地址发生改变,已颁发的 License 可能无效。 所以需要固定 Pod 的 Mac 地址。 Spiderpool 可通过 coordinator 固定应用的 Mac 地址,固定的规则是配置 Mac 地址前缀(2字节) + 转化 Pod 的 IP(4字节) 组成。

注意:

目前支持修改 Macvlan 和 SR-IOV 作为 CNI 的 Pod。 IPVlan L2 模式下主接口与子接口 Mac 地址一致,不支持修改

固定的规则是配置 Mac 地址前缀(2字节) + 转化 Pod 的 IP(4字节) 组成。一个 IPv4 地址长度 4 字节,可以完全转换为2 个 16 进制数。对于 IPv6 地址,只取最后 4 个字节。

固定 Mac 地址后,为避免过时的 ARP 缓存表导致访问失败,Coordinator 插件会发送一个免费 ARP,通告新的 Mac 地址到局域网。

我们可以通过 Spidermultusconfig 配置它:

apiVersion: spiderpool.spidernet.io/v2beta1
kind: SpiderMultusConfig
metadata:
  name: overwrite-mac
  namespace: default
spec:
  cniType: macvlan
  macvlan:
    master: ["eth0"]
  enableCoordinator: true
  coordinator:
    podMACPrefix: "0a:1b"    # Enable detectGateway

当 Pod 创建完成,我们可以检测 Pod 的 Mac 地址的前缀是否是 "0a:1b"

配置网卡传输队列(txQueueLen)

传输队列长度(txqueuelen)是TCP/IP协议栈网络接口的一个值,它设置了网络接口设备内核传输队列中允许的数据包数量。如果txqueuelen值过小,可能导致在Pod之间的通信中丢失数据包。如果需要,我们可以对其进行配置:

apiVersion: spiderpool.spidernet.io/v2beta1
kind: SpiderMultusConfig
metadata:
  name: txqueue-demo 
  namespace: default
spec:
  cniType: macvlan
  macvlan:
    master: ["eth0"]
  enableCoordinator: true
  coordinator:
    txQueueLen: 2000 

为 Pod 的 veth0 网卡配置本地链路地址,支持服务网格场景

默认情况下,Coordinator 不会为 veth0 网卡配置本地链路地址。但有些场景下(比如服务网格),经过 veth0 网卡流入的网格流量会随 istio 设置的 iptables 规则重定向,如果 veth0 没有 IP 地址,这会导致这部分流量被丢弃(见#Issue3568)。所以在这个场景下,我们需要为 veth0 配置一个本地链路地址。

apiVersion: spiderpool.spidernet.io/v2beta1
kind: SpiderMultusConfig
metadata:
  name: istio-demo 
  namespace: default
spec:
  cniType: macvlan
  macvlan:
    master: ["eth0"]
  enableCoordinator: true
  coordinator:
    vethLinkAddress: "169.254.200.1"

vethLinkAddress 默认为空,表示不配置。不为空则必须是一个合法的本地链路地址。

自动获取集群 Service 的 CIDR

Kubernetes 1.29 开始支持以 ServiceCIDR 资源的方式配置集群 Service 的 CIDR,更多信息参考 KEP 1880。如果您的集群支持 ServiceCIDR,Spiderpool-controller 组件 自动监听 ServiceCIDR 资源的变化,将读取到的 Service 子网信息自动更新到 Spidercoordinator 的 Status 中。

~# kubectl get servicecidr kubernetes -o yaml
apiVersion: networking.k8s.io/v1alpha1
kind: ServiceCIDR
metadata:
  creationTimestamp: "2024-01-25T08:36:00Z"
  finalizers:
  - networking.k8s.io/service-cidr-finalizer
  name: kubernetes
  resourceVersion: "504422"
  uid: 72461b7d-fddd-409d-bdf2-83d1a2c067ca
spec:
  cidrs:
  - 10.233.0.0/18
  - fd00:10:233::/116
status:
  conditions:
  - lastTransitionTime: "2024-01-28T06:38:55Z"
    message: Kubernetes Service CIDR is ready
    reason: ""
    status: "True"
    type: Ready

~# kubectl get spidercoordinators.spiderpool.spidernet.io default -o yaml
apiVersion: spiderpool.spidernet.io/v2beta1
kind: SpiderCoordinator
metadata:
  creationTimestamp: "2024-01-25T08:41:50Z"
  finalizers:
  - spiderpool.spidernet.io
  generation: 1
  name: default
  resourceVersion: "41645"
  uid: d1e095db-d6e8-4413-b60e-fcf31ad2bf5e
spec:
  detectGateway: false
  detectIPConflict: false
  hijackCIDR:
  - 10.244.64.0/18
  - fd00:10:244::/112
  podRPFilter: 0
  hostRPFilter: 0
  hostRuleTable: 500
  mode: auto
  podCIDRType: auto
  podDefaultRouteNIC: ""
  podMACPrefix: ""
  tunePodRoutes: true
  txQueueLen: 0
status:
  phase: Synced
  serviceCIDR:
  - 10.233.0.0/18
  - fd00:10:233::/116

已知问题

  • underlay 模式下,underlay Pod 与 Overlay Pod(calico or cilium) 进行 TCP 通信失败

此问题是因为数据包来回路径不一致导致,发出的请求报文匹配源Pod 侧的路由,会通过 veth0 转发到主机侧,再由主机侧转发至目标 Pod。 目标 Pod 看见数据包的源 IP 为 源 Pod 的 Underlay IP,直接走 Underlay 网络而不会经过源 Pod 所在主机。 在该主机看来这是一个非法的数据包(意外的收到 TCP 的第二次握手报文,认为是 conntrack table invalid), 所以被 kube-proxy 的一条 iptables 规则显式的 drop 。 目前可以通过切换 kube-proxy 的模式为 ipvs 规避。这个问题预计在 k8s 1.29 修复。 当 sysctl nf_conntrack_tcp_be_liberal 设置为 1 时,kube-proxy 将不会下发这条 DROP 规则。

  • overlay 模式下, 当 Pod 附加多张网卡时。如果集群的缺省CNI 为 Cilium, Pod 的 underlay 网卡 无法与节点通信。

我们借助缺省CNI创建 Veth 设备,实现 Pod 的 underlay IP 与节点通信(正常情况下,macvlan 在 bridge 模式下, 其父子接口无法直接),但 Cilium 不允许非 Cilium 子网的 IP 从 Veth 设备转发。