概述
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)
|
参考资料
- Traffic Distribution and Topology Aware Hints
- Topology Aware Routing
- traffic-distribution
- 如何在Amazon EKS中使用拓扑感知提示?
- Topology Aware Load-Balancing