借助 Rancher 持续交付,3 步实现金丝雀发布!

  • 2021-05-09
  • 本文字数:5054 字

    阅读完需:约 17 分钟

从 Rancher 2.5 起,Rancher 借助 Fleet 提供了大规模交付的 GitOps 功能,允许用户使用 GitOps 的方法管理其集群的状态。

金丝雀发布是一个被软件开发者广泛使用的方法,它可以用来向一部分用户发布新版本的应用程序,并根据可用性、延迟或自定义指标等指标来扩大规模,进而为更多用户提供服务。在本文中,我们将探索如何使用持续交付来为你的应用程序工作负载执行金丝雀发布。

实际的金丝雀发布将由一个名为 Flagger 的项目执行。Flagger 作为 Kubernetes operator 运行。它允许用户指定一个自定义对象,该对象会通知 Flagger 观察一个部署并创建额外的主要部署(primary deployment)和金丝雀部署。作为本文的一部分,我们将使用 Flagger 与 Istio 作为服务网格。

简而言之,当我们创建一个部署时,Flagger 会将该部署克隆到一个主部署。然后它修改与原始部署相关的服务以指向这个新的主部署。该主部署本身会被缩减到 0。

Flagger 使用 Istio virtualservices 来执行实际的金丝雀发布。当一个新版本的应用程序被部署时,Flagger 将原始部署缩减到原始规格,并将金丝雀服务关联到部署。

现在,一定比例的流量被路由到这个金丝雀服务。基于预定义的指标,Flagger 开始将越来越多的流量路由到这个金丝雀服务。一旦 100%的流量被迁移到金丝雀服务,主部署就会以原始部署相同的规格重新创建。

接下来,将更新 virtualservice 以将 100%的流量返回到主服务。在流量转换之后,原始部署被缩减为 0,Flagger operator 等待并监控后续的部署更新。

Flagger 执行金丝雀发布

为了开始使用 Flagger,我们需要执行以下操作:

  1. 设置监控和 Istio

  2. 设置 Flagger 和 flagger-loadtest

  3. 部署一个 demo 程序并执行金丝雀发布

1.设置监控和 Istio

为了设置 monitoring 和 istio,我们将在持续交付中设置几个 ClusterGroups:

监控

apiVersion: fleet.cattle.io/v1alpha1kind: ClusterGroupmetadata:  name: monitoring  namespace: fleet-defaultspec:  selector:    matchLabels:      monitoring: enable
复制代码

Istio

apiVersion: fleet.cattle.io/v1alpha1kind: ClusterGroupmetadata:  name: istio  namespace: fleet-defaultspec:  selector:    matchLabels:      istio: enabled
复制代码

现在,我们将设置我们的 monitoring 和 istio Gitrepos 以指向使用这些 ClusterGroups:

监控 repo

apiVersion: fleet.cattle.io/v1alpha1kind: GitRepometadata:  name: monitoring  namespace: fleet-defaultspec:  branch: master  insecureSkipTLSVerify: false  paths:  - monitoring  - monitoring-crd  repo: https://github.com/ibrokethecloud/core-bundles  targets:  - clusterGroup: monitoring
复制代码

Istio repo

apiVersion: fleet.cattle.io/v1alpha1kind: GitRepometadata:  name: istio  namespace: fleet-defaultspec:  branch: master  insecureSkipTLSVerify: false  paths:  - istio  - kiali  repo: https://github.com/ibrokethecloud/core-bundles  targets:  - clusterGroup: istio
复制代码

为了触发部署,我们将使用所需的标签为这些 ClusterGroups 分配一个集群:

图片

图片

在几分钟之内,监控和 istio 应用程序应该在指定集群上安装完毕。

2.设置 Flagger 和 flagger-loadtest

作为安装 Flagger 的一部分,我们将安装 flagger-loadtest 以帮助在我们的工作负载上生成请求。

请注意:flagger-loadtest 仅在本次 demo 中需要。在实际应用场景中,你的应用程序将会使用真实的流量。Flagger 将根据来自真实流量的指标启动切换。

我们将设置一个 ClusterGroup 金丝雀,如下所示:

apiVersion: fleet.cattle.io/v1alpha1kind: ClusterGroupmetadata:  name: canary  namespace: fleet-defaultspec:  selector:    matchLabels:      canary: enabled
复制代码

