热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

在Linkerd中实现流量拆分功能

流量分割功能是通过Linkerd的TrafficSplitCRD来控制的(遵循SMI中定义的规范),创建TrafficSplitCRD允许我们控制Linkerd如何将流量代理给Tr

在 Linkerd 中,金丝雀发布是通过流量拆分来管理的,这项功能允许你根据可动态配置的权重,将请求分配给不同的 Kubernetes 服务对象。虽然流量分割可以适用于任意的 Service 对象,但一般情况下是将一个 Service 的传入流量分给不同版本的 Service。

流量分割功能是通过 Linkerd 的 TrafficSplit CRD
来控制的(TrafficSplit CRD
遵循服务网接口(SMI)中定义的规范,这是 Linkerd 实现的几个 SMI API 中的一个)。创建 TrafficSplit CRD
允许我们控制 Linkerd 如何将流量代理给 TrafficSplit
引用的服务。

TrafficSplit CRD
是根据 Kubernetes Service 对象编写的,TrafficSplit
描述了一个中心根或 apex
服务,流量被发送到该服务,以及一个或多个实际接收它的后端服务,与 TrafficSplit
中还指定的权重成比例。

另外需要注意,Kubernetes 的 Service 对象不一定有后台工作负载。虽然这对于普通服务来说很少见,但是我们会在 TrafficSplits
apex
服务中大量使用该功能,因为 TrafficSplit
会导致发往 apex
的流量实际发送到后端服务,所以 apex
实际上不需要拥有自己的 Deployment。

更新服务

接下来我们还是以 Emojivoto
应用为例来创建两个新的 Service 对象,apex
服务将没有关联的 Deployment 资源,第二项服务将是 Emojivoto
的 web 服务的一个更新版本,会在页面顶部添加一些文本信息。

创建这两个服务后,我们将创建一个 TrafficSplit
资源,该资源会将发送到 apex
服务的流量在 web 服务的原始版本和更新版本之间进行拆分。

更新版本的 web 服务资源对象如下所示:

# web-svc-2.yaml
apiVersion: v1
kind: ServiceAccount
metadata:
  name: web-2
  namespace: emojivoto
---
apiVersion: v1
kind: Service
metadata:
  name: web-svc-2
  namespace: emojivoto
spec:
  ports:
    - name: http
      port: 80
      targetPort: 8080
  selector:
    app: web-svc-2
  type: ClusterIP
---
apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    app.kubernetes.io/name: web-svc-2
    app.kubernetes.io/part-of: emojivoto
    app.kubernetes.io/version: linux-training-v2
  name: web-svc-2
  namespace: emojivoto
spec:
  selector:
    matchLabels:
      app: web-svc-2
      version: linux-training-v2
  template:
    metadata:
      annotations:
        linkerd.io/inject: enabled # 设置自动注入的注解
      labels:
        app: web-svc-2
        version: linux-training-v2
    spec:
      containers:
        - env:
            - name: WEB_PORT
              value: "8080"
            - name: EMOJISVC_HOST
              value: emoji-svc.emojivoto:8080
            - name: VOTINGSVC_HOST
              value: voting-svc.emojivoto:8080
            - name: INDEX_BUNDLE
              value: dist/index_bundle.js
            - name: MESSAGE_OF_THE_DAY
              value: "Welcome to version 2! Now with more words!"
          image: buoyantio/emojivoto-web:lf-training
          name: web-svc-2
          ports:
            - containerPort: 8080
              name: http
          resources:
            requests:
              cpu: 100m
      serviceAccountName: web-2

直接应用上面的资源对象:

$ kubectl apply -f web-svc-2.yaml
serviceaccount/web-2 created
service/web-svc-2 created
deployment.apps/web-svc-2 created

部署后先验证更新版本的服务是否已经正确部署了。

$ kubectl get po --selector app=web-svc-2 -n emojivoto
NAME                         READY   STATUS    RESTARTS   AGE
web-svc-2-f9d77474f-hgsg4    2/2     Running       0      10s
$ kubectl get svc web-svc-2 -n emojivoto
NAME        TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)   AGE
web-svc-2   ClusterIP   10.102.99.153           80/TCP    3m45s

部署成功后同样可以使用 kubectl port-forward
命令来暴露服务:

$ kubectl port-forward svc/web-svc-2 8080:80 -n emojivoto

同样我们还是可以在浏览器中通过 localhost:8080
访问新版本的应用。

在页面顶部可以看到新版本的应用多了一行字符信息。

创建 TrafficSplit

接下来我们需要创建一个 apex
服务,我们这里将其称为 web-apex
,不过这次没有 Pod 运行,所以无法向服务发送任何请求,因为没有端点。

# web-apex.yaml
apiVersion: v1
kind: ServiceAccount
metadata:
  name: web-apex
  namespace: emojivoto
---
apiVersion: v1
kind: Service
metadata:
  name: web-apex
  namespace: emojivoto
spec:
  ports:
    - name: http
      port: 80
  selector:
    app: web-apex
  type: ClusterIP

同样直接应用上面的资源对象:

$ kubectl apply -f web-apex.yaml
serviceaccount/web-apex created
service/web-apex created
$ kubectl get svc -n emojivoto -o wide
NAME         TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)             AGE   SELECTOR
emoji-svc    ClusterIP   10.103.235.14            8080/TCP,8801/TCP   8d    app=emoji-svc
voting-svc   ClusterIP   10.102.32.81             8080/TCP,8801/TCP   8d    app=voting-svc
web-apex     ClusterIP   10.104.12.249            80/TCP              84s   app=web-apex
web-svc      ClusterIP   10.106.220.250           80/TCP              8d    app=web-svc
web-svc-2    ClusterIP   10.102.99.153            80/TCP              27m   app=web-svc-2

从上面的输出可以看到 web-apex
服务和其他普通服务一样,但是他并没有端点。

$ kubectl get ep -n emojivoto
NAME         ENDPOINTS                             AGE
emoji-svc    10.244.1.228:8801,10.244.1.228:8080   8d
voting-svc   10.244.1.202:8801,10.244.1.202:8080   8d
web-apex                                     2m55s
web-svc      10.244.1.227:8080                     8d
web-svc-2    10.244.1.233:8080                     28m

在继续之前我们可以先看看当前应用的流量状态:

$ linkerd viz stat po -n emojivoto
NAME                         STATUS   MESHED   SUCCESS      RPS   LATENCY_P50   LATENCY_P95   LATENCY_P99   TCP_CONN
emoji-696d9d8f95-5vn9w      Running      1/1   100.00%   2.3rps           1ms           1ms           1ms          4
vote-bot-6d7677bb68-jvxsg   Running      1/1   100.00%   0.3rps           1ms           1ms           1ms          1
voting-ff4c54b8d-xhjv7      Running      1/1    98.04%   0.8rps           1ms           8ms          10ms          4
web-5f86686c4d-58p7k        Running      1/1   100.00%   1.4rps           1ms           6ms           9ms          2

可以清楚看到虽然我们将 web 服务的更新版本已经部署了,但是现在没有产生任何的流量。接下来我们需要去创建一个 TrafficSplit
对象,然后去拆分一部分流量到我们的新服务中去。

创建一个如下所示的 TrafficSplit
资源对象:

# web-svc-ts.yml
apiVersion: split.smi-spec.io/v1alpha2
kind: TrafficSplit
metadata:
  name: web-svc-ts
  namespace: emojivoto
spec:
  # 客户端用于连接到目标应用程序的 root 服务
  service: web-apex
  # 命名空间中的 Service 以及它们自己的 selectors、端点和配置。
  backends: # 拆分的后端服务
    - service: web-svc
      weight: 500 # 权重
    - service: web-svc-2
      weight: 500

上面的资源对象中主要包括两个属性:

  • service
    :客户端用于连接到目标应用程序的 root 服务
  • backends
    :命名空间内的服务,具有自己的选择器、端点和配置(我们可以将这些服务看成
    服务)。
    • service
      :与可以处理请求的 Pod 关联地具体服务的名称。
    • weight
      :它与分配给服务的总流量的百分比相关。

现在我们来应用上面的资源对象:

$ kubectl apply -f web-svc-ts.yaml
trafficsplit.split.smi-spec.io/web-svc-ts created
$ kubectl get trafficsplit -n emojivoto
NAME         SERVICE
web-svc-ts   web-apex

创建完成后我们可以通过 linkerd viz stat
命令的一个 trafficsplit
子命令(可以缩写为 ts
),来显示所有的流量拆分统计信息。

