蓝绿(Blue-Green)部署简介

在现代软件开发和交付中,确保应用程序的平稳更新和发布对于用户体验和业务连续性至关重要。蓝绿部署是一种备受推崇的部署策略,它允许开发团队在不影响用户的情况下,将新版本的应用程序引入生产环境。

蓝绿部署的核心思想在于维护两个独立的环境:蓝环境和绿环境。蓝环境是当前正在运行的稳定版本,而绿环境是即将发布的新版本。在进行部署时,首先将新版本部署到绿环境中,并在绿环境中进行严格的测试和验证。一旦新版本通过了各项测试,并被确认为稳定和可靠,就可以将流量从蓝环境切换到绿环境,使用户开始访问新版本。

工作流程

考虑一个在线购物应用,用户可以浏览商品、添加到购物车并完成购买。为了演示蓝绿部署,我们假设当前应用的版本为1.0(蓝环境),而开发团队已经开发了一个新版本2.0(绿环境),其中包含了一些界面改进和性能优化。

以下是蓝绿部署的步骤:
在这里插入图片描述

  • 步骤1:部署新版本到绿环境
    开发团队使用自动化部署工具将新版本2.0部署到绿环境。
    绿环境中的新版本经过自动化测试,包括功能测试、性能测试和安全测试。
  • 步骤2:切换流量到绿环境
    新版本部署好之后,可以通过负载均衡器将用户的流量从蓝环境切换到绿环境。
    现在用户开始访问新版本2.0,体验其中的改进和优化。
  • 步骤3:监控和回滚
    监控系统会实时监测应用的性能和稳定性,看是否发生错误或故障。
  • 步骤4:升级或回滚
    如果出现问题,开发团队可以快速回滚,将流量切回到蓝环境1.0,以保障用户体验。否则,将继续使用新版本2.0, 且使新版本2.0成为新的蓝环境。

k8s的Deployment支持蓝绿部署吗

云原生的浪潮下, 越来越多的团队都将应用迁移到了Kubernetes的环境中, Kubernetes使应用的部署变得方便快捷,但Kubernetes却并未原生提供蓝绿部署的功能。它提供了Deployment对象,可以实现“滚动更新”(RollingUpdate)。这使得可以在应用程序更新时实现零停机时间,通过逐步用新版本的应用程序替换Pod。

虽然这类似于蓝绿部署,但并未提供其所有的好处。比如在滚动部署中,如果新版本出现问题,回滚可能到旧版本需要重新部署应用,这就需要更多的时间,而不能像蓝绿部署一样,可以即时切换新旧版本, 从而最大限度的保障系统的可用性。

Argo Rollouts实现k8s的蓝绿部署

虽然Kubernetes没有提供原生的蓝绿部署功能,但丰富的自定义资源往往可以帮我们在Kubernetes的世界中实现各种各样美好的愿望。Argo的Rollouts就是一个比较流行好用的工具。Argo Rollouts安装指南

Argo Rollouts是一个运行在Kubernetes中的渐进式发布控制器,它支持多种部署策略,其中包括蓝绿部署和金丝雀部署。Argo Rollouts提供了一个名为Rollout的新的Kubernetes资源类型,类似于Deployment,用户可以通过指定额外的参数,从而设置高级的部署策略。

下面是Rollout自动执行蓝绿部署的方式:

  • 用户指定一个服务名(activeService),其会将流量路由到当前的(蓝色)版本,并可选的指定另一个服务(previewService),其会将流量路由到新的(绿色)版本。
  • Rollout控制器使用ReplicaSets部署应用程序的当前版本(蓝),并通过向服务选择器注入ReplicaSet的唯一哈希,将流量路由到它。
  • 当应用程序有更新时,开发人员更改Rollout模板(例如,修改镜像版本)。Rollout对象检测到更改,然后创建一个新的具有新版本的ReplicaSet。
  • activeService继续指向旧的ReplicaSet,同时新的ReplicaSet正在部署中。
  • 当新的ReplicaSet变为可用时,控制器会自动修改activeService,将流量路由到新的ReplicaSet。
  • 控制器会等待一段时间(具体时长在Rollout的yaml文件中声明),然后缩减旧的ReplicaSet副本。

通过这种方式,Rollout对象实现了自动的蓝绿部署,使得应用程序的更新能够在不影响用户使用的情况下进行。这为团队提供了更灵活、可控的部署流程,同时最大程度地减少了潜在的风险。

如下是一份配置蓝绿部署策略的Rollout资源配置示例:

apiVersion: argoproj.io/v1alpha1
kind: Rollout
metadata:
  name: rollout-bluegreen
