ASM支持通过TrafficLabel CRD设置流量标签,然后根据流量标签将流量路由到不同的工作负载。本文介绍流量标签和标签路由的功能。

背景信息

流量打标又称作流量染色,指对符合一定流量特征的请求打上具体的染色标记。Istio通过透明拦截的方式劫持了应用流量,基于此技术背景,Sidecar可以对应用流量进行染色标记。

ASM商业版(专业版)扩展了一个新的TrafficLabel CRD ,通过该CRD来定义具体的流量染色逻辑,实现命名空间、工作负载及接口级别的流量打标。

注意事项

仅ASM商业版(专业版)v1.10.5.40及以上版本支持流量打标和标签路由功能。

如何对工作负载进行流量打标

方式一:按照命名空间进行流量打标

对命名空间下的所有应用进行流量打标。

  1. 通过kubectl连接ASM实例
  2. 使用以下内容,创建example1.yaml。
    apiVersion: istio.alibabacloud.com/v1beta1
    kind: TrafficLabel
    metadata:
      name: example1
      namespace: default
    spec:
      rules:
      - labels:
          - name: userdefinelabel1
            valueFrom:
            - $getContext(x-request-id)
            - $localLabel
        attachTo:
        - opentracing
        # 表示生效的协议,空为都不生效,*为都生效。
        protocols: "*"
      hosts: # 表示生效的服务。
      - "*"
    参数 描述
    namespace 该CRD生效的命名空间。
    labels参数下name 标签名称。
    labels参数下valueFrom 标签值,取值:
    说明 valueFrom的参数值采用自然顺序的优先级,例如以上配置表示优先从getContext(x-request-id)获取标签值,当通过getContext变量获取不到才会从localLabel变量获取标签值。
    • getContext(x-request-id):从流量的上下文获取标签值。
    • localLabel:从工作负载的业务Pod标签ASM_TRAFFIC_TAG获取标签值。
    attachTo 取值为opentracing,对应HTTP或GRPC协议,意味着会将该流量标识添加到header下。
    getContext(xxx)和localLabel两个变量详细说明如下:
    • getContext(x-request-id)
      getContext(x-request-id)是个函数型变量,标明流量颜色需要从流量的上下文中获取,其中x-request-id为该函数参数,指代Trace ID。不同的Trace系统采用的Trace ID不同。
      说明 getContext仅针对Sidecar生效。
      Sidecar包含入口和出口两种类型的流量,流量打标其实指的是对出口流量进行打标。流量打标
      ASM商业版(专业版)的Sidecar默认试图通过x-asm-prefer-tag header从入口流量中获取流量tag,并以Trace ID为key记录到上下文map<traceId, tag>中。当业务容器发起的出口请求时,Sidecar会通过Trace ID查找上下文map。若找到关联tag,则Sidecar会附带x-asm-prefer-tag header(默认)以及TrafficLabel CRD定义的标签名userdefinelabel1。
      说明 业务应用采用不同的Trace系统则会有不同Trace ID。更多信息,请参见Tracing

      若不定义getContext函数下的参数,Sidecar默认采用x-request-id为Trace ID。Trace ID需要业务应用进行Header propagation或Context propagation。若Header Propagation逻辑缺失,则出口流量会因为找不到关联的Trace ID key,Sidecar将无法从map<traceId,tag> 找到对应的流量tag。

      若业务应用有对接Trace系统,则Trace SDK会帮助业务代码进行Header propagation或Context propagation,例如采用接入ARMS进行trace。若业务有对接ARMS Prometheus,则只需要在TrafficLabel CRD中修改valueFromgetContext(x-b3-traceid),其中参数x-b3-traceid为Zipkin系统的Trace header。

    • localLabel
      localLabel是从Sidecar对应的业务POD标签ASM_TRAFFIC_TAG获取流量标识,并对出口流量打标。以下工作负载定义了ASM_TRAFFIC_TAGtest
      apiVersion: apps/v1
      kind: Deployment
      metadata:
        name: productpage-v1
        labels:
          app: productpage
          version: v1
      spec:
        replicas: 1
        selector:
          matchLabels:
            app: productpage
            version: v1
        template:
          metadata:
            annotations:
              sidecar.istio.io/logLevel: debug
            labels:
              app: productpage
              version: v1
              ASM_TRAFFIC_TAG: test
          spec:
            serviceAccountName: bookinfo-productpage
            containers:
            - name: productpage
              image: docker.io/istio/examples-bookinfo-productpage-v1:1.16.2
              imagePullPolicy: IfNotPresent
              ports:
              - containerPort: 9080
              volumeMounts:
              - name: tmp
                mountPath: /tmp
            volumes:
            - name: tmp
              emptyDir: {}
  3. 执行以下命令,使CRD生效。
    kubectl apply -f example1.yaml

方式二:按照工作负载进行流量打标

