专栏名称: 阿里云云原生
发布云原生技术最新资讯、汇集云原生技术最全内容,定期举办云原生活动、直播,阿里产品及用户最佳实践发布。与你并肩探索云原生技术点滴,分享你需要的云原生内容。
目录
相关文章推荐
财联社AI daily  ·  AI会玩宝可梦了!Claude打赢道馆馆主 ·  8 小时前  
财联社AI daily  ·  AI会玩宝可梦了!Claude打赢道馆馆主 ·  8 小时前  
51好读  ›  专栏  ›  阿里云云原生

基于阿里云服务网格流量泳道的全链路流量管理(三):无侵入式的宽松模式泳道

阿里云云原生  · 公众号  ·  · 2024-05-28 18:30

正文

在前文 《基于阿里云服务网格流量泳道的全链路流量管理(一):严格模式流量泳道》 《基于阿里云服务网格流量泳道的全链路流量管理(二):宽松模式流量泳道》 中,我们介绍了流量泳道的概念、使用流量泳道进行全链路灰度管理的方案,以及阿里云服务网格 ASM 提供的严格模式与宽松模式的流量泳道。在本文中,我们将介绍一种基于 OpenTelemetry 自动插装方案实现的宽松模式流量泳道场景,无需任何业务代码改造即可为运行在 Kubernetes 集群中的云原生应用实现灵活的全链路灰度管理能力。
01

概述

Cloud Native

流量泳道是将一个云原生应用中的多个服务根据服务版本(或其他特征)隔离成的多个独立的运行环境。

在严格模式下,每条流量泳道中包含应用的调用链路上的全部服务,对于应用程序则没有任何要求。

而在宽松模式下,您只需要确保创建一条包含调用链路中所有服务的泳道:基线泳道。其它泳道可以不包含调用链路上的全部服务。当一个泳道中的服务进行相互调用时,若目标服务在当前泳道中不存在,则请求将被转发到基线泳道中的相同服务,并在请求目标存在当前泳道中存在时将请求重新转发回当前泳道。宽松模式的流量泳道虽然可以实现灵活的全链路灰度,但要求应用程序必须包含一个能够在整条调用链路中透传的请求头(链路透传请求头)。

阿里云服务网格 ASM 已经提供一种基于 baggage 透传的全新宽松模式流量泳道方案,能够在不改造业务代码的情况下,实现泳道服务的灵活灰度。

02

背景介绍

Cloud Native

OpenTelemetry 是云原生计算基金会(Cloud Native Computing Foundation, CNCF)的一个项目,与其他 CNCF 项目如 Kubernetes、Prometheus 和 Envoy 等紧密相连,共同构建了云原生技术生态系统的基础。由于其提供的丰富功能和广泛适用性,OpenTelemetry 在业内已经确立了其领导地位,越来越多的企业和开发者采用它作为构建和维护可观测性平台的核心组件。

baggage 是由 OpenTelemetry 制定并推动的、在分布式系统调用链路中传递链路上下文信息的标准。它具体表现为一个名为 baggage 的请求头,其内部包含了以键值对形式存储的链路上下文信息,例如:

baggage: userId=alice,serverNode=DF%2028,isProduction=false

您可以使用 OpenTelemetry 提供的 SDK,在服务调用链路中传递 baggage 请求头、进而在整条服务链路上传递自定义的上下文信息。当服务部署在 Kubernentes 集群中时,则可以通过 OpenTelemetry Operator 的自动插装来为服务提供 baggage 透传能力、而无需修改业务代码。有关 baggage 的详细信息,可以参考 baggage [ 1]

基于 baggage 的透传,阿里云服务网格 ASM 提供了一种无需修改代码即可实现的宽松模式流量泳道,并针对流量泳道的引流策略进行了增强,支持基于流量权重策略对不同的泳道进行引流。本文将首先使用 OpenTelemetry 自动插装来为服务引用透传 baggage 请求头的能力,接下来创建宽松模式下的三条泳道,并基于流量权重策略对不同的泳道进行引流。

03

演示:实现服务 baggage

透传与宽松模式流量泳道

Cloud Native


