MSE云原生网关以托管的方式来做流量入口,提供丰富的流量治理能力,支持多种服务发现方式,如容器服务、MSE Nacos、MSE Zookeeper、EDAS注册中心、SAE注册中心、固定地址和DNS域名,并以统一的模型支持服务版本以及灰度发布能力。本文介绍基于容器服务K8s和Nacos注册中心两种服务发现机制来实践不同的服务发布策略。

前提条件

服务发现方式:容器服务K8s

在本示例中,使用容器服务K8s原生的服务发现方式,即通过声明式Service API资源将后端服务注册到CoreDNS。示例中的后端服务提供一个查询当前版本的接口:请求路径为/version,并且当前版本为v1。云原生网关深度集成容器服务ACK,可以实时动态地从ACK集群中获取服务信息,方便通过云原生网关将该后端服务暴露给外部用户。

图 1. 业务架构图
基于容器服务K8s服务发现方式的业务架构图

部署应用

  1. 容器服务控制台部署以下应用,当前应用版本为v1。

    应用部署的具体操作,请参见创建无状态工作负载Deployment

    apiVersion: v1
    kind: Service
    metadata:
      name: httpbin
    spec:
      ports:
      - port: 8080
        protocol: TCP
      selector:
        app: httpbin
    ---
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: httpbin-v1
    spec:
      replicas: 3
      selector:
        matchLabels:
          app: httpbin
          version: v1
      template:
        metadata:
          labels:
            app: httpbin
            version: v1
        spec:
          containers:
          - image: specialyang/spring-cloud-httpbin-k8s:v1
            imagePullPolicy: Always
            name: spring-cloud-httpbin-k8s
            ports:
            - containerPort: 8080
  2. 网关详情页面左侧导航栏,选择服务管理 > 来源管理,在创建来源页面,添加容器服务的服务来源。

    为云原生网关添加服务来源的具体操作,请参见新建服务来源

    添加服务来源
  3. 网关详情页面左侧导航栏,选择服务管理 > 服务列表,在创建服务页面,导入要暴露给云原生网关的服务httpbin

    为云原生网关添加服务的具体操作,请参见添加服务

  4. httpbin服务的策略配置中添加服务版本v1。

    为云原生网关添加服务版本的具体操作,请参见管理服务版本

    说明 需要选择对应的标签来筛选出v1版本的节点,目前只部署了v1版本,所以v1版本的节点数占总实例数100%。
    路由服务版本
  5. 在路由管理中为该服务创建一条路由规则,从而将服务暴露给外部用户。httpbin服务暴露的API的路由为/version,请求转发至服务httpbin的v1版本。

    为云原生网关配置路由的具体操作,请参见新建路由规则

  6. 执行以下测试请求命令:
    for i in {1..10}; do curl "${GATEWAY_EXTERNAL_IP}/version"; echo "";  done
    响应结果:
    version: v1
    version: v1
    version: v1
    version: v1
    version: v1
    version: v1
    version: v1
    version: v1
    version: v1
    version: v1

蓝绿部署

蓝绿部署需要按照服务当前版本所占用的资源状况为服务新版本申请同样的资源规格,部署完毕之后将流量整体切换到服务新版本。

图 2. 基于K8s Service服务发现方式的蓝绿部署示意图
基于容器服务K8s服务发现机制的蓝绿发布
  1. 利用容器服务ACK的声明式API资源部署httpbin服务的新版本v2,副本数同样是3。
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: httpbin-v2
    spec:
      replicas: 3
      selector:
        matchLabels:
          app: httpbin
          version: v2
      template:
        metadata:
          labels:
            app: httpbin
            version: v2
        spec:
          containers:
          - image: specialyang/spring-cloud-httpbin-k8s:v2
            imagePullPolicy: Always
            name: spring-cloud-httpbin-k8s
            ports:
            - containerPort: 8080
  2. httpbin服务的策略配置中添加服务版本v2。

    为云原生网关添加服务版本的具体操作,请参见管理服务版本

    说明 需要选择对应的标签来筛选出v2版本的节点,集群中现在v1和v2版本的节点数一致,所以各占50%。
    添加服务版本
  3. 通过蓝绿发布将流量从v1整体切换至v2,仅需要修改之前创建的路由规则中的目标服务。

    修改云原生网关路由规则的具体操作,请参见变更路由规则

    路由规则
  4. 执行以下测试请求命令:
    for i in {1..10}; do curl "${GATEWAY_EXTERNAL_IP}/version"; echo "";  done
    响应结果:
    version: v2
    version: v2
    version: v2
    version: v2
    version: v2
    version: v2
    version: v2
    version: v2
    version: v2
    version: v2

可以发现,访问API资源/version请求的流量已经全部从v1切换至v2。

A/B测试

A/B测试是基于用户请求的元信息将流量路由到新版本,也就是可以根据请求内容来动态路由。在本实例中,希望User-Agent的值为Android的请求 (来自安卓系统的请求)可以访问新版本,其他系统仍然访问旧版本。

