目录

Cilium的拓扑感知路由

概述

Kubernetes 的拓扑感知路由提供了一种机制帮助保持网络流量处于流量发起的区域内。在集群中 Pod 之间优先使用相同区域的流量有助于提高可靠性、性能(网络延迟和吞吐量)或降低成本。Cilium 在经过 KubeProxyReplacement 之后,提供的 Cilium Service 已经实现了 Kubernetes 原生 Service 的拓扑流量的模型,但是我们还需要测试一下 cilium-chain 是否提供相同的功能。

测试条件

其中 loadBalancer.serviceTopology=true 参数开启之后,Service 默认都会使用 Topology Aware Routing,不需要用户在 Service 通过 Annotations 来标记 service.kubernetes.io/topology-aware-hints: "auto"

1
helm upgrade cilium . --reuse-values --set loadBalancer.serviceTopology=true

要给所有的 Node 都标记拓扑信息。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
# zone=gz-a
kubectl label nodes 10.189.110.45 topology.kubernetes.io/region=gz
kubectl label nodes 10.189.110.45 topology.kubernetes.io/zone=gz-a
kubectl label nodes 10.189.110.46 topology.kubernetes.io/region=gz
kubectl label nodes 10.189.110.46 topology.kubernetes.io/zone=gz-a
kubectl label nodes 10.189.110.47 topology.kubernetes.io/region=gz
kubectl label nodes 10.189.110.47 topology.kubernetes.io/zone=gz-b
kubectl label nodes 10.189.110.48 topology.kubernetes.io/region=gz
kubectl label nodes 10.189.110.48 topology.kubernetes.io/zone=gz-b
# zone=gz-b
kubectl label nodes 10.189.110.83 topology.kubernetes.io/region=gz
kubectl label nodes 10.189.110.83 topology.kubernetes.io/zone=gz-a
kubectl label nodes 10.189.110.84 topology.kubernetes.io/region=gz
kubectl label nodes 10.189.110.84 topology.kubernetes.io/zone=gz-a

部署一个 Deployment,以及为这个 Deployment 创建一个 Service。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
cat <<EOF | kubectl apply -f -
apiVersion: apps/v1
kind: Deployment
metadata:
  name: test-app
spec:
  replicas: 4
  selector:
    matchLabels:
      app: test-app
  template:
    metadata:
      labels:
        app: test-app
    spec:
      containers:
        - name: nginx
          image: httpd:latest
          ports:
            - containerPort: 80            
EOF

其中 Service 通过标记 service.kubernetes.io/topology-mode: Auto 来指定开启 Service 的拓扑感知路由.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: Service
metadata:
  name: test-service
  annotations:
    service.kubernetes.io/topology-mode: Auto
spec:
  selector:
    app: test-app
  ports:
    - protocol: TCP
      port: 80
      targetPort: 80
      
EOF

结果展示

首先查看 Pod 的分布,可以看到4个 Pod,分布在了4个节点2个 Zone。

1
2
3
4
5
6
7
# k get po -o wide
NAME                          READY   STATUS       RESTARTS   AGE     IP              NODE            
centos                        1/1     Running      0          5h22m   10.189.51.117   10.189.110.47   
test-app-78ddd75b84-cxxsg     1/1     Running      0          50m     10.189.65.196   10.189.110.84   
test-app-78ddd75b84-hsnx7     1/1     Running      0          14m     10.189.67.81    10.189.110.47   
test-app-78ddd75b84-k7pb9     1/1     Running      0          50m     10.189.65.190   10.189.110.48   
test-app-78ddd75b84-k9fg5     1/1     Running      0          55m     10.189.65.141   10.189.110.83   

查看创建的 Service 的 ClusterIP。

1
2
3
# k get svc
NAME                 TYPE           CLUSTER-IP      EXTERNAL-IP          PORT(S)         AGE
test-service         ClusterIP      10.99.164.171   <none>               80/TCP          91m

查看 cilium-agent 构建的 Service List,从 cilium-agent 的 Service List 可见,在该节点上的 Service 可路由的后端 IP 只有一个 Zone 的 Pod IP。