前提条件

  • 已创建 ASM 企业版或旗舰版实例,且版本为 1.21.6.54 及以上。具体操作,请参见创建 ASM 实例 [ 2]

  • 已添加集群到 ASM 实例。具体操作,请参见添加集群到 ASM 实例 [ 3]

  • 已创建名称为 ingressgateway 的 ASM 网关。具体操作,请参见创建入口网关服务 [ 4]

  • 已创建名称为 ingressgateway 且命名空间为 istio-system 的网关规则。具体操作,请参见管理网关规则 [ 5]

apiVersion: networking.istio.io/v1beta1kind: Gatewaymetadata: name: ingressgateway  namespace: istio-systemspec:  selector:




    
    istio: ingressgateway  servers:    - port:        number: 80        name: http        protocol: HTTP      hosts:        - '*'


步骤一:配置服务透传 baggage 上下文

本节主要展示如何通过 OpenTelemetry Operator 自动插装的方法,为 Kubernetes 集群中的服务添加 baggage 透传能力。

1. 部署 OpenTelemetry Operator。

a. 通过 kubectl 连接到 ASM 实例添加的 Kubernetes 集群。执行以下命令,创建 opentelemetry-operator-system 命名空间。

kubectl create namespace opentelemetry-operator-system

b. 执行以下命令,使用 Helm 在 opentelemetry-operator-system 命名空间下安装 OpenTelemetry Operator。(如果尚未安装 Helm,可以参考安装 Helm 来安装 Helm 命令行工具。)

helm repo add open-telemetry https://open-telemetry.github.io/opentelemetry-helm-chartshelm install \    --namespace=opentelemetry-operator-system \    --version=0.46.0 \    --set admissionWebhooks.certManager.enabled=false \    --set admissionWebhooks.certManager.autoGenerateCert=true \    --set manager.image.repository="registry-cn-hangzhou.ack.aliyuncs.com/acs/opentelemetry-operator" \    --set manager.image.tag="0.92.1" \    --set kubeRBACProxy.image.repository="registry-cn-hangzhou.ack.aliyuncs.com/acs/kube-rbac-proxy" \    --set kubeRBACProxy.image.tag="v0.13.1" \    --set manager.collectorImage.repository="registry-cn-hangzhou.ack.aliyuncs.com/acs/opentelemetry-collector" \    --set manager.collectorImage.tag="0.97.0" \    --set manager.opampBridgeImage.repository="registry-cn-hangzhou.ack.aliyuncs.com/acs/operator-opamp-bridge" \    --set manager.opampBridgeImage.tag="0.97.0" \    --set manager.targetAllocatorImage.repository="registry-cn-hangzhou.ack.aliyuncs.com/acs/target-allocator" \    --set manager.targetAllocatorImage.tag="0.97.0" \    --set manager.autoInstrumentationImage.java.repository="registry-cn-hangzhou.ack.aliyuncs.com/acs/autoinstrumentation-java" \    --set manager.autoInstrumentationImage.java.tag="1.32.1" \    --set manager.autoInstrumentationImage.nodejs.repository="registry-cn-hangzhou.ack.aliyuncs.com/acs/autoinstrumentation-nodejs" \    --set manager.autoInstrumentationImage.nodejs.tag="0.49.1" \    --set manager.autoInstrumentationImage.python.repository="registry-cn-hangzhou.ack.aliyuncs.com/acs/autoinstrumentation-python" \    --set manager.autoInstrumentationImage.python.tag="0.44b0" \    --set manager.autoInstrumentationImage.dotnet.repository="registry-cn-hangzhou.ack.aliyuncs.com/acs/autoinstrumentation-dotnet" \    --set manager.autoInstrumentationImage.dotnet.tag="1.2.0" \    --set manager.autoInstrumentationImage.go.repository="registry-cn-hangzhou.ack.aliyuncs.com/acs/opentelemetry-go-instrumentation" \    --set manager.autoInstrumentationImage.go.tag="v0.10.1.alpha-2-aliyun" \    opentelemetry-operator open-telemetry/opentelemetry-operator

c. 执行以下命令,检查 opentelemetry-operator 是否正常运行。

kubectl get pod -n opentelemetry-operator-system

预期输出:

NAME READY   STATUS    RESTARTS   AGEopentelemetry-operator-854fb558b5-pvllj   2/2     Running   0          1m

2. 配置自动插装(auto-instrumentation)。

a. 使用以下内容,创建 instrumentation.yaml 文件。

apiVersion: opentelemetry.io/v1alpha1kind: Instrumentationmetadata: name: demo-instrumentationspec:  propagators:    - baggage  sampler:    type: parentbased_traceidratio    argument: "1"

b. 执行以下命令,在 default 命名空间下声明自动插装。

kubectl apply -f instrumentation.yaml

🔔 说明: 对于 OpenTelemetry 框架来说,其最佳实践还包括部署 OpenTelemetry Collector 以收集可观测数据。由于本文主要演示 OpenTelemetry 自动插装实现的 baggage 链路透传,因此没有包含部署 OpenTelemetry Collector 的步骤。


步骤二:部署示例服务

1. 为 default 命名空间启用 Siedcar 网格代理自动注入。具体操作,请参见开启  Sidecar 自动注入 [ 6]

关于自动注入的更多信息,请参见配置 Sidecar 注入策略。

2. 使用以下内容,创建 mock.yaml 文件。

apiVersion: v1




    
kind: Servicemetadata: name: mocka  labels:    app: mocka    service: mockaspec:  ports:  - port: 8000    name: http  selector:    app: mocka---apiVersion: apps/v1kind: Deploymentmetadata:  name: mocka-v1  labels:    app: mocka    version: v1spec:  replicas: 1  selector:    matchLabels:      app: mocka      version: v1      ASM_TRAFFIC_TAG: v1  template:    metadata:      labels:        app: mocka        version: v1        ASM_TRAFFIC_TAG: v1      annotations:        instrumentation.opentelemetry.io/inject-java: "true"        instrumentation.opentelemetry.io/container-names: "default"    spec:      containers:      - name: default        image: registry-cn-hangzhou.ack.aliyuncs.com/acs/asm-mock:v0.1-java        imagePullPolicy: IfNotPresent        env:        - name: version          value: v1        - name: app          value: mocka        - name: upstream_url          value: "http://mockb:8000/"        ports:        - containerPort: 8000---apiVersion: v1kind: Servicemetadata:  name: mockb  labels:    app: mockb    service: mockbspec:  ports:  - port: 8000    name: http  selector:    app: mockb---apiVersion: apps/v1kind: Deploymentmetadata:  name: mockb-v1  labels:    app: mockb    version: v1spec:  replicas: 1  selector:    matchLabels:      app: mockb      version: v1      ASM_TRAFFIC_TAG: v1  template:    metadata:      labels:        app: mockb        version: v1        ASM_TRAFFIC_TAG: v1      annotations:        instrumentation.opentelemetry.io/inject-java: "true"        instrumentation.opentelemetry.io/container-names: "default"    spec:      containers:      - name: default        image: registry-cn-hangzhou.ack.aliyuncs.com/acs/asm-mock:v0.1-java        imagePullPolicy: IfNotPresent        env:        - name: version          value: v1        - name: app          value: mockb        - name: upstream_url          value: "http://mockc:8000/"        ports:        - containerPort: 8000
---apiVersion: v1kind: Servicemetadata: name: mockc labels: app: mockc service: mockcspec: ports: - port: 8000 name: http selector: app: mockc---apiVersion: apps/v1kind: Deploymentmetadata: name: mockc-v1 labels: app: mockc version: v1spec: replicas: 1 selector: matchLabels: app: mockc version: v1 ASM_TRAFFIC_TAG: v1 template: metadata: labels: app: mockc version: v1 ASM_TRAFFIC_TAG: v1 annotations: instrumentation.opentelemetry.io/inject-java: "true" instrumentation.opentelemetry.io/container-names: "default" spec: containers: - name: default image: registry-cn-hangzhou.ack.aliyuncs.com/acs/asm-mock:v0.1-java imagePullPolicy: IfNotPresent env: - name: version value: v1 - name: app value: mockc ports: - containerPort: 8000---apiVersion: apps/v1kind: Deploymentmetadata: name: mocka-v2 labels: app: mocka version: v2spec: replicas: 1 selector: matchLabels: app: mocka version: v2 ASM_TRAFFIC_TAG: v2 template: metadata: labels: app: mocka version: v2 ASM_TRAFFIC_TAG: v2 annotations: instrumentation.opentelemetry.io/inject-java: "true" instrumentation.opentelemetry.io/container-names: "default" spec: containers: - name: default image: registry-cn-hangzhou.ack.aliyuncs.com/acs/asm-mock:v0.1-java imagePullPolicy: IfNotPresent env: - name: version value: v2 - name: app value: mocka - name: upstream_url value: "http://mockb:8000/" ports: - containerPort: 8000---apiVersion: apps/v1kind: Deploymentmetadata: name: mockb-v2 labels: app: mockb version: v2spec: replicas: 1 selector: matchLabels: app: mockb version: v2 ASM_TRAFFIC_TAG: v2 template: metadata: labels: app: mockb version: v2 ASM_TRAFFIC_TAG: v2 annotations: instrumentation.opentelemetry.io/inject-java: "true" instrumentation.opentelemetry.io/container-names: "default" spec: containers: - name: default image: registry-cn-hangzhou.ack.aliyuncs.com/acs/asm-mock:v0.1-java imagePullPolicy: IfNotPresent env: - name: version value: v2 - name: app value: mockb - name: upstream_url value: "http://mockc:8000/" ports: - containerPort: 8000
---apiVersion: apps/v1kind: Deploymentmetadata: name: mockc-v2 labels: app: mockc version: v2spec: replicas: 1 selector: matchLabels: app: mockc version: v2 ASM_TRAFFIC_TAG: v2 template: metadata: labels: app: mockc version: v2 ASM_TRAFFIC_TAG: v2 annotations: instrumentation.opentelemetry.io/inject-java: "true" instrumentation.opentelemetry.io/container-names: "default" spec: containers: - name: default image: registry-cn-hangzhou.ack.aliyuncs.com/acs/asm-mock:v0.1-java imagePullPolicy: IfNotPresent env: - name: version value: v2 - name: app value: mockc ports: - containerPort: 8000---apiVersion: apps/v1kind: Deploymentmetadata: name: mocka-v3 labels: app: mocka version: v3spec: replicas: 1 selector: matchLabels: app: mocka version: v3 ASM_TRAFFIC_TAG: v3 template: metadata: labels: app: mocka version: v3 ASM_TRAFFIC_TAG: v3 annotations: instrumentation.opentelemetry.io/inject-java: "true" instrumentation.opentelemetry.io/container-names: "default" spec: containers: - name: default image: registry-cn-hangzhou.ack.aliyuncs.com/acs/asm-mock:v0.1-java imagePullPolicy: IfNotPresent env: - name: version value: v3 - name: app value: mocka - name: upstream_url value: "http://mockb:8000/" ports: - containerPort: 8000---apiVersion: apps/v1kind: Deploymentmetadata: name: mockb-v3 labels: app: mockb version: v3spec: replicas: 1 selector: matchLabels: app: mockb version: v3 ASM_TRAFFIC_TAG: v3 template: metadata: labels: app: mockb version: v3 ASM_TRAFFIC_TAG: v3 annotations: instrumentation.opentelemetry.io/inject-java: "true" instrumentation.opentelemetry.io/container-names: "default" spec: containers: - name: default image: registry-cn-hangzhou.ack.aliyuncs.com/acs/asm-mock:v0.1-java imagePullPolicy: IfNotPresent env: - name: version value: v3 - name: app value: mockb - name: upstream_url value: "http://mockc:8000/" ports: - containerPort: 8000
---apiVersion: apps/v1kind: Deploymentmetadata: name: mockc-v3 labels: app: mockc version: v3spec: replicas: 1 selector: matchLabels: app: mockc version: v3 ASM_TRAFFIC_TAG: v3 template: metadata: labels: app: mockc version: v3 ASM_TRAFFIC_TAG: v3 annotations: instrumentation.opentelemetry.io/inject-java: "true" instrumentation.opentelemetry.io/container-names: "default" spec: containers: - name: default image: registry-cn-hangzhou.ack.aliyuncs.com/acs/asm-mock:v0.1-java imagePullPolicy: IfNotPresent env: - name: version value: v3 - name: app value: mockc ports: - containerPort: 8000

