原生应用蓝绿发布

在现代软件开发中,部署原生应用的新版本是开发周期中的关键部分。然而,将更新发布到生产环境可能是一件风险较高的事情,因为即使是很小的问题也可能导致明显的停机时间和收入损失。蓝绿发布是一种通过确保原生应用新版本可以在零停机时间下部署,从而缓解这一风险的部署策略。

蓝绿发布是一种部署策略,其中会搭建两个相同的环境:“蓝色”环境和“绿色”环境。蓝色环境是生产环境,当前正在运行应用的正式版本;绿色环境是非生产环境,用于部署应用的新版本。

当应用的新版本准备好部署时,它会被部署到绿色环境中。新版本部署并测试完成后,流量会切换到绿色环境,使其成为新的生产环境。随后,蓝色环境将变为非生产环境,供将来部署应用的后续版本使用。

蓝绿发布的优势

  • 零停机时间:蓝绿发布允许原生应用的新版本在零停机时间下部署,因为流量会无缝地从蓝色环境切换到绿色环境。

  • 易于回滚:如果原生应用的新版本出现问题,可以轻松回滚到之前的版本,因为蓝色环境仍然可用。

  • 降低风险:通过使用蓝绿发布,部署原生应用新版本的风险会显著降低。这是因为在流量从蓝色环境切换之前,新版本可以先在绿色环境中部署并测试。这允许进行充分测试,并减少生产环境中出现问题的可能性。

  • 提高可靠性:通过使用蓝绿发布,原生应用的可靠性会提高。这是因为蓝色环境始终可用,而绿色环境中的任何问题都可以在不影响用户的情况下快速识别并解决。

  • 灵活性:蓝绿发布在部署过程中提供了更高的灵活性。可以并排部署同一应用的多个版本,便于测试和实验。

使用 Argo Rollouts 进行蓝绿发布

Argo Rollouts 是一个 Kubernetes controller 和一组 CRD,可为 Kubernetes 提供蓝绿、金丝雀、金丝雀分析、实验以及渐进式交付等高级部署能力。

Argo Rollouts 还可以(可选地)与 ingress controller 和 service mesh 集成,利用它们的流量整形能力,在更新过程中逐步将流量切换到新版本。此外,Rollouts 还可以查询并解析来自各种 provider 的指标,以验证关键 KPI,并在更新过程中驱动自动晋升或回滚。

借助 Argo Rollouts,你可以在 Alauda Container Platform (ACP) 集群上自动化蓝绿发布。典型流程包括:

  1. 定义 Rollout 资源以管理不同的应用版本。
  2. 配置 Kubernetes service 在蓝色(当前)和绿色(新)环境之间路由流量。
  3. 将新版本部署到绿色环境。
  4. 验证并测试新版本。
  5. 通过切换流量,将绿色环境晋升为生产环境。

这种方法可以最小化停机时间,并实现受控、安全的部署。

关键概念:

  • Rollout:Kubernetes 中的一个自定义资源定义(CRD),用于替代标准 Deployment 资源,从而启用蓝绿、金丝雀部署等高级部署控制。

前提条件

  1. ACP(Alauda Container Platform)。
  2. 由 ACP 管理的 Kubernetes Cluster。
  3. 已在集群中安装 Argo Rollouts。
  4. Argo Rollouts kubectl plugin。
  5. 一个可在其中创建 namespace 的 project。
  6. 集群中用于部署应用的 namespace。

操作步骤

创建 Deployment

首先定义应用的“蓝色”版本。这是用户当前将访问的版本。创建一个 Kubernetes Deployment,并设置合适的副本数、container image 版本(例如 hello:1.23.1)以及正确的标签,例如 app=web

使用以下 YAML:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: web
spec:
  replicas: 2
  selector:
    matchLabels:
      app: web
  template:
    metadata:
      labels:
        app: web
    spec:
      containers:
        - name: web
          image: hello:1.23.1
          ports:
            - containerPort: 80

YAML 字段说明:

  • apiVersion:用于创建资源的 Kubernetes API 版本。
  • kind:指定这是一个 Deployment 资源。
  • metadata.name:deployment 的名称。
  • spec.replicas:期望的 pod 副本数。
  • spec.selector.matchLabels:定义 Deployment 如何查找要管理的 pod。
  • template.metadata.labels:应用于 pod 的标签,供 Service 选择它们。
  • spec.containers:要在每个 pod 中运行的容器。
  • containers.name:容器名称。
  • containers.image:要运行的容器镜像。
  • containers.ports.containerPort:容器暴露的端口。