图片

现在我们可以设置 flagger Gitrepo 来使用这个 ClusterGroup

apiVersion: fleet.cattle.io/v1alpha1kind: GitRepometadata:name: flaggernamespace: fleet-defaultspec:branch: masterinsecureSkipTLSVerify: falsepaths:- flagger- flagger-loadtestrepo: https://github.com/ibrokethecloud/user-bundlestargets:- clusterGroup: canary
复制代码

图片

如我们之前所了解的,要触发部署我们将分配一个集群到 Flagger ClusterGroup

图片

图片

在几分钟之内,Flagger 和 flagger-loadtest helm charts 将会被部署到该集群

图片

请注意,在部署 Flagger 时,它将所有的标签和注释从源部署中复制到金丝雀和主部署中。持续交付将使用对象上的标签来核对和识别它们属于哪个底层的 Bundle。Flagger 对此进行了设置,在默认设置中,持续交付将报告不在 GitRepo 中的额外的主部署和金丝雀部署。

为了避免这种情况,Flagger helm chart 中的 includeLabelPrefix 设置被传递并设置为 dummy,以指示 Flagger 只包括前缀为 dummy 的标签。这有助于我们绕过持续交付的 reconciliation logic。

fleet.yaml 如下所示:

defaultNamespace: istio-systemhelm:releaseName: flaggerrepo: https://flagger.appchart: flaggerversion: 1.6.2values:crd.create: truemeshProvider: istiometricsServer: http://rancher-monitoring-prometheus.cattle-monitoring-system:9090includeLabelPrefix: dummydiff:comparePatches:- apiVersion: apps/v1kind: Deploymentname: flaggernamespace: istio-systemoperations:- {"op": "remove", "path": "/spec/template/spec/containers/0/resources/limits/cpu"}- {"op": "remove", "path": "/spec/template/spec/containers/0/volumeMounts"}- {"op": "remove", "path": "/spec/template/spec/volumes"}
复制代码

所有基础服务设置完成后,我们现在可以开始部署我们的工作负载。

3.部署 Demo 应用程序并进行金丝雀发布

现在我们添加 canary-demo-app GitRepo 到目标 canaryClusterGroup

apiVersion: fleet.cattle.io/v1alpha1kind: GitRepometadata:  name: canary-demo-app  namespace: fleet-defaultspec:  branch: master  insecureSkipTLSVerify: false  paths:  - canary-demo-app  repo: https://github.com/ibrokethecloud/user-bundles  targets:  - clusterGroup: canary
复制代码

这将出发 demo app 的部署到 canary-demo 命名空间。

(⎈ |digitalocean:canary-demo)~▶ kubectl get deploymentNAME                       READY   UP-TO-DATE   AVAILABLE   AGEfleet-simple-app           0/0     0            0           80sfleet-simple-app-primary   1/1     1            1           80s(⎈ |digitalocean:canary-demo)
复制代码

控制发布行为的金丝雀对象如下:

apiVersion: flagger.app/v1beta1kind: Canarymetadata:  name: fleet-simple-app  namespace: canary-demospec:  targetRef:    apiVersion: apps/v1    kind: Deployment    name: fleet-simple-app  service:    port: 8080  analysis:    interval: 1m    threshold: 10    maxWeight: 50    stepWeight: 10    metrics:      - name: request-success-rate        thresholdRange:          min: 99        interval: 1m      - name: request-duration        thresholdRange:          max: 500        interval: 1m    webhooks:      - name: load-test        url: http://flagger-loadtester.loadtester/        timeout: 5s        metadata:          type: cmd          cmd: "hey -z 1m -q 10 -c 2 http://fleet-simple-app-canary.canary-demo:8080"
复制代码

这里面的关键项目时 webhook 来进行负载测试,以产生足够的指标让 Flagger 能够开始切换流量。

我们同时能够看到金丝雀对象的状态,如下所示:

(⎈ |digitalocean:canary-demo)~▶ kubectl get canaryNAME               STATUS        WEIGHT   LASTTRANSITIONTIMEfleet-simple-app   Initialized   0        2021-03-22T06:25:17Z
复制代码

我们现在可以通过更新 canary-demo-app 的 GitRepo,用新版本的镜像来触发金丝雀发布。在几分钟之后,我们应该看到源部署使用来自 GitRepo 的新镜像进行扩展。此外,金丝雀对象变成 Progressing 状态,金丝雀发布的比重发生变化。