对于每个实例服务 Pod,都加入了 instrumentation.opentelemetry.io/inject-java: "true"和instrumentation.opentelemetry.io/container-names: "default"两个注解,以声明该实例服务使用 java 语言实现,并要求 OpenTelemetry Operator 对名称为 default 的容器进行自动插装。

3. 执行以下指令,部署实例服务。

kubectl apply -f mock.yaml

基于 OpenTelemetry 自动插装机制,部署的服务 Pod 将自动具有在调用链路中传递 baggage 的能力。


步骤三:创建泳道组和对应泳道

1. 创建泳道组。

a. 登录 ASM 控制台 [ 7] ,在左侧导航栏,选择 服务网格 > 网格管理

b. 在 网格管理 页面,单击目标实例名称,然后在左侧导航栏,选择 流量管理中心 > 流量泳道

c. 在 流量泳道 页面,单击 创建泳道组 ,在 创建泳道组 面板,配置相关信息,然后单击 确定

配置项

说明

泳道组名称

本示例配置为test。

入口网关

选择ingressgateway。

泳道模式

选择宽松模式。

调用链路上下文透传方式

选择透传baggage,并在下方引流请求头中填写x-asm-prefer-tag

泳道服务

选择目标Kubernetes集群和default命名空间,在下方列表中选中mocka、mockb和mockc服务,单击
图标,添加目标服务到已选择区域。