使用 kubectl 应用配置:

kubectl apply -f deployment.yaml

这样就完成了生产环境的搭建。

另外,你也可以使用 Helm Chart 来创建 deployment 和 service。

创建蓝色 Service

创建一个暴露蓝色 deployment 的 Kubernetes Service。该 service 会基于匹配标签将流量转发到蓝色 pod。初始状态下,service selector 会选择带有 app=web 标签的 pod。

apiVersion: v1
kind: Service
metadata:
  name: web
spec:
  selector:
    app: web
  ports:
  - protocol: TCP
    port: 80
    targetPort: 80

YAML 字段说明:

  • apiVersion:用于创建 Service 的 Kubernetes API 版本。
  • kind:指定该资源是一个 Service。
  • metadata.name:Service 的名称。
  • spec.selector:基于标签标识要将流量路由到哪些 pod。
  • ports.protocol:所使用的协议(TCP)。
  • ports.port:Service 暴露的端口。
  • ports.targetPort:流量被转发到的容器端口。

使用以下命令应用:

kubectl apply -f web-service.yaml

这样就可以对蓝色 deployment 提供外部访问。

验证蓝色 Deployment

通过列出 pod,确认 blue deployment 正常运行:

kubectl get pods -l app=web

检查所有预期的副本(2 个)是否都处于 Running 状态。这可以确保应用已准备好接收流量。

验证流量路由到蓝色

确保 web service 正确地将流量转发到蓝色 deployment。使用以下命令:

kubectl describe service web | grep Endpoints

输出应列出蓝色 pod 的 IP 地址。这些就是接收流量的 endpoint。

创建 Rollout

接下来,使用 BlueGreen 策略创建来自 Argo Rollouts 的 Rollout 资源。

apiVersion: argoproj.io/v1alpha1
kind: Rollout
metadata:
  name: rollout-bluegreen
spec:
  replicas: 2
  revisionHistoryLimit: 2
  selector:
    matchLabels:
      app: web
  workloadRef:
    apiVersion: apps/v1
    kind: Deployment
    name: web
    scaleDown: onsuccess
  strategy:
    blueGreen:
      activeService: web
      autoPromotionEnabled: false

YAML 字段说明:

  • spec.selector:pod 的标签选择器。由此选择的现有 ReplicaSet 将受到该 rollout 的影响。它必须与 pod template 的标签匹配。

  • workloadRef:指定要应用 rollouts 的 workload 引用和 scale down 策略。

    • scaleDown:指定在迁移到 Rollout 后是否缩减 workload(Deployment)。可选项如下:
      • "never":Deployment 不会缩减。
      • "onsuccess":当 Rollout 变为 healthy 后,Deployment 会被缩减。
      • "progressively":随着 Rollout 扩容,Deployment 也会被缩减。如果 Rollout 失败,Deployment 会重新扩容。
  • strategy:rollout 策略,支持 BlueGreenCanary 策略。

    • blueGreenBlueGreen rollout 策略定义。
      • activeService:指定在晋升时要更新为新 template hash 的 service。该字段是 blueGreen 更新策略的必填项。
      • autoPromotionEnabled:通过在晋升前立即暂停 rollout 来禁用新版本栈的自动晋升。如果省略,则默认行为是在 ReplicaSet 完全 ready/available 后立即晋升新版本栈。可使用以下命令恢复 Rollout:kubectl argo rollouts promote ROLLOUT

使用以下命令应用:

kubectl apply -f rollout.yaml

这样就为使用 BlueGreen 策略的 deployment 设置好了 rollouts。

验证 Rollouts

创建 Rollout 后,Argo Rollouts 会创建一个与 deployment template 相同的新 ReplicaSet。当新 ReplicaSet 的 pod 处于 healthy 状态时,deployment 会被缩减到 0。

使用以下命令确保 pod 正常运行:

kubectl argo rollouts get rollout rollout-bluegreen
Name:            rollout-bluegreen
Namespace:       default
Status: Healthy
Strategy:        BlueGreen
Images:          hello:1.23.1 (stable, active)
Replicas:
  Desired:       2
  Current:       2
  Updated:       2
  Ready:         2
  Available:     2

