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

简介: 前言 作为业内首个全托管Istio兼容的阿里云服务网格产品ASM,一开始从架构上就保持了与社区、业界趋势的一致性,控制平面的组件托管在阿里云侧,与数据面侧的用户集群独立。ASM产品是基于社区Istio定制实现的,在托管的控制面侧提供了用于支撑精细化的流量管理和安全管理的组件能力。通过托管模式,解耦了Istio组件与所管理的K8s集群的生命周期管理,使得架构更加灵活,提升了系统的可伸缩性。

前言

作为业内首个全托管Istio兼容的阿里云服务网格产品ASM,一开始从架构上就保持了与社区、业界趋势的一致性,控制平面的组件托管在阿里云侧,与数据面侧的用户集群独立。ASM产品是基于社区Istio定制实现的,在托管的控制面侧提供了用于支撑精细化的流量管理和安全管理的组件能力。通过托管模式,解耦了Istio组件与所管理的K8s集群的生命周期管理,使得架构更加灵活,提升了系统的可伸缩性。


服务网格是一个通过“Sidecar”模式进行服务治理简化的平台。整个服务网格可以划分为包括核心组件Istiod的“控制面”以及包括了每个服务的Sidecar的“数据面”。如果各位使用过服务网格,相信对上面的概念也算是略有了解了。

第一次看config_dump中,我们知道每个Sidecar都是一个envoy应用,内部有着包含着listener、route、cluster、secret等部分的完整配置;envoy就是根据这些配置来改变自身行为,实现不同的流量控制手段的。而控制面组件的主要任务,就是将网格中的VirtualService、DestinationRule等资源“翻译”成envoy的具体配置,并将配置发送给数据面的每个envoy,我们简称这个过程为“配置推送”。

在envoy中,cluster配置对应着envoy内部的“集群”这个概念,一个cluster是指“Envoy 连接的一组逻辑相同的上游主机”,其实大多数时候也就是对应着一个具体的服务。

如果我们实际查看envoy的config_dump会发现,我们在什么都没做的时候,envoy内部就已经包含着一些动态下发的cluster了。这里就引出一个核心问题:服务网格的“服务发现”是如何完成的呢?我们通常会用“网格内服务”来称呼对应Pod注入了Sidecar的服务;那么,是不是说服务网格会将注入了Sidecar的“网格内服务”自动的加入每个Sidecar的cluster配置呢?

今天这篇文章就来主要聊一聊服务网格的“服务发现”和“配置推送”。

服务网格的“服务发现”

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

然后,我们为default命名空间开启Sidecar自动注入,也就是说,default命名空间内的服务将自动成为“网格内”的服务,而test命名空间内的服务将不会注入Sidecar,也就是“网格外”的服务。

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

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

你可以在这里找到这个示例服务的YAML,将其拷贝到sleep.yaml,然后执行:

kubectl apply -f sleep.yaml

同理,在test命名空间下,我们随便部署点啥服务,我这里部署了一个Istio使用者的老朋友bookinfo,可以在这里找到它的YAML,将其拷贝到bookinfo.yaml,然后执行:

kubectl apply -f bookinfo.yaml -n test

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

我们现在准备好了,大家可能猜到接下来要干啥了。我们就来看看——这个Sidecar里都有哪些cluster配置。

第一次看config_dump中,我们是通过下载config_dump,再在那个成千上万行的大json里去找的cluster配置的。这回我们就不自虐了(● ̄(エ) ̄●),如果你使用Istio,可以用istioctl命令行工具方便地查看Sidecar中的各项配置的Summary;在服务网格ASM中这招可能行不通,不过ASM也有一个部分兼容的命令行工具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                                                            -         -          -             STRICT_DNS

这里就有一个有意思的事情了,虽然整套bookinfo应用都没有注入Sidecar,但我们还是能在sleep的Sidecar中找到productpage、reviews、ratings等bookinfo应用的服务信息。

这一切是怎么完成的呢?实际上Istio官方在这篇社区文章中,有对这一过程进行解释:

 

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配置了)。

In addition,如果你查看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的功能就能正常工作。

当然,实际使用中,服务网格的其它资源可能生效于inbound配置之中,此时请求接收方也必须注入Sidecar才行。但Sidecar注入并不对网格的服务发现起到决定作用,这一点是可以肯定的 。

服务网格的“配置推送”

上面我们探索了服务网格的“服务发现”机制,可以说还是十分巧妙,这套机制既让服务网格免于再去实现一套冗余的服务发现机制,也方便网格本身与不同的底层平台进行对接。然而,仔细思考就会发现这其中存在的问题与隐藏的反直觉现实情况。

就以上面测试中我们在Kubernetes集群中部署的应用为例。Sleep应用与bookinfo应用是两个独立的应用,彼此之间其实没有太大关系(只不过想访问的话彼此还是访问的通而已)。在实际的生产环境中,相信很多用户都会有这样的实践:利用Kubernetes命名空间的隔离机制,在同一个集群中部署多个应用对外提供服务,每个应用包含几个微服务,而应用之间彼此的关系则比较独立。而其中又只有部分的应用需要使用服务网格的治理能力(多语言服务互通、蓝绿发布等),因此注入了Sidecar。

