1、应用回滚简介
在滚动更新过程中,如果新版本的pod启动失败或者已升级完成,但新版本中存在bug,则可以选择回滚到之前的可用版本。‘kubectl rollout‘命令可以方便的执行回滚和其他滚动更新管理,该命令支持Deployment、DaemonSet和statefulset资源
[root@k8s-master ~]# kubectl rollout history deployment/django-blog -n blog
deployment.apps/django-blog
REVISION CHANGE-CAUSE
1 <none>
3 <none>
4 <none>
5 <none>
6 <none>
7 <none>
REVISION:修订版本,从0开始递增
CHANGE-CAUSE:变更原因,可以通过 kubectl annotate 命令进行设置,例如将最近一次变更原因设置为v2
- 将最近一次变更原因设置为v2
[root@k8s-master ~]# kubectl annotate deployment/django-blog kubernetes.io/change-cause="v2" -n blog
deployment.apps/django-blog annotated
- 再次查看历史版本
[root@k8s-master ~]# kubectl rollout history deployment/django-blog -n blog
deployment.apps/django-blog
REVISION CHANGE-CAUSE
1 <none>
3 <none>
4 <none>
5 <none>
6 <none>
7 v2
- 回滚到上一个版本,既v1版本
[root@k8s-master ~]# kubectl rollout undo deployment/django-blog -n blog
deployment.apps/django-blog rolled back
- 注意:如果想回滚到指定的修订版本,可以使用--to-revision参数指定修订版本号。
操作完成后,可以通过 kubectl rollout status 子命令实时监控回滚进度
2、回滚实现机制
Deployment是通过ReplicaSet实现滚动更新,每次触发滚动更新都会创建一个新的ReplicaSet。完成滚动更新后,旧ReplicaSet会被保留。这样做的原因是,旧的ReplicaSet保存对应版本的pod配置信息。kubectl rollout undo命令的回滚机制是基于这些历史ReplicaSet实现的。
如果执行混滚到修订版本2,则kubernetes首先将修订版本号2重新标记为4,然后根据修订版本号找到对应的ReplicaSet,接着逐步增加该ReplicaSet的pod副本数,同时逐渐减少当前ReplicaSet的pod副本数,已实现平滑的回滚过程
Deployment默认保留10个历史版本,这可以通过revisionHistoryLimit字段进行设置
3、暂停和恢复滚动更新
kubectl roolout pause 和 kubectl rollout resume子命令分别用于暂停和恢复滚动更新过程,通常用于解决滚动更新过程中的问题。例如,当新版本出现问题时,可以执行暂停操作,然后进行问题排查和修复。问题解决后,执行恢复操作,使其继续进行。这两个子命令的用法如下
- 暂停滚动更新过程
kubectl rollout pause 资源类型/资源名称
- 恢复滚动更新过程
kubectl rollout resume 资源类型/资源名称
4、重启pod
在kubernetes1.15版本以后,kubec rollout命令新增了一个子命令restart,用于重新启动指定资源的滚动更新过程,这将导致所有pod重建。这对于需要重建pod的场景非常有用,如重新加载配置、重新拉取镜像等。kubectl rollout restart 子命令的用法如下
kubectl rollout restart 资源类型/资源名称
[root@k8s-master ~]# kubectl rollout restart deployment/django-blog -n blog
[root@k8s-master ~]# kubectl get pod -A -o wide|grep blog
blog django-blog-c6b69955f-cg9cg 1/1 Running 0 36s 10.244.85.251 k8s-node01 <none> <none>
blog django-blog-c6b69955f-dss72 1/1 Running 0 25s 10.244.58.220 k8s-node02 <none> <none>
blog django-blog-c6b69955f-dw59b 1/1 Running 0 13s 10.244.85.243 k8s-node01 <none> <none>
blog django-blog-d7d675654-jfn5b 1/1 Terminating 0 109s 10.244.58.244 k8s-node02 <none> <none>
blog django-blog-d7d675654-jft4h 1/1 Terminating 0 98s 10.244.85.240 k8s-node01 <none> <none>
blog django-blog-d7d675654-tppv4 1/1 Terminating 0 87s 10.244.58.245 k8s-node02 <none> <none>
5、应用扩缩容
- 当应用程序访问量激增时,可以通过扩展pod副本数来提高并发能力。
- 将名为django-blog的Deployment付部署调整为5个
[root@k8s-master ~]# kubectl scale deployment django-blog --replicas=5 -n blog
- replicas参数用于指定pod的副本数
如果当前的服务数小于5个,则会创建新的pod以达到所需的数量。反之,将会删除相应数量的pod以满足所需的数量
6、应用下线
- 当应用程序不在使用时,可以通过以下方式从kubernetes集群中删除相关资源:
- 使用相应的资源文件进行删除
kubectl delete -f file.yaml
- 直接删除相关资源对象
kubectl delete deployment/名称 service/名称
7、 应用灰度发布
灰度发布是一种主流的发布方案。在灰度过程中,一小部分流量首先被转发到新版本进行测试和验证。新版本验证通过后,逐步增加流量比例或将全部流量转发到新版本中。这种分阶段的升级方式更新更加灵活、风险更小,适用于最小化风险的关键业务场景。kubernetes未提供原生的灰度发布功能。不过,kubernetes提供了足够的条件和资源来实现简单的灰度发布。Deployment通过两个ReplicaSet实现滚动更新,可以采用相同的思路,通过两个独立的Deployment实现灰度发布
当一个Deployment需要升级时,首先创建一个相同的Deployment,修改其中资源名称,将image字段指定为新版本镜像地址,并将副本数量设置为1。然后,当pod准备就绪时,将旧版本Deployment副本数量设置为2。此时,集群中有1个新版本pod,2个旧版本pod,service将33%的流量转发到新版本。新版本验证通过后,再将新版本Deployment副本数量设置为3,将旧版本Deployment副本数量设置为0
- 将博客网站从v2版本升级到v3版本,创建一个名为django-blog-v3的Deployment
[root@k8s-master k8s]# cat django-blog-v3.yaml
# api版本
apiVersion: apps/v1
# 资源类型
kind: Deployment
# 资源元数据
metadata:
# 资源名称
name: django-blog-v3
# 资源名称空间
namespace: blog
# 资源规格
spec:
# 资源副本数
replicas: 1
# 标签选择器
selector:
# 匹配标签
matchLabels:
app: django
# pod模版
template:
# pod元数据
metadata:
# pod标签
labels:
app: django
# pod规格
spec:
# pod容器配置
containers:
# pod 镜像地址
- image: uhub.service.ucloud.cn/librarys/django-blog:v3
# pod名称
name: web
kubectl apply -f django-blog-v3.yaml
- pod准备就绪后,将旧版本Deployment副本数缩减为2
[root@k8s-master k8s]# kubectl scale deployment django-blog --replicas=2 -n blog
- 此时访问service将有33%的流量转发到新版本(v3),新版本验证通过后,将新版本Deployment副本数扩展为3
[root@k8s-master k8s]# curl -s http://172.16.99.71:30189|grep 当前版本
当前版本:v1
[root@k8s-master k8s]# curl -s http://172.16.99.71:30189|grep 当前版本
当前版本:v1
[root@k8s-master k8s]# curl -s http://172.16.99.71:30189|grep 当前版本
当前版本:v1
[root@k8s-master k8s]# curl -s http://172.16.99.71:30189|grep 当前版本
当前版本: v3
[root@k8s-master k8s]# curl -s http://172.16.99.71:30189|grep 当前版本
当前版本:v1
[root@k8s-master k8s]# curl -s http://172.16.99.71:30189|grep 当前版本
当前版本:v1
[root@k8s-master k8s]# curl -s http://172.16.99.71:30189|grep 当前版本
当前版本: v3
[root@k8s-master k8s]# curl -s http://172.16.99.71:30189|grep 当前版本
当前版本:v1
[root@k8s-master k8s]# curl -s http://172.16.99.71:30189|grep 当前版本
当前版本:v1
[root@k8s-master k8s]# curl -s http://172.16.99.71:30189|grep 当前版本
当前版本:v1
[root@k8s-master k8s]# curl -s http://172.16.99.71:30189|grep 当前版本
当前版本: v3
[root@k8s-master k8s]# curl -s http://172.16.99.71:30189|grep 当前版本
当前版本:v1
[root@k8s-master k8s]# curl -s http://172.16.99.71:30189|grep 当前版本
当前版本: v3
[root@k8s-master k8s]# curl -s http://172.16.99.71:30189|grep 当前版本
当前版本:v1
[root@k8s-master k8s]# curl -s http://172.16.99.71:30189|grep 当前版本
当前版本:v1
[root@k8s-master k8s]# curl -s http://172.16.99.71:30189|grep 当前版本
当前版本:v1
[root@k8s-master k8s]# curl -s http://172.16.99.71:30189|grep 当前版本
当前版本:v1
[root@k8s-master k8s]# kubectl scale deployment django-blog-v3 --replicas=3 -n blog
- pod准备就绪后,将旧版本Deployment副本数量缩减为0
[root@k8s-master k8s]# kubectl get pod -A -o wide|grep blog
blog django-blog-69dbd4f4b8-hwrx9 1/1 Running 0 6m58s 10.244.58.197 k8s-node02 <none> <none>
blog django-blog-69dbd4f4b8-kswjj 1/1 Running 0 6m58s 10.244.85.207 k8s-node01 <none> <none>
blog django-blog-v3-569f9d9c87-5wkvk 1/1 Running 1 (18h ago) 43h 10.244.58.250 k8s-node02 <none> <none>
blog django-blog-v3-569f9d9c87-9j9fh 1/1 Running 0 6s 10.244.85.215 k8s-node01 <none> <none>
blog django-blog-v3-569f9d9c87-nxxtp 1/1 Running 0 6s 10.244.85.219 k8s-node01 <none> <none>
[root@k8s-master k8s]# kubectl get replicaset -n blog|egrep -v "0 0 0"
NAME DESIRED CURRENT READY AGE
django-blog-69dbd4f4b8 2 2 2 43h
django-blog-v3-569f9d9c87 3 3 3 43h
[root@k8s-master k8s]# kubectl scale deployment django-blog --replicas=0 -n blog
deployment.apps/django-blog scaled
[root@k8s-master k8s]# kubectl get pod -A -o wide|grep blog
blog django-blog-69dbd4f4b8-hwrx9 1/1 Terminating 0 7m18s 10.244.58.197 k8s-node02 <none> <none>
blog django-blog-69dbd4f4b8-kswjj 1/1 Terminating 0 7m18s 10.244.85.207 k8s-node01 <none> <none>
blog django-blog-v3-569f9d9c87-5wkvk 1/1 Running 1 (18h ago) 43h 10.244.58.250 k8s-node02 <none> <none>
blog django-blog-v3-569f9d9c87-9j9fh 1/1 Running 0 26s 10.244.85.215 k8s-node01 <none> <none>
blog django-blog-v3-569f9d9c87-nxxtp 1/1 Running 0 26s 10.244.85.219 k8s-node01 <none> <none>
此时,集群中仅有新版本pod。既service将所有流量转发到新版本,完成升级。
通过自定义实现灰度发布机制,我们可以灵活的控制新旧版本的pod副本数,并逐步引入新版本,以确保在更新过程中对系统和用户的影响最小化