Argo Rollouts

发布时间 2023-08-11 18:49:32作者: evescn

Argo Rollouts

Argo Rollouts 是一个 Kubernetes Operator 实现,它为 Kubernetes 提供更加高级的部署能力,如蓝绿、金丝雀、金丝雀分析、实验和渐进式交付功能,为云原生应用和服务实现自动化、基于 GitOps 的逐步交付。

支持如下特性:

  • 蓝绿更新策略
  • 金丝雀更新策略
  • 更加细粒度、加权流量拆分
  • 自动回滚
  • 手动判断
  • 可定制的指标查询和业务 KPI 分析
  • Ingress 控制器集成:NGINX,ALB
  • 服务网格集成:Istio,Linkerd,SMI
  • Metrics 指标集成:Prometheus、Wavefront、Kayenta、Web、Kubernetes Jobs、Datadog、New Relic

实现原理

与 Deployment 对象类似,Argo Rollouts 控制器将管理 ReplicaSets 的创建、缩放和删除,这些 ReplicaSet 由 Rollout 资源中的 spec.template 定义,使用与 Deployment 对象相同的 pod 模板。

spec.template 变更时,这会向 Argo Rollouts 控制器发出信号,表示将引入新的 ReplicaSet,控制器将使用 spec.strategy 字段内的策略来确定从旧 ReplicaSet 到新 ReplicaSet 的 rollout 将如何进行,一旦这个新的 ReplicaSet 被放大(可以选择通过一个 Analysis),控制器会将其标记为稳定

如果在 spec.template 从稳定的 ReplicaSet 过渡到新的 ReplicaSet 的过程中发生了另一次变更(即在发布过程中更改了应用程序版本),那么之前的新 ReplicaSet 将缩小,并且控制器将尝试发布反映更新 spec.template 字段的 ReplicasSet。

相关概念

Rollout(滚动)

Rollout 是一个 Kubernetes 的 CRD 资源,相当于 Kubernetes Deployment 对象,在需要更高级的部署或渐进式交付功能的情况下,它旨在取代 Deployment 对象,Rollout 提供了 Kubernetes Deployment 所不能提供的功能。

  • 蓝绿部署
  • 金丝雀部署
  • 与 Ingress 控制器和服务网格整合,实现高级流量路由
  • 与用于蓝绿和金丝雀分析的指标提供者集成
  • 根据成功或失败的指标,自动发布或回滚

渐进式交付

渐进式交付是以受控和渐进的方式发布产品更新的过程,从而降低发布的风险,通常将自动化和指标分析结合起来以驱动更新的自动升级或回滚。

img

渐进式交付通常被描述为持续交付的演变,将 CI/CD 中的速度优势扩展到部署过程。通过将新版本限制在一部分用户,观察和分析正确的行为,然后逐渐增加更多的流量,同时不断验证其正确性。

部署策略

虽然业界使用了一致的术语来描述各种部署策略,但这些策略的实现往往因工具而异,为了明确 Argo Rollouts 的行为方式,以下是 Argo Rollouts 提供的各种部署策略实施的描述。

  • RollingUpdate(滚动更新):慢慢地用新版本替换旧版本,随着新版本的出现,旧版本会慢慢缩减,以保持应用程序的总数量。这是 Deployment 对象的默认策略。
  • Recreate(重新创建):Recreate 会在启动新版本之前删除旧版本的应用程序,这可确保应用程序的两个版本永远不会同时运行,但在部署期间会出现停机时间。
  • Blue-Green(蓝绿):蓝绿发布(有时称为红黑)指同时部署了新旧两个版本的应用程序,在此期间,只有旧版本的应用程序会收到生产流量,这允许开发人员在将实时流量切换到新版本之前针对新版本进行测试。

