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

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

金丝雀发布

接下来我们通过几个简单的示例来说明 Rollout 的部署、升级、发布和中断等操作,以此来展示 Rollouts 的各种功能。

1. 部署 Rollout

首先我们部署一个 Rollout 资源和一个针对该资源的 Kubernetes Service 对象,这里我们示例中的 Rollout 采用了金丝雀的更新策略,将 20% 的流量发送到金丝雀上,然后手动发布,最后在升级的剩余时间内逐渐自动增大流量,可以通过如下所示的 Rollout 来描述这个策略:

# basic-rollout.yaml
apiVersion: argoproj.io/v1alpha1
kind: Rollout
metadata:
  name: rollouts-demo
spec:
  replicas: 5 # 定义5个副本
  strategy: # 定义升级策略
    canary: # 金丝雀发布
      steps: # 发布的节奏
        - setWeight: 20
        - pause: {} # 会一直暂停
        - setWeight: 40
        - pause: { duration: 10 } # 暂停10s
        - setWeight: 60
        - pause: { duration: 10 }
        - setWeight: 80
        - pause: { duration: 10 }
  revisionHistoryLimit: 2 # 下面部分其实是和 Deployment 兼容的
  selector:
    matchLabels:
      app: rollouts-demo
  template:
    metadata:
      labels:
        app: rollouts-demo
    spec:
      containers:
        - name: rollouts-demo
          image: argoproj/rollouts-demo:blue
          ports:
            - name: http
              containerPort: 8080
              protocol: TCP
          resources:
            requests:
              memory: 32Mi
              cpu: 5m

还包括一个如下所示的 Service 资源对象:

# basic-service.yaml
apiVersion: v1
kind: Service
metadata:
  name: rollouts-demo
spec:
  ports:
    - port: 80
      targetPort: http
      protocol: TCP
      name: http
  selector:
    app: rollouts-demo

直接创建上面的两个资源对象:

$ kubectl apply -f basic-rollout.yaml
$ kubectl apply -f basic-service.yaml

任何 Rollout 的初始创建都会立即将副本扩展到 100%(跳过任何金丝雀升级步骤、分析等...),因为还没有发生升级。

$ kubectl get pods -l app=rollouts-demo
NAME                             READY   STATUS    RESTARTS   AGE
rollouts-demo-687d76d795-7xztq   1/1     Running   0          4m48s
rollouts-demo-687d76d795-bnnwx   1/1     Running   0          4m48s
rollouts-demo-687d76d795-dtlns   1/1     Running   0          4m48s
rollouts-demo-687d76d795-q6867   1/1     Running   0          4m48s
rollouts-demo-687d76d795-zlzdv   1/1     Running   0          4m48s

Argo Rollouts 的 kubectl 插件允许我们可视化 Rollout 以及相关资源对象,并展示实时状态变化,要在部署过程中观察 Rollout,可以通过运行插件的 ​​get rollout --watch​​ 命令,比如:

$ kubectl argo rollouts get rollout rollouts-demo --watch

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

2. 更新 Rollout

上面已经部署完成,接下来就需要执行更新了,和 Deployment 类似,对 Pod 模板字段的任何变更都会导致新的版本(即 ReplicaSet)被部署,更新 Rollout 通常是修改容器镜像的版本,然后执行 ​​kubectl apply​​​ ,为了方便,rollouts 插件还单独提供了一个 ​​set image​​​ 的命令,比如这里我们运行以下所示命令,用 ​​yellow​​ 版本的容器更新上面的 Rollout:

$ kubectl argo rollouts set image rollouts-demo \
  rollouts-demo=argoproj/rollouts-demo:yellow
rollout "rollouts-demo" image updated

在 rollout 更新期间,控制器将通过 Rollout 更新策略中定义的步骤进行。这个示例的 rollout 为金丝雀设置了 20% 的流量权重,并一直暂停 rollout,直到用户取消或促进发布。在更新镜像后,再次观察 rollout,直到它达到暂停状态。

$ kubectl argo rollouts get rollout rollouts-demo --watch

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

当 demo rollout 到达第二步时,我们可以从插件中看到,Rollout 处于暂停状态,现在有 5 个副本中的 1 个运行新版本的 pod,其余 4 个仍然运行旧版本,这相当于 ​​setWeight: 20​​ 步骤所定义的 20%的金丝雀权重。

3. Promote Rollout

经过上面的更新后,Rollout 现在处于暂停状态,当一个 Rollout 到达一个没有持续时间的暂停步骤时,它将一直保持在暂停状态,直到它被恢复/继续。要手动将 Rollout 切换到下一个步骤,请运行插件的 ​​promotion​​ 命令。

$ kubectl argo rollouts promote rollouts-demo
rollout 'rollouts-demo' promoted

切换后 Rollout 将继续执行剩余的步骤。在我们的例子中,剩余的步骤是完全自动化的,所以 Rollout 最终会完成步骤,直到它已经完全过渡到新版本。再次观察 Rollout,直到它完成所有步骤。

