5.3.8 地域负载均衡
一个地域定义了workload instance
在你的网格中的地理位置。这三个元素定义了一个地域:
地区: 代表较大的地理区域,例如
us-east
. 一个地区通常包含许多可用 zones。在Kubernetes
中,标签topology.kubernetes.io/region
确定节点的区域。区域: 区域内的一组计算资源。通过在区域内的多个区域中运行服务,可以在区域内的区域之间进行故障转移,同时保持最终用户的数据地域性。在
Kubernetes
中,标签topology.kubernetes.io/zone
确定节点的区域。分区: 允许管理员进一步细分区域,以实现更细粒度的控制,例如“相同机架”。
Kubernetes
中不存在分区的概念。结果,Istio
引入了自定义节点标签topology.istio.io/subzone
来定义分区。
如果您使用托管的
Kubernetes
服务,则云提供商应为您配置区域和区域标签。如果您正在运行自己的Kubernetes
集群,则需要将这些标签添加到您的节点上。
地域是分层的,按匹配顺序排列:
地区
区域
分区
这意味着,在foo
地区的bar
区域中运行Pod
是不被认为是在baz
地区的bar
区域中运行的Pod。
Istio
使用地域信息来控制负载平衡行为。按照本系列的任务一,为您的网格配置地域负载均衡。
前置条件
在开始区域负载均衡任务之前,必须首先在多个集群上安装Istio
。群集必须跨越三个地区,其中包含四个可用区域。所需集群的数量可能会因您的云提供商所提供的功能而异。
为简单起见,我们假设只有一个
primary cluster
在网格中。由于更改仅需要应用于一个集群,因此这简化了配置控制平面的过程。
我们将部署 helloWorld
应用程序的多个实例,如下所示:
环境变量
本指南假定将通过 Kubernetes 配置文件 中的上下文切换访问集群。以下环境变量将用于各种上下文:
变量 | 描述 |
---|---|
CTX_PRIMARY |
用于主群集的上下文。 |
CTX_R1_Z1 |
用于与 region1.zone1 中的 Pod 交互的上下文。 |
CTX_R1_Z2 |
用于与 region1.zone2 中的 Pod 交互的上下文。 |
CTX_R2_Z3 |
用于与 region2.zone3 中的 Pod 交互的上下文。 |
CTX_R3_Z4 |
用于与 region3.zone4 中的 Pod 交互的上下文。 |
创建 sample
命名空间
首先,启用自动注入 Sidecar 并为 sample
命名空间生成 yaml
cat <<EOF > sample.yaml
apiVersion: v1
kind: Namespace
metadata:
name: sample
labels:
istio-injection: enabled
EOF
为每个集群添加 sample
命名空间:
for CTX in "$CTX_PRIMARY" "$CTX_R1_Z1" "$CTX_R1_Z2" "$CTX_R2_Z3" "$CTX_R3_Z4"; \
do \
kubectl --context="$CTX" apply -f sample.yaml; \
done
部署helloWorld
使用地域作为版本号,为每个地域生成 helloWorld
的 yaml:
for LOC in "region1.zone1" "region1.zone2" "region2.zone3" "region3.zone4"; \
do \
./@samples/helloworld/gen-helloworld.sh@ \
--version "$LOC" > "helloworld-${LOC}.yaml"; \
done
应用HelloWorld
YAML到每个地域的合适集群:
kubectl apply --context="${CTX_R1_Z1}" -n sample \
-f helloworld-region1.zone1.yaml
kubectl apply --context="${CTX_R1_Z2}" -n sample \
-f helloworld-region1.zone2.yaml
kubectl apply --context="${CTX_R2_Z3}" -n sample \
-f helloworld-region2.zone3.yaml
kubectl apply --context="${CTX_R3_Z4}" -n sample \
-f helloworld-region3.zone4.yaml
部署 sleep
部署 Sleep
应用到 region1
zone1
:
kubectl apply --context="${CTX_R1_Z1}" \
-f @samples/sleep/sleep.yaml@ -n sample
等待 helloWorld
Pods
等到 HelloWorld
在每个区域的 Pod 都为 Running
:
kubectl get pod --context="${CTX_R1_Z1}" -n sample -l app="helloworld" \
-l version="region1.zone1"
NAME READY STATUS RESTARTS AGE
helloworld-region1.zone1-86f77cd7b-cpxhv 2/2 Running 0 30s
kubectl get pod --context="${CTX_R1_Z2}" -n sample -l app="helloworld" \
-l version="region1.zone2"
NAME READY STATUS RESTARTS AGE
helloworld-region1.zone2-86f77cd7b-cpxhv 2/2 Running 0 30s
kubectl get pod --context="${CTX_R2_Z3}" -n sample -l app="helloworld" \
-l version="region2.zone3"
NAME READY STATUS RESTARTS AGE
helloworld-region2.zone3-86f77cd7b-cpxhv 2/2 Running 0 30s
kubectl get pod --context="${CTX_R3_Z4}" -n sample -l app="helloworld" \
-l version="region3.zone4"
NAME READY STATUS RESTARTS AGE
helloworld-region3.zone4-86f77cd7b-cpxhv 2/2 Running 0 30s
恭喜您! 您已成功完成系统配置,现在可以开始进行地域负载均衡任务了
下一步
现在,您可以配置以下负载均衡选项之一:
- 地域故障转移
- 地域权重分布
应当仅配置负载均衡选项之一,因为它们是互斥的。尝试同时配置两者可能会导致意外行为。
地域故障转移
在此任务中,您将使用 sleep
pod 在 region1.zone1
作为请求源发送到 helloWorld
服务。然后,您将触发故障,这些故障将按照以下顺序导致不同地域之间的故障转移:
在内部,Envoy优先级用于控制故障转移。这些优先级将按照以下方式分配来自sleep
Pod(在 region1
zone1
)的流量:
优先级 | 地域 | 细节 |
---|---|---|
0 | region1.zone1 |
地区、区域、分区全部匹配。 |
1 | None | 由于此任务不使用分区,因此没有其他分区的匹配项。 |
2 | region1.zone2 |
同一个地区内的不用区域。 |
3 | region2.zone3 |
没有匹配项,但是为 region1 ->region2 定义了故障转移。 |
4 | region3.zone4 |
没有匹配项并且没有为 region1 ->region3 定义故障转移。 |
配置地域故障转移
应用一个 DestinationRule
配置如下:
- 异常检测: 用于
helloWorld
服务。这是故障转移正常运行所必须的。特别是,它可以配置Sidecar代理以知道服务的Endpoint何时不正常,最终触发故障转移到下一个地域。 故障转移: 地区之间的策略,这确保了超出地区边界的故障转移将具有可预测的行为。
连接池: 强制每个HTTP请求使用一个新连接的策略。该任务利用
Envoy
的逐出 功能强制将故障转移到下一个位置。一旦逐出,Envoy 将拒绝所有新的请求。由于每个请求都使用一个新连接,这将导致在耗尽后立即进行故障转移。此配置仅用于演示目的。
kubectl --context="${CTX_PRIMARY}" apply -n sample -f - <<EOF
apiVersion: networking.istio.io/v1beta1
kind: DestinationRule
metadata:
name: helloworld
spec:
host: helloworld.sample.svc.cluster.local
trafficPolicy:
connectionPool:
http:
maxRequestsPerConnection: 1
loadBalancer:
simple: ROUND_ROBIN
localityLbSetting:
enabled: true
failover:
- from: region1
to: region2
outlierDetection:
consecutive5xxErrors: 1
interval: 1s
baseEjectionTime: 1m
EOF
验证流量保持在region1.zone1
从sleep
Pod调用helloWorld
服务
kubectl exec --context="${CTX_R1_Z1}" -n sample -c sleep \
"$(kubectl get pod --context="${CTX_R1_Z1}" -n sample -l \
app=sleep -o jsonpath='{.items[0].metadata.name}')" \
-- curl -sSL helloworld.sample:5000/hello
Hello version: region1.zone1, instance: helloworld-region1.zone1-86f77cd7b-cpxhv
验证响应中的version
是region1.zone
。
重复几次,验证响应总是相同的。
故障转移到 region1.zone2
接下来, 触发故障转移到region1.zone2
。为此,您在region1.zone1
中helloWorld
逐出 Envoy Sidecar 代理 :
kubectl --context="${CTX_R1_Z1}" exec \
"$(kubectl get pod --context="${CTX_R1_Z1}" -n sample -l app=helloworld \
-l version=region1.zone1 -o jsonpath='{.items[0].metadata.name}')" \
-n sample -c istio-proxy -- curl -sSL -X POST 127.0.0.1:15000/drain_listeners
从 sleep
Pod 调用 helloWorld
服务:
kubectl exec --context="${CTX_R1_Z1}" -n sample -c sleep \
"$(kubectl get pod --context="${CTX_R1_Z1}" -n sample -l \
app=sleep -o jsonpath='{.items[0].metadata.name}')" \
-- curl -sSL helloworld.sample:5000/hello
Hello version: region1.zone2, instance: helloworld-region1.zone2-86f77cd7b-cpxhv
第一个调用将失败,这将触发故障转移。多次重复该命令,并验证响应中的 version
始终为 region1.zone2
。
故障转移到 region2.zone3
现在触发故障转移到 region2.zone3
。正如您之前所做的,配置 helloWorld
在 region1.zone2
中调用失败。
kubectl --context="${CTX_R1_Z2}" exec \
"$(kubectl get pod --context="${CTX_R1_Z2}" -n sample -l app=helloworld \
-l version=region1.zone2 -o jsonpath='{.items[0].metadata.name}')" \
-n sample -c istio-proxy -- curl -sSL -X POST 127.0.0.1:15000/drain_listeners
从sleep
Pod 调用helloWorld
服务:
kubectl exec --context="${CTX_R1_Z1}" -n sample -c sleep \
"$(kubectl get pod --context="${CTX_R1_Z1}" -n sample -l \
app=sleep -o jsonpath='{.items[0].metadata.name}')" \
-- curl -sSL helloworld.sample:5000/hello
Hello version: region2.zone3, instance: helloworld-region2.zone3-86f77cd7b-cpxhv
第一个调用将失败,这将触发故障转移。多次重复该命令,并验证响应中的version
始终为region2.zone3
。
故障转移到 region3.zone4
现在触发故障转移到 region3.zone4
。正如您之前所做的, 配置 helloWorld
在 region2.zone3
中调用失败。
kubectl --context="${CTX_R2_Z3}" exec \
"$(kubectl get pod --context="${CTX_R2_Z3}" -n sample -l app=helloworld \
-l version=region2.zone3 -o jsonpath='{.items[0].metadata.name}')" \
-n sample -c istio-proxy -- curl -sSL -X POST 127.0.0.1:15000/drain_listeners
从sleep
Pod调用helloWorld
服务:
kubectl exec --context="${CTX_R1_Z1}" -n sample -c sleep \
"$(kubectl get pod --context="${CTX_R1_Z1}" -n sample -l \
app=sleep -o jsonpath='{.items[0].metadata.name}')" \
-- curl -sSL helloworld.sample:5000/hello
Hello version: region3.zone4, instance: helloworld-region3.zone4-86f77cd7b-cpxhv
第一次调用将失败,这将触发故障转移。多次重复该命令,并验证响应中的 version
始终为 region3.zone4
。
恭喜! 您成功配置了地域故障转移!
地域权重分布
在这个任务中,您将使用 region1
zone1
中的 sleep
Pod 作为 helloWorld
服务的请求源。您将使用以下分布在不同的地域配置Istio:
地区 | 区域 | 流量(%) |
---|---|---|
region1 |
zone1 |
70 |
region1 |
zone2 |
20 |
region2 |
zone3 |
0 |
region3 |
zone4 |
10 |
配置权重分布
应用 DestinationRule
配置如下:
故障检测 用于
helloWorld
服务。这是 Distribution 正常运行所必需的。特别是,它配置 Sidecar 代理以知道服务的 Endpoint 何时不健康。权重分布 如上表中所述的
helloWorld
服务。
kubectl --context="${CTX_PRIMARY}" apply -n sample -f - <<EOF
apiVersion: networking.istio.io/v1beta1
kind: DestinationRule
metadata:
name: helloworld
spec:
host: helloworld.sample.svc.cluster.local
trafficPolicy:
loadBalancer:
localityLbSetting:
enabled: true
distribute:
- from: region1/zone1/*
to:
"region1/zone1/*": 70
"region1/zone2/*": 20
"region3/zone4/*": 10
outlierDetection:
consecutive5xxErrors: 100
interval: 1s
baseEjectionTime: 1m
EOF
验证分布
从 sleep
Pod 调用 helloWorld
服务:
kubectl exec --context="${CTX_R1_Z1}" -n sample -c sleep \
"$(kubectl get pod --context="${CTX_R1_Z1}" -n sample -l \
app=sleep -o jsonpath='{.items[0].metadata.name}')" \
-- curl -sSL helloworld.sample:5000/hello
重复多次,并验证每个 Pod 的回复数与本指南顶部表格中的预期百分比匹配。
恭喜! 你成功配置了地域权重分布!
清理
1删除生成的文件
rm -f sample.yaml helloworld-region*.zone*.yaml
2删除 sample 命名空间
for CTX in "$CTX_PRIMARY" "$CTX_R1_Z1" "$CTX_R1_Z2" "$CTX_R2_Z3" "$CTX_R3_Z4";
do
kubectl --context="$CTX" delete ns sample --ignore-not-found=true;
done
恭喜! 您成功地完成了地域负载均衡任务!