Blue-Green

  • Canary(金丝雀):金丝雀发布指将一部分用户暴露在新版本的应用程序中,而将其余流量提供给旧版本,一旦新版本被验证是正确的,新版本可以逐渐取代旧版本。Ingress 控制器和服务网格,如 NGINX Ingress 和 Istio,可以使金丝雀的流量拆分模式比原生的更复杂(例如,实现非常细粒度的流量分割,或基于 HTTP 头的分割)。

Canary

上面显示了一个有两个阶段的金丝雀(10%和33%的流量进入新版本),通过使用 Argo Rollouts,我们可以根据实际的使用情况定义确切的阶段数和流量百分比。

场景

  1. 用户希望在新版本开始为生产环境提供服务之前对其进行最后一分钟的功能测试,通过 BlueGreen 策略,Argo Rollouts 允许用户指定预览服务和活动服务,Rollout 将配置预览服务以将流量发送到新版本,同时活动服务继续接收生产流量。一旦达到要求,则可以将预览服务提升为新的活动服务。
  2. 在新版本开始接收实时流量之前,需要预先执行一套通用步骤,通过使用 BlueGreen 策略,用户可以在不接收来自活动服务的流量的情况下启动新版本,一旦这些步骤执行完毕,就可以将流量切换到新版本了。
  3. 用户希望在几个小时内将一小部分生产流量提供给他们应用程序的新版本。之后,他们希望缩小新版本规模,并查看一些指标以确定新版本与旧版本相比是否具有性能问题,然后他们将决定是否为切换到新版本。使用金丝雀策略,rollout 可以用新版本扩大 ReplicaSet 的规模,以接收指定百分比的流量,等待指定的时间,然后将百分比设置回 0,然后等待用户满意后再发布,为所有的流量提供服务。
  4. 一个用户想慢慢给新版增加生产流量,先给它一小部分的实时流量,然后等待一段时间再给新版本更多的流量,最终,新版本将接收所有生产流量。使用金丝雀策略,用户指定他们希望新版本接收的百分比以及在百分比之间等待的时间。
  5. 用户想要使用 Deployment 中的正常滚动更新策略,如果用户使用没有步骤的金丝雀策略,rollout 将使用 maxSurge 和最大不可用值来滚动到新版本。

Argo Rollouts 架构

img

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。

旧版和新版的 ReplicaSets

这些是标准的 Kubernetes ReplicaSet 资源的实例,Argo Rollouts 给它们添加了一些额外的元数据,以便跟踪属于应用程序的不同版本。

还要注意的是,参加 Rollout 的 ReplicaSet 完全由控制器自动管理,你不应该用外部工具来篡改它们。

Ingress/Service

用户的流量进入集群后,被重定向到合适的版本,Argo Rollouts 使用标准的 Kubernetes Service 资源,但有一些额外的元数据。

Argo Rollouts 在网络配置上非常灵活,首先,可以在 Rollout 期间使用不同的服务,这些服务仅适用于新版本、仅适用于旧版本或两者都适用。特别是对于 Canary 部署,Argo Rollouts 支持多种服务网格和 Ingress 解决方案,用于按特定百分比拆分流量,而不是基于 Pod 数量进行简单的配置。

Analysis 与 AnalysisRun

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

Analysis 只是关于要查询哪些指标的模板。附加到 Rollout 的实际结果是 AnalysisRun 自定义资源,你可以在特定 Rollout 上或在集群上全局定义 Analysis 以供多个 rollout 共享。

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

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

Metric Providers

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

CLI 和 UI

还可以使用 Argo Rollouts CLI 或集成 UI 查看和管理 Rollout,两者都是可选的。

安装

要求

  • Kubernetes 集群
  • 一个 kubectl 可访问的 Kubernetes 的集群

Argo Rollouts 也提供两种类型的安装清单

  • install.yaml: 在默认的 ns 中部署,在一个集群部署仅部署一个 argo-rollouts 应用
  • namespaces-install.yaml: 在不同的 ns 中部署,在一个集群中部署多个 argo-rollouts 应用

安装服务

使用版本 v1.5.1

