SuperEdge service group 利用 application-grid-wrapper 实现拓扑感知,完成了同一个 nodeunit 内服务的闭环访问
在深入分析 application-grid-wrapper 之前,这里先简单介绍一下社区 Kubernetes 原生支持的拓扑感知特性
Kubernetes service topology awareness 特性于v1.17发布alpha版本,用于实现路由拓扑以及就近访问特性。用户需要在 service 中添加 topologyKeys 字段标示拓扑key类型,只有具有相同拓扑域的endpoint会被访问到,目前有三种 topologyKeys可供选择:
"kubernetes.io/hostname":访问本节点内(kubernetes.io/hostname label value相同)的 endpoint,如果没有则 service 访问失败
"topology.kubernetes.io/zone":访问相同zone域内(topology.kubernetes.io/zone label value 相同)的 endpoint,如果没有则 service 访问失败
"topology.kubernetes.io/region":访问相同region域内(topology.kubernetes.io/region label value相同)的 endpoint,如果没有则 service 访问失败
除了单独填写如上某一个拓扑key之外,还可以将这些key构造成列表进行填写,例如:["kubernetes.io/hostname", "topology.kubernetes.io/zone", "topology.kubernetes.io/region"],这表示:优先访问本节点内的 endpoint;如果不存在,则访问同一个 zone 内的 endpoint;如果再不存在,则访问同一个 region 内的 endpoint,如果都不存在则访问失败
另外,还可以在列表最后(只能最后一项)添加"*"表示:如果前面拓扑域都失败,则访问任何有效的 endpoint,也即没有限制拓扑了,示例如下:
# A Service that prefers node local, zonal, then regional endpoints but falls back to cluster wide endpoints. apiVersion: v1 kind: Service metadata: name: my-service spec: selector: app: my-app ports: - protocol: TCP port: 80 targetPort: 9376 topologyKeys: - "kubernetes.io/hostname" - "topology.kubernetes.io/zone" - "topology.kubernetes.io/region" - "*"而service group实现的拓扑感知和社区对比,有如下区别:
service group 拓扑key可以自定义,也即为 gridUniqKey,使用起来更加灵活;而社区实现目前只有三种选择:"kubernetes.io/hostname","topology.kubernetes.io/zone" 以及 "topology.kubernetes.io/region"
service group 只能填写一个拓扑 key,也即只能访问本拓扑域内有效的 endpoint,无法访问其它拓扑域的 endpoint;而社区可以通过 topologyKey 列表以及"*"实现其它备选拓扑域 endpoint 的访问
service group 实现的拓扑感知,service 配置如下:
# A Service that only prefers node zone1al endpoints. apiVersion: v1 kind: Service metadata: annotations: topologyKeys: '["zone1"]' labels: superedge.io/grid-selector: servicegrid-demo name: servicegrid-demo-svc spec: ports: - port: 80 protocol: TCP targetPort: 8080 selector: appGrid: echo在介绍完 service group 实现的拓扑感知后,我们深入到源码分析实现细节。同样的,这里以一个使用示例开始分析:
# step1: labels edge nodes $ kubectl get nodes NAME STATUS ROLES AGE VERSION node0 Ready <none> 16d v1.16.7 node1 Ready <none> 16d v1.16.7 node2 Ready <none> 16d v1.16.7 # nodeunit1(nodegroup and servicegroup zone1) $ kubectl --kubeconfig config label nodes node0 zone1=nodeunit1 # nodeunit2(nodegroup and servicegroup zone1) $ kubectl --kubeconfig config label nodes node1 zone1=nodeunit2 $ kubectl --kubeconfig config label nodes node2 zone1=nodeunit2 ... # step3: deploy echo ServiceGrid $ cat <<EOF | kubectl --kubeconfig config apply -f - apiVersion: superedge.io/v1 kind: ServiceGrid metadata: name: servicegrid-demo namespace: default spec: gridUniqKey: zone1 template: selector: appGrid: echo ports: - protocol: TCP port: 80 targetPort: 8080 EOF servicegrid.superedge.io/servicegrid-demo created # note that there is only one relevant service generated $ kubectl get svc NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE kubernetes ClusterIP 192.168.0.1 <none> 443/TCP 16d servicegrid-demo-svc ClusterIP 192.168.6.139 <none> 80/TCP 10m # step4: access servicegrid-demo-svc(service topology and closed-looped) # execute on node0 $ curl 192.168.6.139|grep "node name" node name: node0 # execute on node1 and node2 $ curl 192.168.6.139|grep "node name" node name: node2 $ curl 192.168.6.139|grep "node name" node name: node1在创建完 ServiceGrid CR 后,ServiceGrid Controller 负责根据 ServiceGrid 产生对应的 service (包含由serviceGrid.Spec.GridUniqKey 构成的 topologyKeys annotations);而 application-grid-wrapper 根据 service 实现拓扑感知,下面依次分析。
ServiceGrid Controller 分析ServiceGrid Controller 逻辑和 DeploymentGrid Controller 整体一致,如下:
1、创建并维护 service group 需要的若干CRDs(包括:ServiceGrid)
2、监听 ServiceGrid event,并填充 ServiceGrid 到工作队列中;循环从队列中取出 ServiceGrid 进行解析,创建并且维护对应的 service
3、监听 service event,并将相关的 ServiceGrid 塞到工作队列中进行上述处理,协助上述逻辑达到整体 reconcile 逻辑
注意这里区别于 DeploymentGrid Controller:
一个 ServiceGrid 对象只产生一个 service
只需额外监听 service event,无需监听 node 事件。因为 node的CRUD 与 ServiceGrid 无关