$ linkerd viz stat ts -n emojivoto
Starting in 2.12, the SMI extension will be required for traffic splitting. Please follow the SMI extension getting started guide from https://linkerd.io/2.10/tasks/linkerd-smi

NAME         APEX       LEAF        WEIGHT   SUCCESS   RPS   LATENCY_P50   LATENCY_P95   LATENCY_P99
web-svc-ts   web-apex   web-svc        500         -     -             -             -             -
web-svc-ts   web-apex   web-svc-2      500         -     -             -             -             -

由于投票机器人配置为将流量发送到 web-svc.emojivoto:80
,所以现在我们看不到任何流量拆分的指标。所以我们先更新下 vote-bot
服务将流量发送到 web-apex
服务,而不是 web-svc
。以下 kubectl 命令中使用的文件更改了 vote-bot 部署中的 WEB_HOST 环境变量,以将流量发送到 web-apex 服务,从而使 TrafficSplit 配置生效。

$ kubectl edit deploy vote-bot -n emojivoto
# ......
    spec:
      containers:
      - command:
        - emojivoto-vote-bot
        env:
        - name: WEB_HOST
          value: web-apex.emojivoto:80
        image: docker.l5d.io/buoyantio/emojivoto-web:v11
        imagePullPolicy: IfNotPresent
        name: vote-bot
# ......

更新后新的 vote-bot
服务将向 web-apex
服务发出请求,我们可以使用上面的 trafficsplit
子命令再次来验证:

$ linkerd viz stat ts -n emojivoto
Starting in 2.12, the SMI extension will be required for traffic splitting. Please follow the SMI extension getting started guide from https://linkerd.io/2.10/tasks/linkerd-smi

NAME         APEX       LEAF        WEIGHT   SUCCESS      RPS   LATENCY_P50   LATENCY_P95   LATENCY_P99
web-svc-ts   web-apex   web-svc        500    90.32%   1.0rps           3ms           9ms          10ms
web-svc-ts   web-apex   web-svc-2      500    96.49%   0.9rps           1ms           5ms           5ms

从上面的输出可以看到 web-apex
服务是 web-svc
web-svc-2
服务的 APEX
服务,它们自己则是 LEAF
服务,输出结果还显示了每个服务的权重分布。

调整权重

接着我们再用 linkerd viz stat
命令来查看下应用的流量情况,上一次我们查看的时候 web-svc-2
服务关联的 Pod 没有收到任何流量。

$ linkerd viz stat pod -n emojivoto
NAME                         STATUS   MESHED   SUCCESS      RPS   LATENCY_P50   LATENCY_P95   LATENCY_P99   TCP_CONN
emoji-696d9d8f95-5vn9w      Running      1/1   100.00%   2.3rps           1ms           2ms           3ms          5
vote-bot-646b9fd6fd-js526   Running      1/1   100.00%   0.3rps           1ms           1ms           1ms          1
voting-ff4c54b8d-xhjv7      Running      1/1    89.74%   1.3rps           1ms           7ms           9ms          5
web-5f86686c4d-58p7k        Running      1/1    97.33%   1.2rps           2ms           9ms          10ms          3
web-svc-2-f9d77474f-hgsg4   Running      1/1    92.31%   1.3rps           1ms           6ms           9ms          3

这次我们可以看到与 web-svc
web-svc-2
相关的两个 Pod 都在处理请求了。证明我们的流量拆分配置是正确的。

TrafficSplit
定义中将每个服务的权重设置为 500,以平均分配流量。在实际工作中,我们可以先将 web-svc-2
的权重设置为 1%的或者很低的权重开始,以确保没有错误,然后当我们确定新版本没有问题后,可以调整慢慢调整每个服务的权重,到最终所有流量都切换到新版本上面去。

我们可以通过手动编辑 TrafficSplit
对象来手动调整这两个服务的权重。将 75% 的流量发送到 web-svc-2
,将 25%
的流量发送到 web-svc

# web-svc-ts-2.yml
apiVersion: split.smi-spec.io/v1alpha2
kind: TrafficSplit
metadata:
  name: web-svc-ts
  namespace: emojivoto