https://github.com/argoproj/argo-rollouts/tree/v1.5.1/manifests/install.yaml

  • 第一种安装方式

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

[root@node argocd]# kubectl create namespace argo-rollouts
namespace/argo-rollouts created

[root@node argocd]# kubectl apply -n argo-rollouts -f https://ghproxy.com/https://github.com/argoproj/argo-rollouts/releases/download/v1.5.1/install.yaml

安装创建的资源信息

# CRD
customresourcedefinition.apiextensions.k8s.io/analysisruns.argoproj.io created
customresourcedefinition.apiextensions.k8s.io/analysistemplates.argoproj.io created
customresourcedefinition.apiextensions.k8s.io/clusteranalysistemplates.argoproj.io created
customresourcedefinition.apiextensions.k8s.io/experiments.argoproj.io created
customresourcedefinition.apiextensions.k8s.io/rollouts.argoproj.io created

# ServiceAccount
serviceaccount/argo-rollouts created

# RBAC: ClusterRole ClusterRoleBinding
clusterrole.rbac.authorization.k8s.io/argo-rollouts created
clusterrole.rbac.authorization.k8s.io/argo-rollouts-aggregate-to-admin created
clusterrole.rbac.authorization.k8s.io/argo-rollouts-aggregate-to-edit created
clusterrole.rbac.authorization.k8s.io/argo-rollouts-aggregate-to-view created
clusterrolebinding.rbac.authorization.k8s.io/argo-rollouts created

# ConfigMap
configmap/argo-rollouts-config created

# Secret
secret/argo-rollouts-notification-secret created

# Service
service/argo-rollouts-metrics created

# Deployment
deployment.apps/argo-rollouts created

查看 Argo Rollouts 服务

[root@node argocd]# kubectl  -n argo-rollouts get pods
NAME                             READY   STATUS    RESTARTS   AGE
argo-rollouts-577dd4d6bc-trp2k   1/1     Running   0          2m35s
  • 第二种安装方式

使用 Argo CD 部署 Argo Rollouts,继续使用 Git 仓库 https://gitee.com/gmkk/kustomize-demo.git ,把上步骤一使用的 install.yaml 文件放入代码仓库中

img

使用 Argo CD YAML 资源清单创建 APP 服务,首先我们需要先删除上面创建的 argo-rollouts 服务

[root@node argocd]# kubectl delete -n argo-rollouts -f https://ghproxy.com/https://github.com/argoproj/argo-rollouts/releases/download/v1.5.1/install.yaml
warning: deleting cluster-scoped resources, not scoped to the provided namespace
customresourcedefinition.apiextensions.k8s.io "analysisruns.argoproj.io" deleted
customresourcedefinition.apiextensions.k8s.io "analysistemplates.argoproj.io" deleted
customresourcedefinition.apiextensions.k8s.io "clusteranalysistemplates.argoproj.io" deleted
customresourcedefinition.apiextensions.k8s.io "experiments.argoproj.io" deleted
customresourcedefinition.apiextensions.k8s.io "rollouts.argoproj.io" deleted
serviceaccount "argo-rollouts" deleted
clusterrole.rbac.authorization.k8s.io "argo-rollouts" deleted
clusterrole.rbac.authorization.k8s.io "argo-rollouts-aggregate-to-admin" deleted
clusterrole.rbac.authorization.k8s.io "argo-rollouts-aggregate-to-edit" deleted
clusterrole.rbac.authorization.k8s.io "argo-rollouts-aggregate-to-view" deleted
clusterrolebinding.rbac.authorization.k8s.io "argo-rollouts" deleted
configmap "argo-rollouts-config" deleted
secret "argo-rollouts-notification-secret" deleted
service "argo-rollouts-metrics" deleted
deployment.apps "argo-rollouts" deleted
[root@node argocd]# kubectl  -n argo-rollouts get all
No resources found in argo-rollouts namespace.

定义 argo-rollouts 资源清单,并创建服务

