Skip to main content

Command Palette

Search for a command to run...

Istio 负载均衡的区域感知

Updated
3 min read

Envoy/Istio 1.1 中有个有趣的新特性:负载均衡提供了区域感知的能力。简单说来,就是在分区部署的较大规模的集群,或者公有云上,Istio 负载均衡可以根据节点的区域标签,对调用目标做出就近选择。在跨区部署的应用中,原始的 Kubernetes 负载均衡可能会把来自 A 区的请求发送给远在 B 区的服务,造成高成本的跨区调用。要缩减这种损耗,通常都需要实现更多的逻辑,Istio 的区域感知特性在某种程度上提供了一种解决办法。

准备工作

接下来首先做一些琐碎的安装工作,这里选择了常见的 GCP 作为测试环境,Istio 版本为 1.1.2。

  1. 在 GCP 的 us-central1 创建一个区域集群:

     $ gcloud beta container clusters create "standard-cluster-1" \
     ...
      --no-enable-basic-auth \
      --cluster-version "1.12.6-gke.10" \
      --machine-type "n1-standard-1" --image-type "COS" \
     ...
      --num-nodes "2" \
      --no-enable-cloud-logging --no-enable-cloud-monitoring \
     ...--no-enable-ip-alias \
      --addons HorizontalPodAutoscaling \
      --enable-autoupgrade --enable-autorepair
    
  2. 获取本地认证,为 kubectl 生成 context

     $ gcloud beta container clusters get-credentials \
     standard-cluster-1 --region us-central1 \
     --project dustise-mesh-lab
    
  3. 查看节点标签,这里会看到不同的节点会使用区域标签进行标识:

     $ kubectl get nodes --show-labels
    
     ...
     failure-domain.beta.kubernetes.io/region=us-central1,failure-domain.beta.kubernetes.io/zone=us-central1-a
     ...
     failure-domain.beta.kubernetes.io/region=us-central1,failure-domain.beta.kubernetes.io/zone=us-central1-c
     ...
    
  4. 为 Istio 准备 RBAC:

     $ kubectl create clusterrolebinding cluster-admin-binding \
         --clusterrole=cluster-admin \
         --user=$(gcloud config get-value core/account)
    
  5. 初始化 Istio CRD:

     $ kubectl create namespace istio-system
     $ helm template install/kubernetes/helm/istio-init --name istio-init --namespace istio-system | kubectl apply -f -
    
     configmap/istio-crd-10 created
     configmap/istio-crd-11 created
     serviceaccount/istio-init-service-account created
     clusterrole.rbac.authorization.k8s.io/istio-init-istio-system created
     clusterrolebinding.rbac.authorization.k8s.io/istio-init-admin-role-binding-istio-system created
     job.batch/istio-init-crd-10 created
     job.batch/istio-init-crd-11 created
    
  6. 安装 Isto

     $ helm template install/kubernetes/helm/istio \
         --name istio --namespace istio-system \
         --values install/kubernetes/helm/istio/values-istio-demo-auth.yaml | kubectl apply -f -
     ......
     handler.config.istio.io/kubernetesenv created
     rule.config.istio.io/kubeattrgenrulerule created
     rule.config.istio.io/tcpkubeattrgenrulerule created
     kubernetes.config.istio.io/attributes created
     destinationrule.networking.istio.io/istio-policy created
     destinationrule.networking.istio.io/istio-telemetry created
    
  7. 标记 default 命名空间,启动自动注入:

$ kubectl label namespaces default istio-injection=enabled --overwrite
kubectl namespace/default labeled

部署应用

为了方便演示,我们给惯用的 flaskapp 和 sleep 加上 NodeSelector,要求按照版本分布到不同区域的节点上,例如:

nodeSelector:
        failure-domain.beta.kubernetes.io/zone: us-central1-f

标签内容可以参照上文 kubectl get nodes --show-labels 的显示结果。

修改了部署清单之后,就可以部署了:

$ kubectl apply -f flaskapp/flaskapp.istio.yaml
service/flaskapp created
deployment.extensions/flaskapp-v1 created
deployment.extensions/flaskapp-v2 created
$ kubectl apply -f sleep/sleep.istio.yaml
service/sleep created
deployment.extensions/sleep-v1 created
deployment.extensions/sleep-v2 created
deployment.extensions/sleep-v3 created

稍候片刻,查看部署结果:

$ kubectl get pods -o wide
NAME                          READY   STATUS    RESTARTS   AGE   IP          NODE                                                NOMINATED NODE
flaskapp-v1-b9644bd75-g82nj   2/2     Running   0          92m   10.40.4.9   gke-standard-cluster-1-default-pool-0570ecb1-lm7q   <none>
flaskapp-v2-77d648fbd-cvfql   2/2     Running   0          92m   10.40.3.5   gke-standard-cluster-1-default-pool-f2347d89-q79k   <none>
sleep-v1-84c85c8946-c7bvc     2/2     Running   0          91m   10.40.1.3   gke-standard-cluster-1-default-pool-0570ecb1-1qnq   <none>
sleep-v2-57cf55db78-vrvtc     2/2     Running   0          92m   10.40.3.7   gke-standard-cluster-1-default-pool-f2347d89-q79k   <none>

和上文比较,可以看到,sleep 和 flaskapp 的 v1、v2 两个版本,分别运行在 us-central1-aus-central1-f 中。

验证路由的区域感知功能

接下来分别从网格内部和 Ingress Gateway 来验证这一功能。

服务网格内部请求

$ kubectl exec -it -c sleep sleep-v1-84c85c8946-c7bvc bash
# for i in {1..10}; do http --body  http://flaskapp/env/version ; done
v1
v2
v2
v1
...

可以看到,请求被随机分配到不同的版本,也就是说,此时的调用是无视分区的。接下来我们设置 Pilot 的环境变量,启用区域感知功能,过程很简单,给它的 Pod 加入环境变量 PILOT_ENABLE_LOCALITY_LOAD_BALANCING,并任意赋值即可,例如:

- name: PILOT_TRACE_SAMPLING
  value: "100"
...
- name: PILOT_ENABLE_LOCALITY_LOAD_BALANCING
  value: "1"
...

再次进入 Pod 访问 flaskapp 服务:

$ kubectl exec -it -c sleep sleep-v1-84c85c8946-c7bvc bash
# for i in {1..10}; do http --body  http://flaskapp/env/version ; done
v1
v1
v1
...
# exit
$ kubectl exec -it -c sleep sleep-v2-57cf55db78-vrvtc bash
# for i in {1..10}; do http --body  http://flaskapp/env/version ; done
v2
v2
v2
...

可以看到,果然按照我们预想的情况,不同区域的请求,会交由不同区域的服务来进行响应。如果此时删除同区的目标负载,会发现开始平均访问其它区的服务。

Ingress 网关

Ingress 网关控制器在网格内同样也会分配到不同的节点上,因此也同样会受到区域的影响。例如我们为 flaskapp 创建一个 VirtualService + Gateway 的组合,引入外部流量:

apiVersion: networking.istio.io/v1alpha3
kind: Gateway
metadata:
  name: flaskapp-gateway
spec:
  selector:
    istio: ingressgateway
  servers:
  - port:
      number: 80
      name: http
      protocol: HTTP
    hosts:
    - "flaskapp.example.com"
---
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: httpbin
spec:
  hosts:
  - "flaskapp.example.com"
  gateways:
  - flaskapp-gateway
  http:
  - route:
    - destination:
        port:
          number: 80
        host: flaskapp

提交后,可以在外使用 curl --resolve 来验证:

$ export INGRESS_HOST=$(kubectl -n istio-system get service istio-ingressgateway -o jsonpath='{.status.loadBalancer.ingress[0].ip}')
$ for i in {1..10}; do curl --resolve flaskapp.example.com:80:$INGRESS_HOST http://flaskapp.example.com/env/version ; done
v3v3v3v3v3v3v3v3v3v3

可以看到,对 Ingress Gateway 进入的流量,区域感知功能也是同样生效的。

区域间分流

如果只是简单的就近原则,虽然方便,但也难免有些枯燥,例如我的集群中的三个分区之间存在优先次序,或者强行指派一个区的请求需要由指定的其它分区的服务进行处理,又该怎样呢?

