文章目录
- 前言
- 蓝绿发布概述
- 手动实现蓝绿发布
- 创建蓝色环境
- 创建蓝色环境 Ingressroute
- 部署绿色环境
- 切换到绿色环境
- 蓝绿发布自动化
- 安装 Argo Rollout
- 创建 Rollout 对象
- 创建 Service 和 Ingress
- 访问蓝色环境
- 发布自动化
- 访问 Argo Rollout Dashboard
- 自动化原理
- 结语
前言
在前几篇【GitOps系列】文章中,通过构建 GitOps 工作流实现了自动发布。不过,我们并没有专门去关注新老版本在做更新时是如何切换流量的?这是因为 Kubernetes 的 Service 和 Pod 滚动更新机制自动帮助我们完成了这部分的工作。
在实际的生产环境中,为了提高发布的可靠性,我们通常需要借助发布策略来更加精细地控制流量切换。在几种发布策略中,蓝绿发布是较为简单且容易理解的一种,所以,本次主要介绍如何在 GitOps 工作流中实施蓝绿发布?
什么是蓝绿发布?
蓝绿发布核心思想是: 为应用提供两套环境,并且可以很方便地对它们进行流量切换。
在一次实际发布过程中,新版本的应用将以“绿色”环境部署到生产环境中,但在流量切换之前它并不接收外部流量。当我们完成“绿色”环境的测试之后,可以通过流量切换的方式让“绿色”环境接收外部请求,而旧的“蓝色”环境并不会立即销毁,而是作为灾备来使用。一旦发布过程产生故障,我们就可以将流量立即切换到旧的“蓝色”环境下。
这种部署方式比较适合那些存在兼容问题,或者因为状态原因导致不能很好地使用 Kubernetes 滚动更新的应用。还有的项目希望在更新时部署一个新的版本,同时控制流量切换过程;或者是在发布出现问题时快速回滚。蓝绿发布也是不错的选择。
蓝绿发布概述
上述架构图中,我们对同一个应用部署了两个版本的环境,称之为蓝绿环境,流量通过 Ingress-Nginx 进入到 Service,然后再由它将流量转发至 Pod。在没有切换流量之前,“蓝色”环境负责接收外部请求流量。
需要进行流量切换时,只要调整 Ingress 策略就可以让“绿色”环境接收外部流量,如下图所示。
手动实现蓝绿发布
通过一个例子来说明如何使用 Kubernetes 原生的 Deployment 和 Service 来进行蓝绿发布.
创建蓝色环境
cat blue_deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: blue
labels:
app: blue
spec:
replicas: 3
selector:
matchLabels:
app: blue
template:
metadata:
labels:
app: blue
spec:
containers:
- name: demo
image: argoproj/rollouts-demo:blue
imagePullPolicy: Always
ports:
- containerPort: 8080
---
apiVersion: v1
kind: Service
metadata:
name: blue-service
labels:
app: blue
spec:
ports:
- protocol: TCP
port: 80
targetPort: 8080
selector:
app: blue
type: ClusterIP
kubectl wait pods -l app=blue --for condition=Ready --timeout=90s
pod/blue-69f5b46c99-5lkc4 condition met
pod/blue-69f5b46c99-dl7t5 condition met
pod/blue-69f5b46c99-n7sdk condition met
创建蓝色环境 Ingressroute
cat blue_ingressroute.yaml
apiVersion: traefik.containo.us/v1alpha1
kind: IngressRoute
metadata:
name: demo-ingress
spec:
entryPoints:
- web
routes:
- match: Host(`bluegreen.demo`) && PathPrefix(`/`)
kind: Rule
services:
- name: blue-service
port: 80
访问蓝色环境demo http://bluegreen.demo/
demo页面中,浏览器每秒钟会向后端发出 50 个请求,蓝色的方块代表后端返回接口的内容为 blue,对应 blue 版本的镜像,代表蓝色环境。
部署绿色环境
cat green_deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: green
labels:
app: green
spec:
replicas: 3
selector:
matchLabels:
app: green
template:
metadata:
labels:
app: green
spec:
containers:
- name: demo
image: argoproj/rollouts-demo:green
imagePullPolicy: Always
ports:
- containerPort: 8080
---
apiVersion: v1
kind: Service
metadata:
name: green-service
labels:
app: green
spec:
ports:
- protocol: TCP
port: 80
targetPort: 8080
selector:
app: green
type: ClusterIP
kubectl wait pods -l app=green --for condition=Ready --timeout=90s
pod/green-58c4957f75-86kd7 condition met
pod/green-58c4957f75-ftlg2 condition met
pod/green-58c4957f75-xkr4m condition met
切换到绿色环境
现在,当绿色环境已经准备好接收外部流量时,我们就可以通过调整 Ingress 策略来切换流量了
cat green_ingress.yaml
apiVersion: traefik.containo.us/v1alpha1
kind: IngressRoute
metadata:
name: demo-ingress
spec:
entryPoints:
- web
routes:
- match: Host(`bluegreen.demo`) && PathPrefix(`/`)
kind: Rule
services:
- name: green-service
port: 80
kubectl apply -f green_ingress.yaml
将 backend.service 字段由原来的 blue-service 修改为了 green-service,这表示将 Ingress 接收到的外部请求转发到绿色环境的 Service 中,以此达到流量切换的目的。
看到请求将逐渐从蓝色切换到绿色,如下图所示:
过几秒钟后,请求已经完全变为绿色,这表示流量已经完全从蓝色环境切换到了绿色环境。
到这里,蓝绿发布就已经完成了。
蓝绿发布自动化
到这里,我们都是通过创建 Kubernetes 原生对象并修改 Ingress 策略的方式来完成蓝绿发布的。这存在一些缺点,首先,在更新过程中,我们一般只关注镜像版本的变化,而不会去操作 Ingress 策略;其次,这种方式不利于将蓝绿发布和 GitOps 流水线进行整合。
接下来,我们来看看如何通过 Argo Rollout 工具来自动化蓝绿发布的过程。
安装 Argo Rollout
Argo Rollout 是一款专门提供 Kubernetes 高级部署能力的自动化工具,它可以独立运行,同时也可以和 ArgoCD 协同在 GitOps 流水线中来使用。
kubectl create ns argo-rollouts
kubectl apply -n argo-rollouts -f https://ghproxy.com/https://github.com/argoproj/argo-rollouts/releases/latest/download/install.yaml
customresourcedefinition.apiextensions.k8s.io/analysisruns.argoproj.io created
customresourcedefinition.apiextensions.k8s.io/analysistemplates.argoproj.io created
customresourcedefinition.apiextensions.k8s.io/clusteranalysistemplates.argoproj.io created
customresourcedefinition.apiextensions.k8s.io/experiments.argoproj.io created
customresourcedefinition.apiextensions.k8s.io/rollouts.argoproj.io created
serviceaccount/argo-rollouts created
clusterrole.rbac.authorization.k8s.io/argo-rollouts created
clusterrole.rbac.authorization.k8s.io/argo-rollouts-aggregate-to-admin created
clusterrole.rbac.authorization.k8s.io/argo-rollouts-aggregate-to-edit created
clusterrole.rbac.authorization.k8s.io/argo-rollouts-aggregate-to-view created
clusterrolebinding.rbac.authorization.k8s.io/argo-rollouts created
configmap/argo-rollouts-config created
secret/argo-rollouts-notification-secret created
service/argo-rollouts-metrics created
deployment.apps/argo-rollouts created
kubectl wait --for=condition=Ready pods --all -n argo-rollouts --timeout=300s
pod/argo-rollouts-577dd4d6bc-7vbsz condition met
创建 Rollout 对象
和手动实施蓝绿发布的过程不同的是,为了实现自动化,Argo Rollout 采用了自定义资源(CRD)的方式来管理工作负载。
首先,需要先创建 Rollout 对象。将下面的内容保存为 blue-green-service.yaml 文件
cat blue-green-rollout.yaml
apiVersion: argoproj.io/v1alpha1
kind: Rollout
metadata:
name: bluegreen-demo
labels:
app: bluegreen-demo
spec:
replicas: 3
revisionHistoryLimit: 1
selector:
matchLabels:
app: bluegreen-demo
template:
metadata:
labels:
app: bluegreen-demo
spec:
containers:
- name: bluegreen-demo
image: argoproj/rollouts-demo:blue
imagePullPolicy: Always
ports:
- name: http
containerPort: 8080
protocol: TCP
resources:
requests:
memory: 32Mi
cpu: 5m
strategy:
blueGreen:
autoPromotionEnabled: true
activeService: bluegreen-demo
kubectl apply -f blue-green-rollout.yaml
rollout.argoproj.io/bluegreen-demo created
在这个 Rollout 对象中,它大部分的字段定义和 Kubernetes 原生的 Deployment 工作负载并没有太大的区别,只是将 apiVersion 从
apps/v1
修改为argoproj.io/v1alpha1
,同时将 kind 字段从Deployment
修改为Rollout
,并且增加了strategy
字段。在容器配置方面,Rollout 对象同样也使用了argoproj/rollouts-demo:blue
来创建蓝色环境。
需要留意的是,strategy
字段是用来定义部署策略的。其中,autoPromotionEnabled
字段表示自动实施蓝绿发布,activeService
用来关联蓝绿发布的 Service,也就是我们在后续要创建的 Service 名称。
总结来说,当我们将这段 Rollout 对象应用到集群内之后,Argo Rollout 首先会创建 Kubernetes 原生对象 ReplicaSet,然后,ReplicaSet 会创建对应的 Pod。为了帮助你理解,你可以将它与之前手动实施蓝绿发布过程中创建的 Deployment 工作负载进行对比,如下图所示:
创建 Service 和 Ingress
cat blue-green-service.yaml
apiVersion: v1
kind: Service
metadata:
name: bluegreen-demo
labels:
app: bluegreen-demo
spec:
ports:
- port: 80
targetPort: http
protocol: TCP
name: http
selector:
app: bluegreen-demo
kubectl apply -f blue-green-service.yaml
service/bluegreen-demo created
ingressroute资源:
和之前创建的 Ingress 对象不同的是,这里使用 bluegreen.auto 域名,以便和之前创建的 Ingress 域名区分开,记得做域名解析。
cat blue-green-ingress.yaml
apiVersion: traefik.containo.us/v1alpha1
kind: IngressRoute
metadata:
name: bluegreen-demo
spec:
entryPoints:
- web
routes:
- match: Host(`bluegreen.auto`) && PathPrefix(`/`)
kind: Rule
services:
- name: bluegreen-demo
port: 80
kubectl apply -f blue-green-ingress.yaml
访问蓝色环境
访问由 Argo Rollout 创建的蓝色环境了。 http://bluegreen.auto
发布自动化
现在,假设我们需要更新到绿色环境,在 Argo Rollout 的帮助下,你只需要修改 Rollout 对象中的镜像版本就可以了,流量切换过程将由 Argo Rollout 自动控制。
要更新到绿色环境,你需要编辑 blue-green-rollout.yaml 文件的 image 字段,将 blue 修改为 green 版本。
containers:
- name: bluegreen-demo
image: argoproj/rollouts-demo:green
kubectl apply -f blue-green-rollout.yaml
rollout.argoproj.io/bluegreen-demo configured
几秒钟后,所有请求都变成了绿色方格,这表示蓝绿发布的自动化过程已经完成。
相比较手动的方式,在使用 Argo Rollout 进行蓝绿发布的过程中,我们不再需要手动去切换流量,除了更新镜像版本以外,我们也无需关注其他的 Kubernetes 对象。
访问 Argo Rollout Dashboard
下载链接:https://github.com/argoproj/argo-rollouts/releases
./kubectl-argo-rollouts-linux-amd64 version
kubectl-argo-rollouts: v1.5.1+839f05d
BuildDate: 2023-05-24T19:09:27Z
GitCommit: 839f05d46f838c04b44eff0e573227d40e89ac7d
GitTreeState: clean
GoVersion: go1.19.9
Compiler: gc
Platform: linux/amd64
启用Dashboard:
kubectl argo rollouts dashboard
time="2023-07-30T14:59:54+08:00" level=info msg="Argo Rollouts Dashboard is now available at http://localhost:3100/rollouts"
点击进入 Rollout 的详情界面,可以通过图形化的方式来查看 Rollout 的信息或进行回滚操作,非常Nice!!!
自动化原理
Argo Rollout 为什么能够帮助我们自动切换流量呢?接下来,我为你详细分析一下它的工作原理。
在刚开始创建蓝色环境时,Ingress、Service 和 Rollout 的关系是下图这样:
在这个例子中,当 Rollout 对象创建后,Argo Rollout 将会随之创建 ReplicaSet 对象,名称为 blue-green-fbc7b7f55,这个 ReplicaSet 会在创建 Pod 时额外为 Pod 打上rollouts-pod-template-hash=fbc7b7f55
的标签,同时为 Service 添加rollouts-pod-template-hash=fbc7b7f55
选择器,这样,就打通了从 Ingress 到 Pod 的请求链路。
当我们修改 Rollout 对象的镜像版本后,Argo Rollout 将会重新创建一个新的 ReplicaSet 对象,名称为bluegreen-demo-7d6459646d
,新的 ReplicaSet 也会在创建 Pod 时额外为 Pod 打上rollouts-pod-template-hash=7d6459646d
标签。这时候蓝绿环境的 ReplicaSet 同时存在。
当绿色环境的 Pod 全部就绪之后,Argo Rollout 会将 Service 原来的选择器删除,并添加rollouts-pod-template-hash=7d6459646d
的选择器,这样就将 Service 指向了绿色环境的 Pod,从而达到了切换流量的目的。同时,Argo Rollout 还会将蓝色环境的 ReplicaSet 副本数缩容为 0,但并不删除它,而是把它作为灾备。如下图所示:
这样,当我们需要重新回滚到蓝色环境时,Argo Rollout 只需调整蓝色环境的 ReplicaSet 副本数并且修改 Service 的选择器,就可以达到快速回滚的目的。
结语
首先通过手动的方式实践了蓝绿发布的过程。这个过程的核心是部署两套 Deployment 和 Service,同时通过修改 Ingress 策略来实现切换流量。
但手动的方式并不适合与 GitOps 流水线结合使用,所以又介绍了通过 Argo Rollout 将蓝绿发布自动化的方法。
要将手动过程切换到自动化过程其实也非常简单,我们只需要安装 Argo Rollout,并修改 Deployment 对象的 apiVersion 和 Kind 字段,然后增加 strategy 字段配置蓝绿发布策略就可以了。
然后分析了 Argo Rollout 实现自动化蓝绿发布的原理。和手动修改 Ingress 策略来实现的蓝绿发布不同的是,它主要是通过自动修改 Service 的选择器来对流量进行切换的。这种方式将蓝绿发布的过程变成了更新镜像的操作,极大降低了蓝绿发布的门槛。
最后,需要注意的是:如果你希望在微服务架构下实施蓝绿发布,那么情况会复杂得多,你需要关注整个微服务链路的蓝绿流量的切换过程,并且在数据库层面也需要考虑对蓝绿发布的支持和适配情况,使数据库在升级过程中能够同时支持蓝绿(新旧)应用。