istio.io/content/zh/blog/2019/multicluster-version-routing/index.md

13 KiB
Raw Permalink Blame History

title description publishdate subtitle attribution keywords target_release
多集群服务网格中的分版本路由 在多集群服务网格环境中配置 Istio 的路由规则。 2019-02-07 Frank Budinsky (IBM)
traffic-management
multicluster
1.0

如果花一点时间对 Istio 进行了解,你可能会注意到,大量的功能都可以在单一的 Kubernetes 集群中,用简单的任务示例所表达的方式来运行。但是真实世界中的云计算和基于微服务的应用往往不是这么简单的,会需要在不止一个地点分布运行,用户难免会产生怀疑,生产环境中是否还能这样运行?

幸运的是Istio 提供了多种服务网格的配置方式,应用能够用近乎透明的方式加入一个跨越多个集群运行的服务网格之中,也就是多集群服务网格 。最简单的设置多集群网格的方式,就是使用多控制平面拓扑 ,这种方式不需要特别的网络依赖。在这种条件下,每个 Kubernetes 集群都有自己的控制平面,但是每个控制平面都是同步的,并接受统一的管理。

本文中,我们会在多控制平面拓扑形式的多集群网格中尝试一下 Istio 的流量管理功能。我们会展示如何配置 Istio 路由规则,在多集群服务网格中部署 Bookinfo 示例reviews 服务的 v1 版本运行在一个集群上,而 v2v3 运行在另一个集群上,并完成远程服务调用。

集群部署

首先需要部署两个 Kubernetes 集群,并各自运行一个做了轻度定制的 Istio。

  • 依照使用 Gateway 连接多个集群中提到的步骤设置一个多集群环境。

  • kubectl 命令可以使用 --context 参数访问两个集群。 使用下面的命令列出所有 context

    {{< text bash >}} $ kubectl config get-contexts CURRENT NAME CLUSTER AUTHINFO NAMESPACE

    •     cluster1   cluster1   user@foo.com   default
          cluster2   cluster2   user@foo.com   default
      

    {{< /text >}}

  • 将配置文件中的 context 名称赋值给两个环境变量:

    {{< text bash >}} $ export CTX_CLUSTER1= $ export CTX_CLUSTER2= {{< /text >}}

cluster1 中部署 bookinfov1 版本

cluster1 中运行 productpagedetails 服务,以及 reviews 服务的 v1 版本。

{{< text bash >}} $ kubectl label --context=$CTX_CLUSTER1 namespace default istio-injection=enabled $ kubectl apply --context=$CTX_CLUSTER1 -f - <<EOF apiVersion: v1 kind: Service metadata: name: productpage labels: app: productpage spec: ports:

  • port: 9080 name: http selector: app: productpage

apiVersion: extensions/v1beta1 kind: Deployment metadata: name: productpage-v1 spec: replicas: 1 template: metadata: labels: app: productpage version: v1 spec: containers: - name: productpage image: istio/examples-bookinfo-productpage-v1:1.10.0 imagePullPolicy: IfNotPresent ports: - containerPort: 9080

apiVersion: v1 kind: Service metadata: name: details labels: app: details spec: ports:

  • port: 9080 name: http selector: app: details

apiVersion: extensions/v1beta1 kind: Deployment metadata: name: details-v1 spec: replicas: 1 template: metadata: labels: app: details version: v1 spec: containers: - name: details image: istio/examples-bookinfo-details-v1:1.10.0 imagePullPolicy: IfNotPresent ports: - containerPort: 9080

apiVersion: v1 kind: Service metadata: name: reviews labels: app: reviews spec: ports:

  • port: 9080 name: http selector: app: reviews

apiVersion: extensions/v1beta1 kind: Deployment metadata: name: reviews-v1 spec: replicas: 1 template: metadata: labels: app: reviews version: v1 spec: containers: - name: reviews image: istio/examples-bookinfo-reviews-v1:1.10.0 imagePullPolicy: IfNotPresent ports: - containerPort: 9080 EOF {{< /text >}}

cluster2 中部署 bookinfov2v3

