全部產品
Search
文件中心

Alibaba Cloud Service Mesh:結合泳道與雜湊打標實現基於使用者身份的灰階測試

更新時間:Nov 12, 2024

Service Mesh (ASM)支援將應用的多個版本或者特徵隔離成一個獨立的運行環境(即泳道),然後通過設定泳道規則,將滿足規則的請求流量路由到目標版本或特徵的應用上。在生產環境中,開發人員可能會希望使用泳道對穩定版本和灰階版本進行隔離,並根據使用者身份路由至不同的泳道中。具體來說,您可能希望指定一部分特定身份的使用者路由至灰階版本進行測試,其餘使用者則通過權重的方式隨機匹配一定數量的請求路由至灰階版本。本文將介紹如何結合泳道和雜湊打標來實現按使用者身份的灰階測試。

前提條件

操作步驟

本樣本情境將建立三個應用,調用鏈如下圖。

  • mocka,包含v1版本。

  • mockb,包含v1版本。

  • mockc,包含v1版本和v2版本。

其中應用通過x-user-id要求標頭來標識使用者身份,同時應用之間也會透傳此要求標頭。本情境將示範以下內容:

  • x-user-id: jason時,請求流向新版本應用。

  • 對於其餘使用者,根據x-user-id雜湊,並按照雜湊結果將指定比例的使用者路由到新版本。

步驟一:部署樣本應用

  1. 使用以下內容建立sample.yaml。

    展開查看YAML內容

    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: mocka-v1
      labels:
        app: mocka
        version: v1
    spec:
      replicas: 1
      selector:
        matchLabels:
          app: mocka
          version: v1
          ASM_TRAFFIC_TAG: v1
      template:
        metadata:
          labels:
            app: mocka
            version: v1
            ASM_TRAFFIC_TAG: v1
        spec:
          containers:
          - name: default
            image: registry-cn-hangzhou.ack.aliyuncs.com/ack-demo/go-http-sample:tracing
            imagePullPolicy: IfNotPresent
            env:
            - name: version
              value: v1
            - name: app
              value: mocka
            - name: upstream_url
              value: "http://mockb:8000/"
            ports:
            - containerPort: 8000
    ---
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: mockb-v1
      labels:
        app: mockb
        version: v1
    spec:
      replicas: 1
      selector:
        matchLabels:
          app: mockb
          version: v1
          ASM_TRAFFIC_TAG: v1
      template:
        metadata:
          labels:
            app: mockb
            version: v1
            ASM_TRAFFIC_TAG: v1
        spec:
          containers:
          - name: default
            image: registry-cn-hangzhou.ack.aliyuncs.com/ack-demo/go-http-sample:tracing
            imagePullPolicy: IfNotPresent
            env:
            - name: version
              value: v1
            - name: app
              value: mockb
            - name: upstream_url
              value: "http://mockc:8000/"
            ports:
            - containerPort: 8000
    ---
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: mockc-v1
      namespace: default
      labels:
        app: mockc
        version: v1
    spec:
      replicas: 1
      selector:
        matchLabels:
          app: mockc
          version: v1
          ASM_TRAFFIC_TAG: v1
      template:
        metadata:
          labels:
            app: mockc
            version: v1
            ASM_TRAFFIC_TAG: v1
        spec:
          containers:
          - name: default
            image: registry-cn-hangzhou.ack.aliyuncs.com/ack-demo/go-http-sample:tracing
            imagePullPolicy: IfNotPresent
            env:
            - name: version
              value: v1
            - name: app
              value: mockc
            ports:
            - containerPort: 8000
    ---
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: mockc-v2
      namespace: default
      labels:
        app: mockc
        version: v2
    spec:
      replicas: 1
      selector:
        matchLabels:
          app: mockc
          version: v2
          ASM_TRAFFIC_TAG: v2
      template:
        metadata:
          labels:
            app: mockc
            version: v2
            ASM_TRAFFIC_TAG: v2
        spec:
          containers:
          - name: default
            image: registry-cn-hangzhou.ack.aliyuncs.com/ack-demo/go-http-sample:tracing
            imagePullPolicy: IfNotPresent
            env:
            - name: version
              value: v2
            - name: app
              value: mockc
            ports:
            - containerPort: 8000
  2. 使用資料面叢集的kubeconfig,執行以下命令,部署樣本應用。

    kubectl apply -f sample.yaml

