基于MSE云原生网关实现前端灰度

前端灰度发布与可监控、可回滚策略相结合,形成了一个强大的系统稳定性保障机制。通过这三个策略的协同工作,可以确保前端应用在不断迭代和更新的同时,保持高性能和高稳定性,本文介绍如何通过配置MSE云原生网关实现前端灰度。

端到端全链路灰度实现

在微服务场景中,应用间的调用是随机的。当您部署的Spring Cloud应用或Dubbo应用存在升级版本时,可能会导致无法将具有一定特征的流量路由到应用的目标版本。通过MSE提供的云原生网关实现全链路灰度,配合前端灰度方案,即可实现端到端的全链路灰度

前端用户每一次的请求都经过云原生网关,经过权限系统验证后,所有请求的Cookie中都带上了用户的唯一标识,比如 userid: 001

说明

网关挂载了一个 frontend-gray插件,通过配置插件规则,将灰度流量进行映射并传递。

image

前提条件

Ingress类型服务实现前端灰度

重要

安装MSE Ingress Controller,通过MSE Ingress访问容器服务,详情可参见MSE Ingress访问容器服务

步骤一:使用容器服务部署应用

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

展开YAML

frontend-base.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: frontend
  namespace: default
spec:
  replicas: 1
  selector:
    matchLabels:
      app: frontend
  template:
    metadata:
      labels:
        app: frontend
    spec:
      containers:
        - image: 'registry.cn-hangzhou.aliyuncs.com/mse-demo-hz/user-gray:base'
          imagePullPolicy: Always
          name: frontend
          resources: {}
---
apiVersion: v1
kind: Service
metadata:
  name: frontend-base-svc
  namespace: default
spec:
  ports:
    - port: 80
      protocol: TCP
      targetPort: 80
  selector:
    app: frontend
  type: ClusterIP

---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  labels:
    ingress-controller: mse
  namespace: default
  name: frontend-base-ingress
spec:
  ingressClassName: mse
  rules:
    - http:
        paths:
          - backend:
              service:
                name: frontend-base-svc
                port:
                  number: 80
            path: /
            pathType: Prefix
frontend-gray.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: frontend-gray
  namespace: default
spec:
  replicas: 1
  selector:
    matchLabels:
      app: frontend-gray
  template:
    metadata:
      labels:
        app: frontend-gray
    spec:
      containers:
        - image: 'registry.cn-hangzhou.aliyuncs.com/mse-demo-hz/user-gray:gray'
          imagePullPolicy: Always
          name: frontend-gray
          resources: {}
---
apiVersion: v1
kind: Service
metadata:
  name: frontend-gray-svc
  namespace: default
spec:
  ports:
    - port: 80
      protocol: TCP
      targetPort: 80
  selector:
    app: frontend-gray
  type: ClusterIP

---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  labels:
    ingress-controller: mse
  annotations:
    nginx.ingress.kubernetes.io/canary: 'true'
    nginx.ingress.kubernetes.io/canary-by-header: x-higress-tag
    nginx.ingress.kubernetes.io/canary-by-header-value: gray
  name: frontend-gray-ingress
  namespace: default
spec:
  ingressClassName: mse
  rules:
    - http:
        paths:
          - backend:
              service:
                name: frontend-gray-svc
                port:
                  number: 80
            path: /
            pathType: Prefix

步骤二:MSE控制台配置灰度插件

  1. 登录MSE网关管理控制台,并在顶部菜单栏选择地域。

  2. 在左侧导航栏,选择云原生网关 > 网关列表,单击目标网关名称。

  3. 在左侧导航栏,单击插件市场

  4. 插件市场页面,搜索frontend-gray关键字,然后单击插件frontend-gray卡片。

  5. 选择插件配置 > 域名级插件规则,单击新建规则,在新建规则页面配置如下规则,详细配置可参见配置规则

    grayKey: userid
    rules:
      - name: beta-user
        grayKeyValue:
          - "00000002"
          - "00000003"
    baseDeployment:
      version: base
    grayDeployments:
      - name: beta-user
        version: gray
        enabled: true

    image

步骤三:结果验证

  1. 登录容器服务控制台,在左侧导航栏选择集群列表,在集群列表页面单击所创建的容器服务集群,进入集群详情页,在左侧导航栏选择网络 > 路由,查看公网访问端点。

    image

  2. 访问公网端点nlb-qv04p*******cn-hangzhou.nlb.aliyuncsslb.com,登录 admin/ice 账号,访问主版本,用户ID为 00000001。

    image

  3. 访问公网端点nlb-qv04p*******cn-hangzhou.nlb.aliyuncsslb.com,登录普通用户user/ice,访问灰度版本,用户ID为 00000002。

    image

