使用 Flomesh 服务网格进行流量拆分

在这里插入图片描述

在微服务的架构中,随着业务迭代的加速和服务数量的增加,每一次服务的更新发布都存在潜在的故障风险,对系统的可靠性带来挑战。如何降低新版本发布对业务的影响,让更新更加可控成为微服务治理的重要工作之一。

通过灰度发布,通过对流量的细粒度控制,可以控制新版本发布影响的范围。比如可以控制新版本只作用于少部分流量,或者只在某些用户中试用,然后边扩大范围边测试,逐步地将新版本覆盖所有流量。

灰度发布的实现,底层实际上是对流量进行拆分。就像负载均衡一样,将流量均衡的拆分到上游实例中。灰度发布则是将这种拆分控制得更加精细,今天就来介绍如何使用服务网格来实现精细的流量拆分。

相比于在微服务 SDK 实现灰度发布,服务网格将该能力卸载到了 sidecar 中,解耦带来的显著优势这里不在过多赘述。

演示

说明

在这里插入图片描述

在今天的演示中,我们使用两种应用 curl 以及 Pipy 实现的 httpbin 分别作为客户端和服务端。服务有两个版本 v1 和 v2,通过部署 httpbin-v1httpbin-v2 来模拟版本发布中的新旧两个版本。

可能细心的看客有留意到在演示中经常使用 Pipy 来实现 httpbin 的功能,得益于使用 Pipy 实现的 web 服务可以很容易地定制响应内容,方便观察测试结果。

前置条件

  • Kubernetes 集群
  • kubectl CLI

安装服务网格

下载 osm-edge CLI。

system=$(uname -s | tr [:upper:] [:lower:])
arch=$(dpkg --print-architecture)
release=v1.3.4
curl -L https://github.com/flomesh-io/osm-edge/releases/download/${release}/osm-edge-${release}-${system}-${arch}.tar.gz | tar -vxzf -
./${system}-${arch}/osm version
cp ./${system}-${arch}/osm /usr/local/bin/

安装服务网格,并等待所有组件成功运行。

osm install --timeout 120s

部署示例应用

应用 curlhttpbin 运行在各自的命名空间下,且命名空间通过命令 osm namespace add xxx 交由服务网格纳管。

kubectl create ns httpbin
kubectl create ns curl
osm namespace add httpbin curl

部署 v1 版本的 httpbin,这个版本对所有 HTTP 请求返回 Hi, I am v1!。其他应用访问通过 Service httpbin 来访问 httpbin

kubectl apply -n httpbin -f - <<EOF
apiVersion: v1
kind: Service
metadata:
  name: httpbin
spec:
  ports:
    - name: pipy
      port: 8080
      targetPort: 8080
      protocol: TCP
  selector:
    app: pipy
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: httpbin-v1
  labels:
    app: pipy
    version: v1
spec:
  replicas: 1
  selector:
    matchLabels:
      app: pipy
      version: v1
  template:
    metadata:
      labels:
        app: pipy
        version: v1
    spec:
      containers:
        - name: pipy
          image: flomesh/pipy:latest
          ports:
            - name: pipy
              containerPort: 8080
          command:
            - pipy
            - -e
            - |
              pipy()
              .listen(8080)
              .serveHTTP(new Message('Hi, I am v1!\n'))
EOF

部署 curl 应用。

kubectl apply -n curl -f - <<EOF
apiVersion: v1
kind: Service
metadata:
  name: curl
  labels:
    app: curl
    service: curl
spec:
  ports:
    - name: http
      port: 80
  selector:
    app: curl
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: curl
spec:
  replicas: 1
  selector:
    matchLabels:
      app: curl
  template:
    metadata:
      labels:
        app: curl
    spec:
      containers:
      - image: curlimages/curl
        imagePullPolicy: IfNotPresent
        name: curl
        command: ["sleep", "365d"]
EOF

等待所有应用成功运行。

kubectl wait --for=condition=ready pod --all -A

测试应用访问。

curl_client="$(kubectl get pod -n curl -l app=curl -o jsonpath='{.items[0].metadata.name}')"
# 这里发送 4 个请求
kubectl exec "$curl_client" -n curl -c curl -- curl -s httpbin.httpbin:8080 httpbin.httpbin:8080 httpbin.httpbin:8080 httpbin.httpbin:8080

可以看到如下结果。

Hi, I am v1!
Hi, I am v1!
Hi, I am v1!
Hi, I am v1!

接下来部署 v2 版本的 httpbin

部署 v2 版本

v2 版本的 httpbin 对所有 HTTP 请求返回 Hi, I am v2!。在部署之前,我们需要设置默认的流量拆分策略,否则通过 Service httpbin 可以访问到新版本的实例。

创建 Service httpbin-v1,其标签选择器相比 Service httpbin 多了 version 标签。当前二者有相同的 endpoints。

kubectl apply -n httpbin -f - <<EOF
apiVersion: v1
kind: Service
metadata:
  name: httpbin-v1
spec:
  ports:
    - name: pipy
      port: 8080
      targetPort: 8080
      protocol: TCP
  selector:
    app: pipy
    version: v1
EOF