$ kubectl argo rollouts get rollout rollouts-demo --watch

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

​promote​​​ 命令还支持用 ​​--full​​ 标志跳过所有剩余步骤和分析。

可以看到 ​​stable​​​ 版本已经切换到 ​​revision:2​​​ 这个 ReplicaSet 了。在更新过程中,无论何时,无论是通过失败的金丝雀分析自动中止,还是由用户手动中止,Rollout 都会退回到 ​​stable​​ 版本。

4. 中断 Rollout

接下来我们来了解如何在更新过程中手动中止 Rollout,首先,使用 ​​set image​​​ 命令部署一个新的 ​​red​​ 版本的容器,并等待 rollout 再次达到暂停的步骤。

$ kubectl argo rollouts set image rollouts-demo \
  rollouts-demo=argoproj/rollouts-demo:red
rollout "rollouts-demo" image updated

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

$ kubectl argo rollouts abort rollouts-demo

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

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

为了使 Rollout 再次被认为是健康的而不是有问题的版本,有必要将所需的状态改回以前的稳定版本。在我们的例子中,我们可以简单地使用之前的 ​​yellow​​​ 镜像重新运行 ​​set image​​ 命令即可。

$ kubectl argo rollouts set image rollouts-demo \
  rollouts-demo=argoproj/rollouts-demo:yellow

运行这个命令后,可以看到 Rollout 立即变成了 health 状态,而且没有任何关于创建新 ReplicaSets 的动态。

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

当 Rollout 还没有达到预期状态(例如它被中止了,或者正在更新中),而稳定版本的资源清单被重新应用,Rollout 检测到这是一个回滚,而不是一个更新,并将通过跳过分析和步骤快速部署稳定的 ReplicaSet。

Argo Rollouts 与 NGINX Ingress 集成

上面例子中的 Rollout 没有使用 Ingress 控制器或服务网格来控制流量。它使用 Kubernetes Service 来实现近似的金丝雀权重,基于新旧副本数量的比例来实现。所以,这个 Rollout 有限制,为了实现更细粒度的金丝雀,这就需要一个 Ingress 控制器或服务网格了。

接下来我们介绍下 Argo Rollouts 如何与 NGINX Ingress Controller 集成以进行流量控制。

当然首先要保证已经在集群中安装了 ingress-nginx 控制器。当 NGINX Ingress 用作流量路由器时,Rollout 金丝雀策略必须定义以下强制字段:

apiVersion: argoproj.io/v1alpha1
kind: Rollout
metadata:
  name: rollouts-demo
spec:
  strategy:
    canary:
      # 引用一个 Service,控制器将更新该服务以指向金丝雀 ReplicaSet
      canaryService: rollouts-demo-canary
      # 引用一个 Service,控制器将更新该服务以指向稳定的 ReplicaSet
      stableService: rollouts-demo-stable
      trafficRouting:
        nginx:
          # 指向稳定 Service 的规则所引用的 Ingress
          # 该 Ingress 将被克隆并赋予一个新的名称,以实现NGINX流量分割。
          stableIngress: rollouts-demo-stable

其中 ​​canary.trafficRouting.nginx.stableIngress​​​ 中引用的 Ingress 需要有一个 host 规则,该规则具有针对 ​​canary.stableService​​ 下引用的服务的后端。

接下来按照上面的描述来定义我们示例的资源清单文件:

# rollout.yaml
apiVersion: argoproj.io/v1alpha1
kind: Rollout
metadata:
  name: rollouts-demo
spec:
  replicas: 1
  strategy:
    canary:
      canaryService: rollouts-demo-canary
      stableService: rollouts-demo-stable
      trafficRouting:
        nginx:
          stableIngress: rollouts-demo-stable
      steps:
        - setWeight: 5
        - pause: {}
  revisionHistoryLimit: 2
  selector:
    matchLabels:
      app: rollouts-demo
  template:
    metadata:
      labels:
        app: rollouts-demo
    spec:
      containers:
        - name: rollouts-demo
          image: argoproj/rollouts-demo:blue
          ports:
            - name: http
              containerPort: 8080
              protocol: TCP
          resources:
            requests:
              memory: 32Mi
              cpu: 5m

上面的资源清单中,我们定义了一个 ​​rollouts-demo​​​ 的 Rollout 资源,它的 ​​canaryService​​​ 和 ​​stableService​​​ 分别引用了两个 Service 资源, ​​stableIngress​​​ 引用了一个 Ingress 资源,​​steps​​ 定义了金丝雀发布的步骤,这里我们定义了两个步骤,第一个步骤将权重设置为 5%,第二个步骤是暂停,这样就可以在第一个步骤中将 5% 的流量发送到金丝雀上,然后手动发布,最后在升级的剩余时间内逐渐自动增大流量。对应的 Service 资源对象如下所示:

