作者:铖朴、牧思

站在 2023 年的今日,Service Mesh 早已不是一个新兴的概念, 回顾过去 6 年多的开展进程,Service Mesh 从一经推出就受到来自全世界的干流技能公司注重和追捧。

  • 2016 年作为 Service Mesh 的元年,Buoyant 公司 CEO William Morgan 率先发布Linkerd [ 1] ,成为业界首个 Service Mesh 项目,同年 Lyft 发布Envoy [ 2] ,成为第二个 Service Mesh 项目。
  • 2017年,Google、IBM、Lyft 联手发布了 Istio [ 3] ,它与 Linkerd / Envoy 等项目比较,它首次给我们添加了操控平面的概念,供给了强壮的流量操控才能。通过多年的开展 Istio,现已逐渐成为服务网格领域操控平面的事实规范。
  • 2018年7月,Istio 1.0版别发布 [ 4] ,标志着其进入了能够出产可用的时代,逐渐也有越来越多的企业开端考虑和测验将服务网格运用于出产中。

Istio 作为当时最流行的开源服务网格技能,它由操控平面和数据平面两部分构成。

Spring Cloud Alibaba 在 Proxyless Mesh 上的探索

在 Istio Mesh 架构中,其操控平面是一个名为 Istiod 的进程,网络署理是 Envoy 。Istiod 作为操控面的一致组件,负责对接服务注册发现、路由规矩管理、证书管理等才能,Envoy 则是作为数据面通过 Sidecar 方法署理事务流量,Istio 和 Envoy 之间通过 xDS 协议接口完成服务发现、路由规矩等数据的传递。Istiod 通过监听 K8s 资源例如 Service、Endpoint 等,获取服务信息,并将这些资源一致通过 xDS 协议下发给位于数据平面的网络署理。Envoy 则是独立于运用之外的一个进程,以 Sidecar 的方法(一般是以 Container 方法)随同事务运用 Pod 运转,它与运用进程共用同一个主机网络,通过修正路由表的方法绑架事务运用的网络流量然后达到为运用无侵入地供给如服务鉴权、标签路由等才能。

Proxyless Mesh

Proxyless Mesh 全称是 Proxyless Service Mesh,其是近几年在 Service Mesh 根底上开展而来的一种新型软件架构。Service Mesh 理想很丰满,但实际很骨感!通过一层署理虽然做到了对运用无侵入,但添加的网络署理开销对很多性能要求很高的互联网事务落地形成不少应战。因而 Proxyless Mesh 作为一种在传统侵入式微服务框架与 Service Mesh 之间的折中计划,通过取众家之所长,为很多的非 Service Mesh 运用在云原生时代,拥抱云原生根底设施,处理流量管理等痛点供给了一种有效的处理计划。Service Mesh 和 Proxyless Mesh 架构区别如下图所示:

Spring Cloud Alibaba 在 Proxyless Mesh 上的探索

过去几年,国内外的知名软件开源社区也都在相关领域进行了很多探究,例如在 2021 年 10 月,gRPC 社区为用户供给架构方式 [ 5] ,通过对接Istio操控平面,遵从 VirtualService & DestinationRule CRD 规范为 gRPC 运用供给流量管理才能。

Spring Cloud Alibaba 在 Proxyless Mesh 上的探索

Spring Cloud Alibaba Mesh 化计划

Spring Cloud Alibaba 作为一种侵入式的微服务处理计划,通过根据 Spring Cloud 微服务规范为用户供给了微服务运用构建过程中的如服务注册与发现、限流降级、分布式事务与分布式消息等在内的一站式微服务处理计划。过去几年被国内很多中小企业所选用,帮助很多企业愈加方便地拥抱微服务。

