前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >在 Istio 服务网格中使用 Argo Rollouts 实现智能的渐进式发布

在 Istio 服务网格中使用 Argo Rollouts 实现智能的渐进式发布

作者头像
Se7en258
发布2023-02-26 15:58:49
9090
发布2023-02-26 15:58:49
举报
文章被收录于专栏:Se7en的架构笔记Se7en的架构笔记

1 Argo Rollouts 介绍

Kubernetes 原生的 Deployment 利用 Rolling Update 滚动更新的策略在应用升级时提供基本的安全保证(例如就绪探针)。然而默认的滚动更新策略存在着一些明显的缺点,例如:

  • 无法控制流向新版本的流量。
  • 无法控制升级的速度,有可能过于激进地推进升级。
  • 在出现故障时无法进行自动回滚。
  • Readiness probe 仅支持对容器自身进行简单的探测,无法通过查询外部指标来验证更新,例如应用层面整体的请求成功率。

基于以上种种原因,Argo Rollouts[1] 应运而生。Argo Rollouts 可以为 Kubernetes 中的应用提供诸如蓝绿、金丝雀、金丝雀分析、渐进式发布等高级功能。在 Argo Rollouts 中,使用 Rollout 对象替代 Deployment 对象来管理 ReplicaSets 的创建,缩放和删除,这些 ReplicaSet 由 Rollout 资源中的 spec.template 定义,使用与 Deployment 对象相同的 pod 模板。除此之外,Rollout 对象还提供了额外的功能:

  • Blue-Green(蓝绿)Canary(金丝雀) 发布策略。
  • ingress Controller(例如 NGINX, Traefik, AWS ALB) 或者服务网格(例如 Istio, SMI)等进行集成,利用它们的流量整形能力在更新期间逐渐将流量转移到新版本。
  • 在更新的时候执行 Analysis 分析以推动渐进式发布,并根据分析的结果,决定继续更新或者回滚。Analysis 支持与 Prometheus,Datadog, CloudWatch 等监控组件集成来获取相关指标来进行分析。

另外 Analysis 分析会涉及到以下两个 CRD 资源:

  • AnalysisTemplate:AnalysisTemplate 是一个模板,它定义了如何执行金丝雀分析,例如它应该执行的指标、频率以及被视为成功或失败的值,AnalysisTemplate 还可以通过输入值进行参数化。
  • AnalysisRun:当分析开始时,会创建出一个 AnalysisRun 对象,AnalysisRun 是根据一个或多个 AnalysisTemplate 的定义以及输入的参数生成的。AnalysisRun 运行的结果有 3 种状态,分别是:Successful, Failed, Inconclusive,运行的结果分别影响 Rollout 的更新是否继续、中止或暂停。

Argo Rollouts Controller 是一个 Kubernetes 控制器[2] ,负责监视 Argo Rollouts 相关的 CRD 资源,并在资源发生更改时做出反应,另外 Argo Rollouts Controller 还会对 Service 和 VirtualService 进行调整来对流量进行干预。

关于蓝绿发布,金丝雀发布,渐进式交付等概念参见 Concepts[3]

2 前提准备

在开始实验之前,你需要确保安装以下工具:

  • kind[4] 可以用来在本地运行和测试 Kubernetes 集群,它使用 Docker 容器来作为 Kubernetes 的节点。
  • kubectl[5] 是用于管理 Kubernetes 的命令行界面(CLI)工具。
  • Argo Rollouts kubectl plugin[6] 是用于管理 Argo Rollouts 的 kubectl 插件。
  • Istioctl[7] 是用于管理 Istio 服务网格的命令行工具。

本实验涉及的所有文件可以在 Github 上找到。

代码语言:javascript
复制
https://github.com/cr7258/hands-on-lab/tree/main/argo-rollouts/istio

3 创建 Kubernetes 集群

执行以下命令,在本地创建一个 3 节点的 Kubernets 集群。

代码语言:javascript
复制
kind create cluster --config cluster.yaml

集群的配置文件 cluster.yaml 如下。

