使用 Argo Rollouts 实现应用渐进式发布

WilliamGates
发布于 2023-11-24 11:27
浏览
0收藏

架构

下面展示了由 Argo Rollouts 管理的 Deployment 的所有组件。

使用 Argo Rollouts 实现应用渐进式发布-鸿蒙开发者社区

Rollout Controller

这是主控制器,用于监视集群的事件并在 Rollout 类型的资源发生更改时做出反应。控制器将读取 rollout 的所有详细信息,并使集群处于 rollout 定义中描述的相同状态。

请注意,Argo Rollouts 不会篡改或响应正常 Deployment 资源上发生的任何变更,这意味着你可以在一个使用其他方法部署应用的集群中安装 Argo Rollouts。

Rollout 资源

Rollout 资源是 Argo Rollouts 引入和管理的一种自定义 Kubernetes 资源,它与原生的 Kubernetes Deployment 资源基本兼容,但有额外的字段来控制更加高级的部署方法,如金丝雀和蓝/绿部署。

Argo Rollouts 控制器将只对 Rollout 资源中的变化做出反应,不会对正常的 Deployment 资源做任何事情,所以如果你想用 Argo Rollouts 管理你的 Deployment,你需要将你的 Deployment 迁移到 Rollouts。

AnalysisTemplate 与 AnalysisRun

​Analysis​​ 是一种自定义 Kubernetes 资源,它将 Rollout 连接到指标提供程序,并为某些指标定义特定阈值,这些阈值将决定 Rollout 是否成功。对于每个 Analysis,你可以定义一个或多个指标查询及其预期结果,如果指标查询正常,则 Rollout 将继续发布;如果指标显示失败,则自动回滚;如果指标无法提供成功/失败的结果,则暂停发布。

为了执行分析,Argo Rollouts 提供了两个自定义的 Kubernetes 资源:​​AnalysisTemplate​​​ 和 ​​AnalysisRun​​。

​AnalysisTemplate​​​ 包含有关要查询哪些指标的说明。附加到 ​​Rollout​​​ 的实际结果是 ​​AnalysisRun​​​ 自定义资源,可以在特定 的 ​​Rollout​​​ 上定义 ​​AnalysisTemplate​​​,也可以在集群上定义全局的 ​​AnalysisTemplate​​​,以供多个 ​​Rollout​​​ 共享作为 ​​ClusterAnalysisTemplate​​​,而 ​​AnalysisRun​​ 资源的范围仅限于特定的 rollout。

请注意,在 Rollout 中使用分析和指标是完全可选的,你可以通过 API 或 CLI 手动暂停和继续发布,也可以使用其他外部方法(例如冒烟测试)。你不需要仅使用 Argo Rollouts 的指标解决方案,你还可以在 Rollout 中混合自动(即基于分析)和手动步骤。

除了指标之外,你还可以通过运行 Kubernetes Job 或运行 webhook 来决定发布的成功与否。

Metric Providers

Argo Rollouts 包括多个流行指标提供程序的本机集成,您可以在分析资源中使用这些提供程序来自动升级或回滚部署。有关特定设置选项,请参阅每个提供商的文档。

Argo Rollouts 包括几个流行的指标提供者的集成,你可以在分析资源中使用,来自动升级或回滚发布。

安装

直接使用下面的命令安装 Argo Rollouts:

$ kubectl create namespace argo-rollouts
$ kubectl apply -n argo-rollouts -f https://github.com/argoproj/argo-rollouts/releases/download/v1.6.0/install.yaml

这里会创建一个名为 ​​argo-rollouts​​ 的命名空间,Argo Rollouts 控制器运行在上面。

$ kubectl get pods -n argo-rollouts
NAME                            READY   STATUS    RESTARTS   AGE
argo-rollouts-b9bbbc884-5h5jz   1/1     Running   0          7m21s
$ kubectl get crd |grep argo
analysisruns.argoproj.io               2023-09-21T06:20:34Z
analysistemplates.argoproj.io          2023-09-21T06:20:34Z
clusteranalysistemplates.argoproj.io   2023-09-21T06:20:34Z
experiments.argoproj.io                2023-09-21T06:20:35Z
rollouts.argoproj.io                   2023-09-21T06:20:35Z