但随着企业运用微服化的不断深入,微服务给运用带来体系解耦、高可扩展性等诸多优势的一同,也让运用变得愈加复杂。怎么管理好微服务?成为了很多企业逐渐开端注重和注重的一个新的问题。Spring Cloud Alibaba 社区也注意到很多用户有微服务管理方面的诉求,所以从 2022 年头,就开端了在该方面的探究,社区觉得比较于 Service Mesh,Proxyless Mesh 是一种对广阔中小企业更适宜的技能计划,其不只不会有额定 Sidecar 署理所带来的较大性能损耗,而且更重要的是对企业来说,其落地本钱很低!

要通过Mesh化计划处理微服务管理需求,一个能给运用动态下发规矩的操控面不可或缺,社区本着不重复造轮子,拥抱业界干流处理计划的原则,通过支撑xDS协议不只为用户供给通过干流的Istio操控面来对 Spring Cloud Alibaba 运用进行服务管理以外,用户也能够运用阿里巴巴开源的 OpenSergo 微服务管理操控面所供给的差异化管理才能进行运用管理。相关供给 Mesh 技能计划社区在最近发布的 2.2.10-RC 版别 [ 6] 中进行了供给。作为供给微服管理才能的第一个版别,社区当时现已部分兼容了 Istio VirtualService & DestinationRule 的标签路由和服务鉴权才能,用户能够通过 Istio 操控面给运用下发相关规矩,对运用进行流量管理。

Spring Cloud Alibaba 在 Proxyless Mesh 上的探索

准备工作

Proxyless Mesh 的计划首要需求准备好一个能给运用动态下发规矩的操控面,本次Spring Cloud Alibaba 2.2.10-RC1 版别支撑了2种当时市面上的干流操控面来更好的满意各类用户诉求:

1. Istio 操控面

为了运用 Istio 操控面下发管理规矩,首要需求在K8s环境中装置 Istio 操控面,您能够运用 Spring Cloud Alibaba 社区供给的测验用的Istio环境,也能够选择自己测验装置一套 Istio 操控面,装置 Istio 操控面的流程如下:

  1. 装置 K8s 环境,请参阅 K8s 的装置工具 **[ 7] **末节
  2. 在 K8s 上装置并启用 Istio,请参阅 Istio 官方文档的装置末节 [ 8]

2. OpenSergo 操控面

OpenSergo 是敞开通用的,掩盖微服务及上下游相关组件的微服务管理项目。OpenSergo 从微服务的角度出发,涵盖流量管理、服务容错、服务元信息管理、安全管理等要害管理领域,供给一系列的管理才能与规范、生态适配与最佳实践,支撑 Java, Go, Rust 等多语言生态。

OpenSergo 操控平面 (Control Plane) 作为 OpenSergo CRD 的一致管控组件,承载服务管理装备转化与下发的职责。

  1. 装置 K8s 环境,请参阅 K8s 的装置工具末节
  2. 在 K8s 上装置并启用 OpenSergo Control Plane,请参阅 OpenSergo 官方供给的OpenSergo 操控面装置文档 [ 9]

Spring Cloud Alibaba 在 Proxyless Mesh 上的探索

标签路由

运用布景

在现在的微服务架构中,服务的数量非常巨大,为了更好的管理这些微服务运用,或许需求给这些运用打上标签,而且将一个或多个服务的供给者划分到同一个分组,然后约束流量只在指定分组中流通,完成流量阻隔的目的。标签路由能够作为蓝绿发布、灰度发布等场景的才能根底,它能够被运用在以下场景中:

  • 多版别开发测验

多个版别并行开发时,需求为每个版别准备一套开发环境。假如版别较多,开发环境本钱会非常大。流量阻隔计划能够在多版别开发测验时大幅度下降资源本钱。运用根据标签路由的全链路流量阻隔机制,能够将特定的流量路由到指定的开发环境。例如在开发环境 1 中只修正运用 B 和运用 D,则为这两个运用在开发环境1中的版别创立 Tag1 标签,并装备对应的路由规矩。入口运用 A 调用 B 时,会判别流量是否满意路由规矩。假如满意,路由到开发环境 1 中运用B的 V1.1 版别;假如不满意,路由到基线环境中的运用 B 的 V1 版别。运用 C 调用 D 的时分相同根据流量决议路由到 D 的 V1 版别或 V1.1 版别。