代码语言:javascript
复制
kind: Cluster
apiVersion: kind.x-k8s.io/v1alpha4
name: argo-rollout-testing
nodes:
- role: control-plane
- role: worker
- role: worker

4 部署 Istio

Istio 是一个开源的服务网格,以透明的接入到分布式服务中,提供了流量管理、安全、可观测性等丰富的功能。在本实验中,Argo Rollouts 将会借助 Istio 的服务治理能力对应用的流量进行控制,在更新时逐步将流量转移到新版本的服务上。执行以下命令,在 Kubernetes 集群中部署 Istio。使用 demo profile 会在集群部署 istio-egressgateway, istio-egressgateway, istiod 组件。关于不同 profile 的介绍参见 Inst‍allation Configuration Profiles[8]

代码语言:javascript
复制
istioctl install --set profile=demo

确保 Istio 的相关组件都已正常运行。

代码语言:javascript
复制
> kubectl get pod -n istio-system
NAME                                    READY   STATUS    RESTARTS   AGE
istio-egressgateway-5bdd756dfd-sbxfv    1/1     Running   0          2m26s
istio-ingressgateway-67f7b5f88d-wb7q5   1/1     Running   0          2m26s
istiod-58c6454c57-44tn4                 1/1     Running   0          3m

5 部署 Argo Rollouts Controller

创建一个新的命名空间 argo-rollouts,并在里面部署 Argo Rollouts Controller。

代码语言:javascript
复制
kubectl create namespace argo-rollouts
kubectl apply -n argo-rollouts -f https://github.com/argoproj/argo-rollouts/releases/latest/download/install.yaml

确保 Argo Rollouts Controller 已正常运行。

代码语言:javascript
复制
> kubectl get pod -n argo-rollouts
NAME                             READY   STATUS    RESTARTS   AGE
argo-rollouts-7f75b9fb76-fxjns   1/1     Running   0          84s

6 部署 Prometheus

Prometheus 是一个开源监控系统和时序数据库,可以使用 Prometheus 来记录 Istio 相关的指标数据从而追踪 Istio 和服务网格中应用程序的健康状况。

Istio 提供了一个基本的示例[9] 安装来快速启动和运行 Prometheus,我们先将该资源文件下载下来。

代码语言:javascript
复制
wget https://raw.githubusercontent.com/istio/istio/release-1.16/samples/addons/prometheus.yaml

用于在第 9 小节中我们需要借助请求的指标(istio_requests_total)来分析新版本应用的健康状态,而该指标来自 Envoy 的统计数据,Envoy 是 Istio 服务网格中的数据平面,因此我们需要在 Prometheus 的配置文件中添加以下内容:

代码语言:javascript
复制
- job_name: 'envoy-stats'
  metrics_path: /stats/prometheus
  kubernetes_sd_configs:
  - role: pod

  relabel_configs:
  - source_labels: [__meta_kubernetes_pod_container_port_name]
    action: keep
    regex: '.*-envoy-prom'

修改完成后,应用该资源文件。确认 Prometheus 已经正常运行。

代码语言:javascript
复制
kubectl get pod -n istio-system -l app=prometheus
NAME                         READY   STATUS    RESTARTS   AGE
prometheus-85949fddb-dbwhd   2/2     Running   0          30s

等待 Prometheus 部署成功后,可以执行以下命令,打开 Prometheus Dashboard。

代码语言:javascript
复制
istioctl dashboard prometheus

点击 Status -> Target 确认可以发现 envoy-stats 。

7 部署 Kiali

kiali 是一款用于管理 istio 服务网格的可视化工具,提供了服务拓扑、全链路跟踪、指标遥测、健康探测、配置校验等功能。

Istio 提供了一个基本的示例[10] 安装来快速启动和运行 Kiali。执行以下命令,在集群中部署 Kiali。

代码语言:javascript
复制
kubectl apply -f https://raw.githubusercontent.com/istio/istio/release-1.16/samples/addons/kiali.yaml

确认 Kiali 的相关组件已经正常运行。

