4、网络拓扑数据结构设计
网络拓扑感知调度插件的核心在于将物理或虚拟的网络拓扑结构抽象为调度器可理解的数据模型。本章将详细定义三个关键数据结构:Node网络区域标签、Pod网络需求以及拓扑距离矩阵,为后续的插件实现奠定数据基础。
4.1 Node网络区域标签设计
为了将Kubernetes节点映射到实际的网络拓扑中,我们需要为每个Node打上标准化的标签。这些标签描述了节点所处的网络层级,例如可用区(Zone)、机架(Rack)或交换机(Switch)级别。
推荐使用以下标签键(Key)体系,所有标签均以 topology.kubernetes.io/ 或 node.topology/ 为前缀,以确保与Kubernetes原生拓扑域兼容。
| 标签键 (Label Key) | 示例值 (Example Value) | 描述 |
|---|---|---|
topology.kubernetes.io/zone |
us-east-1a |
云提供商或数据中心的可用区 |
node.topology/rack |
rack-12 |
物理机架或逻辑机架ID |
node.topology/switch |
spine-01 |
接入交换机或汇聚交换机标识 |
node.topology/host |
host-group-3 |
宿主机组或超融合集群标识 |
设计原则:标签值应具有全局唯一性或至少在集群范围内可解析。建议使用扁平化的键值对,避免复杂的层级编码,将层级关系交由拓扑距离矩阵处理。
以下是一个带有网络区域标签的Node YAML示例片段:
apiVersion: v1
kind: Node
metadata:
name: worker-node-5
labels:
topology.kubernetes.io/zone: "zone-a"
node.topology/rack: "rack-07"
node.topology/switch: "leaf-03"
spec:
...
4.2 Pod网络需求定义
Pod需要声明其对网络拓扑的偏好或硬性要求。我们通过在Pod Spec中增加自定义注解(Annotation)来实现,避免修改Kubernetes核心API。
定义以下注解键(Annotation Key):
scheduler.topology/affinity:指定Pod希望与哪些拓扑域亲和,例如希望与某个Zone或Rack内的Pod同节点。scheduler.topology/anti-affinity:指定Pod希望与哪些拓扑域互斥,例如避免将Pod调度到同一交换机下。scheduler.topology/max-distance:指定Pod能接受的最大拓扑距离(整数),用于控制延迟敏感型应用的部署范围。
| 注解键 (Annotation Key) | 值格式 (Value Format) | 示例 |
|---|---|---|
scheduler.topology/affinity |
topologyKey=value |
node.topology/rack=rack-07 |
scheduler.topology/anti-affinity |
topologyKey=value |
topology.kubernetes.io/zone=zone-b |
scheduler.topology/max-distance |
integer |
2 |
Pod YAML示例:
apiVersion: v1
kind: Pod
metadata:
name: latency-sensitive-pod
annotations:
scheduler.topology/affinity: "node.topology/rack=rack-07"
scheduler.topology/max-distance: "1"
spec:
containers:
- name: app
image: nginx:latest
注意:如果Pod同时声明了
affinity 和 anti-affinity,调度器应优先处理 anti-affinity 规则,以避免调度冲突。
4.3 拓扑距离矩阵数据结构
拓扑距离矩阵是调度器进行网络拓扑感知决策的核心。它是一个二维矩阵,定义了集群中任意两个拓扑域(如Zone、Rack、Switch)之间的“网络距离”。距离值越小,表示网络延迟越低或带宽越高。
我们使用Go语言的结构体来定义这个矩阵:
// TopologyDistance 表示两个拓扑域之间的距离
type TopologyDistance struct {
Source string `json:"source"` // 源拓扑域标识,例如 "rack-07"
Target string `json:"target"` // 目标拓扑域标识,例如 "rack-12"
Distance int `json:"distance"` // 距离值,例如 1, 2, 3
MetricType string `json:"metric_type"` // 度量类型,例如 "latency_ms" 或 "hop_count"
}
// TopologyMatrix 是整个集群的拓扑距离集合
type TopologyMatrix struct {
Distances []TopologyDistance `json:"distances"`
Version string `json:"version"` // 矩阵版本号,用于缓存失效
}
矩阵数据通常由外部网络监控系统(如NetBox、Cisco APIC)生成,并通过ConfigMap或自定义资源(CRD)注入到调度器中。以下是一个JSON格式的矩阵示例:
{
"version": "v20250301",
"distances": [
{"source": "zone-a", "target": "zone-a", "distance": 0, "metric_type": "hop_count"},
{"source": "zone-a", "target": "zone-b", "distance": 2, "metric_type": "hop_count"},
{"source": "rack-07", "target": "rack-07", "distance": 0, "metric_type": "hop_count"},
{"source": "rack-07", "target": "rack-12", "distance": 1, "metric_type": "hop_count"},
{"source": "leaf-03", "target": "spine-01", "distance": 1, "metric_type": "hop_count"}
]
}
性能优化:在调度器内部,建议将
TopologyMatrix 转换为一个 map[string]map[string]int 的嵌套哈希表,以实现O(1)时间复杂度的距离查询。键为拓扑域ID,值为到其他域的距离映射。
下图展示了从Node标签到Pod需求,再到距离矩阵的完整数据流架构:
4.4 数据结构关系总结
下表总结了三种数据结构在调度流程中的角色与交互关系:
| 数据结构 | 数据来源 | 存储位置 | 调度器使用方式 |
|---|---|---|---|
| Node网络区域标签 | 集群管理员 / 自动标注工具 | Node对象的 metadata.labels |
通过 NodeLister 获取,用于确定候选节点的拓扑归属 |
| Pod网络需求 | 应用开发者 / 运维人员 | Pod对象的 metadata.annotations |
在 PreFilter 阶段解析,生成调度约束 |
| 拓扑距离矩阵 | 外部网络监控系统 | ConfigMap 或自定义资源 (CRD) | 在 Score 阶段查询,计算节点拓扑得分 |
扩展思考:对于大规模集群(超过1000个节点),建议将拓扑距离矩阵存储在Redis或类似的内存数据库中,并通过调度器插件定期同步,以避免ConfigMap更新带来的性能瓶颈。