# service.yaml
apiVersion: v1
kind: Service
metadata:
  name: rollouts-demo-canary
spec:
  ports:
    - port: 80
      targetPort: http
      protocol: TCP
      name: http
  selector:
    app: rollouts-demo
    # 该 selector 将使用金丝雀 ReplicaSet 的 pod-template-hash 进行更新,比如 rollouts-pod-template-hash: 7bf84f9696
---
apiVersion: v1
kind: Service
metadata:
  name: rollouts-demo-stable
spec:
  ports:
    - port: 80
      targetPort: http
      protocol: TCP
      name: http
  selector:
    app: rollouts-demo
    # 该 selector 将使用稳定版的 ReplicaSet 的 pod-template-hash 进行更新,比如 rollouts-pod-template-hash: 789746c88d

然后最后还需要定义一个 Ingress 对象:

# ingress.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: rollouts-demo-stable
spec:
  ingressClassName: nginx
  rules:
    - host: rollouts-demo.local
      http:
        paths:
          - path: /
            pathType: Prefix
            backend:
              service:
                # 引用服务名称,也在 Rollout spec.strategy.canary.stableService 字段中指定
                name: rollouts-demo-stable
                port:
                  number: 80

接下来我们先删除前面示例的资源对象:

$ kubectl delete -f basic-rollout.yaml
$ kubectl delete -f basic-service.yaml

然后再创建上面的资源对象:

$ kubectl apply -f rollout.yaml
$ kubectl apply -f service.yaml
$ kubectl apply -f ingress.yaml

应用清单后,我们可以在集群中看到以下资源对象:

$ kubectl get ro
NAME            DESIRED   CURRENT   UP-TO-DATE   AVAILABLE   AGE
rollouts-demo   1         1         1            1           69s
$ kubectl get svc
NAME                   TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)   AGE
rollouts-demo-canary   ClusterIP   10.111.85.229    <none>        80/TCP    72s
rollouts-demo-stable   ClusterIP   10.110.107.123   <none>        80/TCP    72s
$ kubectl get ing
NAME                                        CLASS   HOSTS                 ADDRESS   PORTS   AGE
rollouts-demo-rollouts-demo-stable-canary   nginx   rollouts-demo.local             80      41s
rollouts-demo-stable                        nginx   rollouts-demo.local             80      41s

我们可以注意到新增了一个名为 ​​rollouts-demo-rollouts-demo-stable-canary​​​ 的 Ingress 对象。这个对象是 ​​canary ingress​​​,它是 ​​nginx.stableIngress​​​ 下引用的用户管理 Ingress 的克隆。 nginx ingress 控制器使用它来实现金丝雀流量分割。生成的入口的名称是使用 ​​<ROLLOUT-NAME>-<INGRESS-NAME>-canary​​ 制定的。

同样现在也可以查看 Rollout 对象的具体状态:

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

接下来我们通过更改镜像版本来更新发布,然后等待它达到暂停状态。

$ kubectl argo rollouts set image rollouts-demo rollouts-demo=argoproj/rollouts-demo:yellow
kubectl argo rollouts get rollout rollouts-demo

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

此时,Rollout 的金丝雀版和稳定版都在运行,其中 ​​5%​​ 的流量路由到金丝雀版。需要注意的一件事是,尽管只运行两个 pod,但此次发布仍能够实现 5% 的金丝雀权重。这是能够实现的,因为流量分割发生在 Ingress 控制器处。

可以通过访问该 Demo 来大致了解:

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

当检查 rollout 控制器生成的 Ingress 副本时,我们发现它比原始 Ingress 有以下变化:

  • 注解中添加了两个额外的 NGINX 特定金丝雀注解。
  • Ingress 规则将有一条将后端指向金丝雀服务的规则。

对应的资源清单如下所示:

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  annotations:
    nginx.ingress.kubernetes.io/canary: "true"
    nginx.ingress.kubernetes.io/canary-weight: "5"
  name: rollouts-demo-rollouts-demo-stable-canary
  namespace: default
spec:
  ingressClassName: nginx
  rules:
    - host: rollouts-demo.local
      http:
        paths:
          - backend:
              service:
                name: rollouts-demo-canary
                port:
                  number: 80
            path: /
            pathType: Prefix

随着 Rollout 逐步进行,​​canary-weight​​​ 注解将调整以匹配步骤的当前 ​​setWeight​​。NGINX Ingress 控制器检查原始 Ingress、金丝雀 Ingress 和金丝雀权重注解,以确定在两个入口之间分配的流量百分比。NGINX Ingress 如何实现金丝雀流量分割在 NGINX Ingress 章节中我们已经详细讲解过了。

最后我们可以执行 ​​promote​​ 命令来将 Rollout 推进到下一个步骤,这样就完成了金丝雀发布。

$ kubectl argo rollouts promote rollouts-demo
rollout 'rollouts-demo' promoted

当然此时应用会全部切换到 ​​yellow​​ 版本的容器:

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


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

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