## argo-rollouts.yaml
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: argo-rollouts
  namespace: argocd
spec:
  destination:
    name: ''
    namespace: argo-rollouts
    server: 'https://kubernetes.default.svc'
  source:
    path: argorollouts
    repoURL: 'https://gitee.com/gmkk/kustomize-demo.git'
    targetRevision: main
  sources: []
  project: default
  syncPolicy:
    automated:
      prune: true
      selfHeal: false
    syncOptions:
      - CreateNamespace=true

## create
[root@node argocd]# kubectl apply -f argo-rollouts.yaml
application.argoproj.io/argo-rollouts created

[root@node argocd]# kubectl -n argocd get applications
NAME            SYNC STATUS   HEALTH STATUS
argo-rollouts   Synced        Progressing

argo-rollouts

  • 安装 cli 工具

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

[root@node argocd]# curl -LO https://ghproxy.com/https://github.com/argoproj/argo-rollouts/releases/download/v1.5.1/kubectl-argo-rollouts-linux-amd64

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

[root@node argocd]# chmod +x ./kubectl-argo-rollouts-linux-amd64

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

[root@node argocd]# mv ./kubectl-argo-rollouts-linux-amd64 /usr/local/bin/kubectl-argo-rollouts

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

[root@node argocd]# kubectl argo rollouts version
kubectl-argo-rollouts: v1.5.1+839f05d
  BuildDate: 2023-05-24T19:09:27Z
  GitCommit: 839f05d46f838c04b44eff0e573227d40e89ac7d
  GitTreeState: clean
  GoVersion: go1.19.9
  Compiler: gc
  Platform: linux/amd64

安装 Dashboard

使用版本 v1.5.1

https://github.com/argoproj/argo-rollouts/blob/v1.5.1/manifests/dashboard-install.yaml

dashboard-install.yaml 文件,放入 Git 仓库 https://gitee.com/gmkk/kustomize-demo.git 仓库中

img

服务自动进行创建

img

创建 ingress ,访问 Dashboard

## traefik-dashboard.yaml
apiVersion: traefik.containo.us/v1alpha1
kind: IngressRoute
metadata:
  name: argorollouts-dashboard
  namespace: argo-rollouts
spec:
  entryPoints:
    - web
  routes:
  - kind: Rule
    match: Host(`argorollouts.evescn.com`)
    services:
    - name: argo-rollouts-dashboard
      port: 3100

## create
[root@node argocd]# kubectl apply -f traefik-dashboard.yaml
ingressroute.traefik.containo.us/argorollouts-dashboard created

[root@node argocd]# kubectl -n argo-rollouts get ingressroute
NAME                     AGE
argorollouts-dashboard   15s

访问 Dashboard web 界面,目前没有创建数据,所以页面暂时为空

img

蓝绿部署

蓝绿流程

蓝绿部署中需要使用 2 个 SVCactive-svc 对应真实用户访问,preview-svc 对应开发测试同学,当开发测试同学验证 V2 版本没有问题后,回通过 argo rollouts 命令,切换流量到 V2 版本

img

详细的流程如下图:

  • 初始化部署

img

  • 发布新系统到绿环境,开发测试同学验证

img

  • 新版本验证没有问题,进行系统切换

img

  • Argo Rollouts 自动回收老版本 POD

img

创建 Rollout

首先我们需要创建一个 Rollout 资源和一个针对该资源的 Kubernetes Service 对象,这里的 Rollout 采用了蓝绿部署

  • rollout.yaml
## rollout.yaml
apiVersion: argoproj.io/v1alpha1
kind: Rollout
metadata:
  name: simple-rollout
spec:
  replicas: 2
  strategy:
    blueGreen:     
      activeService: bluegreen-active   
      previewService: bluegreen-preview
      # Rollouts can be resumed using: `kubectl argo rollouts promote ROLLOUT`      
      autoPromotionEnabled: false
  revisionHistoryLimit: 2
  selector:
    matchLabels:
      app: web-app
  template:
    metadata:
      labels:
        app: web-app
    spec:
      containers:
      - name: web
        image: evescn/argocd-blue-green:v1
        ports:
        - name: http
          containerPort: 80
          protocol: TCP
  • service-active.yaml