此外,我们还可以安装一个 kubectl 插件,对于命令行管理和可视化发布非常方便。使用 curl 安装 Argo Rollouts kubectl 插件:

# https://ghproxy.com/https://github.com//argoproj/argo-rollouts/releases/download/v1.6.0/kubectl-argo-rollouts-linux-amd64
$ curl -LO https://github.com/argoproj/argo-rollouts/releases/download/v1.6.0/kubectl-argo-rollouts-linux-amd64

然后赋予 ​​kubectl-argo-rollouts​​ 二进制文件可执行权限:

$ chmod +x ./kubectl-argo-rollouts-linux-amd64

将该二进制文件移动到你的 PATH 路径下面去:

$ sudo mv ./kubectl-argo-rollouts-linux-amd64 /usr/local/bin/kubectl-argo-rollouts

执行下面的命令来验证插件是否安装成功:

$ kubectl argo rollouts version
kubectl-argo-rollouts: v1.6.0+7eae71e
  BuildDate: 2023-09-06T18:36:42Z
  GitCommit: 7eae71ed89f1a3769864435bddebe3ca05384df3
  GitTreeState: clean
  GoVersion: go1.20.7
  Compiler: gc
  Platform: linux/amd64

Dashboard

Argo Rollouts Kubectl 插件可以提供一个本地 Dashboard,来可视化你的 Rollouts。

要启动这个 Dashboard,需要在包含 Rollouts 资源对象的命名空间中运行 ​​kubectl argo rollouts dashboard​​​ 命令,然后访问​​localhost:3100​​ 即可。

使用 Argo Rollouts 实现应用渐进式发布-鸿蒙开发者社区

点击 Rollout 可以进行详细页面,在详细页面可以看到 Rollout 的配置信息,还可以直接在 UI 界面上执行一些常用的操作,比如重启、重启、中断等。

使用 Argo Rollouts 实现应用渐进式发布-鸿蒙开发者社区

Analysis 和渐进式交互

Argo Rollouts 提供了几种执行分析的方法来推动渐进式交付,首先需要了解几个 CRD 资源:

  • ​Rollout​​​:Rollout 是 Deployment 资源的直接替代品,它提供额外的​​blueGreen​​​ 和​​canary​​​ 更新策略,这些策略可以在更新期间创建​​AnalysisRuns​​​ 和​​Experiments​​,可以推进更新,或中止更新。
  • ​Experiments​​:Experiments CRD 允许用户临时运行一个或多个 ReplicaSet。除了运行临时 ReplicaSet 之外,Experiments CRD 还可以与 ReplicaSet 一起启动 AnalysisRuns。通常,这些 AnalysisRun 用于确认新的 ReplicaSet 是否按预期运行。
  • ​AnalysisTemplate​​:AnalysisTemplate 是一个模板,它定义了如何执行金丝雀分析,例如它应该执行的指标、频率以及被视为成功或失败的值,AnalysisTemplate 可以用输入值进行参数化。
  • ​ClusterAnalysisTemplate​​:ClusterAnalysisTemplate 和 AnalysisTemplate 类似,但它是全局范围内的,它可以被整个集群的任何 Rollout 使用。
  • ​AnalysisRun​​:AnalysisRun 是 AnalysisTemplate 的实例化。AnalysisRun 就像 Job 一样,它们最终会完成,完成的运行被认为是成功的、失败的或不确定的,运行的结果分别影响 Rollout 的更新是否继续、中止或暂停。

使用 Argo Rollouts 实现应用渐进式发布-鸿蒙开发者社区

后台分析

金丝雀正在执行其部署步骤时,分析可以在后台运行。

