GitOps and Kubernetes Continuous Deployment with Argo CD, Jenkins X, and Flux

1、部署基础

1.1、ReplicaSet 不是声明式的

ReplicaSet 不是声明式的,因此不适合 GitOps。

现在有一个 ReplicaSet.yaml 文件:

apiVersion: apps/v1 
kind: ReplicaSet 
metadata: 
  name: demo
  labels: 
    app: demo 
spec: 
  replicas: 2 
  selector: 
    matchLabels: 
      app: demo 
  template: 
    metadata: 
      labels: 
        app: demo 
    spec: 
      containers: 
      - name: demo 
        image: argoproj/rollouts-demo:blue 
        imagePullPolicy: Always 
        ports: 
        - containerPort: 8080 
---
apiVersion: v1 
kind: Service 
metadata: 
  name: demo 
  labels: 
    app: demo 
spec: 
  ports: 
  - protocol: TCP 
    port: 80 
    targetPort: 8080 
  selector: 
    app: demo
kubectl apply -f ReplicaSet.yaml

在初始的 ReplicaSet.yaml 中指定的副本数是2个,并且镜像是 blue 的。

现在我们把副本数改为3,并且镜像改为 green。

kubectl apply -f ReplicaSet.yaml

第三个 Pod 的镜像标签是绿色的,但前两个 Pod 仍然是蓝色的,因为 ReplicaSet 控制器的工作只是保证运行的 Pod 数量。

如果 ReplicaSet 是声明式的,则所有三个 Pod 都应该是绿色的。

1.2、Deployment 是声明式的

部署是完全声明式的,并且完美补充了 GitOps。Deployment 执行滚动更新以零停机时间部署服务。让我们通过一个教程来了解 Deployment 如何使用多个 ReplicaSet 实现滚动更新。

滚动更新允许通过使用新的 Pod 实例增量更新来实现零停机更新。如果服务是无状态且向后兼容的,则滚动更新效果很好。否则,您将不得不研究其他部署策略,例如蓝绿部署策略。

让我们想象一下它如何适用的现实生活场景。假设您为小型企业提供处理信用卡的支付服务。该服务需要 24/7 可用,并且您已经运行了两个 Pod(蓝色)来处理。您注意到两个 Pod 已达到最大容量,因此您决定扩展到三个 Pod(蓝色)以支持增加的流量。接下来,您的产品经理想要添加借记卡支持,因此您需要部署一个具有三个 Pod(绿色)且停机时间为零的版本:

刚开始,我们有一个 Deployment 和一个 ReplicaSet ,由 demo deployment 创建和控制。 ReplicaSet 使用蓝色管理 Pod 的两个副本。接下来,我们将 yaml 文件中的副本数改为3。
更新后,我们应该看到现在管理三个蓝色 Pod 的相同 Deployment 和 ReplicaSet。此时,部署看起来如图 5.5 所示。接下来,我们将 yaml 中的镜像更新为绿色并应用更改。由于镜像已更改,Deployment 将创建第二个 ReplicaSet 来部署绿色镜像。

会发现:deployment 使用第二个 ReplicaSet 来启动一个绿色 Pod,并使用第一个 ReplicaSet 终止一个蓝色 Pod,如图 5.6 所示。此过程将重复,直到创建所有三个绿色 Pod,同时终止所有蓝色 Pod。

在讨论 Deployment 的同时,我们还应该讨论 Deployment 中滚动更新策略的两个重要配置参数:max unavailablemax surge

部署可确保更新时只有一定数量的 Pod 处于关闭状态。默认情况下,它确保至少有 75% 的所需 Pod 数量处于运行状态(25%max unavailable)。

部署还确保仅创建高于所需 Pod 数量的一定数量的 Pod。默认情况下,它确保最多 125% 的所需 Pod 数量处于启动状态( 25%max surge)。

让我们看看它是如何运作的。我们将图像 ID 更改回蓝色,并将 max unavailable 设置为 3,将 max surge 设置为 3:

从 ReplicaSet 更改状态可以看到,ReplicaSet 绿色立即变为 0 个 Pod,ReplicaSet 蓝色立即变为 3 个 Pod,而不是一次 1 个。

至此, Deployment 通过利用一个蓝色 ReplicaSet 和另一个绿色 ReplicaSet,实现了零停机部署。本章的其他部署策略,都是使用两个不同的 ReplicaSet 来类似地实现的。

1.3、流量路由

K8s中使用 service 这个概念进行流量路由:

如果底层 Pod 是无状态且向后兼容的,服务会进行循环负载平衡,并且非常适合滚动更新。如果您需要为您的部署自定义负载平衡,则需要探索其他路由选择。

NGINX Ingress Controller 可用于许多用例,并支持各种平衡和路由规则。 Ingress Controller 可以配置为前端负载均衡器,以执行自定义路由,例如 TLS 终止、URL 重写或通过定义自定义规则将流量路由到任意数量的服务。图说明了 NGINX 控制器配置了规则,将 40% 的传入流量发送到服务蓝色,将 60% 的传入流量发送到服务绿色。

Istio Gateway 是另一个支持丰富的流量路由配置的负载均衡器。在此示例中,自定义配置被定义为将 40% 的流量发送到蓝色服务,将 60% 的流量发送到绿色服务。

2、Blue-green

正如您在上一节中了解到的,部署的滚动更新是更新应用程序的好方法,因为应用程序将在部署期间使用大约相同数量的资源,并且停机时间为零且对性能的影响最小。然而,由于向后不兼容或有状态,许多遗留应用程序不能很好地支持滚动更新。某些应用程序可能还需要部署新版本并立即切换到新版本或在出现问题时快速回滚。

对于这些用例,蓝绿部署将是合适的部署策略。蓝绿部署通过同时完全扩展两个 deployment 来实现这些动机,但仅将传入流量定向到两个 deployment 之一。

初始部署将配置 NGINX 控制器将所有流量发送到 blue 服务。蓝色服务将依次将流量发送到蓝色 Pod。

NGINX 控制器中的配置更新后,所有流量将发送到绿色服务。绿色服务将依次将流量发送到绿色 Pod。

蓝绿发布的过程是:

  • 创建蓝色 deployment 和 service。

  • 创建 ingress 以将流量引导至蓝色 service。

  • 一段时间后,需要将蓝色变为绿色。

  • 部署绿色 deployment 和 service,等待所有 Pod 准备就绪。

  • 更新 ingress 以将流量引导至绿色 service。

  • 不需要蓝色了就全部删除

3、Canary

金丝雀部署是一种降低在生产环境中引入新软件版本的风险的技术,方法是在短时间内向一小部分用户推出更改,然后再将其提供给所有人。金丝雀充当失败的早期指示器,以避免有问题的部署同时对所有客户产生全面影响。如果一个金丝雀部署失败,其余服务器不会受到影响,可以简单地终止金丝雀并对问题进行分类。

随着 Canary 运行并获得生产流量,我们可以在固定时间段(例如一小时)内监控 Canary 健康状况(延迟、错误等),以确定是否扩大绿色部署并将所有流量路由到绿色。

Ingress 控制器将同时面向蓝色和绿色服务,但在这种情况下,90% 的流量将流向蓝色(生产)服务,10% 将流向绿色(金丝雀)服务。由于 green 仅获得 10% 的流量,因此我们将仅扩展 1 个 green Pod 以最大程度地减少资源使用。

如果金丝雀 Pod 没有错误,绿色部署将扩展到三个 Pod,并接收 100% 的生产流量。

金丝雀发布的过程是:

  • 创建蓝色 deployment 和 service(生产)。

  • 创建 ingress 以将流量引导至蓝色 service。

  • 部署绿色 deployment(1个Pod)和 service,等待所有 Pod 准备就绪。

  • 创建金丝雀 ingress,将 10% 的流量引导至绿色 service。

  • 没有错误后

  • 将绿色 deployment 扩展到三个 Pod。

  • 更新金丝雀 ingress,将 100% 的流量发送到绿色 service。

  • 将蓝色 deployment 缩减至 0。

4、总结

优点

缺点

Deployment

内置于 Kubernetes 滚动更新

仅向后兼容和无状态应用程序

Blue-green

适用于有状态应用程序和非向后兼容部署快速回滚

部署期间需要两倍的资源

Canary

使用生产流量和与部分用户的依赖关系来验证新版本

需要额外的自动化、更长的部署过程、仅向后兼容和无状态应用程序

  • ReplicaSet 不是声明式的,不适合 GitOps。

  • 部署是完全声明式的,并且是对 GitOps 的补充。

  • 部署执行滚动更新,最适合无状态和向后兼容的部署。

  • 可以使用 max surge 来自定义部署,以指定新 Pod 的数量,并使用 max unavailable 来限制被终止的 Pod 数量。

  • Argo Rollouts 是一个开源项目,可以简化蓝绿、金丝雀和渐进式部署。