代码语言:javascript
复制
> kubectl get pod -n istio-system -l app=kiali
NAME                    READY   STATUS    RESTARTS   AGE
kiali-849958788-r8ml9   1/1     Running   0          65s

执行以下命令,打开 Kiali Dashboard。

代码语言:javascript
复制
istioctl dashboard kiali

8 部署应用

接下来开始部署我们的应用程序。首先创建一个 Namespace rollouts-demo 用于部署应用,添加 Lable istio-injection: enabled 表示在该 Namespace 启用 Istio 自动注入 ,在后面我们需要通过 Istio 的 VirtualService 和 Gateway 对流量进行管理。

代码语言:javascript
复制
apiVersion: v1
kind: Namespace
metadata:
  labels:
    istio-injection: enabled
  name: rollouts-demo

然后分别为 Stable 和 Canary 两个服务各创建一个 Service。当前这两个 Service 除了名字以外,其他内容完全相同。

代码语言:javascript
复制
apiVersion: v1
kind: Service
metadata:
  name: myapp-canary-svc
  namespace: rollouts-demo
spec:
  ports:
  - port: 80
    targetPort: http
    protocol: TCP
    name: http
  selector:
    app: myapp
    # 进行金丝雀发布时,Argo Rollouts Controller 会自动帮我们添加 Canary 服务 Pod 的 label,例如:
    # rollouts-pod-template-hash: 55bdff45cb

---
apiVersion: v1
kind: Service
metadata:
  name: myapp-stable-svc
  namespace: rollouts-demo
spec:
  ports:
  - port: 80
    targetPort: http
    protocol: TCP
    name: http
  selector:
    app: myapp
    # 进行金丝雀发布时,Argo Rollouts Controller 会自动帮我们添加 Stable 服务 Pod 的 label,例如:
    # rollouts-pod-template-hash: 85f45f96

创建 VirtualService,其中包含一条 HTTP 路由,路由名称以及 Destination 会和后面创建的 Rollout 资源进行关联。当前我们将 stable Service 的权重设置为 100,canary Service 的权重设置为 0,表示所有流量刚开始只发往 stable Service。

代码语言:javascript
复制
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: myapp-vsvc
  namespace: rollouts-demo
spec:
  gateways:
  - myapp-gateway # 关联 Gateway 资源
  hosts:
  - myapp.apps.argoproj.io # 客户端访问的 host
  http:
  - name: primary # 关联 Rollout 的 canary.trafficRouting.istio.virtualService.routes
    route:
    - destination:
        host: myapp-stable-svc # 关联 Rollout 的 canary.stableService
      weight: 100 # 当进行金丝雀发布时,Argo Rollouts Controller 会自动帮助我们调整权重
    - destination:
        host: myapp-canary-svc # 关联 Rollout 的 canary.canaryService
      weight: 0

当进行金丝雀发布时,Argo Rollouts Controller 会自动帮我们做以下事情:

  • 修改 canary Service 的 spec.selector ,添加 rollouts-pod-template-hash label 以匹配 canary 服务的 Pod。
  • 修改 stable Service 的 spec.selector ,添加 rollouts-pod-template-hash label 以匹配 Stable 服务的 Pod。
  • 修改 VirtualService 的 spec.http[].route[].weight 来匹配当前期望的流量比例。

创建 Gateway 资源,接收从客户端入访的流量。

代码语言:javascript
复制
apiVersion: networking.istio.io/v1alpha3
kind: Gateway
metadata:
  name: myapp-gateway
  namespace: rollouts-demo
spec:
  selector:
    istio: ingressgateway # 默认创建的 istio ingressgateway pod 有这个 Label
  servers:
  - port:
      number: 80
      name: http
      protocol: HTTP
    hosts:
    - "*" # 匹配所有 host

9 创建 Rollout 和 AnalysisTemplate