以下示例是每 10 分钟逐渐将 Canary 权重增加 20%,直到达到 100%。在后台,基于名为 ​​success-rate​​​ 的 ​​AnalysisTemplate​​​ 启动 ​​AnalysisRun​​​,​​success-rate​​ 模板查询 Prometheus 服务器,以 5 分钟间隔/样本测量 HTTP 成功率,它没有结束时间,一直持续到停止或失败。如果测量到的指标小于 95%,并且有三个这样的测量值,则分析被视为失败。失败的分析会导致 Rollout 中止,将 Canary 权重设置回零,并且 Rollout 将被视为降级。否则,如果 Rollout 完成其所有 Canary 步骤,则认为 rollout 是成功的,并且控制器将停止运行分析。

如下所示的 Rollout 资源对象:

apiVersion: argoproj.io/v1alpha1
kind: Rollout
metadata:
  name: guestbook
spec:
  # ...
  strategy:
    canary:
      analysis:
        templates:
          - templateName: success-rate
        startingStep: 2 # 延迟开始分析,到第3步开始
        args:
          - name: service-name
            value: guestbook-svc.default.svc.cluster.local
      steps:
        - setWeight: 20
        - pause: { duration: 10m }
        - setWeight: 40
        - pause: { duration: 10m }
        - setWeight: 60
        - pause: { duration: 10m }
        - setWeight: 80
        - pause: { duration: 10m }

上面我们引用了一个 ​​success-rate​​ 的模板:

apiVersion: argoproj.io/v1alpha1
kind: AnalysisTemplate
metadata:
  name: success-rate
spec:
  args:
    - name: service-name
  metrics:
    - name: success-rate
      interval: 5m
      # NOTE: prometheus queries return results in the form of a vector.
      # So it is common to access the index 0 of the returned array to obtain the value
      successCondition: result[0] >= 0.95
      failureLimit: 3
      provider:
        prometheus:
          address: http://prometheus.example.com:9090
          query: |
            sum(irate(
              istio_requests_total{reporter="source",destination_service=~"{{args.service-name}}",response_code!~"5.*"}[5m]
            )) /
            sum(irate(
              istio_requests_total{reporter="source",destination_service=~"{{args.service-name}}"}[5m]
            ))

内联分析

分析也可以作为内嵌分析步骤来执行,当分析以内联方式进行时,在到达该步骤时启动 AnalysisRun,并在运行完成之前阻止其推进。分析运行的成功或失败决定了部署是继续进行下一步,还是完全中止部署。

如下所示的示例中我们将 Canary 权重设置为 20%,暂停 5 分钟,然后运行分析。如果分析成功,则继续推出,否则中止。

apiVersion: argoproj.io/v1alpha1
kind: Rollout
metadata:
  name: guestbook
spec:
  # ...
  strategy:
    canary:
      steps:
        - setWeight: 20
        - pause: { duration: 5m }
        - analysis:
            templates:
              - templateName: success-rate
            args:
              - name: service-name
                value: guestbook-svc.default.svc.cluster.local

上面的对象中我们将 analysis 作为一个步骤内联到了 Rollout 步骤中,当 20%流量暂停 5 分钟后,开始执行 ​​success-rate​​ 这个分析模板。

这里 AnalysisTemplate 与上面的后台分析例子相同,但由于没有指定间隔时间,分析将执行一次测量就完成了。

apiVersion: argoproj.io/v1alpha1
kind: AnalysisTemplate
metadata:
  name: success-rate
spec:
  args:
    - name: service-name
    - name: prometheus-port
      value: 9090
  metrics:
    - name: success-rate
      successCondition: result[0] >= 0.95
      provider:
        prometheus:
          address: "http://prometheus.example.com:{{args.prometheus-port}}"
          query: |
            sum(irate(
              istio_requests_total{reporter="source",destination_service=~"{{args.service-name}}",response_code!~"5.*"}[5m]
            )) /
            sum(irate(
              istio_requests_total{reporter="source",destination_service=~"{{args.service-name}}"}[5m]
            ))

此外我们可以通过指定 count 和 interval 字段,可以在一个较长的时间段内进行多次测量。

