作者:尹航

作为业内首个全托管 Istio 兼容的阿里云服务网格产品 ASM,一开端从架构上就坚持了与社区、业界趋势的一致性,操控平面的组件托管在阿里云侧,与数据面侧的用户集群独立。ASM 产品是根据社区 Istio 定制完结的,在托管的操控面侧供给了用于支撑精细化的流量办理和安全办理的组件才能。通过托管形式,解耦了 Istio 组件与所办理的 K8s 集群的生命周期办理,使得架构更加灵敏,提升了体系的可伸缩性。从 2022 年 4 月 1 日起,阿里云服务网格 ASM 正式推出商业化版别, 供给了更丰富的才能、更大的规划支撑及更完善的技能保证,更好地满足客户的不同需求场景,详情可点击原文链接检查。

前语

服务网格是一个通过“Sidecar”形式进行服务治理简化的渠道。整个服务网格可以划分为包括中心组件 Istiod 的“操控面”以及包括了每个服务的 Sidecar 的“数据面”。假如各位运用过服务网格,信任对上面的概念也算是略有了解了。

在服务网格 Istio 中,咱们知道每个 Sidecar 都是一个 envoy 运用,内部有着包括着 listener、route、cluster、secret 等部分的完好装备;envoy 便是根据这些装备来改动自身行为,完结不同的流量操控手段的。而操控面组件的首要任务,便是将网格中的 VirtualService、DestinationRule 等资源“翻译”成 envoy 的详细装备,并将装备发送给数据面的每个 envoy,咱们简称这个进程为“装备推送”。

在 envoy 中,cluster 装备对应着 envoy 内部的“集群”这个概念,一个 cluster 是指“Envoy 连接的一组逻辑相同的上游主机”,其实大多数时分也便是对应着一个详细的服务。

假如咱们实践检查 envoy 的完好装备会发现,咱们在什么都没做的时分,envoy 内部就现已包括着一些动态下发的 cluster 了,也便是说,Sidecar 主动发现并包括了集群中的服务信息。这儿就引出一个中心问题:服务网格的“服务发现”是怎么完结的呢?咱们一般会用“网格内服务”来称呼对应 Pod 注入了 Sidecar 的服务;那么,是不是压服务网格会将注入了 Sidecar 的“网格内服务”主动的加入每个 Sidecar 的 cluster 装备呢?

今日这篇文章就来首要聊一聊服务网格的“服务发现”和“装备推送”。

服务网格的“服务发现”

一个简单的小实验就可以解答上面的这些问题。咱们在 Kubernetes 集群中装置服务网格渠道(可以运用 aliyun ASM + ACK 来快速建立服务网格渠道),然后在 default 默许命名空间之外,再建立一个 test 命名空间。

然后,咱们为 default 命名空间敞开 Sidecar 主动注入,也便是说,default 命名空间内的服务将主动成为“网格内”的服务,而 test 命名空间内的服务将不会注入 Sidecar,也便是“网分外”的服务。

在服务网格 ASM 中,咱们可以在操控台的“全局命名空间”办理中来方便地敞开和关闭主动注入(敞开/关闭后别忘了同步一下主动注入哦):

你的 Sleep 服务会梦到服务网格外的 bookinfo 吗

咱们可以随意在这两个命名空间内布置一些中意的服务,我在这儿向 default 命名空间布置了一个 sleep 服务。这个服务就如字面意思,里边是一个 curl 容器,而且一进去就一直在睡大觉( ̄o ̄).zZ ,可以进入这个服务的 Pod 方便地 curl 其它服务。

在 Istio 的社区官方 github 库房中,可以找到 sleep 这个示例服务的 YAML 文件:istio/samples/sleep/sleep.yaml,咱们可以复制这个文件后履行:

kubectl apply -f sleep.yaml

同理,在 test 命名空间下,咱们随意布置点啥服务,我这儿布置了一个 Istio 运用者的老朋友 bookinfo,咱们同样可以在 Istio 的官方 github 中找到它的 YAML 文件:istio/samples/bookinfo/platform/kube/bookinfo.yaml,将其复制后履行:

kubectl apply -f bookinfo.yaml -n test

顺带一提,为了不让 sleep 太孤寂,我还在 default 命名空间布置了一个 httpbin 运用陪他,不过不布置也无所谓┐(゚~゚)┌。

咱们现在预备好了,咱们或许猜到接下来要干啥了。咱们就来看看——这个 Sidecar 里都有哪些 cluster 装备。