创建一个 AnalysisTemplate 资源,当分析开始时延迟 60s 后启动,每隔 20s 向 Prometheus 查询我们自定义的 PromQL 语句,它没有结束时间,一直持续到停止或失败。该语句表示查询 canary Service 的请求成功率,指标来源于第 6 小节中配置的从 Envoy 采集到的统计数据。

如果查询到的指标值小于 90%,并且存在三个这样的测量值,则分析被视为失败。失败的分析会导致 Rollout 中止,canary Service 的权重将会被设置回零。否则,如果 Rollout 完成所有 的 steps 步骤,则认为本次 Rollout 更新是成功的,之后 Argo Rollouts Controller 将停止运行分析。

代码语言:javascript
复制
apiVersion: argoproj.io/v1alpha1
kind: AnalysisTemplate
metadata:
  name: istio-success-rate
  namespace: rollouts-demo
spec:
  args:
  - name: service
  - name: namespace
  metrics:
  - name: success-rate
    initialDelay: 60s # 延迟 60s 后启动
    interval: 20s # 查询指标的频率
    successCondition: len(result) == 0 || result[0] > 0.90 # 成功条件:测量值为空(指标还没采集到)或者大于 90%
    failureLimit: 3 # 3 次不满足 successCondition 则视为失败
    provider: 
      prometheus:
        address: http://prometheus.istio-system:9090 # Prometheus 地址
        query: >+ # 查询语句
          sum(rate(istio_requests_total{
            reporter="source",
            destination_service=~"{{args.service}}.{{args.namespace}}.svc.cluster.local",
            response_code!~"5.*"}[2m])
          )
          /
          sum(rate(istio_requests_total{
            reporter="source",
            destination_service=~"{{args.service}}.{{args.namespace}}.svc.cluster.local"}[2m])
          )
          unless sum(rate(istio_requests_total{
            reporter="source",
            destination_service=~"{{args.service}}.{{args.namespace}}.svc.cluster.local"}[2m])
          ) == 0

创建 Rollout 资源引用上面创建的 AnalysisTemplates,并传入 servicenamespace 两个参数。然后关联 canary Service,stable Service 以及 Istio VirtualService。在 steps 中设置 Rollout 升级的步骤,一开始会给 canary Service 分配 20% 的流量,需要手动确认通过才会进行下一阶段,然后每隔 60s 依次把 canary Service 的流量增加 20%。Analysis 分析从第 2 步开始,也就是从流量是 20% 的时候开始,也可以设置在后面的阶段再开始分析。

代码语言:javascript
复制
apiVersion: argoproj.io/v1alpha1
kind: Rollout
metadata:
  name: myapp
  namespace: rollouts-demo
spec:
  revisionHistoryLimit: 2
  selector:
    matchLabels:
      app: myapp
  template:
    metadata:
      labels:
        app: myapp
    spec:
      containers:
      - name: myapp
        image: argoproj/rollouts-demo:blue
        ports:
        - name: http
          containerPort: 8080
          protocol: TCP
        resources:
          requests:
            memory: 32Mi
            cpu: 5m
  strategy:
    canary:
      canaryService: myapp-canary-svc # 关联 canary Service
      stableService: myapp-stable-svc # 关联 stable Service
      analysis:
        startingStep: 1   # step 的索引,从第 2 个 step 开始分析(20%),第 1 个是 0% 初始的时候
        templates:
        - templateName: istio-success-rate # 使用的 AnalysisTemplates
        args:   # 传入 AnalysisTemplates 的参数
        - name: service
          value: myapp-canary-svc
        - name: namespace
          valueFrom:
            fieldRef:
              fieldPath: metadata.namespace
      trafficRouting:
        istio:
          virtualService:
            name: myapp-vsvc # 关联的 Istio virtualService
            routes:
            - primary
      steps:
      - setWeight: 20
      - pause: {}         # 需要手动确认通过
      - setWeight: 40
      - pause: {duration: 60s}
      - setWeight: 60
      - pause: {duration: 60s}
      - setWeight: 80
      - pause: {duration: 60s}

10 应用升级

10.1 应用升级前