步驟二:建立網關規則

使用以下內容建立ingressgateway且命名空間為istio-system的網關規則。具體操作,請參見管理網關規則

apiVersion: networking.istio.io/v1beta1
kind: Gateway
metadata:
  name: ingressgateway
  namespace: istio-system
spec:
  selector:
    istio: ingressgateway
  servers:
    - port:
        number: 80
        name: http
        protocol: HTTP
      hosts:
        - '*'

步驟三:建立泳道組和泳道

  1. 建立泳道組。

    1. 登入ASM控制台,在左側導覽列,選擇服務網格 > 網格管理

    2. 網格管理頁面,單擊目標執行個體名稱,然後在左側導覽列,選擇流量管理中心 > 流量泳道

    3. 流量泳道頁面,單擊建立泳道組,在建立泳道組面板,配置相關資訊,然後單擊確定

      配置項

      說明

      泳道組名稱

      本樣本配置為canary

      入口網關

      選擇ingressgateway

      泳道模式

      選擇寬鬆模式

      調用鏈路上下文透傳方式

      選擇透傳trace id

      trace id要求標頭

      本樣本配置為x-user-id。

      引流要求標頭

      用於網關根據要求標頭內容向不同泳道引流及泳道上下文保持,可任意指定。本樣本配置為x-asm-prefer-tag

      泳道服務

      選擇目標Kubernetes叢集和default命名空間,在下方列表中選中mockamockbmockc服務,單擊移動表徵圖,添加目標服務到已選擇地區。

  2. 建立s1和s2泳道,並分別綁定v1和v2版本。

    1. 流量泳道頁面的流量規則定義地區,單擊建立泳道

    2. 建立泳道對話方塊,配置相關資訊,然後單擊確定

      配置項

      說明

      泳道名稱

      分別配置為s1和s2

      佈建服務標籤

      標籤名稱:選擇ASM_TRAFFIC_TAG

      標籤值:兩條泳道分別選擇v1v2

      添加服務

      s1泳道:選擇mocka(default)mockb(default)mockc(default)

      s2泳道:選擇mockc(default)

      建立s1泳道的樣本圖如下:

      image

      兩條泳道建立完成後,樣本效果如下:

      image

      說明

      預設情況下,您在泳道組中建立的第一條泳道將被設定為基準泳道。您可以修改基準泳道,當流量發往其他泳道中不存在的服務時,通過回退機制將請求轉寄至基準泳道。具體操作,請參見在寬鬆模式中修改基準泳道

  3. 建立泳道對應的引流規則。

    1. 使用以下內容,為泳道建立網關引流規則,該引流規則可以分為三部分:

      1. 包含x-user-id: jason的請求流向s2泳道,並為請求加入x-asm-prefer-tag: s2要求標頭用於標識該請求流向s2泳道。

      2. 包含x-asm-prefer-tag: s2的請求流向s2泳道。

      3. 包含x-asm-prefer-tag: s1的請求流向s1泳道。

      展開查看YAML內容

      apiVersion: networking.istio.io/v1alpha3
      kind: VirtualService
      metadata:
        name: swimlane-ingress-vs
        namespace: istio-system
      spec:
        gateways:
        - istio-system/ingressgateway
        hosts:
        - '*'
        http:
        # 路由規則 1:包含 x-user-id: jason 的請求流向 s2 泳道
        # 並為請求加入 x-asm-prefer-tag: s2 要求標頭用於標識該請求流向 s2 泳道
        - match:
          - headers:
              x-user-id:
                exact: jason
            uri:
              exact: /
          name: r2
          route:
          - destination:
              host: mocka.default.svc.cluster.local
              subset: s2
            fallback:
              target:
                host: mocka.default.svc.cluster.local
                subset: s1
            headers:
              request:
                set:
                  x-asm-prefer-tag: s2
        # 路由規則 2:包含 x-asm-prefer-tag: s2 的請求流向 s2 泳道
        - match:
          - headers:
              x-asm-prefer-tag:
                exact: s2
            uri:
              exact: /
          name: r2
          route:
          - destination:
              host: mocka.default.svc.cluster.local
              subset: s2
            # 當 s2 泳道中不包含 mocka 應用時,將請求轉寄至 s1 泳道中的 mocka
            fallback:
              target:
                host: mocka.default.svc.cluster.local
                subset: s1
        # 路由規則 3:包含 x-asm-prefer-tag: s1 的請求流向 s1 泳道
        - match:
          - headers:
              x-asm-prefer-tag:
                exact: s1
            uri:
              exact: /
          name: r1
          route:
          - destination:
              host: mocka.default.svc.cluster.local
              subset: s1