NAME                                           KIND        STATUS     AGE  INFO
 rollout-bluegreen                            Rollout Healthy  95s
└──# revision:1
   └──⧉ rollout-bluegreen-595d4567cc           ReplicaSet Healthy  18s  stable,active
      ├──□ rollout-bluegreen-595d4567cc-mc769  Pod Running  8s   ready:1/1
      └──□ rollout-bluegreen-595d4567cc-zdc5x  Pod Running  8s   ready:1/1

web service 会将流量转发到由 rollouts 创建的 pod。使用以下命令:

kubectl describe service web | grep Endpoints

准备绿色 Deployment

接下来,将应用的新版本作为绿色 deployment 准备好。将 deployment web 更新为新的 image 版本(例如 hello:1.23.2)。

apiVersion: apps/v1
kind: Deployment
metadata:
  name: web
spec:
  replicas: 2
  selector:
    matchLabels:
      app: web
  template:
    metadata:
      labels:
        app: web
    spec:
      containers:
        - name: web
          image: hello:1.23.2
          ports:
            - containerPort: 80

YAML 字段说明:

  • 与原始 deployment 相同,除了:
    • containers.image:更新为新的 image 版本。

使用以下命令应用:

kubectl apply -f deployment.yaml

这样就为测试设置好了新的应用版本。

Rollouts 会创建一个新的 ReplicaSet 来管理绿色 pod,而流量仍然会转发到蓝色 pod。使用以下命令验证:

kubectl argo rollouts get rollout rollout-bluegreen
Name:            rollout-bluegreen
Namespace:       default
Status: Paused
Message:         BlueGreenPause
Strategy:        BlueGreen
Images:          hello:1.23.1 (stable, active)
                 hello:1.23.2
Replicas:
  Desired:       2
  Current:       4
  Updated:       2
  Ready:         2
  Available:     2

NAME                                           KIND        STATUS     AGE  INFO
 rollout-bluegreen                            Rollout Paused   14m
├──# revision:2
  └──⧉ rollout-bluegreen-776b688d57           ReplicaSet Healthy  24s
     ├──□ rollout-bluegreen-776b688d57-kxr66  Pod Running  23s  ready:1/1
     └──□ rollout-bluegreen-776b688d57-vv7t7  Pod Running  23s  ready:1/1
└──# revision:1
   └──⧉ rollout-bluegreen-595d4567cc           ReplicaSet Healthy  12m  stable,active
      ├──□ rollout-bluegreen-595d4567cc-mc769  Pod Running  12m  ready:1/1
      └──□ rollout-bluegreen-595d4567cc-zdc5x  Pod Running  12m  ready:1/1

当前有 4 个 pod 在运行,分别对应蓝色和绿色版本。而 active service 仍然指向蓝色版本,rollout 流程处于暂停状态。

如果你使用 Helm Chart 来部署应用,请使用 helm 工具将应用升级到绿色版本。

将 Rollout 晋升到绿色

当绿色版本准备就绪后,晋升 rollout 以将流量切换到绿色 pod。使用以下命令:

kubectl argo rollouts promote rollout-bluegreen

验证 rollout 是否已完成:

kubectl argo rollouts get rollout rollout-bluegreen
Name:            rollout-bluegreen
Namespace:       default
Status: Healthy
Strategy:        BlueGreen
Images:          hello:1.23.2 (stable, active)
Replicas:
  Desired:       2
  Current:       2
  Updated:       2
  Ready:         2
  Available:     2

NAME                                           KIND        STATUS         AGE   INFO
 rollout-bluegreen                            Rollout Healthy      3h2m
├──# revision:2
  └──⧉ rollout-bluegreen-776b688d57           ReplicaSet Healthy      168m  stable,active
     ├──□ rollout-bluegreen-776b688d57-kxr66  Pod Running      168m  ready:1/1
     └──□ rollout-bluegreen-776b688d57-vv7t7  Pod Running      168m  ready:1/1
└──# revision:1
   └──⧉ rollout-bluegreen-595d4567cc           ReplicaSet ScaledDown   3h1m
      ├──□ rollout-bluegreen-595d4567cc-mc769  Pod Terminating  3h    ready:1/1
      └──□ rollout-bluegreen-595d4567cc-zdc5x  Pod Terminating  3h    ready:1/1

如果 active Images 已更新为 hello:1.23.2,并且蓝色 ReplicaSet 已缩减到 0,则表示 rollout 已完成。