Argo Rollouts 为我们提供了可视化的 UI 界面方便观察和管理 Rollout 更新。执行以下命令,打开 Argo Rollouts Dashboard。

代码语言:javascript
复制
kubectl argo rollouts dashboard

浏览器输入 http://localhost:3100/rollouts 访问页面。可以看到,当前所有的流量都发往了 stable Service。

除了在图形化界面操作以外,也可以选择使用 Argo Rollout 的命令行工具。执行以下命令获取 Rollout 当前的状态。更多关于命令行的使用方法参见 Rollouts Commands[11]

代码语言:javascript
复制
kubectl argo rollouts get rollout -n rollouts-demo myapp

接下来我们来访问一下应用程序的界面,首先执行以下命令,通过 kubectl port-forward 将 istio ingressgateway 暴露到本地的 28888 端口。

代码语言:javascript
复制
kubectl port-forward -n istio-system svc/istio-ingressgateway 28888:80

由于 VirtualService 根据客户端的 host 进行路由转发,当前我们并没有 DNS 服务器能够解析到在 VirtualService 中设置的域名 myapp.apps.argoproj.io, 因此我们需要在本地主机上添加一条 host 记录。

代码语言:javascript
复制
127.0.0.1  myapp.apps.argoproj.io

在浏览器输入 http://myapp.apps.argoproj.io:28888 访问应用页面,在升级前的应用是 blue 版本。

10.2 第一次升级

执行以下命令,更新应用服务的镜像为 yellow 版本。

代码语言:javascript
复制
kubectl argo rollouts set image myapp -n rollouts-demo myapp=argoproj/rollouts-demo:yellow

你也可以在 Dashboard 上修改镜像版本来触发 Rollout 更新。

现在 canary Service 的流量会维持在 20% 左右,需要等待我们 PROMOTE 推进才会进入到下一阶段。

观察应用界面,发现现在已经开始有少量的黄色方块出现。

在 Kiali 面板可以看到当前 canary Service 和 stable Service 的流量比接近我们设置的 2:8。点击 Display -> 勾选 Traffic Distribution 可以在 Kiali Graph 上显示流量的百分比。

查看 VirtualService 可以发现服务的 weight 值被 Argo Rollouts Controller 修改了。

代码语言:javascript
复制
apiVersion: networking.istio.io/v1beta1
kind: VirtualService
metadata:
  name: myapp-vsvc
  namespace: rollouts-demo
spec:
  gateways:
  - myapp-gateway
  hosts:
  - myapp.apps.argoproj.io
  http:
  - name: primary
    route:
    - destination:
        host: myapp-stable-svc
      weight: 80
    - destination:
        host: myapp-canary-svc
      weight: 20

查看 canary 和 stable Service 会发现 Argo Rollout Controller 为我们自动添加的选择标签来匹配 canary 和 stable 的 Pod。

代码语言:javascript
复制
apiVersion: v1
kind: Service
metadata:
  annotations:
    argo-rollouts.argoproj.io/managed-by-rollouts: myapp
  name: myapp-canary-svc
  namespace: rollouts-demo
spec:
  clusterIP: 10.96.34.227
  clusterIPs:
  - 10.96.34.227
  internalTrafficPolicy: Cluster
  ipFamilies:
  - IPv4
  ipFamilyPolicy: SingleStack
  ports:
  - name: http
    port: 80
    targetPort: http
  selector:
    app: myapp
    rollouts-pod-template-hash: 55bdff45cb # Argo Rollout Controller 自动添加的选择标签
---
apiVersion: v1
kind: Service
metadata:
  annotations:
    argo-rollouts.argoproj.io/managed-by-rollouts: myapp
  name: myapp-stable-svc
  namespace: rollouts-demo
spec:
  clusterIP: 10.96.187.30
  clusterIPs:
  - 10.96.187.30
  internalTrafficPolicy: Cluster
  ipFamilies:
  - IPv4
  ipFamilyPolicy: SingleStack
  ports:
  - name: http
    port: 80
    targetPort: http
  selector:
    app: myapp
    rollouts-pod-template-hash: 85f45f96 # Argo Rollout Controller 自动添加的选择标签