cluster2 中运行 ratings 服务以及 reviews 服务的 v2v3 版本:

{{< text bash >}} $ kubectl label --context=$CTX_CLUSTER2 namespace default istio-injection=enabled $ kubectl apply --context=$CTX_CLUSTER2 -f - <<EOF apiVersion: v1 kind: Service metadata: name: ratings labels: app: ratings spec: ports:

  • port: 9080 name: http selector: app: ratings

apiVersion: extensions/v1beta1 kind: Deployment metadata: name: ratings-v1 spec: replicas: 1 template: metadata: labels: app: ratings version: v1 spec: containers: - name: ratings image: istio/examples-bookinfo-ratings-v1:1.10.0 imagePullPolicy: IfNotPresent ports: - containerPort: 9080

apiVersion: v1 kind: Service metadata: name: reviews labels: app: reviews spec: ports:

  • port: 9080 name: http selector: app: reviews

apiVersion: extensions/v1beta1 kind: Deployment metadata: name: reviews-v2 spec: replicas: 1 template: metadata: labels: app: reviews version: v2 spec: containers: - name: reviews image: istio/examples-bookinfo-reviews-v2:1.10.0 imagePullPolicy: IfNotPresent ports: - containerPort: 9080

apiVersion: extensions/v1beta1 kind: Deployment metadata: name: reviews-v3 spec: replicas: 1 template: metadata: labels: app: reviews version: v3 spec: containers: - name: reviews image: istio/examples-bookinfo-reviews-v3:1.10.0 imagePullPolicy: IfNotPresent ports: - containerPort: 9080 EOF {{< /text >}}

访问 bookinfo 应用

和平常一样,我们需要使用一个 Istio gateway 来访问 bookinfo 应用。

  • cluster1 中创建 bookinfo 的网关:

    {{< text bash >}} $ kubectl apply --context=$CTX_CLUSTER1 -f @samples/bookinfo/networking/bookinfo-gateway.yaml@ {{< /text >}}

  • 遵循 Bookinfo 示例应用中的步骤,确定 Ingress 的 IP 和端口,用浏览器打开 http://$GATEWAY_URL/productpage

这里会看到 productpage,其中包含了 reviews 的内容,但是没有出现 ratings,这是因为只有 reviews 服务的 v1 版本运行在 cluster1 上,我们还没有配置到 cluster2 的访问。

cluster1 上为远端的 reviews 服务创建 ServiceEntry 以及 DestinationRule

根据配置指南中的介绍,远程服务可以用一个 .global 的 DNS 名称进行访问。在我们的案例中,就是 reviews.default.global,所以我们需要为这个主机创建 ServiceEntryDestinationRuleServiceEntry 会使用 cluster2 网关作为端点地址来访问服务。可以使用网关的 DNS 名称或者公共 IP

{{< text bash >}} export CLUSTER2_GW_ADDR=(kubectl get --context=$CTX_CLUSTER2 svc --selector=app=istio-ingressgateway
-n istio-system -o jsonpath="{.items[0].status.loadBalancer.ingress[0].ip}") {{< /text >}}

用下面的命令来创建 ServiceEntryDestinationRule

{{< text bash >}} $ kubectl apply --context=$CTX_CLUSTER1 -f - <<EOF apiVersion: networking.istio.io/v1alpha3 kind: ServiceEntry metadata: name: reviews-default spec: hosts:

  • reviews.default.global location: MESH_INTERNAL ports:
  • name: http1 number: 9080 protocol: http resolution: DNS addresses:
  • 240.0.0.3 endpoints:
  • address: ${CLUSTER2_GW_ADDR} labels: cluster: cluster2 ports: http1: 15443 # 不要修改端口值

apiVersion: networking.istio.io/v1alpha3 kind: DestinationRule metadata: name: reviews-global spec: host: reviews.default.global trafficPolicy: tls: mode: ISTIO_MUTUAL subsets:

  • name: v2 labels: cluster: cluster2
  • name: v3 labels: cluster: cluster2 EOF {{< /text >}}