1
2
3
4
# kubectl exec -n kube-system ds/cilium -- cilium service list
ID     Frontend              Service Type   Backend
1143   10.99.164.171:80      ClusterIP      1 => 10.189.65.141:80 (active)
                                            2 => 10.189.65.196:80 (active)

最后查看一下 EndpointSlice 上的拓扑信息,可以见到每个 addresses 下都有 hints 字段标记这个 addresses 会被路由到哪个 Zone。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
# k get endpointslice test-service-9rwh5 -o yaml
addressType: IPv4
apiVersion: discovery.k8s.io/v1
endpoints:
- addresses:
  - 10.189.65.141
  conditions:
    ready: true
    serving: true
    terminating: false
  hints:
    forZones:
    - name: gz-a
  nodeName: 10.189.110.83
  targetRef:
    kind: Pod
    name: test-app-78ddd75b84-k9fg5
    namespace: default
    uid: 8e5dad78-12de-461c-a1c3-a0bad62b17a1
  zone: gz-a
- addresses:
  - 10.189.65.190
  conditions:
    ready: true
    serving: true
    terminating: false
  hints:
    forZones:
    - name: gz-b
  nodeName: 10.189.110.48
  targetRef:
    kind: Pod
    name: test-app-78ddd75b84-k7pb9
    namespace: default
    uid: f056c609-54d8-4b9d-83b4-be99e9f45d09
  zone: gz-b
- addresses:
  - 10.189.65.196
  conditions:
    ready: true
    serving: true
    terminating: false
  hints:
    forZones:
    - name: gz-a
  nodeName: 10.189.110.84
  targetRef:
    kind: Pod
    name: test-app-78ddd75b84-cxxsg
    namespace: default
    uid: 05ae9e83-af29-4d91-b1e6-a26715e3128b
  zone: gz-a
- addresses:
  - 10.189.67.81
  conditions:
    ready: true
    serving: true
    terminating: false
  hints:
    forZones:
    - name: gz-b
  nodeName: 10.189.110.47
  targetRef:
    kind: Pod
    name: test-app-78ddd75b84-hsnx7
    namespace: default
    uid: ac0d391d-e88a-4583-ad5d-7840da5ce286
  zone: gz-b
kind: EndpointSlice
...

其他

Annotation添加的问题

经过测试,Service 上的 service.kubernetes.io/topology-aware-hints: "auto" 都必须添加,否则 Service 会按默认的方式路由,从下可以知道,当前 Service 会按 Pod 的数量和规则进行路由,完全忽视了拓扑信息。

1
2
3
4
5
6
# kubectl exec -n kube-system ds/cilium -- cilium service list
ID     Frontend              Service Type   Backend
1143   10.99.164.171:80      ClusterIP      1 => 10.189.65.141:80 (active)
                                            2 => 10.189.65.196:80 (active)
                                            3 => 10.189.65.190:80 (active)
                                            4 => 10.189.67.81:80 (active)

Pod数量问题

经过测试,每个拓扑结果必须要有2个以上的 Pod 才可能实现拓扑感知路由,这个很容易理解,因为如果有一个 Zone 只有一个 Pod,如果这个 Zone 的流量只往这个 Zone 的 Pod 发送流量,当 Pod 临时挂了,流量就无法切到其他 Zone 了,因此如果 Pod 数量太少,就会影响拓扑感知路由的规则配置。比如把测试例子的 Deployment 的副本数降为3,那么肯定有 Zone 是只有一个 Pod 的,此时即使配饰了 Annotation,但为了防止上述提到的情况,还是会把所有的 Pod 作为后端提供给 Service。

1
2
3
4
# kubectl exec -n kube-system ds/cilium -- cilium service list
1143   10.99.164.171:80      ClusterIP      1 => 10.189.65.141:80 (active)
                                            2 => 10.189.65.196:80 (active)
                                            3 => 10.189.65.190:80 (active)

参考资料

  1. Traffic Distribution and Topology Aware Hints
  2. Topology Aware Routing
  3. traffic-distribution
  4. 如何在Amazon EKS中使用拓扑感知提示?
  5. Topology Aware Load-Balancing