metrics:
  - name: success-rate
    successCondition: result[0] >= 0.95
    interval: 60s
    count: 5
    provider:
      prometheus:
        address: http://prometheus.example.com:9090
        query: ...

多个模板的分析

Rollout 在构建 AnalysisRun 时可以引用多个 AnalysisTemplate。这样我们就可以从多个 AnalysisTemplate 中来组成分析,如果引用了多个模板,那么控制器将把这些模板合并在一起,控制器会结合所有模板的指标和 args 字段。如下所示:

apiVersion: argoproj.io/v1alpha1
kind: Rollout
metadata:
  name: guestbook
spec:
  # ...
  strategy:
    canary:
      analysis:
        templates:
          - templateName: success-rate
          - templateName: error-rate
        args:
          - name: service-name
            value: guestbook-svc.default.svc.cluster.local
---
apiVersion: argoproj.io/v1alpha1
kind: AnalysisTemplate
metadata:
  name: success-rate
spec:
  args:
    - name: service-name
  metrics:
    - name: success-rate
      interval: 5m
      successCondition: result[0] >= 0.95
      failureLimit: 3
      provider:
        prometheus:
          address: http://prometheus.example.com:9090
          query: |
            sum(irate(
              istio_requests_total{reporter="source",destination_service=~"{{args.service-name}}",response_code!~"5.*"}[5m]
            )) /
            sum(irate(
              istio_requests_total{reporter="source",destination_service=~"{{args.service-name}}"}[5m]
            ))---
apiVersion: argoproj.io/v1alpha1
kind: AnalysisTemplate
metadata:
  name: error-rate
spec:
  args:
    - name: service-name
  metrics:
    - name: error-rate
      interval: 5m
      successCondition: result[0] <= 0.95
      failureLimit: 3
      provider:
        prometheus:
          address: http://prometheus.example.com:9090
          query: |
            sum(irate(
              istio_requests_total{reporter="source",destination_service=~"{{args.service-name}}",response_code=~"5.*"}[5m]
            )) /
            sum(irate(
              istio_requests_total{reporter="source",destination_service=~"{{args.service-name}}"}[5m]
            ))

当执行的分析的时候,控制器会将上面的 ​​success-rate​​​ 和 ​​error-rate​​​ 两个模板合并到一个 ​​AnalysisRun​​ 对象中去。

需要注意的是如果出现以下情况,控制器在合并模板时将出错:

  • 模板中的多个指标具有相同的名称
  • 两个同名的参数都有值

分析模板参数

AnalysisTemplates 可以声明一组参数,这些参数可以由 Rollouts 传递。然后,这些参数可以像在 metrics 配置中一样使用,并在 AnalysisRun 创建时被实例化,参数占位符被定义为 ​​{{ args.<name> }}​​,如下所示:

apiVersion: argoproj.io/v1alpha1
kind: AnalysisTemplate
metadata:
  name: args-example
spec:
  args:
    # required
    - name: service-name
    - name: stable-hash
    - name: latest-hash
    # optional
    - name: api-url
      value: http://example/measure
    # from secret
    - name: api-token
      valueFrom:
        secretKeyRef:
          name: token-secret
          key: apiToken
  metrics:
    - name: webmetric
      successCondition: result == 'true'
      provider:
        web:
          # placeholders are resolved when an AnalysisRun is created
          url: "{{ args.api-url }}?service={{ args.service-name }}"
          headers:
            - key: Authorization
              value: "Bearer {{ args.api-token }}"
          jsonPath: "{$.results.ok}"

在创建 AnalysisRun 时,Rollout 中定义的参数与 AnalysisTemplate 的参数会合并,如下所示:

apiVersion: argoproj.io/v1alpha1
kind: Rollout
metadata:
  name: guestbook
spec:
---
strategy:
  canary:
    analysis:
      templates:
        - templateName: args-example
      args:
        # required value
        - name: service-name
          value: guestbook-svc.default.svc.cluster.local
        # override default value
        - name: api-url
          value: http://other-api
        # pod template hash from the stable ReplicaSet
        - name: stable-hash
          valueFrom:
            podTemplateHashValue: Stable
        # pod template hash from the latest ReplicaSet
        - name: latest-hash
          valueFrom:
            podTemplateHashValue: Latest