ACK容器服务实现前端灰度

步骤一:使用容器服务部署应用

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

展开YAML

frontend-base.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: frontend
  namespace: default
spec:
  replicas: 1
  selector:
    matchLabels:
      app: frontend
  template:
    metadata:
      labels:
        app: frontend
    spec:
      containers:
        - image: 'registry.cn-hangzhou.aliyuncs.com/mse-demo-hz/user-gray:base'
          imagePullPolicy: Always
          name: frontend
          resources: {}
---
apiVersion: v1
kind: Service
metadata:
  name: frontend-base-svc
  namespace: default
spec:
  ports:
    - port: 80
      protocol: TCP
      targetPort: 80
  selector:
    app: frontend
  type: ClusterIP
frontend-gray.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: frontend-gray
  namespace: default
spec:
  replicas: 1
  selector:
    matchLabels:
      app: frontend-gray
  template:
    metadata:
      labels:
        app: frontend-gray
    spec:
      containers:
        - image: 'registry.cn-hangzhou.aliyuncs.com/mse-demo-hz/user-gray:gray'
          imagePullPolicy: Always
          name: frontend-gray
          resources: {}
---
apiVersion: v1
kind: Service
metadata:
  name: frontend-gray-svc
  namespace: default
spec:
  ports:
    - port: 80
      protocol: TCP
      targetPort: 80
  selector:
    app: frontend-gray
  type: ClusterIP

步骤二:MSE控制台配置灰度插件

  1. 登录MSE网关管理控制台,并在顶部菜单栏选择地域。

  2. 在左侧导航栏,选择云原生网关 > 网关列表,单击目标网关名称。

  3. 在左侧导航栏,单击插件市场

  4. 插件市场页面,搜索frontend-gray关键字,然后单击插件frontend-gray卡片。

  5. 选择插件配置 > 域名级插件规则,单击新建规则,在新建规则页面配置如下规则,详细配置可参见配置规则

    grayKey: userid
    rules:
      - name: beta-user
        grayKeyValue:
          - "00000002"
          - "00000003"
    baseDeployment:
      version: base
    grayDeployments:
      - name: beta-user
        version: gray
        enabled: true

    image

步骤三:添加网关服务来源

  1. 登录MSE网关管理控制台,并在顶部菜单栏选择地域。

  2. 在左侧导航栏,选择云原生网关 > 网关列表,单击目标网关名称。

  3. 在左侧导航栏,选择路由管理,然后选择来源页签。

  4. 单击创建来源。在创建来源面板,选择来源类型容器服务ACK/ASK/ACS 集群选择所创建的容器服务集群, 然后单击确定

    image

步骤四:创建服务

  1. 登录MSE网关管理控制台,并在顶部菜单栏选择地域。

  2. 在左侧导航栏选择云原生网关 > 网关列表

  3. 网关列表页面,单击目标网关名称。

  4. 在左侧导航栏,选择路由管理,然后选择服务页签。

  5. 单击创建服务。在创建服务面板,配置服务相关参数,然后单击确定

    image

步骤五:创建base路由

  1. 登录MSE网关管理控制台,并在顶部菜单栏选择地域。

  2. 在左侧导航栏,选择云原生网关 > 网关列表,单击目标网关名称。

  3. 在左侧导航栏,单击路由管理,然后在路由页签单击创建路由

  4. 创建路由页面,配置如下相关项,然后单击保存并发布

    image

步骤六:创建gray路由

  1. 登录MSE网关管理控制台,并在顶部菜单栏选择地域。

  2. 在左侧导航栏,选择云原生网关 > 网关列表,单击目标网关名称。

  3. 在左侧导航栏,单击路由管理,然后在路由页签单击创建路由

  4. 创建路由页面,配置相关配置项,然后单击保存并发布

    image

    说明

    gray代表灰度版本,和frontend-gray插件配置中 grayDeployments.version对应。

步骤七:结果验证

  1. 登录MSE网关管理控制台,并在顶部菜单栏选择地域。

  2. 在左侧导航栏,选择云原生网关 > 网关列表,单击目标网关名称。

  3. 基本概览页面,单击接入点页签找到网关入口,查看公网访问端点。

    image

  4. 访问公网端点nlb-qv04p*******cn-hangzhou.nlb.aliyuncsslb.com,登录 admin/ice 账号,访问主版本,用户ID为 00000001。

    image

  5. 访问公网端点nlb-qv04p*******cn-hangzhou.nlb.aliyuncsslb.com,登录普通用户user/ice,访问灰度版本,用户ID为 00000002。

    image

