Istio 负载均衡的区域感知

栏目: 服务器 · 发布时间: 6年前

内容简介:Envoy/Istio 1.1 中有个有趣的新特性:负载均衡提供了接下来首先做一些琐碎的安装工作,这里选择了常见的 GCP 作为测试环境,Istio 版本为 1.1.2。为了方便演示,我们给惯用的 flaskapp 和 sleep 加上

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

以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Pro JavaScript Design Patterns

Pro JavaScript Design Patterns

Dustin Diaz、Ross Harmes / Apress / 2007-12-16 / USD 44.99

As a web developer, you’ll already know that JavaScript™ is a powerful language, allowing you to add an impressive array of dynamic functionality to otherwise static web sites. But there is more power......一起来看看 《Pro JavaScript Design Patterns》 这本书的介绍吧!

JSON 在线解析
JSON 在线解析

在线 JSON 格式化工具

在线进制转换器
在线进制转换器

各进制数互转换器