假如你运用 Istio,可以用 istioctl 命令行东西方便地检查 Sidecar 中的各项装备的总结信息;在服务网格 ASM 中这招或许行不通,不过 ASM 也有一个可以部分兼容的命令行东西 asmctl,咱们可以进入阿里云协助中心,查找 asmctl,找到“装置和运用确诊东西 asmctl”,依照文档提示下载装置此东西。

以 asmctl 为例,可以用这个姿势来检查 Sidecar 内部的 cluster 装备(需求提早装备好数据面集群的 Kubeconfig):

$ asmctl proxy-config cluster sleep-557747455f-g4lcs
SERVICE FQDN                                                      PORT      SUBSET     DIRECTION     TYPE             DESTINATION RULE
                                                                  80        -          inbound       ORIGINAL_DST     
BlackHoleCluster                                                  -         -          -             STATIC           
InboundPassthroughClusterIpv4                                     -         -          -             ORIGINAL_DST     
InboundPassthroughClusterIpv6                                     -         -          -             ORIGINAL_DST     
PassthroughCluster                                                -         -          -             ORIGINAL_DST     
agent                                                             -         -          -             STATIC           
asm-validation.istio-system.svc.cluster.local                     443       -          outbound      EDS              
controlplane-metrics-aggregator.kube-system.svc.cluster.local     443       -          outbound      ORIGINAL_DST     
details.test.svc.cluster.local                                    9080      -          outbound      EDS              
envoy_accesslog_service                                           -         -          -             STRICT_DNS       
heapster.kube-system.svc.cluster.local                            80        -          outbound      EDS              
httpbin.default.svc.cluster.local                                 8000      -          outbound      EDS              
istio-ingressgateway.istio-system.svc.cluster.local               80        -          outbound      EDS              
istio-ingressgateway.istio-system.svc.cluster.local               443       -          outbound      EDS              
istio-sidecar-injector.istio-system.svc.cluster.local             443       -          outbound      EDS              
istio-sidecar-injector.istio-system.svc.cluster.local             15014     -          outbound      EDS              
istiod.istio-system.svc.cluster.local                             15012     -          outbound      ORIGINAL_DST     
kiali.istio-system.svc.cluster.local                              20001     -          outbound      EDS              
kube-dns.kube-system.svc.cluster.local                            53        -          outbound      EDS              
kube-dns.kube-system.svc.cluster.local                            9153      -          outbound      EDS              
kubernetes.default.svc.cluster.local                              443       -          outbound      EDS              
metrics-server.kube-system.svc.cluster.local                      443       -          outbound      EDS              
productpage.test.svc.cluster.local                                9080      -          outbound      EDS              
prometheus_stats                                                  -         -          -             STATIC           
ratings.test.svc.cluster.local                                    9080      -          outbound      EDS              
reviews.test.svc.cluster.local                                    9080      -          outbound      EDS              
sds-grpc                                                          -         -          -             STATIC           
sleep.default.svc.cluster.local                                   80        -          outbound      EDS              
storage-crd-validate-service.kube-system.svc.cluster.local        443       -          outbound      EDS              
storage-monitor-service.kube-system.svc.cluster.local             11280     -          outbound      EDS              
xds-grpc                                                          -         -          -             STATIC           
zipkin

这儿就有一个有意思的作业了,尽管整套 bookinfo 运用都没有注入 Sidecar,但咱们仍是能在 sleep 的 Sidecar 中找到 productpage、reviews、ratings 等 bookinfo 运用的服务信息。

这一切是怎么完结的呢?实践上 Istio 官方在社区文章《Traffic Management》中,有对这一进程进行解释:

In order to direct traffic within your mesh, Istio needs to know where all your endpoints are, and which services they belong to. To populate its own service registry, Istio connects to a service discovery system. For example, if you’ve installed Istio on a Kubernetes cluster, then Istio automatically detects the services and endpoints in that cluster.

简要地说,服务网格 Istio 并不进行服务发现。一切的服务都经由服务网格底层渠道的服务发现(Kubernetes、Consul 等,大多数情况下都是 Kubernetes),通过操控面适配后传入网格自己的服务注册中心(也便是 Sidecar 的那一堆 cluster 装备了)。

此外,假如你检查 Sidecar 中记载的 endpoint,你会发现无论是否注入 Sidecar,Kubernetes 集群内一切 Pod的 ip 地址都会记载在内。

尝试在 test 命名空间内布置下面这么个 VirtualService:

apiVersion: networking.istio.io/v1beta1
kind: VirtualService
metadata:
  namespace: test
  name: test-vs
spec:
  hosts:
    - productpage.test.svc.cluster.local
  http:
    - match:
        - uri:
            prefix: /test/
      rewrite:
        uri: /
      route:
        - destination:
            host: productpage.test.svc.cluster.local
            port:
              number: 9080

这个 VirtualService 完结了一个 uri 的重写,但方针 host 是一个“网分外”的服务 productpage。

尝试一下,curl 一个会被重写的路径/test/productpage

kubectl exec -it sleep-557747455f-g4lcs -c sleep -- curl productpage.test:9080/test/productpage

会发现重写收效了,恳求正常有返回。

上述行为可以阐明,所谓“网格内外”只是以是否注入 Sidecar 确认的一个区分手段,并不是说网格自身和网分外的服务有着严厉的隔离边界。在上面的例子中,VirtualService 实践上收效于恳求发送方 Sidecar 的 route 装备之中,而 productpage 服务即使没有 Sidecar,也是会被服务网格操控面发现、并加入 cluster 装备之中的,有对应的 cluster。因而,网格当然可以设定针对此 cluster 的路由规矩,只要恳求发送方的 Pod 是注入 Sidecar 的,VirtualService 的功能就能正常作业。

当然,实践运用中,服务网格的其它资源或许收效于入站流量装备之中,此刻恳求接收方也必须注入 Sidecar 才行。但 Sidecar 注入并不对网格的服务发现起到决定作用,这一点是可以必定的 。

服务网格的“装备推送”

上面咱们探究了服务网格的“服务发现”机制,可以说仍是十分巧妙,这套机制既让服务网格免于再去完结一套冗余的服务发现机制,也方便网格自身与不同的底层渠道进行对接。但是,仔细考虑就会发现这其间存在的问题与隐藏的反直觉现实情况。

就以上面测试中咱们在 Kubernetes 集群中布置的运用为例。Sleep 运用与 bookinfo 运用是两个独立的运用,互相之间其实没有太大联系(只不过想拜访的话互相仍是拜访的通算了)。在实践的出产环境中,信任许多用户都会有这样的实践:运用 Kubernetes 命名空间的隔离机制,在同一个集群中布置多个运用对外供给服务,每个运用包括几个微服务,而运用之间互相的联系则比较独立。而其间又只要部分的运用需求运用服务网格的治理才能(多语言服务互通、蓝绿发布等),因而注入了 Sidecar。