步驟四:部署雜湊打標外掛程式

  1. 使用以下內容,建立wasm.yaml。

    apiVersion: extensions.istio.io/v1alpha1
    kind: WasmPlugin
    metadata:
      name: hash-tagging
      namespace: istio-system
    spec:
      imagePullPolicy: IfNotPresent 
      selector:
        matchLabels:
          istio: ingressgateway
      url: registry-cn-hangzhou.ack.aliyuncs.com/acs/asm-wasm-hash-tagging:v1.22.6.2-g72656ba-aliyun 
      phase: AUTHN
      pluginConfig:
        rules:
          - header: x-user-id
            modulo: 100
            tagHeader: x-asm-prefer-tag
            policies:
              # 20% 的使用者的請求流量會路由至泳道 s2
              - range: 20
                tagValue: s2
              # 80% 的使用者的請求流量會路由至泳道 s1
              - range: 100
                tagValue: s1
  2. 使用ASM執行個體的kubeconfig,執行以下命令,部署打標外掛程式。

    kubectl apply -f wasm.yaml

步驟五:驗證

  1. 執行以下命令,配置入口網關地址的臨時環境變數。

    export GATEWAY_ADDRESS=`kubectl get svc -n istio-system | grep istio-ingressgateway | awk '{print $4}'`
  2. 執行以下命令,以Jason身份訪問應用。

    curl ${GATEWAY_ADDRESS} -H 'x-user-id: jason'

    預期輸出:

    -> mocka(version: v1, ip: 10.0.0.15)-> mockb(version: v1, ip: 10.0.0.130)-> mockc(version: v2, ip: 10.0.0.133)%     

    可以看到,請求直接路由到mockc應用的v2版本。

  3. 執行以下命令,指定隨機使用者路由到新版本。

     for i in 'bob' 'stacy' 'jessie' 'vance' 'jack'; do curl ${GATEWAY_ADDRESS} -H "x-user-id: $i";echo "   user $i requested"; done

    預期輸出:

    -> mocka(version: v1, ip: 10.0.0.15)-> mockb(version: v1, ip: 10.0.0.130)-> mockc(version: v1, ip: 10.0.0.131)   user bob requested
    -> mocka(version: v1, ip: 10.0.0.15)-> mockb(version: v1, ip: 10.0.0.130)-> mockc(version: v1, ip: 10.0.0.131)   user stacy requested
    -> mocka(version: v1, ip: 10.0.0.15)-> mockb(version: v1, ip: 10.0.0.130)-> mockc(version: v2, ip: 10.0.0.133)   user jessie requested
    -> mocka(version: v1, ip: 10.0.0.15)-> mockb(version: v1, ip: 10.0.0.130)-> mockc(version: v1, ip: 10.0.0.131)   user vance requested
    -> mocka(version: v1, ip: 10.0.0.15)-> mockb(version: v1, ip: 10.0.0.130)-> mockc(version: v2, ip: 10.0.0.133)   user jack requested

    可以看到,使用者Jessie和Jack的請求直接路由到了mockc應用的v2版本,其他使用者路由到了v1版本。