此时 AnalysisRun 会被创建出来,在后台分析 canary Service 的健康状态。

代码语言:javascript
复制
> kubectl get analysisruns.argoproj.io -n rollouts-demo
NAME                 STATUS    AGE
myapp-55bdff45cb-2   Running   4m3s

> kubectl get analysisruns.argoproj.io -n rollouts-demo myapp-55bdff45cb-2 -oyaml
apiVersion: argoproj.io/v1alpha1
kind: AnalysisRun
metadata:
  annotations:
    rollout.argoproj.io/revision: "2"
  creationTimestamp: "2022-12-08T04:07:52Z"
  generation: 12
  labels:
    rollout-type: Background
    rollouts-pod-template-hash: 55bdff45cb
  name: myapp-55bdff45cb-2
  namespace: rollouts-demo
  ownerReferences:
  - apiVersion: argoproj.io/v1alpha1
    blockOwnerDeletion: true
    controller: true
    kind: Rollout
    name: myapp
    uid: 7ec02222-1fc3-4a5e-8cd8-8b6eb7d425a4
  resourceVersion: "171599"
  uid: 3f096c6c-7c6f-4a3f-a96a-e493416b23f8
spec:
  args:
  - name: service
    value: myapp-canary-svc
  - name: namespace
    value: rollouts-demo
  metrics:
  - initialDelay: 60s
    interval: 20s
    name: success-rate
    provider:
      prometheus:
        address: http://prometheus.istio-system:9090
        query: | # 模板
          sum(rate(istio_requests_total{
            reporter="source",
            destination_service=~"{{args.service}}.{{args.namespace}}.svc.cluster.local",
            response_code!~"5.*"}[2m])
          ) / sum(rate(istio_requests_total{
            reporter="source",
            destination_service=~"{{args.service}}.{{args.namespace}}.svc.cluster.local"}[2m])
          ) unless sum(rate(istio_requests_total{
            reporter="source",
            destination_service=~"{{args.service}}.{{args.namespace}}.svc.cluster.local"}[2m])
          ) == 0
    successCondition: len(result) == 0 || result[0] > 0.90
status:
  dryRunSummary: {}
  metricResults:
  - count: 10
    measurements: # 查询结果
    - finishedAt: "2022-12-08T04:08:52Z"
      phase: Successful
      startedAt: "2022-12-08T04:08:52Z"
      value: '[1]'
    - finishedAt: "2022-12-08T04:09:12Z"
      phase: Successful
      startedAt: "2022-12-08T04:09:12Z"
      value: '[1]'
    - finishedAt: "2022-12-08T04:09:32Z"
      phase: Successful
      startedAt: "2022-12-08T04:09:32Z"
      value: '[1]'
    - finishedAt: "2022-12-08T04:09:52Z"
      phase: Successful
      startedAt: "2022-12-08T04:09:52Z"
      value: '[1]'
    - finishedAt: "2022-12-08T04:10:12Z"
      phase: Successful
      startedAt: "2022-12-08T04:10:12Z"
      value: '[1]'
    - finishedAt: "2022-12-08T04:10:32Z"
      phase: Successful
      startedAt: "2022-12-08T04:10:32Z"
      value: '[1]'
    - finishedAt: "2022-12-08T04:10:52Z"
      phase: Successful
      startedAt: "2022-12-08T04:10:52Z"
      value: '[1]'
    - finishedAt: "2022-12-08T04:11:12Z"
      phase: Successful
      startedAt: "2022-12-08T04:11:12Z"
      value: '[1]'
    - finishedAt: "2022-12-08T04:11:32Z"
      phase: Successful
      startedAt: "2022-12-08T04:11:32Z"
      value: '[1]'
    - finishedAt: "2022-12-08T04:11:52Z"
      phase: Successful
      startedAt: "2022-12-08T04:11:52Z"
      value: '[]'
    metadata:
      ResolvedPrometheusQuery: |
        # 渲染后的 PromQL 查询语句
        sum(rate(istio_requests_total{
          reporter="source",
          destination_service=~"myapp-canary-svc.rollouts-demo.svc.cluster.local",
          response_code!~"5.*"}[2m])
        ) / sum(rate(istio_requests_total{
          reporter="source",
          destination_service=~"myapp-canary-svc.rollouts-demo.svc.cluster.local"}[2m])
        ) unless sum(rate(istio_requests_total{
          reporter="source",
          destination_service=~"myapp-canary-svc.rollouts-demo.svc.cluster.local"}[2m])
        ) == 0
    name: success-rate
    phase: Running
    successful: 10
  phase: Running
  runSummary:
    count: 1
  startedAt: "2022-12-08T04:07:52Z"