ServiceEntry 的地址 240.0.0.3 可以是任意的未分配 IP。在 240.0.0.0/4 的范围里面进行选择是个不错的主意。阅读通过网关进行连接的多集群一文,能够获得更多相关信息。

注意 DestinationRule 中的 subset 的标签,cluster: cluster2 对应的是 cluster2 网关。一旦流量到达目标集群,就会由本地目的 DestinationRule 来鉴别实际的 Pod 标签(version: v1 或者 version: v2

在所有集群上为本地 reviews 服务创建 DestinationRule

技术上来说,我们只需要为每个集群定义本地的 subset 即可(cluster1 中的 v1cluster2 中的 v2v3),但是定义一个用不到的并未部署的版本也没什么大碍,为了清晰一点,我们会在两个集群上都创建全部三个 subset

{{< text bash >}} $ kubectl apply --context=$CTX_CLUSTER1 -f - <<EOF apiVersion: networking.istio.io/v1alpha3 kind: DestinationRule metadata: name: reviews spec: host: reviews.default.svc.cluster.local trafficPolicy: tls: mode: ISTIO_MUTUAL subsets:

  • name: v1 labels: version: v1
  • name: v2 labels: version: v2
  • name: v3 labels: version: v3 EOF {{< /text >}}

{{< text bash >}} $ kubectl apply --context=$CTX_CLUSTER2 -f - <<EOF apiVersion: networking.istio.io/v1alpha3 kind: DestinationRule metadata: name: reviews spec: host: reviews.default.svc.cluster.local trafficPolicy: tls: mode: ISTIO_MUTUAL subsets:

  • name: v1 labels: version: v1
  • name: v2 labels: version: v2
  • name: v3 labels: version: v3 EOF {{< /text >}}

创建 VirtualService 来路由 reviews 服务的流量

目前所有调用 reviews 服务的流量都会进入本地的 reviews Pod也就是 v1,如果查看一下远吗,会发现 productpage 的实现只是简单的对 http://reviews:9080 (也就是 reviews.default.svc.cluster.local)发起了请求,也就是本地版本。对应的远程服务名称为 reviews.default.global,所以需要用路由规则来把请求转发到远端集群。

{{< tip >}} 注意如果所有版本的 reviews 服务都在远端,也就是说本地没有 reviews 服务,那么 DNS 就会把 reviews 直接解析到 reviews.default.global,在本文的环境里,无需定义任何路由规则就可以发起对远端集群的请求。 {{< /tip >}}

创建下列的 VirtualService,把 jason 的流量转发给运行在 cluster2 上的 v2v3 版本的 reviews,两个版本各负责一半流量。其他用户的流量还是会发给 v1 版本的 reviews

{{< text bash >}} $ kubectl apply --context=$CTX_CLUSTER1 -f - <<EOF apiVersion: networking.istio.io/v1alpha3 kind: VirtualService metadata: name: reviews spec: hosts: - reviews.default.svc.cluster.local http:

  • match:
    • headers: end-user: exact: jason route:
    • destination: host: reviews.default.global subset: v2 weight: 50
    • destination: host: reviews.default.global subset: v3 weight: 50
  • route:
    • destination: host: reviews.default.svc.cluster.local subset: v1 EOF {{< /text >}}

{{< tip >}} 这种平均分配的规则并不实际,只是一种用于演示远端服务多版本之间流量分配的方便手段。 {{< /tip >}}

回到浏览器,用 jason 的身份登录。刷新页面几次,会看到星形图标在红黑两色之间切换(v2v3)。如果登出,就只会看到没有 ratingsreviews 服务了。

总结

本文中,我们看到在多控制平面拓扑的多集群网格中,如何使用 Istio 路由规则进行跨集群的流量分配。 这里我们手工配置了 .globalServiceEntry 以及 DestinationRule,用于进行对远端集群中 reviews 服务的访问。实际上如果我们想要的话,可以让任何服务都在远端或本地运行,当然需要为远端服务配置 .global 的相关资源。幸运的是,这个过程可以自动化,并且可能在 Istio 的未来版本中实现。