2. 创建 s1、s2、s3 泳道,并分别绑定 v1、v2、v3 版本。

a. 在 流量泳道 页面的 流量规则定义 区域,单击 创建泳道

b. 在 创建泳道 对话框,配置相关信息,然后单击 确定

配置项

说明

泳道名称

三条泳道分别配置为s1、s2、s3。

配置服务标签

标签名称:配置为ASM_TRAFFIC_TAG标签值:三条泳道分别配置为v1、v2和v3。

添加服务

s1泳道:选择mocka(default)、mockb(default)、mockc(default)。s2泳道:选择mocka(default)、mockc(default)。s3泳道:选择mockb(default)。

创建 s1 泳道的示例图如下:

三个泳道创建完成后,示例效果如下。默认情况下,您在泳道组中创建的第一个泳道将被设定为基线泳道。您也可以修改基线泳道,当流量发往其它泳道中不存在的服务时,通过回退机制将请求转发至基线泳道。关于修改基线泳道的具体操作,请参见修改基线泳道 [ 8]

三个泳道创建完成后,针对泳道组中的每个服务都将生成泳道规则对应的目标规则 DestinationRule 和虚拟服务 VirtualService。您可以在控制台左侧导航栏,选择 流量管理中心 > 目标规则 虚拟服务 进行查看。例如,针对 mocka 服务会自动创建如下 DestinationRule 和 VirtualService。
apiVersion: networking.istio.io/v1beta1kind: DestinationRulemetadata: labels:    asm-system: 'true'    provider: asm    swimlane-group: test  name: trafficlabel-dr-test-default-mocka  namespace: istio-systemspec:  host: mocka.default.svc.cluster.local  subsets:    - labels:        ASM_TRAFFIC_TAG: v1      name: s1    - labels:        ASM_TRAFFIC_TAG: v2      name: s2

apiVersion: networking.istio.io/v1beta1kind: VirtualServicemetadata: labels: asm-system: 'true' provider: asm swimlane-group: test name: trafficlabel-vs-test-default-mocka namespace: istio-systemspec: hosts: - mocka.default.svc.cluster.local http: - match: - headers: x-asm-prefer-tag: exact: s1 route: - destination: host: mocka.default.svc.cluster.local subset: s1 fallback: target: host: mocka.default.svc.cluster.local subset: s1 - match: - headers: x-asm-prefer-tag: exact: s2 route: - destination: host: mocka.default.svc.cluster.local subset: s2 fallback: target: host: mocka.default.svc.cluster.local subset: s1 - match: - headers: x-asm-prefer-tag:






请到「今天看啥」查看全文