ECS类型服务实现前端灰度

步骤一:ECS分别部署两个前端应用

  • 基线应用地址为:120.***.137.243:80

  • 灰度应用地址为:120.***.137.243:8081

步骤二:创建服务

  1. 登录MSE网关管理控制台,并在顶部菜单栏选择地域。

  2. 在左侧导航栏选择云原生网关 > 网关列表

  3. 网关列表页面,单击目标网关名称。

  4. 在左侧导航栏,选择路由管理,然后选择服务页签。

  5. 单击创建服务。在创建服务面板,服务来源为固定地址,配置服务相关参数,然后单击确定

    image

    image

步骤三:创建base路由

  1. 登录MSE网关管理控制台,并在顶部菜单栏选择地域。

  2. 在左侧导航栏选择云原生网关 > 网关列表

  3. 网关列表页面,单击目标网关名称。

  4. 在左侧导航栏,单击路由管理,然后在路由页签单击创建路由

  5. 创建路由页面,配置相关配置项,然后单击保存并发布

    image

步骤四:创建gray路由

  1. 登录MSE网关管理控制台,并在顶部菜单栏选择地域。

  2. 在左侧导航栏选择云原生网关 > 网关列表

  3. 网关列表页面,单击目标网关名称。

  4. 在左侧导航栏,单击路由管理,然后在路由页签单击创建路由

  5. 创建路由页面,配置相关项,然后单击保存并发布

    说明

    gray代表灰度版本,和frontend-gray插件配置中 grayDeployments.version对应。

    image

步骤五:MSE控制台配置灰度插件

  1. 登录MSE网关管理控制台,并在顶部菜单栏选择地域。

  2. 在左侧导航栏选择云原生网关 > 网关列表

  3. 网关列表页面,单击目标网关名称。

  4. 在左侧导航栏,单击插件市场

  5. 插件市场页面,搜索frontend-gray关键字,然后单击插件frontend-gray卡片。

  6. 选择插件配置 > 域名级插件规则,单击新建规则,在新建规则页面配置如下规则,详细配置可参见配置规则

    grayKey: userid
    rules:
      - name: beta-user
        grayKeyValue:
          - "00000002"
          - "00000003"
    baseDeployment:
      version: base
    grayDeployments:
      - name: beta-user
        version: gray
        enabled: true

    image

步骤六:结果验证

  1. 登录MSE网关管理控制台,并在顶部菜单栏选择地域。

  2. 在左侧导航栏,选择云原生网关 > 网关列表,单击目标网关名称。

  3. 基本概览页面,单击接入点页签找到网关入口,查看公网访问端点。

    image

  4. 访问公网端点nlb-qv04p*******cn-hangzhou.nlb.aliyuncsslb.com,登录 admin/ice 账号,访问主版本,用户ID为 00000001。

    image

  5. 访问公网端点nlb-qv04p*******cn-hangzhou.nlb.aliyuncsslb.com,登录普通用户user/ice,访问灰度版本,用户ID为 00000002。

    image

CDN/OSS类型服务实现前端灰度

步骤一:OSS文件规划

展开YAML

- app1 # 应用
  - dev # dev版本
    - index.html
    - js
      ...
    - css
      ...
    - images
      ...
  - 0.0.1  # 001版本
    - index.html
    - js
      ...
    - css
      ...
    - images
      ...
  - 0.0.2  # 002版本
    - index.html
    - js
      ...
    - css
      ...
    - images
      ...
- app2
  - dev
    - index.html
    - js
      ...
    - css
      ...
    - images
      ...
  - 0.0.1
    - index.html
    - js
      ...
    - css
      ...
    - images
      ...
  - 0.0.2
    - index.html
    - js
      ...
    - css
      ...
    - images
      ...

步骤二:创建服务

  1. 登录MSE网关管理控制台,并在顶部菜单栏选择地域。

  2. 在左侧导航栏选择云原生网关 > 网关列表

  3. 网关列表页面,单击目标网关名称。

  4. 在左侧导航栏,选择路由管理,然后选择服务页签。

  5. 单击创建服务。在创建服务面板,服务来源为DNS域名,域名列表填写OSS地址,然后单击确定

    image

    重要

    如果OSS的和网关在同一个Region,建议填写OSS的内网地址,如果不在一个Region,请填写公网地址。

步骤三:创建路由

  1. 登录MSE网关管理控制台,并在顶部菜单栏选择地域。

  2. 在左侧导航栏选择云原生网关 > 网关列表

  3. 网关列表页面,单击目标网关名称。

  4. 在左侧导航栏,单击路由管理,然后在路由页签单击创建路由

  5. 创建路由页面,配置相关项,然后单击保存并发布

    image