istio-system 中有个叫做 istio 的 configmap,其中包含了 Istio 的一些核心配置,里面的 LocalityLoadBalancerSetting,包含了对区域感知负载均衡的一些行为配置。例如我们分配所有分区的流量,都分配到前面两个区域:

    localityLbSetting:
      distribute:
      - from: us-central1/us-central1-a/*
        to:
          us-central1/us-central1-a/*: 90
          us-central1/us-central1-b/*: 10
      - from: us-central1/us-central1-b/*
        to:
          us-central1/us-central1-a/*: 90
          us-central1/us-central1-b/*: 10
      - from: us-central1/us-central1-f/*
        to:
          us-central1/us-central1-a/*: 90
          us-central1/us-central1-b/*: 10

应用之后,重启 Galley、Pilot、Injector,并重新注入应用,再次在不同分区的 sleep 容器中进行测试。会发现其中的请求呈现了符合配置要求的分配,并且没有发送到 us-central1-b 区。

事实上本次测试,并没有发现比率生效,仅达到有或无的区别。

结论

目前的分区域分流功能似乎还有些问题,但是不失为一个新的服务亲和思路。 分区是基于 Kubernetes Node 标签完成的,通过对标签的调整(例如机柜、楼层),能够比较方便的在无侵入的情况下,实现就近调用,对服务的跨区 HA,有一定的辅助作用。

参考链接

  1. Istio 负载均衡的区域感知:https://istio.io/help/ops/traffic-management/locality-load-balancing/
  2. 使用 Helm 安装 Istio:https://istio.io/docs/setup/kubernetes/install/helm/
  3. Kubernetes 区域标签:https://kubernetes.io/docs/reference/kubernetes-api/labels-annotations-taints/#failure-domain-beta-kubernetes-io-region

More from this blog

龙虾恐慌:AIOps 又要改名了?

ChatGPT 开始,把 AI 拉近到普罗大众的面前,让无数人感受到 AI 的亲民魅力。而龙虾,则把大模型驱动的自动化能力,突然间变得水灵灵、活泼泼地走进千家万户。它不只是“风口上的猪”,而是风口本身。热度高到让 Mac mini 一度断货,不知道这在不在库克的预料之内。 每代人都有每代人的鸡蛋,春节期间,我就领了我的鸡蛋。翻出古老的 MacBook Air M1,充值各种大模型。当然了,这个工具

Mar 9, 20261 min read

再见 2025

我猜不少人以为这个号废了吧?并没有,只是今年变化有点大,一直有种抄起键盘,无从说起的感觉,所以一直偷懒到今天,2025 的最后一天。 今年是我的第四个本命年,去年末一期播客里,大内说本命年不是灾年,是变化年,有危也有机。可是讲真啊,只看到危,没看到机。 各种因缘际会,从鹅厂跳槽到前东家,已经接近四年,第一个合同期已经进入尾声。除了前两年还在云原生领域嗷嗷叫,后两年基本都是些鸡零狗碎的东西了,用老东家的术语说是——偏离主航道,可谓是前景暗淡了。 一旦确定要滚蛋,反倒心思轻松起来,每天骑着我的小红车...

Jan 5, 20261 min read

辅助编程?dora 说:我知道你很急可是请你别急

从 OpenGPT 把大模型的火烧旺了之后,这三年来,相信很多组织或摩拳擦掌、或躬身入局,希望借助聪明能干的大模型,或想偿还技术宅,或想降本增效,或想弯道超车。一时间,沉寂许久的 AIxx 又活过来了,LLM Ops、Vibe Coding、中医大模型、GPT 算命等等,全都老树发新芽,焕发了勃勃生机。那么视角拉回从业者最关注的饭碗相关的领域之一——AI 辅助开发,产生了什么触动,应该如何拥抱呢? DORA 的年度报告中给出了很有意思的结论——强者恒强。 执行摘要部分总结了几个有趣的点: 问题...

Oct 6, 20251 min read

[译]dora:ai 辅助软件开发状态报告

执行摘要 在 2025 年,科技领导者面临的核心问题已不再是“是否要采用 AI”,而是“如何实现其价值”。 DORA 的研究基于超过 100 小时的定性访谈和来自全球近 5,000 名技术专业人士的问卷调查。研究揭示了一个关键事实:AI 在软件开发中的主要角色是“放大器”。它会放大高效能组织的优势,也会凸显组织的缺陷。 关键结论:AI 是放大器 AI 投资的最大回报并非来自工具本身,而是来自组织底层系统的战略性建设: 高质量的内部平台 清晰的工作流 团队的协同能力 缺少这些基础,AI ...

Oct 2, 202514 min read

僭越了,有人在用 Rust 写 Kubernetes

一个新语言问世,最爱做的事情之一,就是重写存量软件了。 云原生喝酒 SIG 重点扶持项目——rk8s(https://github.com/rk8s-dev/rk8s) 也可以归在这个范畴里,只不过这个项目重写的东西比较大,是 Kubernetes。 从 2025 年 1 月第一个 Commit 开始,到现在有了 200 多次 Commit,十几万行代码。当然距离 Kubernetes 的几百万行代码还差得远——老马就是喜欢整这种大无畏项目。 另外该项目也是国内第一个脱离 Cargo 转向使用 ...

Sep 27, 20253 min read

【伪】架构师

342 posts