spec:
[...] # 省略的配置的格式与Deployment的配置格式完全相同
  strategy:
    blueGreen: 
      activeService: service-active
      previewService: service-preview
      autoPromotionEnabled: false
  • activeService: 该项指定的服务会将流量导向蓝服务(活跃版本)
  • previewService(可选配置项): 该项指定的服务会将流量导向绿服务(预览版本)。这使得可以在不将新版本暴露给生产流量的情况下预览新版本。
  • autoPromotionEnabled: 如果设置为false,新版本不会立即自动升级为活跃版本。可以使用命令kubectl argo rollouts promote <ROLLOUT>手动进行版本切换。如果设置为true,默认情况下,当新版本Pod Ready时,Rollout会立即切换活跃版本到新版本pod。

值得注意的是,上述配置中的activeService和previewService这两项指定的服务不会被自动创建,而需要根据Rollout的配置手动创建,以上面的Rollout的示例配置为基础,应当创建两个Service,例如:

---
apiVersion: v1
kind: Service
metadata:
  name: service-active
spec:
  selector:
    app: your-app-label
  ports:
    - protocol: TCP
      port: 80
      targetPort: 8080
  type: ClusterIP
---
apiVersion: v1
kind: Service
metadata:
  name: service-preview
spec:
  selector:
    app: your-app-label
  ports:
    - protocol: TCP
      port: 80
      targetPort: 8080 
  type: ClusterIP

仅与配置相关的蓝绿部署

一个服务的行为不仅取决于源代码,也与其运行时的配置相关, 在kubernetes中,配置通常通过Configmap来生成,例如下面的配置:

---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: demo-app
spec:
  replicas: 1
  revisionHistoryLimit: 2
  selector:
    matchLabels:
      app: demo-configmap
  template:
    metadata:
      labels:
        app: demo-configmap
    spec:
      containers:
      - name: demo-container
        image: demo-app:latest
        env:
        - name: DB_USER
          valueFrom:
            configMapKeyRef:
              name: demo-settings
              key: DB_USER
        - name: DB_URL
          valueFrom:
            configMapKeyRef:
              name: demo-settings
              key: DB_URL
[...snip...]
---
apiVersion: v1
kind: ConfigMap
metadata:
  name: demo-settings
data:
  DB_URL: "10.1.1.1:3306"
  DB_USER: "myuser"

上面的配置中, 在容器运行时会从demo-settings这个Configmap中获取对应的值作为环境变量,分别是:

  DB_URL: "10.1.1.1:3306"
  DB_USER: "myuser"

此时,我们希望将应用连接到另一个数据库(使用不同的url和用户)进行测试,例如:

  DB_URL: "10.1.1.2:3306"
  DB_USER: "testuser"

ConfigMap Generator

为了使环境中同时存在使用两个不同数据库的服务,我们需要一种方式来同时保持两个 ConfigMap的存在,并且每个都具有其相应的配置。这可以通过使用 ConfigMap Generator来实现, 这是一个与 Argo Rollouts 无关的功能,它是 Kustomize 的内置功能,可以用于标准的滚动部署,我们也可以利用它进行渐进式交付。

Configmap Generator的工作原理如下:kustomize会根据Configmap Generator中配置的name, 动态的创建一个ConfigMap, 创建的这个ConfigMap的名称是name的值加上一个唯一的后缀, 例如:

apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- deployment.yml
- service.yml

# declare ConfigMap from a ConfigMapGenerator
configMapGenerator:
- name: demo-settings
  literals:
  - DB_URL="10.1.1.2:3306"
  - DB_USER="testuser"

这时我们查看deployment的yaml内容, 其中使用了这个动态生成的ConfigMap:

[...snip...]
		spec:
		  containers:
		  - env:
		    - name: DB_URL
		    - valueFrom:
		        configMapKeyRef:
		          key: DB_URL 
		          name: demo-settings-2k9m722878
		    - name: DB_USER
		      valueFrom:
		        configMapKeyRef:
		          key: DB_USER 
		          name: demo-settings-2k9m722878
[...snip...]

查看这个动态的ConfigMap的内容:

apiVersion: v1 
name: demo-settings-2km722878
data:
  DB_URL: "10.1.1.2:3306"
  DB_USER: "testuser"

在Argo Rollout中使用Configmap Generator

在上一小节中,我们已经知道了Configmap Generator的工作原理,在Argo Rollout中合理的利用它的特性,就可以实现配置的蓝绿部署和渐进式发布。首先,我们将上文中的Deployment清单转换成Rollout清单:

# example-rollout.yml
apiVersion: argoproj.io/v1alpha1
kind: Rollout
metadata:
  name: demo-app