图 3. 基于K8s Service服务发现方式的A/B测试示意图
基于容器服务K8s服务发现机制的A/B测试
  1. 仍然通过之前实践中部署的httpbin服务v1和v2的应用。同时,需要创建两条路由规则。
    • 匹配Path为/version的请求访问服务版本v1。
    • 匹配Path为/version,且User-Agent头部含有Android的请求访问服务版本v2。
    说明 version-v2的路由规则中需要增加请求头的匹配规则。
  2. 执行以下测试请求命令(User-Agent中不含有Android):
    curl ${GATEWAY_EXTERNAL_IP}/version
    响应结果:
    version: v1
  3. 执行以下测试请求命令(User-Agent中含有Android):
    curl -H "User-Agent: Mozilla/5.0 (Linux; Android 4.0.3)" ${GATEWAY_EXTERNAL_IP}/version
    响应结果:
    version: v2

可以发现,当前请求会按照来源的操作系统对流量进行分流。

金丝雀发布

金丝雀发布允许引流一小部分流量到服务新版本,待验证通过后,逐步调大流量,直至切流完毕,期间可伴随着新版本的扩容,旧版本的缩容操作,达到资源利用率最大化。

图 4. 基于K8s Service服务发现方式的金丝雀发布示意图
基于容器服务K8s服务发现机制的金丝雀发布
  1. 在金丝雀发布策略中,服务新版本的副本初始部署数无需与原始保持一致。仅需保持资源始终满足灰度流量,所以将新版本的副本数调为1,可以在服务策略中服务版本模块看到当前各版本节点数的占比情况。
    服务版本
  2. 创建一条路由规则,在目标服务中按照权重将流量转发至新旧版本。

    其中,需要配置两个目标服务,httpbin的v1和v2版本,并设置对应的流量比。例如,目标服务为标签路由方式,且v1权重设置为80%,v2权重设置为20%。

  3. 执行以下测试请求命令:
    for i in {1..10}; do curl "${GATEWAY_EXTERNAL_IP}/version"; echo "";  done
    响应结果:
    version: v1
    version: v1
    version: v1
    version: v1
    version: v1
    version: v2
    version: v1
    version: v2
    version: v1
    version: v1

可以发现,10个请求中有2个是访问的新版本v2,其流量比确实符合期望比例。

说明 在真实业务场景中,新版本验证完毕后,就可以继续调大访问新版本的流量权重,期间注意对新版本扩容,按需对旧版本缩容。

服务发现方式:Nacos注册中心

本示例中的后端服务提供一个查询当前版本的接口/version,并且当前版本为v1。云原生网关深度集成MSE Nacos注册中心,可以实时动态地从MSE Nacos实例中获取服务信息,方便通过云原生网关将该后端服务暴露给外部用户。

图 5. 业务架构图
基于Nacos注册中心服务发现方式的业务架构图

部署应用

  1. 容器服务控制台部署以下应用,并将服务发布到Nacos注册中心,当前应用版本为v1。

    应用部署的具体操作,请参见创建无状态工作负载Deployment

    说明
    • 该YAML资源中变量${NACOS_SERVER_ADDRESS}需要替换为您的MSE Nacos地址,如果和网关在一个VPC,那么内网域名即可;否则,您需要配置公网域名。
    • 在K8s Service服务发现中,Pod中Labels信息可看做是节点的元数据信息。而在Nacos注册中心中,节点的元数据信息取决于服务注册时携带的信息。在Spring Cloud框架中,通过环境变量spring.cloud.nacos.discovery.metadata.xxx无侵入式为节点添加元数据信息,在该例子中,以version作为版本标用来区分不同版本的节点。因此,需要为业务容器添加环境变量spring.cloud.nacos.discovery.metadata.version=v1
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: httpbin-v1
    spec:
      replicas: 3
      selector:
        matchLabels:
          app: httpbin
      template:
        metadata:
          labels:
            app: httpbin
        spec:
          containers:
          - image: specialyang/spring-cloud-httpbin-nacos:v1
            imagePullPolicy: Always
            name: spring-cloud-httpbin-nacos
            ports:
            - containerPort: 8080
            env:
            - name: spring.cloud.nacos.discovery.server-addr
              value: ${NACOS_SERVER_ADDRESS} 
            - name: spring.cloud.nacos.discovery.metadata.version
              value: v1
  2. 网关详情页面左侧导航栏,选择服务管理 > 来源管理,添加目标MSE Nacos注册中心的服务来源。

    为云原生网关添加服务来源的具体操作,请参见新建服务来源

  3. 网关详情页面左侧导航栏,选择服务管理 > 服务列表,导入要暴露给云原生网关的服务httpbin,服务来源选择MSE Nacos注册中心。

    为云原生网关添加服务的具体操作,请参见添加服务

  4. httpbin服务的策略配置中添加服务版本v1。
    说明 需要选择对应的标签来筛选出v1版本的节点,目前只部署了v1版本,所以v1版本的节点数占总实例数100%。
    路由服务版本
  5. 在路由管理中为该服务创建一条路由规则,从而将服务暴露给外部用户。httpbin服务暴露的API的路由为/version,请求转发至服务httpbin的v1版本。

    为云原生网关配置路由的具体操作,请参见新建路由规则

  6. 执行以下测试请求命令:
    for i in {1..10}; do curl "${GATEWAY_EXTERNAL_IP}/version"; echo "";  done
    响应结果:
    version: v1
    version: v1
    version: v1
    version: v1
    version: v1
    version: v1
    version: v1
    version: v1
    version: v1
    version: v1