spec:
  # 客户端用于连接到目标应用程序的 root 服务
  service: web-apex
  # 命名空间中的 Service 以及它们自己的 selectors、端点和配置。
  backends: # 拆分的后端服务
    - service: web-svc
      weight: 250 # 权重
    - service: web-svc-2
      weight: 750

更新上面的资源对象后,再次查看流量拆分的情况。

$ linkerd viz stat ts -n emojivoto
Starting in 2.12, the SMI extension will be required for traffic splitting. Please follow the SMI extension getting started guide from https://linkerd.io/2.10/tasks/linkerd-smi

NAME         APEX       LEAF        WEIGHT   SUCCESS      RPS   LATENCY_P50   LATENCY_P95   LATENCY_P99
web-svc-ts   web-apex   web-svc        250    87.88%   0.6rps           6ms          17ms          20ms
web-svc-ts   web-apex   web-svc-2      750    94.12%   1.4rps           2ms           8ms          10ms

在输出中,你将看到 WEIGHT
列与上面的变更相匹配,web-svc-2
为 750、web-svc
为 250。接着我们再更改 TrafficSplit
对象,将所有流量发送到 web-svc-2
服务去。

# web-svc-ts-3.yml
apiVersion: split.smi-spec.io/v1alpha2
kind: TrafficSplit
metadata:
  name: web-svc-ts
  namespace: emojivoto
spec:
  # 客户端用于连接到目标应用程序的 root 服务
  service: web-apex
  # 命名空间中的 Service 以及它们自己的 selectors、端点和配置。
  backends: # 拆分的后端服务
    - service: web-svc
      weight: 0 # 权重
    - service: web-svc-2
      weight: 1

更新后我们再次查看流量拆分情况:

$ linkerd viz stat ts -n emojivoto
Starting in 2.12, the SMI extension will be required for traffic splitting. Please follow the SMI extension getting started guide from https://linkerd.io/2.10/tasks/linkerd-smi

NAME         APEX       LEAF        WEIGHT   SUCCESS      RPS   LATENCY_P50   LATENCY_P95   LATENCY_P99
web-svc-ts   web-apex   web-svc          0         -        -             -             -             -
web-svc-ts   web-apex   web-svc-2        1    99.15%   1.9rps           2ms           3ms           3ms

正常我们可以看到 web-svc-2
服务对应的 WEIGHT
为 1,而 web-svc
为 0。

到这里我们就了解了 Linkerd 中的流量拆分的使用,为了简单起见,我们这里使用的是一个单独的 web-apex
服务,当然 apex
服务也可以是后端之一的服务,apex
和后端之一具有相同服务的 TrafficSplit
会将发往该服务的流量发送到该服务,但会与其余后端服务成比例,这是可以动态完成的,允许你在现有服务之上插入一个 TrafficSplit

例如,我们可以简单地使用 web-svc
作为 apex
(并继续使用它以及 web-svc-2
作为后端),而不是使用 web-apex
。在创建 TrafficSplit
的那一刻,到 web-svc
的现有流量将遵循 TrafficSplit
的规则;并且在它被删除的那一刻,到 web-svc 的流量将恢复正常。

在实践中我们往往还会将 Linkerd 的流量拆分功能与 CI/CD 系统进行集成,以自动化发布过程,Linkerd 本身就提供了相关指标,这结合起来是不是就可以实现渐进式交付了:通过将指标和流量拆分捆绑在一起,可以以增量、安全和完全自动化的方式发布新代码,前面我们介绍过 Argo Rollouts,我们也可以使用像 https://flagger.app/
这样的项目,因为它是建立在 Linkerd 的指标和流量拆分功能之上来执行渐进式交付的。

 点击上方卡片关注K8s技术圈,掌握前沿云原生技术


点击下方图片,查看近期精彩课程