Spring Cloud Alibaba 在 Proxyless Mesh 上的探索

  • 运用流量阻隔

假如一个运用有多个版别在线上一同运转,布置在不同环境中,如日常环境和特别环境,则能够运用标签路由对不同环境中的不同版别进行流量阻隔,将秒杀订单流量或不同渠道订单流量路由到特别环境,将正常的流量路由到日常环境。即便特别环境异常,本应进入特别环境的流量也不会进入日常环境,不影响日常环境的运用。

Spring Cloud Alibaba 在 Proxyless Mesh 上的探索

  • A/B Testing

线上有多个运用版别一同运转,希望对不同版别的运用进行 A/B Testing,则能够运用标签路由的全链路流量操控将地域 A(如杭州)的客户流量路由到 V1 版别,地域 B(如上海)的客户流量路由到 V1.1 版别,对不同版别进行验证,然后下降新产品或新特性的发布风险,为产品创新供给保障。

Spring Cloud Alibaba 在 Proxyless Mesh 上的探索

目前,Spring Cloud Alibaba Mesh 供给的标签路由才能支撑根据恳求途径、恳求头和 HTTP 恳求参数等恳求元信息对恳求做标签路由,让运用发出的恳求根据 Istio 操控面下发的规矩发送至指定版别的上游服务。

运用方法

1. 导入依靠并装备运用

首要,创立服务顾客运用,引荐通过云原生运用脚手架进行项目构建,修正完装备即可快捷试用:

云原生运用脚手架:

start.aliyun.com/

Spring Cloud Alibaba 在 Proxyless Mesh 上的探索

假如手动创立项目,请修正服务顾客的 pom.xml 文件,导入 Spring Cloud Alibaba 2.2.10-RC1 版别下的标签路由以及 Istio 资源转化模块的相关依靠:

<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-alibaba-dependencies</artifactId>
            <version>2.2.10-RC1</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
    </dependencies>
</dependencyManagement>
<dependencies>
    <dependency>
        <groupId>com.alibaba.cloud</groupId>
        <artifactId>spring-cloud-starter-alibaba-governance-routing</artifactId>
    </dependency>
    <dependency>
        <groupId>com.alibaba.cloud</groupId>
        <artifactId>spring-cloud-starter-xds-adapter</artifactId>
    </dependency>
</dependencies>

在 application.yml 装备文件给顾客装备 Istio 操控面以及 Nacos 注册中心的相关信息:

server:
  port: 18084
spring:
  main:
    allow-bean-definition-overriding: true
  application:
    name: service-consumer
  cloud:
    nacos:
      discovery:
        server-addr: 127.0.0.1:8848
        fail-fast: true
        username: nacos
        password: nacos
    istio:
      config:
        # 是否敞开Istio装备转化
        enabled: ${ISTIO_CONFIG_ENABLE:true}
        # Istiod IP
        host: ${ISTIOD_ADDR:127.0.0.1}
        # Istiod 端口
        port: ${ISTIOD_PORT:15010}
        # 轮询Istio线程池巨细
        polling-pool-size: ${POLLING_POOL_SIZE:10}
        # 轮询Istio时间间隔
        polling-time: ${POLLING_TIME:10}
        # Istiod鉴权token(拜访Istiod 15012端口时可用)
        istiod-token: ${ISTIOD_TOKEN:}
        # 是否打印xds相关日志
        log-xds: ${LOG_XDS:true}

在 application.yml 装备文件给出产者运用装备元信息:

# 第一个出产者,版别为v1
spring.cloud.nacos.discovery.metadata.version=v1
# 第二个出产者,版别为v2
spring.cloud.nacos.discovery.metadata.version=v2