## service-active.yaml
apiVersion: v1
kind: Service
metadata:
  name: bluegreen-active
spec:
  type: NodePort
  selector:
    app: web-app
  ports:
  - nodePort: 31000
    protocol: TCP
    port: 80
  • service-preview.yaml
## service-preview.yaml
apiVersion: v1
kind: Service
metadata:
  name: bluegreen-preview
spec:
  type: NodePort
  selector:
    app: web-app  
  ports:
  - nodePort: 32000
    protocol: TCP
    port: 80

把上述3个文件放入代码仓库 https://gitee.com/gmkk/argocd-example-apps.git argorollout-blue-green 目录下,后续在 Argo CD 上使用 YAML 资源清单创建服务

创建 APP

## demo.yaml
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: demo
  namespace: argocd
spec:
  destination:
    name: ''
    namespace: default
    server: 'https://kubernetes.default.svc'
  source:
    path: argorollout-blue-green
    repoURL: 'https://gitee.com/gmkk/argocd-example-apps.git'
    targetRevision: main
  sources: []
  project: default

## create
[root@node argocd]# kubectl apply -f demo.yaml 
application.argoproj.io/demo created

app

点击 SYNC 同步 APP 服务

img

img

Argo Rollouts 查看服务

[root@node argocd]# kubectl argo rollouts list rollouts 
NAME            STRATEGY   STATUS        STEP  SET-WEIGHT  READY  DESIRED  UP-TO-DATE  AVAILABLE
simple-rollout  BlueGreen  Healthy       -     -           2/2    2        2           2        

[root@node argocd]# kubectl argo rollouts status simple-rollout 
Healthy

## 获取滚动更新的信息
[root@node argocd]# kubectl argo rollouts get rollout simple-rollout

img

更新镜像

方法1 更新 git 仓库配置文件,修改镜像版本从 v1 --> v2

img

查看 Web UI 界面,手动点击 Sync 触发服务更新

img

img

img

因为配置文件中 autoPromotionEnabled: false,需要在命令行手动执行版本切换

[root@node argocd]# kubectl argo rollouts promote simple-rollout
rollout 'simple-rollout' promoted

gif

img

方案2 使用命令行更新

## 更新镜像
[root@node argocd]# kubectl argo rollouts set image simple-rollout web=evescn/argocd-blue-green:v3

## 查看版本信息
[root@node argocd]# kubectl argo rollouts get rollout simple-rollout

img

## 手动执行版本切换
[root@node argocd]# kubectl argo rollouts promote simple-rollout

## 动态观察服务切换信息
[root@node argocd]# kubectl argo rollouts get rollout simple-rollout --watch

img

Dashboard 界面

img

img

中断 Rollout

在生产过程中,如果新版本部署后测试有问题,如何在更新过程中手动中止 Rollout,首先,使用 set image 命令部署一个新的 V1 版本的容器,并等待 rollout 再次达到暂停的步骤。

[root@node argocd]# kubectl argo rollouts set image simple-rollout web=evescn/argocd-blue-green:v1

img

中止更新,而不是将滚动切换到下一步,这样它就回到了 V2 版本,该插件同样提供了一个 abort 命令,可以在更新过程中的任何时候手动中止 Rollout

[root@node argocd]# kubectl argo rollouts abort simple-rollout
rollout 'simple-rollout' aborted

当中止滚动时,它将扩大 ReplicaSetstable 版本(在本例中是 V2 版本),并缩小任何其他版本。尽管 ReplicaSet 的稳定版本可能正在运行,并且是健康的,但整个 Rollout 仍然被认为是退化的,因为期望的版本(V1 版本)不是实际运行的版本。

img