问题是,服务网格的操控面也不能假定用户服务之间的联系,因而仍是需求一视同仁地 watch 集群内一切的服务与端点:-(

更难受的是,操控面还需求向及时向数据面的每一位 Sidecar 同步集群内最新的服务信息,这就导致了以下的“费力不讨好”局势:

1、一开端咱们相安无事,岁月静好

你的 Sleep 服务会梦到服务网格外的 bookinfo 吗

2、Service2 扩容了!

你的 Sleep 服务会梦到服务网格外的 bookinfo 吗

3、Istiod 下发新的装备

你的 Sleep 服务会梦到服务网格外的 bookinfo 吗

4、尴尬的作业发生了,Service1 和 Service2 其实是两个独立的运用,网格内的 Sidecar 不需求记载 Service2 的任何信息。

你的 Sleep 服务会梦到服务网格外的 bookinfo 吗

假如网格内的服务不多,这倒也不能造成什么巨大的问题,无非便是网格的操控面组件多做点无用功算了。但是正所谓量变引起质变,无用功堆积起来就会成为不可忽视的大问题。假如您的集群中布置着成千上百个服务,而其间只要少量的服务加入了网格,网格的操控面就会淹没在大量的无效信息中,操控面组件的负载居高不下,而且不断向一切 Sidecar 推送他们并不需求的信息。

因为操控面组件不比网关,只是担任向 Sidecar 推送装备,操控面的负载过高或许很难引起服务网格用户的注意。但是一旦负载过高导致 Pilot SLB 超限/操控面组件重启等情况,用户就会轻则面对新的路由装备推送过慢、重则面对注入 Sidecar 的 Pod 起不来的困境。因而,在享受服务网格为咱们带来的便利的流量治理才能的一起,适度地关心服务网格操控面的身心健康,对操控面进行装备推送的优化,也是十分有必要的。

装备推送优化-之挑选性服务发现

针对上面所述的情况,咱们可以手动地去装备服务网格,让网格的操控面只去“发现”特定命名空间内的服务,而对其它的命名空间置之不理。在社区中,Istio 于 1.10 版别后供给了“discovery selector”的才能。而服务网格 ASM 也对应供给了“挑选性服务发现”的才能,二者的收效机制是完全相同的。

咱们以服务网格 ASM 的“挑选性服务发现”为例。首先给网格内运用地点的命名空间打一个特定的标签,用来区分网格内与网分外运用地点的命名空间(注意是给数据面的命名空间打标签):

# 在这儿,default命名空间敞开了主动注入,属于“网格内”命名空间
kubectl label namespace default in-mesh=yes
# 其实咱们也可以直接用 istio-injection:enabled标签,不必再打一个

进入咱们的 ASM 实例办理页面,在左边菜单中挑选“装备推送优化 -> 挑选性服务发现”。

在“挑选性服务发现”页面中,挑选“增加标签挑选器” -> “增加标签精确匹配规矩”,输入咱们方才打好的标签。

你的 Sleep 服务会梦到服务网格外的 bookinfo 吗

然后点击“确认”就好了,真是十分地方便。这之后网格会通过一个时刻短的更新阶段,更新咱们方才写下的这个装备,然后重新进入“运行中”状况。

再来运行一遍咱们最开端的指令,检查一下 sleep 服务的 Sidecar 中的 cluster 装备:

$ asmctl proxy-config cluster sleep-557747455f-g4lcs
SERVICE FQDN                             PORT     SUBSET     DIRECTION     TYPE             DESTINATION RULE
                                         80       -          inbound       ORIGINAL_DST     
BlackHoleCluster                         -        -          -             STATIC           
InboundPassthroughClusterIpv4            -        -          -             ORIGINAL_DST     
InboundPassthroughClusterIpv6            -        -          -             ORIGINAL_DST     
PassthroughCluster                       -        -          -             ORIGINAL_DST     
agent                                    -        -          -             STATIC           
envoy_accesslog_service                  -        -          -             STRICT_DNS       
httpbin.default.svc.cluster.local        8000     -          outbound      EDS              
kubernetes.default.svc.cluster.local     443      -          outbound      EDS              
prometheus_stats                         -        -          -             STATIC           
sds-grpc                                 -        -          -             STATIC           
sleep.default.svc.cluster.local          80       -          outbound      EDS              
xds-grpc                                 -        -          -             STATIC           
zipkin                                   -        -          -             STRICT_DNS

可以看到 sleep 服务的 Sidecar 中现已没有任何一个 bookinfo 运用中服务的信息了,现在 Sidecar 中的装备看起来精简多了。可喜可贺可喜可贺(^o^)/

当然,咱们做的不只是削减 Sidecar 中的装备数量算了。如上文所说,运用“挑选性服务发现后”,操控面将不会 watch 除 default 命名空间外的任何服务,也因而操控面的作业担负得到了大幅削减,服务网格重回高效工作状况~咱们也可以没有后顾之忧地向集群中布置其它服务了。

总结

服务网格的服务发现机制其实说起来是一个十分简单的东西,毕竟服务网格根本就没有服务发现机制呢!

不过不去实践了解的话,想必很少有人可以直接确认每个 Sidecar 里记载的那些各式各样的服务到底是怎么发现的。一起,Istiod 作为服务网格中担任装备推送的中心组件,做的却是修正翻译和修正装备这样的后台作业,也导致网格的用户一般很难意识到操控面组件到底在进行什么作业,以及现有的实践是否给操控面组件造成了过大的剩余担负。

期望这篇文章能让更多的服务网格用户意识到,装备推送的优化也是网格渠道保护的重要一环。运用“挑选性服务发现”的话,仅用1分钟的时刻就可以大幅度优化网格的装备优化,削减运用网格时无谓的危险,岂不美哉?

关于大多数用户来说,“挑选性服务发现”就现已满足对装备推送进行优化了。不过假如您想做的更“绝”,还可以直接运用服务网格的 Sidecar 资源来对 Sidecar 的装备进行最大限度地优化。服务网格 ASM 针对 Sidecar 资源这一机制,也供给了根据拜访日志剖析主动推荐的 Sidecar 资源来协助客户进行运用上的深度简化。欢迎运用服务网格 ASM,即刻让您具有简化的无侵入式服务治理才能!

从 2022 年 4 月 1 日起,阿里云服务网格 ASM 正式推出商业化版别, 供给了更丰富的才能、更大的规划支撑及更完善的技能保证,更好地满足客户的不同需求场景。