蓝绿部署

蓝绿部署需要按照服务当前版本所占用的资源状况为服务新版本申请同样的资源规格,部署完毕之后将流量整体切换到服务新版本。

图 6. 基于Nacos注册中心服务发现方式的蓝绿部署示意图
1
  1. 部署httpbin服务的新版本v2。
    说明 注册中心与容器服务ACK保持一致,同时为业务容器增加环境变量spring.cloud.nacos.discovery.metadata.version=v2,业务应用启动时会向指定Nacos注册服务,同时携带上自定义的元数据信息。云原生网关可以利用这些元数据信息来对节点区分不同的版本。
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: httpbin-v2
    spec:
      replicas: 3
      selector:
        matchLabels:
          app: httpbin
      template:
        metadata:
          labels:
            app: httpbin
        spec:
          containers:
          - image: specialyang/spring-cloud-httpbin-nacos:v2
            imagePullPolicy: Always
            name: spring-cloud-httpbin-nacos
            ports:
            - containerPort: 8080
            env:
            - name: spring.cloud.nacos.discovery.server-addr
              value: ${NACOS_SERVER_ADDRESS}
            - name: spring.cloud.nacos.discovery.metadata.version
              value: v2
  2. httpbin服务的策略配置中添加服务版本v2。

    为云原生网关添加服务版本的具体操作,请参见管理服务版本

    说明 需要选择对应的标签来筛选出v2版本的节点,集群中现在v1和v2版本的节点数一致,所以各占50%。
    添加服务版本
  3. 通过蓝绿部署将流量从v1整体切换至v2,仅需要之前修改之前创建的路由规则中的目标服务。

    修改云原生网关路由规则的具体操作,请参见变更路由规则

  4. 执行以下测试请求命令:
    for i in {1..10}; do curl "${GATEWAY_EXTERNAL_IP}/version"; echo "";  done
    响应结果:
    version: v2
    version: v2
    version: v2
    version: v2
    version: v2
    version: v2
    version: v2
    version: v2
    version: v2
    version: v2

可以发现,访问API资源/version请求的流量已经全部从v1切换至v2。

A/B测试

A/B测试是基于用户请求的元信息将流量路由到新版本,也就是可以根据请求内容来动态路由。在本实例中,希望User-Agent的值为Android的请求 (来自安卓系统的请求)可以访问新版本,其他系统仍然访问旧版本。

图 7. 基于Nacos注册中心服务发现方式的A/B测试示意图
2
  1. 仍然通过之前实践中部署的httpbin服务v1和v2的应用。同时,需要创建两条路由规则。
    • 匹配Path为/version的请求访问服务版本v1。
    • 匹配Path为/version,且User-Agent头部含有Android的请求访问服务版本v2。
    说明 version-v2的路由规则中需要增加请求头的匹配规则。
  2. 执行以下测试请求命令(User-Agent中不含有Android):
    curl ${GATEWAY_EXTERNAL_IP}/version
    响应结果:
    version: v1
  3. 执行以下测试请求命令(User-Agent中含有Android):
    curl -H "User-Agent: Mozilla/5.0 (Linux; Android 4.0.3)" ${GATEWAY_EXTERNAL_IP}/version
    响应结果:
    version: v2

可以发现,当前请求会按照来源的操作系统对流量进行分流。

金丝雀发布

金丝雀发布允许引流一小部分流量到服务新版本,待验证通过后,逐步调大流量,直至切流完毕,期间可伴随着新版本的扩容,旧版本的缩容操作,达到资源利用率最大化。

图 8. 基于Nacos注册中心服务发现方式的金丝雀发布示意图
3
  1. 在金丝雀发布策略中,服务新版本的副本初始部署数无需与原始保持一致。仅需保持资源始终满足灰度流量,所以将新版本的副本数调为1,可以在服务策略中服务版本模块看到当前各版本节点数的占比情况。
    服务版本
  2. 创建一条路由规则,在目标服务中按照权重将流量转发至新旧版本。

    其中,需要配置两个目标服务,httpbin的v1和v2版本,并设置对应的流量比。例如,目标服务为标签路由方式,且v1权重设置为80%,v2权重设置为20%。

  3. 执行以下测试请求命令:
    for i in {1..10}; do curl "${GATEWAY_EXTERNAL_IP}/version"; echo "";  done
    响应结果:
    version: v1
    version: v1
    version: v1
    version: v1
    version: v1
    version: v2
    version: v1
    version: v2
    version: v1
    version: v1

可以发现,10个请求中有2个是访问的新版本v2,其流量比确实符合期望比例。

说明 在真实业务场景中,新版本验证完毕后,就可以继续调大访问新版本的流量权重,期间注意对新版本扩容,按需对旧版本缩容。