步骤四:MSE控制台配置灰度插件

  1. 登录MSE网关管理控制台,并在顶部菜单栏选择地域。

  2. 在左侧导航栏选择云原生网关 > 网关列表

  3. 网关列表页面,单击目标网关名称。

  4. 在左侧导航栏,单击插件市场

  5. 插件市场页面,搜索frontend-gray关键字,然后单击插件frontend-gray卡片。

  6. 选择插件配置 > 域名级插件规则,单击新建规则,在新建规则页面配置如下规则,详细配置可参见配置规则

    grayKey: userid
    rules:
      - name: beta-user
        grayKeyValue:
          - "00000002"
          - "00000003"
    rewrite:
      host: xx.oss-cn-shanghai.aliyuncs.com ##OSS 地址
      indexRouting:
        "/app1": "/project-a/app1/{version}/index.html" #首页(html)路径重写
      fileRouting:
         "/app1": "/project-a/app1/{version}" #资源(css/js/images)路径重写
    baseDeployment:
      version: dev
    grayDeployments:
      - name: beta-user
        version: 0.0.1
        enabled: true

步骤五:结果验证

  1. 登录MSE网关管理控制台,并在顶部菜单栏选择地域。

  2. 在左侧导航栏,选择云原生网关 > 网关列表,单击目标网关名称。

  3. 基本概览页面,单击接入点页签找到网关入口,查看公网访问端点。

    image

  4. 访问公网端点nlb-qv04p*******cn-hangzhou.nlb.aliyuncsslb.com,登录 admin/ice 账号,访问主版本,用户ID为 00000001。

    image

  5. 访问公网端点nlb-qv04p*******cn-hangzhou.nlb.aliyuncsslb.com,登录普通用户user/ice,访问灰度版本,用户ID为 00000002。

    image

FAQ

前端灰度是否还可以配置重写策略?

  • 如果服务来源是非CDN/OSS ,可以搭配重写策略生效。

  • 如果服务来源是CDN/OSS的前端灰度是不可以搭配重写策略,因为相关的重写策略在frontend-gray灰度插件中实现了,如果配置重写策略,会发生冲突,返回403等一些异常情况。

是否可以往HTML首页注入一些全局变量?

  • 可以在html<head> 标签中(一般是CSS样式等属性),或者<body>标签的头部和尾部注入一些全局JavaScript脚本。

  • 通过injectionHTML首页注入代码,可以在head标签注入代码,也可以在body标签的firstlast位置注入代码。

grayKey: userid
rules:
- name: inner-user
  grayKeyValue:
  - '00000001'
  - '00000005'
baseDeployment:
  version: base
grayDeployments:
  - name: beta-user
    version: gray
    enabled: true
    weight: 80
injection:
  head: 
    - <script>console.log('Header')</script>
  body:
    first:
      - <script>console.log('hello world before')</script>
      - <script>console.log('hello world before1')</script>
    last:
      - <script>console.log('hello world after')</script>
      - <script>console.log('hello world after2')</script>

灰度版本生效时机?

假设A用户现在的前端版本是0.0.1, 这时候发布前端版本 0.0.2, 并且A客户命中了灰度规则,是否能立即生效?

是不会立即生效,出于下面几点原因考虑:

  • 如果发布版本需要实时生效,这时候就需要由后端来动态控制版本。首先无法实现前后端发布解耦,其次页面的稳定性强依赖这个接口,无法做CDN加速。

  • 假设版本能够实时生效,客户在使用某个功能的时候,可能出现上一秒还在使用某个按钮,下一秒这个按钮就不见了的情况。体验非常糟糕。

什么时机刷新页面?

  • 一般网站是有设置Session超时重新登录,一段时间没有访问后,需重新登录页面。

  • 用户通过登录页面登录到应用中。

所以,在登录页面的时候,需要刷新页面,以获取最新的灰度信息。前端登录示例代码如下:

async function handleLogin(values: LoginParams) {
    try {
      const result = await login(values);
      if (result.success) {
        message.success('登录成功!');
        await updateUserInfo();
        const urlParams = new URL(window.location.href).searchParams;
  	    window.location.href = `${urlParams.get('redirect') || '/'}`;
        return;
      }
      console.log(result);
      // 如果失败去设置用户错误信息,显示提示信息
      setLoginResult(result);
    } catch (error) {
      message.error('登录失败,请重试!');
      console.log(error);
    }
  }