此外分析参数也支持 ​​valueFrom​​,用于读取 meta 数据并将其作为参数传递给 AnalysisTemplate,如下例子是引用元数据中的 env 和 region 标签,并将它们传递给 AnalysisTemplate。

apiVersion: argoproj.io/v1alpha1
kind: Rollout
metadata:
  name: guestbook
  labels:
    appType: demo-app
    buildType: nginx-app
    ...
    env: dev
    region: us-west-2
spec:
...
  strategy:
    canary:
      analysis:
        templates:
        - templateName: args-example
        args:
        ...
        - name: env
          valueFrom:
            fieldRef:
              fieldPath: metadata.labels['env']
        # region where this app is deployed
        - name: region
          valueFrom:
            fieldRef:
              fieldPath: metadata.labels['region']

蓝绿预发布分析

使用 BlueGreen 策略的 Rollout 可以在使用预发布将流量切换到新版本之前启动一个 AnalysisRun。分析运行的成功或失败决定 Rollout 是否切换流量,或完全中止 Rollout,如下所示:

kind: Rollout
metadata:
  name: guestbook
spec:
---
strategy:
  blueGreen:
    activeService: active-svc
    previewService: preview-svc
    prePromotionAnalysis:
      templates:
        - templateName: smoke-tests
      args:
        - name: service-name
          value: preview-svc.default.svc.cluster.local

上面我们的示例中一旦新的 ReplicaSet 完全可用,Rollout 会创建一个预发布的 AnalysisRun,Rollout 不会将流量切换到新版本,而是会等到分析运行成功完成。

注意:如果指定了 ​​autoPromotionSeconds​​​ 字段,并且 Rollout 已经等待了 ​​auto promotion seconds​​​ 的时间,Rollout 会标记 AnalysisRun 成功,并自动将流量切换到新版本。如果 AnalysisRun 在此之前完成,Rollout 将不会创建另一个 AnalysisRun,并等待 ​​autoPromotionSeconds​​ 的剩余时间。

蓝绿发布后分析

使用 BlueGreen 策略的 Rollout 还可以在流量切换到新版本后使用发布后分析。如果发布后分析失败或出错,Rollout 则进入中止状态,并将流量切换回之前的稳定 ReplicaSet,当后分析成功时,Rollout 被认为是完全发布状态,新的 ReplicaSet 将被标记为稳定,然后旧的 ReplicaSet 将根据 ​​scaleDownDelaySeconds​​(默认为 30 秒)进行缩减。

apiVersion: argoproj.io/v1alpha1
kind: Rollout
metadata:
  name: guestbook
spec:
---
strategy:
  blueGreen:
    activeService: active-svc
    previewService: preview-svc
    scaleDownDelaySeconds: 600 # 10 minutes
    postPromotionAnalysis:
      templates:
        - templateName: smoke-tests
      args:
        - name: service-name
          value: preview-svc.default.svc.cluster.local

失败条件

​failureCondition​​ 可以用来配置分析运行失败,下面的例子是每隔 5 分钟持续轮询 Prometheus 服务器来获得错误总数,如果遇到 10 个或更多的错误,则认为分析运行失败。

metrics:
  - name: total-errors
    interval: 5m
    failureCondition: result[0] >= 10
    failureLimit: 3
    provider:
      prometheus:
        address: http://prometheus.example.com:9090
        query: |
          sum(irate(
            istio_requests_total{reporter="source",destination_service=~"{{args.service-name}}",response_code~"5.*"}[5m]
          ))

无结果的运行

分析运行 j 结果也可以被认为是不确定的,这表明运行既不成功,也不失败。无结果的运行会导致发布在当前步骤上暂停。这时需要人工干预,以恢复运行,或中止运行。当一个指标没有定义成功或失败的条件时,分析运行可能成为无结果的一个例子。

