从 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,我们需要执行以下操作:
为了设置 monitoring 和 istio,我们将在持续交付中设置几个 ClusterGroups:
监控
apiVersion: fleet.cattle.io/v1alpha1
kind: ClusterGroup
metadata:
name: monitoring
namespace: fleet-default
spec:
selector:
matchLabels:
monitoring: enable
Istio
apiVersion: fleet.cattle.io/v1alpha1
kind: ClusterGroup
metadata:
name: istio
namespace: fleet-default
spec:
selector:
matchLabels:
istio: enabled
现在,我们将设置我们的 monitoring 和 istio Gitrepos 以指向使用这些 ClusterGroups:
监控 repo
apiVersion: fleet.cattle.io/v1alpha1
kind: GitRepo
metadata:
name: monitoring
namespace: fleet-default
spec:
branch: master
insecureSkipTLSVerify: false
paths:
- monitoring
- monitoring-crd
repo: https://github.com/ibrokethecloud/core-bundles
targets:
- clusterGroup: monitoring
Istio repo
apiVersion: fleet.cattle.io/v1alpha1
kind: GitRepo
metadata:
name: istio
namespace: fleet-default
spec:
branch: master
insecureSkipTLSVerify: false
paths:
- istio
- kiali
repo: https://github.com/ibrokethecloud/core-bundles
targets:
- clusterGroup: istio
为了触发部署,我们将使用所需的标签为这些 ClusterGroups 分配一个集群:
在几分钟之内,监控和 istio 应用程序应该在指定集群上安装完毕。
作为安装 Flagger 的一部分,我们将安装 flagger-loadtest 以帮助在我们的工作负载上生成请求。
请注意:flagger-loadtest 仅在本次 demo 中需要。在实际应用场景中,你的应用程序将会使用真实的流量。Flagger 将根据来自真实流量的指标启动切换。
我们将设置一个 ClusterGroup 金丝雀,如下所示:
apiVersion: fleet.cattle.io/v1alpha1
kind: ClusterGroup
metadata:
name: canary
namespace: fleet-default
spec:
selector:
matchLabels:
canary: enabled
现在我们可以设置 flagger Gitrepo 来使用这个 ClusterGroup
apiVersion: fleet.cattle.io/v1alpha1
kind: GitRepo
metadata:
name: flagger
namespace: fleet-default
spec:
branch: master
insecureSkipTLSVerify: false
paths:
- flagger
- flagger-loadtest
repo: https://github.com/ibrokethecloud/user-bundles
targets:
- 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-system
helm:
releaseName: flagger
repo: https://flagger.app
chart: flagger
version: 1.6.2
values:
crd.create: true
meshProvider: istio
metricsServer: http://rancher-monitoring-prometheus.cattle-monitoring-system:9090
includeLabelPrefix: dummy
diff:
comparePatches:
- apiVersion: apps/v1
kind: Deployment
name: flagger
namespace: istio-system
operations:
- {"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"}
所有基础服务设置完成后,我们现在可以开始部署我们的工作负载。
现在我们添加 canary-demo-app GitRepo 到目标 canaryClusterGroup
apiVersion: fleet.cattle.io/v1alpha1
kind: GitRepo
metadata:
name: canary-demo-app
namespace: fleet-default
spec:
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 deployment
NAME READY UP-TO-DATE AVAILABLE AGE
fleet-simple-app 0/0 0 0 80s
fleet-simple-app-primary 1/1 1 1 80s
(⎈ |digitalocean:canary-demo)
控制发布行为的金丝雀对象如下:
apiVersion: flagger.app/v1beta1
kind: Canary
metadata:
name: fleet-simple-app
namespace: canary-demo
spec:
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 canary
NAME STATUS WEIGHT LASTTRANSITIONTIME
fleet-simple-app Initialized 0 2021-03-22T06:25:17Z
我们现在可以通过更新 canary-demo-app 的 GitRepo,用新版本的镜像来触发金丝雀发布。在几分钟之后,我们应该看到源部署使用来自 GitRepo 的新镜像进行扩展。此外,金丝雀对象变成 Progressing 状态,金丝雀发布的比重发生变化。
▶ kubectl get deploy
NAME READY UP-TO-DATE AVAILABLE AGE
fleet-simple-app 1/1 1 1 6m5s
fleet-simple-app-primary 1/1 1 1 6m5s
(⎈ |digitalocean:canary-demo)
~
▶ kubectl get canary
NAME STATUS WEIGHT LASTTRANSITIONTIME
fleet-simple-app Progressing 0 2021-03-22T06:30:17Z
▶ kubectl get canary
NAME STATUS WEIGHT LASTTRANSITIONTIME
fleet-simple-app Progressing 10 2021-03-22T06:31:17Z
执行中的金丝雀还与 Istio virtualservice 中不断变化的比重相对应。
apiVersion: networking.istio.io/v1beta1
kind: VirtualService
metadata:
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-b60756943da8
spec:
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 canary
NAME STATUS WEIGHT LASTTRANSITIONTIME
fleet-simple-app Promoting 0 2021-03-22T06:37:17Z
▶ kubectl get pods
NAME READY STATUS RESTARTS AGE
fleet-simple-app-64cd54dfd-tkk8v 2/2 Running 0 9m2s
fleet-simple-app-primary-854d4d84b5-qgfc8 2/2 Running 0 74s
在最终完成部署之后,我们应该看到原来的部署被缩减:
▶ kubectl get canary
NAME STATUS WEIGHT LASTTRANSITIONTIME
fleet-simple-app Finalising 0 2021-03-22T06:38:17Z
(⎈ |digitalocean:canary-demo)
~
▶ kubectl get pods
NAME READY STATUS RESTARTS AGE
fleet-simple-app-64cd54dfd-tkk8v 2/2 Terminating 0 9m53s
fleet-simple-app-primary-854d4d84b5-qgfc8 2/2 Running 0 2m5s
▶ kubectl get deploy
NAME READY UP-TO-DATE AVAILABLE AGE
fleet-simple-app 0/0 0 0 15m
fleet-simple-app-primary 1/1 1 1 15m
在这之后,金丝雀对象应该是成功状态:
▶ kubectl get canary
NAME STATUS WEIGHT LASTTRANSITIONTIME
fleet-simple-app Succeeded 0 2021-03-22T06:39:17Z
大功告成!在本文中,我们展示了如何使用持续交付、利用第三方工具(如 Flagger)来为我们的工作负载执行金丝雀发布。欢迎跟着本教程进行操作,如果有任何问题,也欢迎扫描文末二维码,添加小助手为好友,进入 Rancher 官方技术交流群与各位 Rancher 用户一起交流。
本文转载自:RancherLabs(ID:RancherLabs)
领取专属 10元无门槛券
私享最新 技术干货