假如是需求对接 OpenSergo 操控面的,则需求给顾客运用加上 spring-cloud-starter-alibaba-governance-routing 跟 spring-cloud-starter-opensergo-adapter 相关依靠,并装备 OpenSergo 所需的装备即可。

2. 运转运用程序

发动两个出产者运用和一个顾客运用,并将这些运用都注册到本地的 Nacos 注册中心里,顾客在调用出产者时,会根据操控面下发的标签路由规矩来调用不同的出产者实例。发动顾客和两个出产者后,能够在 Nacos 注册中心里看到这几个已注册的服务:

Spring Cloud Alibaba 在 Proxyless Mesh 上的探索

操控台上会打印出以下信息,说明此运用正在监听 Istio 操控面下发的装备:

Spring Cloud Alibaba 在 Proxyless Mesh 上的探索

3. 通过 Istio 操控面下发标签路由规矩

通过 Istio 操控面下发标签路由规矩,首要下发 DestinationRule 规矩:

kubectl apply -f - << EOF
apiVersion: networking.istio.io/v1alpha3
kind: DestinationRule
metadata:
  name: my-destination-rule
spec:
  host: sca-virtual-service
  subsets:
  - name: v1
    labels:
      version: v1
  - name: v2
    labels:
      version: v2
EOF

此规矩将后端服务拆分为两个版别,label 为 v1 的 pod 被分到 v1 版别,label 为 v2 的 pod 被分到 v2 版别。

之后,下发 VirtualService 规矩:

kubectl apply -f - << EOF
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: sca-virtual-service
spec:
  hosts:
    - service-provider
  http:
  - match:
    - headers:
        tag:
          exact: gray
      uri:
        exact: /istio-label-routing
    route:
    - destination:
        host: service-provider
        subset: v2
  - route:
    - destination:
        host: service-provider
        subset: v1
EOF

这条 VirtualService 指定了一条最简略的标签路由规矩,将恳求头 tag 为 gray,恳求途径为 /istio-label-routing 的 HTTP 恳求路由到 v2 版别,其他的流量都路由到 v1 版别。

发送若干条不带恳求头的 HTTP 恳求至 IstioConsumerApplication

while true;
  do curl localhost:18084/istio-label-routing;
  sleep 0.1;
  echo "";
done;

由于恳求头不为 gray,所以恳求将会被路由到 v1 版别,回来如下

Spring Cloud Alibaba 在 Proxyless Mesh 上的探索

之后发送一条恳求头 tag 为 gray,且恳求途径为 /istio-label-routing 的 HTTP 恳求

while true;
  do curl localhost:18084/istio-label-routing -H "tag: gray";
  sleep 0.1;
  echo "";
done;

由于满意路由规矩,所以恳求会被路由至 v2 版别

Spring Cloud Alibaba 在 Proxyless Mesh 上的探索

4. 通过 OpenSergo 操控面下发标签路由规矩

通过 OpenSergo 操控面也定义了特定的流量路由规矩 TrafficRouter,如下是一个 OpenSergo 操控面对应的流量路由规矩:

kubectl apply -f - << EOF
apiVersion: traffic.opensergo.io/v1alpha1
kind: TrafficRouter
metadata:
  name: service-provider
  namespace: default
  labels:
    app: service-provider
spec:
  hosts:
    - service-provider
  http:
    - match:
        - headers:
            tag:
              exact: v2
      route:
        - destination:
            host: service-provider
            subset: v2
            fallback:
              host: service-provider
              subset: v1
    - route:
        - destination:
            host: service-provider
            subset: v1
EOF

这条 TrafficRouter 指定了一条最简略的流量路由规矩,将恳求头 tag 为 v2 的 HTTP 恳求路由到 v2 版别,其他的流量都路由到 v1 版别。假如 v2 版别没有对应的节点,则将流量 fallback 至 v1 版别。