问题是,服务网格的控制面也不能假设用户服务之间的关系,因此还是需要一视同仁地watch集群内所有的服务与端点:-( 

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

 

1、一开始大家相安无事,岁月静好

2、Service2扩容了!

3、Istiod下发新的配置

4、尴尬的事情发生了,Service1和Service2其实是两个独立的应用,网格内的Sidecar不需要记录Service2的任何信息。

如果网格内的服务不多,这倒也不能造成什么巨大的问题,无非就是网格的控制面组件多做点无用功罢了。可是正所谓量变引起质变,无用功堆积起来就会成为不可忽视的大问题。如果您的集群中部署着成千上百个服务,而其中只有少量的服务加入了网格,网格的控制面就会淹没在大量的无效信息中,控制面组件的负载居高不下,并且不断向所有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服务的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里那些林林总总的服务到底是怎么写到Sidecar配置里的。同时,Istiod作为服务网格中负责配置推送的核心组件,做的却是修改翻译和修改配置这样的后台工作,也导致网格的用户通常很难意识到控制面组件到底在进行什么工作,以及现有的实践是否给控制面组件造成了过大的多余负担。

 

希望这篇文章能让更多的网格用户意识到,配置推送的优化也是网格平台维护的重要一环。使用“选择性服务发现”的话,仅用1分钟的时间就能够大幅度优化网格的配置优化,减少使用网格时无谓的隐患,岂不美哉?

对于大多数用户来说,“选择性服务发现”就已经足够对配置推送进行优化了。不过如果你想做的更“绝”,还可以直接使用服务网格的Sidecar资源来对Sidecar的配置进行最大限度地优化。Sidecar资源的YAML真的很难写,不过服务网格ASM还提供了基于访问日志分析自动推荐的Sidecar资源来帮你完成这一伟业。

此为后话,不表但是可以参考https://developer.aliyun.com/article/848355

参考

相关文章
|
4月前
|
存储 机器学习/深度学习 负载均衡
模型服务网格:云原生下的模型服务管理
模型服务网格:云原生下的模型服务管理
78378 2
模型服务网格:云原生下的模型服务管理
|
6月前
|
监控 安全 大数据
阿里服务的ASM、MSE和ARMS都有其各自的应用场景
阿里服务的ASM、MSE和ARMS都有其各自的应用场景
189 39
|
6月前
|
安全 数据安全/隐私保护 开发者
实现安全的服务通信:探索如何使用服务网格来确保服务间的安全通信
实现安全的服务通信:探索如何使用服务网格来确保服务间的安全通信
59 0
|
11月前
|
自然语言处理 运维 监控
《云原生架构容器&微服务优秀案例集》——01 互联网——站酷 基于 ASM 解决多语言技术栈下服务管理难题,实现运维提效
《云原生架构容器&微服务优秀案例集》——01 互联网——站酷 基于 ASM 解决多语言技术栈下服务管理难题,实现运维提效
201 0
|
11月前
|
自然语言处理 运维 监控
《2023云原生实战案例集》——04 互联网——站酷 基于ASM解决多语言技术栈下服务管理难题,实现运维提效
《2023云原生实战案例集》——04 互联网——站酷 基于ASM解决多语言技术栈下服务管理难题,实现运维提效
|
算法 Serverless 测试技术
使用ASM管理Knative服务(6):基于流量请求数实现服务自动扩缩容
Knative on ASM中提供了开箱即用、基于流量请求的自动扩缩容KPA(Knative Pod Autoscaler)功能。本文介绍如何基于流量请求数实现服务自动扩缩容。
7795 0
使用ASM管理Knative服务(6):基于流量请求数实现服务自动扩缩容
|
测试技术 Serverless
使用ASM管理Knative服务(5):在Knative on ASM中基于流量灰度发布服务
Knative on ASM提供了基于流量的灰度发布能力。当创建Knative服务时,Knative会自动为服务创建第一个修订版本Revision。此后当Knative服务的配置发生变化时,Knative都会创建一个新的修订版本。通过修改流量发往不同修订版本的分配比例,即可实现灰度发布功能。本文介绍如何在Knative on ASM中基于流量灰度发布服务。
211 0
使用ASM管理Knative服务(5):在Knative on ASM中基于流量灰度发布服务
|
Serverless Perl 测试技术
使用ASM管理Knative服务(4):使用ASM网关实现HTTPS访问Knative服务
ASM网关支持HTTPS协议和动态加载证书功能。在使用Knative on ASM时,可以通过ASM网关来实现HTTPS访问。本文将演示如何使用ASM网关来实现HTTPS访问Knative服务。
224 0
使用ASM管理Knative服务(4):使用ASM网关实现HTTPS访问Knative服务
|
网络协议 Serverless 测试技术
使用ASM管理Knative服务(3):在Knative on ASM中使用自定义域名
对于Knative服务,服务的DNS名默认格式为:{服务名}.{服务所在命名空间}.{默认域名},Knative会默认使用example.com作为服务的域名。Knative on ASM支持使用自定义域名作为默认域名。本文介绍如何在Knative Serving中使用自定义域名。
181 0
使用ASM管理Knative服务(3):在Knative on ASM中使用自定义域名
|
存储 Serverless 异构计算
使用ASM管理Knative服务(2):使用Knative on ASM部署Serverless应用
如何在阿里云服务网格ASM中开启Knative on ASM功能, 并结合ACK或者ASK部署管理Serverless应用服务。
601 0
使用ASM管理Knative服务(2):使用Knative on ASM部署Serverless应用