spec:
  replicas: 3
  strategy:
    blueGreen:    
      activeService: configmaps-example-active      
      previewService: configmaps-example-preview    
      autoPromotionEnabled: false  
  revisionHistoryLimit: 2
  selector:
    matchLabels:
      app: demo-configmap
  template:
    metadata:
      labels:
        app: demo-configmap
    spec:
      containers:
      - name: my-container
        image: demo-app:latest
        env:
        - name: DB_URL
          valueFrom:
            configMapKeyRef:
              name: demo-settings
              key: DB_URL
        - name: DB_USER
          valueFrom:
            configMapKeyRef:
              name: demo-settings
              key: DB_USER
[...snip...]

然后修改我们的kustomization清单:

apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
# declare ConfigMap as a resource
resources:
- example-rollout.yml
- service-active.yml
- service-preview.yml

configurations:
  - https://argoproj.github.io/argo-rollouts/features/kustomize/rollout-transform.yaml

注意:

  1. 上面的配置中, service-active.yml 和 service-preview.yml分别对应的蓝绿版本的service清单文件,参考上节,此处省略具体配置。
  2. configuration 这一行不可省略,其作用是启用kustomization的rollout功能,由于Argo Rollout不是原生的Kubernetes资源,因此必须通过yaml来告知kustomization, Rollout资源的详细信息。

检验结果

首先对应用进行首次部署

kustomize build . | kubectl apply  -f -
kubectl-argo-rollouts get rollout demo-app

结果如下:

Name:       demo-app
Namespace:  default
Status:     ~ Healthy
Strategy:   BlueGreen
Images:     demo-app:latest (stable, active)
Replicas:   
    Desired:    3
    Current:    3
    Updated:    3
    Ready:      3
    Available:  3

NAME                                 KIND                   STATUS  AGE INFO
~ demo-app                           Rollout                Healthy 15s
└──# revision: 1
   └── demo-app-55df5b623d           ReplicaSet             Healthy 15s stable,active
      ├── demo-app-55df5b623d-2nlgf  Pod                    Healthy 15s ready:1/1
      ├── demo-app-55df5b623d-78udn  Pod                    Healthy 15s ready:1/1      
      └── demo-app-55df5b623d-6sceo  Pod                    Healthy 15s ready:1/1      

现在我们来改变配置,在Configmap Generator中更改配置:

apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
# declare ConfigMap as a resource
resources:
- example-rollout.yml
- service-active.yml
- service-preview.yml

configurations:
  - https://argoproj.github.io/argo-rollouts/features/kustomize/rollout-transform.yaml

configMapGenerator:
  - name: demo-settings
	literals:
	  - DB_URL="10.1.1.2:3306"
  	  - DB_USER="testuser"

运行命令进行蓝绿部署并查看结果:

kustomize build . | kubectl apply  -f -
kubectl-argo-rollouts get rollout demo-app

结果如下:

Name:       demo-app
Namespace:  default
Status:     Paused
Message:    BlueGreenPause
Strategy:   BlueGreen
Images:     demo-app:latest (active, preview, stable)
Replicas:   
    Desired:    3
    Current:    6
    Updated:    3
    Ready:      3
    Available:  3

NAME                                 KIND                   STATUS  AGE INFO
~ demo-app                           Rollout                Paused  100s
├──# revision: 2
│  └── demo-app-76tk9i812c           ReplicaSet             Healthy 10s preview
│     ├── demo-app-76tk9i812c-1nvlf  Pod                    Healthy 10s ready:1/1
│     ├── demo-app-76tk9i812c-70qce  Pod                    Healthy 10s ready:1/1      
│     └── demo-app-76tk9i812c-21kap  Pod                    Healthy 10s ready:1/1      
└──# revision: 1
   └── demo-app-55df5b623d           ReplicaSet             Healthy 100s stable,active
      ├── demo-app-55df5b623d-2nlgf  Pod                    Healthy 100s ready:1/1
      ├── demo-app-55df5b623d-78udn  Pod                    Healthy 100s ready:1/1      
      └── demo-app-55df5b623d-6sceo  Pod                    Healthy 100s ready:1/1      

进入对应的Pod中查看环境变量,可以看到已经生效,检验成功。

通过上面的方法,我们可以仅使用 Argo Rollouts 进行配置更改,在不修改容器镜像的情况下,只需更改配置即可执行蓝/绿部署和金丝雀部署。如果你想要在生产 Kubernetes 集群中微调应用程序配置参数,而不想使用新的容器镜像,那么希望这篇文章将会给你一些启发和帮助。

Logo

开源、云原生的融合云平台

更多推荐