metrics:
  - name: my-query
    provider:
      prometheus:
        address: http://prometheus.example.com:9090
        query: ...

此外当同时指定了成功和失败的条件,但测量值没有满足任何一个条件时,也可能发生不确定的分析运行。

metrics:
  - name: success-rate
    successCondition: result[0] >= 0.90
    failureCondition: result[0] < 0.50
    provider:
      prometheus:
        address: http://prometheus.example.com:9090
        query: ...

不确定的分析运行的一个场景是使 Argo Rollouts 能够自动执行分析运行,并收集测量结果,但仍然允许我们来判断决定测量值是否可以接受,并决定继续或中止。

延迟分析运行

如果分析运行不需要立即开始(即给指标提供者时间来收集金丝雀版本的指标),分析运行可以延迟特定的指标分析。每个指标可以被配置为有不同的延迟,除了特定指标的延迟之外,具有后台分析的发布可以延迟创建分析运行,直到达到某个步骤为止

如下所示延迟一个指定的分析指标:

metrics:
  - name: success-rate
    # Do not start this analysis until 5 minutes after the analysis run starts
    initialDelay: 5m
    successCondition: result[0] >= 0.90
    provider:
      prometheus:
        address: http://prometheus.example.com:9090
        query: ...

延迟开始后台分析运行,直到步骤 3(设定重量 40%)。

apiVersion: argoproj.io/v1alpha1
kind: Rollout
metadata:
  name: guestbook
spec:
  strategy:
    canary:
      analysis:
        templates:
          - templateName: success-rate
        startingStep: 2
      steps:
        - setWeight: 20
        - pause: { duration: 10m }
        - setWeight: 40
        - pause: { duration: 10m }

Job Metrics

此外 Kubernetes Job 还可用于运行分析,使用 Job 时,如果 Job 完成且退出代码为零,则指标被视为成功,否则指标失败。

metrics:
  - name: test
    provider:
      job:
        metadata:
          annotations:
            foo: bar # annotations defined here will be copied to the Job object
          labels:
            foo: bar # labels defined here will be copied to the Job object
        spec:
          backoffLimit: 1
          template:
            spec:
              containers:
                - name: test
                  image: my-image:latest
                  command:
                    [my-test-script, my-service.default.svc.cluster.local]
              restartPolicy: Never

Web Metrics

同样还可以针对某些外部服务执行 HTTP 请求来获取测量结果。下面示例向某个 URL 发出 HTTP GET 请求。 Webhook 响应必须返回 JSON 内容。​​jsonPath​​​ 表达式的结果将分配给可在 ​​successCondition​​​ 和 ​​failureCondition​​​ 表达式中引用的 result 变量。如果省略,将使用整个 ​​body​​ 作为结果变量。

metrics:
  - name: webmetric
    successCondition: result == true
    provider:
      web:
        url: "http://my-server.com/api/v1/measurement?service={{ args.service-name }}"
        timeoutSeconds: 20 # defaults to 10 seconds
        headers:
          - key: Authorization
            value: "Bearer {{ args.api-token }}"
        jsonPath: "{$.data.ok}"

比如下面的示例表示如果 ​​data.ok​​​ 字段为真且 ​​data.successPercent​​​ 大于 ​​0.90​​,测量将是成功的。

{ "data": { "ok": true, "successPercent": 0.95 } }

metrics:
  - name: webmetric
    successCondition: "result.ok && result.successPercent >= 0.90"
    provider:
      web:
        url: "http://my-server.com/api/v1/measurement?service={{ args.service-name }}"
        headers:
          - key: Authorization
            value: "Bearer {{ args.api-token }}"
        jsonPath: "{$.data}"

当然关于 Argo Rollouts 的使用还有很多细节,可以参考官方文档:​​https://argoproj.github.io/argo-rollouts/以了解更多。​


文章转载自公众号:k8s技术圈

分类
已于2023-11-24 11:27:48修改
收藏
回复
举报
回复
    相关推荐