▶ kubectl get deployNAME                       READY   UP-TO-DATE   AVAILABLE   AGEfleet-simple-app           1/1     1            1           6m5sfleet-simple-app-primary   1/1     1            1           6m5s(⎈ |digitalocean:canary-demo)~▶ kubectl get canaryNAME               STATUS        WEIGHT   LASTTRANSITIONTIMEfleet-simple-app   Progressing   0        2021-03-22T06:30:17Z▶ kubectl get canaryNAME               STATUS        WEIGHT   LASTTRANSITIONTIMEfleet-simple-app   Progressing   10       2021-03-22T06:31:17Z
复制代码

执行中的金丝雀还与 Istio virtualservice 中不断变化的比重相对应。

apiVersion: networking.istio.io/v1beta1kind: VirtualServicemetadata:  creationTimestamp: "2021-03-22T06:25:17Z"  generation: 2  managedFields:  - apiVersion: networking.istio.io/v1alpha3    fieldsType: FieldsV1    fieldsV1:      f:metadata:        f:ownerReferences:          .: {}          k:{"uid":"6ae2a7f1-6949-484b-ab48-c385e9827a11"}:            .: {}            f:apiVersion: {}            f:blockOwnerDeletion: {}            f:controller: {}            f:kind: {}            f:name: {}            f:uid: {}      f:spec:        .: {}        f:gateways: {}        f:hosts: {}        f:http: {}    manager: flagger    operation: Update    time: "2021-03-22T06:25:17Z"  name: fleet-simple-app  namespace: canary-demo  ownerReferences:  - apiVersion: flagger.app/v1beta1    blockOwnerDeletion: true    controller: true    kind: Canary    name: fleet-simple-app    uid: 6ae2a7f1-6949-484b-ab48-c385e9827a11  resourceVersion: "10783"  uid: b5aaaf34-7b16-4ba9-972c-b60756943da8spec:  gateways:  - mesh  hosts:  - fleet-simple-app  http:  - route:    - destination:        host: fleet-simple-app-primary      weight: 90    - destination:        host: fleet-simple-app-canary      weight: 10
复制代码

再过一会儿,我们应该看到 Flagger 在推动金丝雀发布,并且主要的部署被切换到新版本。

▶ kubectl get canaryNAME               STATUS      WEIGHT   LASTTRANSITIONTIMEfleet-simple-app   Promoting   0        2021-03-22T06:37:17Z▶ kubectl get podsNAME                                        READY   STATUS    RESTARTS   AGEfleet-simple-app-64cd54dfd-tkk8v            2/2     Running   0          9m2sfleet-simple-app-primary-854d4d84b5-qgfc8   2/2     Running   0          74s
复制代码

在最终完成部署之后,我们应该看到原来的部署被缩减:

▶ kubectl get canaryNAME               STATUS       WEIGHT   LASTTRANSITIONTIMEfleet-simple-app   Finalising   0        2021-03-22T06:38:17Z(⎈ |digitalocean:canary-demo)~▶ kubectl get podsNAME                                        READY   STATUS        RESTARTS   AGEfleet-simple-app-64cd54dfd-tkk8v            2/2     Terminating   0          9m53sfleet-simple-app-primary-854d4d84b5-qgfc8   2/2     Running       0          2m5s▶ kubectl get deployNAME                       READY   UP-TO-DATE   AVAILABLE   AGEfleet-simple-app           0/0     0            0           15mfleet-simple-app-primary   1/1     1            1           15m
复制代码

在这之后,金丝雀对象应该是成功状态:

▶ kubectl get canaryNAME               STATUS      WEIGHT   LASTTRANSITIONTIMEfleet-simple-app   Succeeded   0        2021-03-22T06:39:17Z
复制代码

大功告成!在本文中,我们展示了如何使用持续交付、利用第三方工具(如 Flagger)来为我们的工作负载执行金丝雀发布。欢迎跟着本教程进行操作,如果有任何问题,也欢迎扫描文末二维码,添加小助手为好友,进入 Rancher 官方技术交流群与各位 Rancher 用户一起交流。

本文转载自:RancherLabs(ID:RancherLabs)

原文链接:借助Rancher持续交付,3步实现金丝雀发布!