停止 v2 版别的 ProviderApplication 后,继续发送一条恳求头 tag 为 v2 的 HTTP 恳求

curl --location --request GET '127.0.0.1:18083/router-test' --header 'tag: v2'

由于 v2 版别没有服务供给者,因而流量被 fallback 至 v1 版别。

Route in 30.221.132.228: 18081,version is v1.

上述具体示例代码能够在社区 Github 上示例代码 **[ 10] **中获取。

服务鉴权

正常出产场景,微服务运用都具有安全要求,不会让恣意的服务都可直接调用。因而需求对调用该运用的上游运用进行服务鉴权,确保运用本身的安全。

未装备服务鉴权 Consumer 1、2、3 和 Provider 在同一个命名空间内,Consumer 1、2、3 默认能够调用 Provider 的一切 Path(Path 1、2和3)。

Spring Cloud Alibaba 在 Proxyless Mesh 上的探索

装备服务鉴权规矩后,运用间合法的调用联系如下图所示:

Spring Cloud Alibaba 在 Proxyless Mesh 上的探索

设置一切 Path 的鉴权能够对 Provider 的一切Path设置鉴权规矩,例如 Provider 一切 Path 的鉴权规矩设置为回绝 Consumer 1 调用(黑名单),则答应 Consumer 2、3 调用(白名单)。

设置指定 Path 的鉴权在设置一切 Path 的鉴权根底上,还能够设置 Consumer 指定 Path 的鉴权规矩,例如按一切 Path 的鉴权方法,Consumer 2、3能够拜访 Provider 的一切 Path,但 Provider 的 Path2 涉及一些中心事务或数据,不希望 Consumer 2 调用,能够将 Path 2 对 Consumer 2 的鉴权方法设置为黑名单(回绝调用),则 Consumer 2 只能拜访 Provider 的 Path 1和 Path 3。

目前,Spring Cloud Alibaba Mesh 支撑了除需 mTLS 支撑以外 Istio 的大部分鉴权规矩,而且支撑了多种字符串匹配方式以及规矩的逻辑运算。

Spring Cloud Alibaba 在 Proxyless Mesh 上的探索

运用方法

1. 导入依靠并装备运用

首要,创立运用,引荐通过云原生运用脚手架进行项目构建,修正完装备即可快捷试用:

云原生运用脚手架:

start.aliyun.com/

Spring Cloud Alibaba 在 Proxyless Mesh 上的探索

假如手动创立项目,请修正服务顾客的 pom.xml 文件,导入 Spring Cloud Alibaba 2.2.10-RC1 版别下的标签路由以及 Istio 资源转化模块的相关依靠:

<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-alibaba-dependencies</artifactId>
            <version>2.2.10-RC1</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
    </dependencies>
</dependencyManagement>
<dependencies>
    <dependency>
        <groupId>com.alibaba.cloud</groupId>
        <artifactId>spring-cloud-starter-alibaba-governance-auth</artifactId>
    </dependency>
    <dependency>
        <groupId>com.alibaba.cloud</groupId>
        <artifactId>spring-cloud-starter-xds-adapter</artifactId>
    </dependency>
</dependencies>

在运用的 application.yml 装备文件中装备 Istio 相关元数据:

server:
  port: ${SERVER_PORT:80}
spring:
  cloud:
    governance:
      auth:
        # 是否敞开鉴权
        enabled: ${ISTIO_AUTH_ENABLE:true}
    istio:
      config:
        # 是否敞开Istio装备转化
        enabled: ${ISTIO_CONFIG_ENABLE:true}
        # Istiod IP
        host: ${ISTIOD_ADDR:127.0.0.1}
        # Istiod 端口
        port: ${ISTIOD_PORT:15010}
        # 轮询Istio线程池巨细
        polling-pool-size: ${POLLING_POOL_SIZE:10}
        # 轮询Istio时间间隔
        polling-time: ${POLLING_TIMEOUT:10}
        # Istiod鉴权token(拜访Istiod 15012端口时可用)
        istiod-token: ${ISTIOD_TOKEN:}
        # 是否打印xds相关日志
        log-xds: ${LOG_XDS:true}