我们可以将 AnalysisRun 的 PromQL 查询语句复制到 Prometheus 中进行查询。

当前我们请求的成功率为 100%(1),接下来点击 PROMOTE 推进 Rollout 更新。

此时在应用界面可以看到有越来越多的黄色方格。

在 Kiali 上也可以观察到越来越多的流量开始往 canary Service 倾斜。

查看 VirtualService 发现 weight 值再次被 Argo Rollouts Controller 修改了。

代码语言:javascript
复制
apiVersion: networking.istio.io/v1beta1
kind: VirtualService
metadata:
  name: myapp-vsvc
  namespace: rollouts-demo
spec:
  gateways:
  - myapp-gateway
  hosts:
  - myapp.apps.argoproj.io
  http:
  - name: primary
    route:
    - destination:
        host: myapp-stable-svc
      weight: 60
    - destination:
        host: myapp-canary-svc
      weight: 40

等待一会后,升级完成,此时应用界面全部都是黄色的方格。

在 Kiali 上可以看到流量只发往一个 Service 了,这里我觉得 Kiali 的显示有些问题,此时应该全部指向 stable Service,而不是 canary Service,因为当完成升级后,Argo Rollouts Controller 会把 stable Service 的 spec.selector 改成新的 yellow 版本的 Pod 的 Label。

并且 VirtualService 的 destination 也会将 100% 的流量权重设置到 stable Service 上。

代码语言:javascript
复制
apiVersion: networking.istio.io/v1beta1
kind: VirtualService
metadata:
  name: myapp-vsvc
  namespace: rollouts-demo
spec:
  gateways:
  - myapp-gateway
  hosts:
  - myapp.apps.argoproj.io
  http:
  - name: primary
    route:
    - destination:
        host: myapp-stable-svc
      weight: 100
    - destination:
        host: myapp-canary-svc
      weight: 0

10.3 第二次升级

执行以下命令,进行第二次升级,将应用升级到 green 版本。

代码语言:javascript
复制
kubectl argo rollouts set image myapp -n rollouts-demo myapp=argoproj/rollouts-demo:green

观察应用界面,可以看到开始出现少量绿色方格。

点击 PROMOTE 推进 Rollout 更新。

接下来我们模拟应用在升级过程中出现了故障,点击界面上方的绿色按钮,并将访问 ERROR 的比例设置为 65%。

观察 Kiali 界面,可以看到此时访问 canary Service 的流量出现的红色,表明有请求失败,右侧的方框显示了当前请求的成功和失败的比例。

在 Prometheus 界面查询之前的 PromQL 语句,可以看到当前 canary Service 的请求成功率仅有 30% 左右。

查看 Argo Rollouts 界面,发现 Analysis 分析已经失败,Rollout 开始自动回退。

10.4 修复 ERROR 后重新升级

假设经过排查后,我们修复了这个问题,执行以下命令,准备重新升级。

代码语言:javascript
复制
kubectl argo rollouts set image myapp -n rollouts-demo myapp=argoproj/rollouts-demo:purple

这次我们升级到 purple 版本。

点击 PROMOTE 推进 Rollout。

等待一会,这次顺利完成了升级。

11 清理环境

完成实验后,执行以下命令删除 Kubernetes 集群。

代码语言:javascript
复制
kind delete clusters argo-rollout-testing