对某个命名空间下某个应用进行流量打标。

  1. 通过kubectl连接ASM实例
  2. 使用以下内容,创建example2.yaml。
    apiVersion: istio.alibabacloud.com/v1beta1
    kind: TrafficLabel
    metadata:
      name: example2
      namespace: workshop
    spec:
      workloadSelector:
        labels:
          app: test
      rules:
      - labels:
          - name: userdefinelabel1
            valueFrom:
            - $localLabel
            - $getContext(x-request-id)
        attachTo:
        - opentracing
        protocols: "*"
      hosts:
      - "*"
    参数 描述
    namespace 该CRD生效的命名空间。
    labels参数下name 标签名称。
    labels参数下valueFrom 标签值,取值:
    说明 valueFrom具有优先级,以上配置表示优先从getContext(x-request-id)获取标签值,当通过getContext变量获取不到才会从localLabel变量获取标签值。
    • getContext(x-request-id):从流量的上下文获取标签值。
    • localLabel:从工作负载的业务Pod标签ASM_TRAFFIC_TAG获取标签值。
    workloadSelector参数下的app 匹配工作负载的标签,例如本文的CRD只作用于带有test标签的工作负载。
    attachTo 取值为opentracing,对应HTTP或GRPC协议,意味着会将该流量标识添加到header下。
  3. 执行以下命令,使CRD生效。
    kubectl apply -f example2.yaml

方式三:按照接口进行流量打标

对某个命名空间下某个应用接口进行流量打标。

  1. 通过kubectl连接ASM实例
  2. 使用以下内容,创建example3.yaml。
    apiVersion: istio.alibabacloud.com/v1beta1
    kind: TrafficLabel
    metadata:
      name: example3
      namespace: workshop
    spec:
      workloadSelector:
        labels:
          app: test
      rules:
      - match:
        - headers:
              end-user: "jason"
          uri:
            prefix: "/test"
          labels:
          - name: userdefinelabel1
            valueFrom:
            - $getContext(x-b3-traceid)
        attachTo:
        - opentracing
        protocols: "*"
      hosts:
        - "*"
    参数 描述
    namespace 该CRD生效的命名空间。
    workloadSelector参数下的app 匹配工作负载的标签,例如本文的CRD只作用于带有app: test 标签的工作负载。
    match参数下headers 请求头,本文设置请求头为jason用户
    match参数下prefix 请求URL,描述特定接口请求,本文设置为带有/test的请求URL。
    labels参数下name 标签名称。
    labels参数下valueFrom 标签值,取值:
    说明 valueFrom具有优先级,以上配置表示优先从getContext(x-request-id)获取标签值,当通过getContext变量获取不到才会从localLabel变量获取标签值。
    • getContext(x-request-id):从流量的上下文获取标签值。
    • localLabel:从工作负载的业务Pod标签ASM_TRAFFIC_TAG获取标签值。
    attachTo 取值为opentracing,对应HTTP或GRPC协议,意味着会将该流量标识添加到header下。
  3. 执行以下命令,使CRD生效。
    kubectl apply -f example3.yaml

基于流量标签进行标签路由

通过TrafficLabel定义了流量标签userdefinelabel1,其取值为test1、test2、test3等,您还需要创建DestinationRule和VirtualService,将流量根据标签路由到对应工作负载。

  1. 使用以下内容,创建example4.yaml
    使用以下内容将productpage分为test1 、test2 、test3等组。
    apiVersion: networking.istio.io/v1alpha3
    kind: DestinationRule
    metadata:
      name: productpage
    spec:
      host: productpage
      subsets:
      - name: test1
        labels:
          version: test1
      - name: test2
        labels:
          version: test2
      - name: test3
        labels:
          version: test3
      ...
      - name: testn
        labels:
          version: testn
      - name: base
        labels:
          version: base
  2. 执行以下命令,创建DestinationRule。
    kubectl apply -f example4.yaml
  3. 使用以下内容,创建example5.yaml
    apiVersion: networking.istio.io/v1alpha3
    kind: VirtualService
    metadata:
      name: example-app
      namespace: default
    spec:
      hosts:
        - example
      http:
      - match:
        - headers:
            userdefinelabel1:
             exact: test1
        route:
        - destination:
            host: example
            subset: test1
      - match:
        - headers:
            userdefinelabel1:
             exact: test2
        route:
        - destination:
            host: example
            subset: test2
      - match:
        - headers:
            userdefinelabel1:
             exact: test3
        route:
        - destination:
            host: example
            subset: test3
      - route:
        - destination:
            host: example
            subset: base

    headers和subset决定了将流量根据标签路由到对应工作负载,例如本文将带有值为test1,名称为userdefinelabel1的标签的流量路由到test1组别的工作负载。参数解释如下:

    参数 描述
    headers参数下userdefinelabel1 流量标签名称。
    headers参数下exact 流量标签值。
    subset 路由到的目标工作负载的组别。
  4. 执行以下命令,创建VirtualService。
    kubectl apply -f example5.yaml

其他操作:简化VirtualService变量配置方式

若工作负载的版本有很多个的时候,VirtualService配置会比较臃肿,您可以使用以下内容简化VirtualService变量配置方式,并且对流量降级。
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: example-app
  namespace: default
spec:
  hosts:
    - example
  http:
  - route:
    - destination:
        host: example
        subset: $userdefinelabel1
      fallback:
        case: noinstances|noavailabled
        target:
          host: example
          subset: v1
                
其中fallback配置spec说明如下:
参数 描述
case 以竖线(|)分隔的字符串,取值:
  • noinstances:缺失实例
  • noavailabled:后端实例不可用
  • noisolationunit:后端分组不存在
target 路由的目标服务。本文定义了当缺少实例或者实例不可用时,将流量理由到v1组别的工作负载。