推荐阅读
  • 本文讨论了Alink回归预测的不完善问题,指出目前主要针对Python做案例,对其他语言支持不足。同时介绍了pom.xml文件的基本结构和使用方法,以及Maven的相关知识。最后,对Alink回归预测的未来发展提出了期待。 ... [详细]
  • 如何使用Java获取服务器硬件信息和磁盘负载率
    本文介绍了使用Java编程语言获取服务器硬件信息和磁盘负载率的方法。首先在远程服务器上搭建一个支持服务端语言的HTTP服务,并获取服务器的磁盘信息,并将结果输出。然后在本地使用JS编写一个AJAX脚本,远程请求服务端的程序,得到结果并展示给用户。其中还介绍了如何提取硬盘序列号的方法。 ... [详细]
  • 本文介绍了通过ABAP开发往外网发邮件的需求,并提供了配置和代码整理的资料。其中包括了配置SAP邮件服务器的步骤和ABAP写发送邮件代码的过程。通过RZ10配置参数和icm/server_port_1的设定,可以实现向Sap User和外部邮件发送邮件的功能。希望对需要的开发人员有帮助。摘要长度:184字。 ... [详细]
  • flowable工作流 流程变量_信也科技工作流平台的技术实践
    1背景随着公司业务发展及内部业务流程诉求的增长,目前信息化系统不能够很好满足期望,主要体现如下:目前OA流程引擎无法满足企业特定业务流程需求,且移动端体 ... [详细]
  • 在Xamarin XAML语言中如何在页面级别构建ControlTemplate控件模板
    本文介绍了在Xamarin XAML语言中如何在页面级别构建ControlTemplate控件模板的方法和步骤,包括将ResourceDictionary添加到页面中以及在ResourceDictionary中实现模板的构建。通过本文的阅读,读者可以了解到在Xamarin XAML语言中构建控件模板的具体操作步骤和语法形式。 ... [详细]
  • tcpdump 4.5.1 crash 深入分析
    tcpdump 4.5.1 crash 深入分析 ... [详细]
  • 本文总结了Java中日期格式化的常用方法,并给出了示例代码。通过使用SimpleDateFormat类和jstl fmt标签库,可以实现日期的格式化和显示。在页面中添加相应的标签库引用后,可以使用不同的日期格式化样式来显示当前年份和月份。该文提供了详细的代码示例和说明。 ... [详细]
  • 本文介绍了Java工具类库Hutool,该工具包封装了对文件、流、加密解密、转码、正则、线程、XML等JDK方法的封装,并提供了各种Util工具类。同时,还介绍了Hutool的组件,包括动态代理、布隆过滤、缓存、定时任务等功能。该工具包可以简化Java代码,提高开发效率。 ... [详细]
  • FeatureRequestIsyourfeaturerequestrelatedtoaproblem?Please ... [详细]
  • 如何查询zone下的表的信息
    本文介绍了如何通过TcaplusDB知识库查询zone下的表的信息。包括请求地址、GET请求参数说明、返回参数说明等内容。通过curl方法发起请求,并提供了请求示例。 ... [详细]
  • 本文记录了在vue cli 3.x中移除console的一些采坑经验,通过使用uglifyjs-webpack-plugin插件,在vue.config.js中进行相关配置,包括设置minimizer、UglifyJsPlugin和compress等参数,最终成功移除了console。同时,还包括了一些可能出现的报错情况和解决方法。 ... [详细]
  • 基于Socket的多个客户端之间的聊天功能实现方法
    本文介绍了基于Socket的多个客户端之间实现聊天功能的方法,包括服务器端的实现和客户端的实现。服务器端通过每个用户的输出流向特定用户发送消息,而客户端通过输入流接收消息。同时,还介绍了相关的实体类和Socket的基本概念。 ... [详细]
  • 本文详细介绍了cisco路由器IOS损坏时的恢复方法,包括进入ROMMON模式、设置IP地址、子网掩码、默认网关以及使用TFTP服务器传输IOS文件的步骤。 ... [详细]
  • centos安装Mysql的方法及步骤详解
    本文介绍了centos安装Mysql的两种方式:rpm方式和绿色方式安装,详细介绍了安装所需的软件包以及安装过程中的注意事项,包括检查是否安装成功的方法。通过本文,读者可以了解到在centos系统上如何正确安装Mysql。 ... [详细]
  • 解决Sharepoint 2013运行状况分析出现的“一个或多个服务器未响应”问题的方法
    本文介绍了解决Sharepoint 2013运行状况分析中出现的“一个或多个服务器未响应”问题的方法。对于有高要求的客户来说,系统检测问题的存在是不可接受的。文章详细描述了解决该问题的步骤,包括删除服务器、处理分布式缓存留下的记录以及使用代码等方法。同时还提供了相关关键词和错误提示信息,以帮助读者更好地理解和解决该问题。 ... [详细]
author-avatar
駱宏艷_230
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有