2. 运转运用程序

在导入好以上的依靠而且在 application.yml 文件中装备了相关装备之后,能够将此运用程序运转起来,发动一个简略的 Spring Boot 运用,其中只含有一个简略的接口,此接口将会把本次恳求的具体信息回来给客户端。

发动运用后,操控台上会打印出以下信息,说明此运用正在监听 Istio 操控面下发的装备:

Spring Cloud Alibaba 在 Proxyless Mesh 上的探索

3. 通过 Istio 操控面下发鉴权装备

在运用如下命令通过 Istio 下发一条鉴权规矩至 demo 运用,这条规矩的限制了拜访该运用的恳求 header:

kubectl apply -f - << EOF
apiVersion: security.istio.io/v1beta1
kind: AuthorizationPolicy
metadata:
  name: http-headers-allow
  namespace: ${namespace_name}
spec:
  selector:
    matchLabels:
      app: ${app_name}
  action: ALLOW
  rules:
  - when:
    - key: request.headers[User-Agent]
      values: ["PostmanRuntime/*"]
EOF

之后发送带User-Agent头部的HTTP恳求来验证规矩是否收效:

while true;
  do curl localhost/auth -H "User-Agent: PostmanRuntime/7.29.2";
  sleep 0.1;
  echo "";
done;

由于此恳求由于带着了正确的 HTTP Header 信息,将会回来:

Spring Cloud Alibaba 在 Proxyless Mesh 上的探索

之后发送一个不带User-Agent头部的HTTP恳求来验证规矩是否收效:

while true;
  do curl localhost/auth;
  sleep 0.1;
  echo "";
done;

由于此恳求没有带着正确的 HTTP Header 信息,将会回来:

Spring Cloud Alibaba 在 Proxyless Mesh 上的探索

上述具体示例代码能够在社区 Github 上示例代码 **[ 11] **中获取。

社区动态

新 Committer 介绍

Spring Cloud Alibaba 社区近几个月涌现了一些积极参与社区维护迭代的外部贡献者,在此,向他们表示感谢!另外,对于其中一向参与社区活动,做出重要贡献 feature 的阮胜同学,社区按照新 Committer 提名与投票制度正式提名其为社区 Committer 并投票通过,成功中选,在此也向其表示祝贺!欢迎更多外部同学注重 Spring Cloud Alibaba 开源社区和贡献开源社区。

Spring Cloud Alibaba 在 Proxyless Mesh 上的探索

未来规划

通过过去几年开展迭代,Spring Cloud Alibaba 当时在微服务运用的构建的如服务注册与发现、分布式装备、限流降级等才能方面现已做得日趋完善,社区的工作重心会投入到构建 Spring Cloud 生态的微服务管理才能上。欢迎感兴趣的同学扫描下方钉钉二维码加入社区交流群,一同参与社区未来建设!

Spring Cloud Alibaba 在 Proxyless Mesh 上的探索

相关链接

[1]Linkerd

linkerd.io/

[2]Envoy

www.envoyproxy.io/

[3]Istio

github.com/istio/istio

[4]Istio 1.0版别

istio.io/latest/news…

[5]架构方式

istio.io/v1.12/blog/…

[6]2.2.10-RC 版别

github.com/alibaba/spr…

[7]装置工具

kubernetes.io/zh-cn/docs/…

[8]装置末节

istio.io/latest/zh/d…

[9]OpenSergo 操控面装置文档

opensergo.io/zh-cn/docs/…

[10]示例代码

github.com/alibaba/spr…

[11]示例代码

github.com/alibaba/spr…