12 总结

在本文中我们介绍了如何使用 Argo Rollouts 结合 Istio 服务网格中丰富的流量治理以及可观测性能力;并通过 Argo Rollouts 提供的 Analysis 机制,在应用升级时对应用的健康状态进行分析,根据分析结果自动决定是否继续更新或者回滚,从而实现了智能的渐进式发布。

13 参考资料

  • [1] Argo Rollouts 官方文档: https://argoproj.github.io/argo-rollouts/
  • [2] Kubernetes 控制器: https://kubernetes.io/docs/concepts/architecture/controller/
  • [3] Concepts: https://argoproj.github.io/argo-rollouts/concepts/
  • [4] kind: https://kind.sigs.k8s.io/docs/user/quick-start/#installatio
  • [5] kubectl: https://kubernetes.io/docs/tasks/tools/
  • [6] Argo Rollouts kubectl plugin: https://argoproj.github.io/argo-rollouts/installation/#kubectl-plugin-installation
  • [7] Istioctl: https://istio.io/latest/docs/setup/getting-started/#download
  • [8] Installation Configuration Profiles: https://istio.io/latest/docs/setup/additional-setup/config-profiles/
  • [9] Prometheus 安装: https://istio.io/latest/docs/ops/integrations/prometheus/#option-1-quick-start
  • [10] Kiali 安装: https://istio.io/latest/docs/ops/integrations/kiali/#installation
  • [11] Rollouts Commands: https://argoproj.github.io/argo-rollouts/generated/kubectl-argo-rollouts/kubectl-argo-rollouts/
  • [12] Argo Rollouts Demo: https://www.youtube.com/watch?v=hIL0E2gLkf8
  • [13] 使用 Argo Rollouts 实现渐进式发布: https://mp.weixin.qq.com/s/BP9MfGAgPiOYx_EpNOWqjQ
  • [14] Argo Rollouts 实现蓝绿/金丝雀发布: https://mp.weixin.qq.com/s/vTzrNUrG3UvAIQUfbSruow
  • [15] Canary Deployment in Kubernetes (Part 3) — Smart Canary Deployment using Argo Rollouts and Prometheus: https://jhandguy.github.io/posts/smart-canary-deployment/
  • [16] Understanding Istio Telemetry v2: https://blog.christianposta.com/understanding-istio-telemetry-v2/
  • [17] How to monitor Istio, the Kubernetes service mesh: https://sysdig.com/blog/monitor-istio/
  • [18] How to configure Prometheus-Operator & scrape metrics from Istio 1.6: https://tetrate.io/blog/how-to-configure-prometheus-operator-scrape-metrics-from-istio-1-6/#Install-Prometheus
  • [19] Progressive Delivery with Argo Rollouts: Canary with Analysis: https://www.infracloud.io/blogs/progressive-delivery-argo-rollouts-canary-analysis/
本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2022-12-10,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 Se7en的架构笔记 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 1 Argo Rollouts 介绍
  • 2 前提准备
  • 3 创建 Kubernetes 集群
  • 4 部署 Istio
  • 5 部署 Argo Rollouts Controller
  • 6 部署 Prometheus
  • 7 部署 Kiali
  • 8 部署应用
  • 9 创建 Rollout 和 AnalysisTemplate
  • 10 应用升级
    • 10.1 应用升级前
      • 10.2 第一次升级
        • 10.3 第二次升级
          • 10.4 修复 ERROR 后重新升级
          • 11 清理环境
          • 12 总结
          • 13 参考资料
          相关产品与服务
          容器服务
          腾讯云容器服务(Tencent Kubernetes Engine, TKE)基于原生 kubernetes 提供以容器为核心的、高度可扩展的高性能容器管理服务,覆盖 Serverless、边缘计算、分布式云等多种业务部署场景,业内首创单个集群兼容多种计算节点的容器资源管理模式。同时产品作为云原生 Finops 领先布道者,主导开源项目Crane,全面助力客户实现资源优化、成本控制。
          领券
          问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档