前言
部署在 Kubernetes 集群中的应用,在升级发布时可能会存在的问题:
1,由于 Kuberneter 底层 Pod 容器生命周期与网络组件生命周期是异步管理的,在升级时如果没有处理好应用优雅退出的问题,就很容易导致 http 访问请求 5xx
2,原生 Deployment 应用的滚动发布功能是一把梭的全量发布模式,没有灰度和分批控制发布的概念,一旦出现问题,故障影响范围就会迅速扩大
这也是为什么需要灰度发布,蓝绿发布,彩虹发布,金丝雀发布、A/B Test等多样化形式发布的重要原因,核心目标只有一个,就是为了确保服务的稳定性,减少或避免因变更带来的不稳定因素
今天我们主要来聊下,如何使用阿里云开源的 Kruise Rollouts 进行灰度发布(官网地址:Introduction | OpenKruise)Kruise Rollouts 是一个旁路组件,提供高级渐进式交付功能。它对金丝雀、灰度发布,蓝绿发布,A/B Test都有很好的支持
安装
kruise-rollout
# Firstly add openkruise charts repository if you haven't do this.
$ helm repo add openkruise https://openkruise.github.io/charts/
# [Optional]
$ helm repo update
#
helm install kruise-rollout openkruise/kruise-rollout --version 0.4.0
# 下载安装包
# helm pull openkruise/kruise-rollout --untar --untardir .
安装完成后,查看 crd 资源的方式:
(base) ➜ blue_green_deploy kubectl get crd -A
NAME CREATED AT
batchreleases.rollouts.kruise.io 2023-08-25T09:59:30Z
rollouthistories.rollouts.kruise.io 2023-08-25T09:59:30Z
rollouts.rollouts.kruise.io 2023-08-25T09:59:30Z
trafficroutings.rollouts.kruise.io 2023-08-25T09:59:30Z
kubectl-kruise
这里使用手动安装方式,下载安装包:Releases · openkruise/kruise-tools · GitHub
这里是 mac m1 系统,选择 darwin-arm64 即可,解压之后拷贝到系统的 bin 目录即可:
tar -zxvf kubectl-kruise-darwin-amd64.tar.gz
mv darwin-arm64/kubectl-kruise /usr/local/bin/
现在就可以使用:
# 查看帮助文档了
kubectl-kruise --help
注意在 mac 上由于会验证安全身份,所以如果遇到弹窗:
就在设置 -> 安装性与隐私 -> 通用里面 选择放行和信任这个应用即可
后面再弹窗,直接选择打开就行了
Demo 例子
假设,我们有个 Deployment 目前是 V1 版本:
apiVersion: apps/v1
kind: Deployment
metadata:
name: py-hello-blue
spec:
selector:
matchLabels:
app: hello
color: blue
replicas: 6
template:
metadata:
labels:
app: hello
color: blue
spec:
terminationGracePeriodSeconds: 30
containers:
- name: hello
imagePullPolicy: Always
image: localhost:5001/py-http:1
ports:
- containerPort: 8888
resources:
requests:
memory: "50Mi"
limits:
memory: "200Mi"
lifecycle:
preStop:
exec:
command: ["sleep", "5"]
# command: ["/usr/bin/tini", "--", "bash", "-c"]
command: ["sh", "-c"]
args:
- |
python app.py
为了让发布更丝滑,我们先绑定 kruise-rollout 灰度发布策略:
apiVersion: rollouts.kruise.io/v1alpha1
kind: Rollout
metadata:
name: rollout-blue
namespace: default
annotations:
rollouts.kruise.io/rolling-style: partition
spec:
objectRef:
workloadRef:
apiVersion: apps/v1
kind: Deployment
name: py-hello-blue
strategy:
canary:
steps:
- replicas: 1
- replicas: 50%
- replicas: 100%
策略如下:6 个副本的发布批次
第一批:发布一个副本 = 1
第二批:发布剩下的 50%,5*0.5 不四舍五入取整 = 2
第三批:发布剩下的所有 = 3
现在,我们将 yaml 文件里面的版本升级为 2,然后重新执行 apply 后,使用 kubectl get pods -w 命令观察发布过程:
第一批发布
过程,旧的先终止,然后等优雅退出的 30 秒过后,就彻底销毁了,新的一个来拉起来了:
查看发布 rollout 策略的状态,执行命令
kubectl get rollout
结果显示,灰度完就终止了:
这个时候,我们去请求我们的 pod多请求几次就能看到新发布的pod 已经生效了:
第二批发布
继续发布 第二批
kubectl kruise rollout approve rollout/rollout-blue -n default
查看 deployment 状态和发布进度:
# 查看发布状态
kubectl get deployments.apps
# 查看发布的 hash 值,按时间可以看出来
kubectl get replicasets.apps -L pod-template-hash
第二批发完之后,显示如下:
然后我们继续查看灰度发布的执行阶段:
可以看到进行到了完成了第二个阶段:
第三批发布
如果没问题,继续执行第三批发布:
kubectl kruise rollout approve rollout/rollout-blue -n default
如果在没有发布完,显示Progressing,StepUpgrade
执行完显示:
回滚
kurise 并不直接提供回滚能力,需要借助原生的方式重新 set image 即可, 在这里不需要对 rollout crd 做任何事情,yaml 文件里面的镜像版本改回到之前的 v1 版本即可,然后 kubectl apply -f 到 k8s 集群,再次查看状态会显示 rollout 已经取消
NAME STATUS CANARY_STEP CANARY_STATE MESSAGE AGE
rollout-blue Healthy 1 StepReady Rollout progressing has been cancelled 77m