应用下面的 TrafficSplit 拆分策略,将所有流量都拆分到 httpbin-v1

kubectl apply -n httpbin -f - <<EOF
apiVersion: split.smi-spec.io/v1alpha4
kind: TrafficSplit
metadata:
  name: httpbin-split
spec:
  service: httpbin
  backends:
  - service: httpbin-v1
    weight: 100
EOF

然后部署新版本。

kubectl apply -n httpbin -f - <<EOF
apiVersion: v1
kind: Service
metadata:
  name: httpbin-v2
spec:
  ports:
    - name: pipy
      port: 8080
      targetPort: 8080
      protocol: TCP
  selector:
    app: pipy
    version: v2
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: httpbin-v2
  labels:
    app: pipy
    version: v2
spec:
  replicas: 1
  selector:
    matchLabels:
      app: pipy
      version: v2
  template:
    metadata:
      labels:
        app: pipy
        version: v2
    spec:
      containers:
        - name: pipy
          image: flomesh/pipy:latest
          ports:
            - name: pipy
              containerPort: 8080
          command:
            - pipy
            - -e
            - |
              pipy()
              .listen(8080)
              .serveHTTP(new Message('Hi, I am v2!\n'))
EOF

等待新版本成功运行。

kubectl wait --for=condition=ready pod -n httpbin -l version=v2

此时再次发送请求,可以看到处理请求的仍然是 v1 版本的 httpbin

kubectl exec "$curl_client" -n curl -c curl -- curl -s httpbin.httpbin:8080 httpbin.httpbin:8080 httpbin.httpbin:8080 httpbin.httpbin:8080
Hi, I am v1!
Hi, I am v1!
Hi, I am v1!
Hi, I am v1!

灰度发布

接下来,修改拆分的策略将 25% 的流量拆分到 v2 版本。

kubectl apply -n httpbin -f - <<EOF
apiVersion: split.smi-spec.io/v1alpha4
kind: TrafficSplit
metadata:
  name: httpbin-split
spec:
  service: httpbin
  backends:
  - service: httpbin-v1
    weight: 75
  - service: httpbin-v2
    weight: 25
EOF

再次发送请求,可以看到有 1/4 的流量是有 v2 版本处理的。

kubectl exec "$curl_client" -n curl -c curl -- curl -s httpbin.httpbin:8080 httpbin.httpbin:8080 httpbin.httpbin:8080 httpbin.httpbin:8080
Hi, I am v1!
Hi, I am v2!
Hi, I am v1!
Hi, I am v1!

灰度发布进阶

在这里插入图片描述

假如 v2 版本中,更新的是 /test 端点的功能。出于风险控制,我们希望只有部分流量访问 v2 版本的 /test 端点,其他端点如 /demo 只访问 v1 版本。

此时我们需要引入另一个资源来对访问 /test 的流量进行定义:定义路由。这里定义了两种路由:

  • httpbin-test:使用动词 GET 访问 /test 的流量。
  • httpbin-all:使用动词 GET 访问 / 的流量,注意这里是前缀匹配。
kubectl apply -n httpbin -f - <<EOF
apiVersion: specs.smi-spec.io/v1alpha4
kind: HTTPRouteGroup
metadata:
  name: httpbin-test
spec:
  matches:
  - name: test
    pathRegex: "/test"
    methods:
    - GET
---
apiVersion: specs.smi-spec.io/v1alpha4
kind: HTTPRouteGroup
metadata:
  name: httpbin-all
spec:
  matches:
  - name: test
    pathRegex: ".*"
    methods:
    - GET
EOF

然后更新流量拆分策略,将路由关联到拆分策略中。同时创建新的策略

kubectl apply -n httpbin -f - <<EOF
apiVersion: split.smi-spec.io/v1alpha4
kind: TrafficSplit
metadata:
  name: httpbin-split
spec:
  service: httpbin
  matches:
  - name: httpbin-test
    kind: HTTPRouteGroup
  backends:
  - service: httpbin-v1
    weight: 75
  - service: httpbin-v2
    weight: 25
---
apiVersion: split.smi-spec.io/v1alpha4
kind: TrafficSplit
metadata:
  name: httpbin-all
spec:
  service: httpbin
  matches:
  - name: httpbin-all
    kind: HTTPRouteGroup
  backends:
  - service: httpbin-v1
    weight: 100
EOF

此时尝试访问 /test 端点,只有 25% 的流量由新版本处理。

kubectl exec "$curl_client" -n curl -c curl -- curl -s httpbin.httpbin:8080/test httpbin.httpbin:8080/test httpbin.httpbin:8080/test httpbin.httpbin:8080/test
Hi, I am v1!
Hi, I am v2!
Hi, I am v1!
Hi, I am v1!

再请求下 /demo 端点,可以看到全部流量都去到了旧的 v1 版本。

kubectl exec "$curl_client" -n curl -c curl -- curl -s httpbin.httpbin:8080/demo httpbin.httpbin:8080/demo httpbin.httpbin:8080/demo httpbin.httpbin:8080/demo
Hi, I am v1!
Hi, I am v1!
Hi, I am v1!
Hi, I am v1!

符合预期。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

PipyFlomesh

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值