目录
四、通过 k8s 实现滚动更新
4.3 自定义滚动更新策略
取值范围
建议配置
总结
测试:自定义策略
重建式更新:Recreate
五、生产环境如何实现蓝绿部署?
5.1 什么是蓝绿部署?
5.2 蓝绿部署的优势和缺点
优点:
缺点:
5.3 通过 k8s 实现线上业务的蓝绿部署
1.创建绿色部署环境(基于第一版代码做的镜像运行的 pod)
2.创建前端 service(实现在浏览器访问页面)
3.创建蓝色部署环境(新上线的环境,要替代绿色环境)
六、通过 k8s 完成线上业务的金丝雀发布
6.1 金丝雀发布简介
6.2 在 k8s 中实现金丝雀发布
四、通过 k8s 实现滚动更新
4.3 自定义滚动更新策略
maxSurge 和 maxUnavailable 用来控制滚动更新的更新策略。
取值范围
数值
- maxUnavailable: [0, 副本数]
- maxSurge: [0, 副本数]
注意:两者不能同时为 0。
比例
- maxUnavailable: [0%, 100%] 表示向下取整,比如10个副本,5%的话==0.5个,但计算按照0个;
- maxSurge: [0%, 100%] 表示向上取整,比如10个副本,5%的话==0.5个,但计算按照1个;
注意:两者不能同时为0。
建议配置
- maxUnavailable == 0
- maxSurge == 1
这是我们生产环境提供给用户的默认配置。即“一上一下,先上后下”最平滑原则:
1个新版本 pod ready(结合readiness)后,才销毁旧版本 pod。此配置适用场景是平滑更新、保证服务平稳,但也有缺点,就是“太慢”了。
总结
- maxUnavailable:和期望的副本数比,不可用副本数最大比例(或最大值),这个值越小,越能保证服务稳定,更新越平滑;
- maxSurge:和期望的副本数比,超过期望副本数最大比例(或最大值),这个值调的越大,副本更新速度越快。
测试:自定义策略
[root@k8s-master01 ~]# kubectl explain deployment.spec
[root@k8s-master01 ~]# kubectl explain deployment.spec.strategy
[root@k8s-master01 ~]# kubectl explain deployment.spec.strategy.rollingUpdate
# 修改更新策略:maxUnavailable=1,maxSurge=1
[root@k8s-master01 ~]# vim deploy-demo.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: myapp-v1
spec:
strategy:
rollingUpdate:
maxSurge: 1
maxUnavailable: 1
replicas: 3
# 因为上一篇咱们回滚了版本,否则需要修改镜像之后才能 pod 创建成功
[root@k8s-master01 ~]# kubectl apply -f deploy-demo.yaml
deployment.apps/myapp-v1 configured
# 查看 myapp-v1 这个控制器的详细信息
[root@k8s-master01 ~]# kubectl describe deployment myapp-v1
Name: myapp-v1
Namespace: default
CreationTimestamp: Sat, 10 Dec 2022 18:09:22 +0800
Labels: <none>
Annotations: deployment.kubernetes.io/revision: 4
Selector: app=myapp,version=v1
Replicas: 3 desired | 3 updated | 3 total | 3 available | 0 unavailable
StrategyType: RollingUpdate
MinReadySeconds: 0
RollingUpdateStrategy: 1 max unavailable, 1 max surge
Pod Template:
Labels: app=myapp
version=v1
上面可以看到 RollingUpdateStrategy: 1 max unavailable, 1 max surge。这个 rollingUpdate更新策略变成了刚才设定的,因为我们设定的pod副本数是3,1和1表示最少不能少于2个pod,最多不能超过4个pod。这个就是通过控制 RollingUpdateStrategy 这个字段来设置滚动更新策略的例子。
重建式更新:Recreate
# 把 pod 更新策略变成 Recreate
[root@k8s-master01 ~]# vim deploy-demo.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: myapp-v1
spec:
strategy:
type: Recreate
replicas: 3
······
spec:
containers:
- name: myapp
image: janakiramm/myapp:v1 # 镜像也要更改为 v1
[root@k8s-master01 ~]# kubectl apply -f deploy-demo.yaml
deployment.apps/myapp-v1 configured
总结:recreate 这种更新策略,会把之前的所有 pod 都删除,再创建新的pod,风险很大。
五、生产环境如何实现蓝绿部署?
5.1 什么是蓝绿部署?
蓝绿部署中,一共有两套系统:一套是正在提供服务系统,标记为“绿色”;另一套是准备发布的系统,标记为“蓝色”。两套系统都是功能完善的、正在运行的系统,只是系统版本和对外服务情况不同。
开发新版本,要用新版本替换线上的旧版本,在线上的系统之外,搭建了一个使用新版本代码的全新系统。 这时候,一共有两套系统在运行,正在对外提供服务的老系统是绿色系统,新部署的系统是蓝色系统。
蓝色系统不对外提供服务,用来做什么呢?
用来做发布前测试,测试过程中发现任何问题,可以直接在蓝色系统上修改,不干扰用户正在使用的系统。(注意,两套系统没有耦合的时候才能百分百保证不干扰)
蓝色系统经过反复的测试、修改、验证,确定达到上线标准之后,直接将用户切换到蓝色系统:
切换后的一段时间内,依旧是蓝绿两套系统并存,但是用户访问的已经是蓝色系统。这段时间内观察蓝色系统(新系统)工作状态,如果出现问题,直接切换回绿色系统。
当确信对外提供服务的蓝色系统工作正常,不对外提供服务的绿色系统已经不再需要的时候,蓝色系统正式成为对外提供服务系统,成为新的绿色系统。 原先的绿色系统可以销毁,将资源释放出来,用于部署下一个蓝色系统。
5.2 蓝绿部署的优势和缺点
优点:
- 更新过程无需停机,风险较少
- 回滚方便,只需要更改路由或者切换DNS服务器,效率较高
缺点:
- 成本较高,需要部署两套环境。如果基础服务出现问题,会瞬间影响全网用户;如果新版本有问题也会影响全网用户。
- 需要部署两套机器,费用开销大
- 在非隔离的机器(Docker、VM)上操作时,可能会导致蓝绿环境被摧毁风险
- 负载均衡器/反向代理/路由/DNS处理不当,将导致流量没有切换过来情况出现
5.3 通过 k8s 实现线上业务的蓝绿部署
下面实验需要的镜像包上传到 k8s 的各个工作节点,ctr -n=k8s.io images import 解压:
[root@k8s-node1 ~]# ctr -n=k8s.io images import myapp-lan.tar.gz
[root@k8s-node1 ~]# ctr -n=k8s.io images import myapp-lv.tar.gz
[root@k8s-node2 ~]# ctr -n=k8s.io images import myapp-lan.tar.gz
[root@k8s-node2 ~]# ctr -n=k8s.io images import myapp-lv.tar.gz
Kubernetes 不支持内置的蓝绿部署。目前最好的方式是创建新的 deployment,然后更新应用程序的 service 以指向新的 deployment 部署的应用。
1.创建绿色部署环境(基于第一版代码做的镜像运行的 pod)
[root@k8s-master01 ~]# vim lv.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: myapp-v1
namespace: blue-green
spec:
replicas: 3
selector:
matchLabels:
app: myapp
version: v2
template:
metadata:
labels:
app: myapp
version: v2
spec:
containers:
- name: myapp
image: janakiramm/myapp:v2
imagePullPolicy: IfNotPresent
ports:
- containerPort: 80
# 创建名称空间
[root@k8s-master01 ~]# kubectl create ns blue-green
namespace/blue-green created
# 创建资源
[root@k8s-master01 ~]# kubectl apply -f lv.yaml
deployment.apps/myapp-v1 created
# 查看指定名称空间下的 pod 详细信息:
[root@k8s-master01 ~]# kubectl get pods -n blue-green --show-labels -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES LABELS
myapp-v1-75d7db5cf7-4tglq 1/1 Running 0 26s 10.244.169.133 k8s-node2 <none> <none> app=myapp,pod-template-hash=75d7db5cf7,version=v2
myapp-v1-75d7db5cf7-w6ln2 1/1 Running 0 26s 10.244.169.134 k8s-node2 <none> <none> app=myapp,pod-template-hash=75d7db5cf7,version=v2
myapp-v1-75d7db5cf7-zkj5b 1/1 Running 0 26s 10.244.36.114 k8s-node1 <none> <none> app=myapp,pod-template-hash=75d7db5cf7,version=v2
2.创建前端 service(实现在浏览器访问页面)
[root@k8s-master01 ~]# vim service_lanlv.yaml
apiVersion: v1
kind: Service
metadata:
name: myapp-lan-lv
namespace: blue-green
labels:
app: myapp
spec:
type: NodePort
ports:
- port: 80
nodePort: 30062
name: http
selector:
app: myapp
version: v2
[root@k8s-master01 ~]# kubectl apply -f service_lanlv.yaml
service/myapp-lan-lv created
[root@k8s-master01 ~]# kubectl get service -n blue-green
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
myapp-lan-lv NodePort 10.97.110.87 <none> 80:30062/TCP 29s
在浏览器访问 http://k8s-master节点ip:30062 (http://192.168.78.133:30062/)显示如下:
3.创建蓝色部署环境(新上线的环境,要替代绿色环境)
[root@k8s-master01 ~]# vim lan.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: myapp-v2
namespace: blue-green
spec:
replicas: 3
selector:
matchLabels:
app: myapp
version: v1
template:
metadata:
labels:
app: myapp
version: v1
spec:
containers:
- name: myapp
image: janakiramm/myapp:v1
imagePullPolicy: IfNotPresent
ports:
- containerPort: 80
[root@k8s-master01 ~]# kubectl apply -f lan.yaml
deployment.apps/myapp-v2 created
# 可以看到一共有六个pods,上面三个是绿色系统,下面三个是蓝色系统:
[root@k8s-master01 ~]# kubectl get pods -n blue-green --show-labels -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES LABELS
myapp-v1-75d7db5cf7-4tglq 1/1 Running 0 15m 10.244.169.133 k8s-node2 <none> <none> app=myapp,pod-template-hash=75d7db5cf7,version=v2
myapp-v1-75d7db5cf7-w6ln2 1/1 Running 0 15m 10.244.169.134 k8s-node2 <none> <none> app=myapp,pod-template-hash=75d7db5cf7,version=v2
myapp-v1-75d7db5cf7-zkj5b 1/1 Running 0 15m 10.244.36.114 k8s-node1 <none> <none> app=myapp,pod-template-hash=75d7db5cf7,version=v2
myapp-v2-85cc897d89-9rqlc 1/1 Running 0 29s 10.244.36.115 k8s-node1 <none> <none> app=myapp,pod-template-hash=85cc897d89,version=v1
myapp-v2-85cc897d89-gqv77 1/1 Running 0 29s 10.244.169.137 k8s-node2 <none> <none> app=myapp,pod-template-hash=85cc897d89,version=v1
myapp-v2-85cc897d89-x2c42 1/1 Running 0 29s 10.244.169.135 k8s-node2 <none> <none> app=myapp,pod-template-hash=85cc897d89,version=v1
# 修改 service_lanlv.yaml 配置文件,修改标签,让其匹配到蓝系统服务(升级之后的系统)
selector:
app: myapp
version: v1
# 由 v2 变为 v1 即可
# 更新资源清单文件:
[root@k8s-master01 ~]# kubectl apply -f service_lanlv.yaml
service/myapp-lan-lv configured
[root@k8s-master01 ~]# kubectl get service -n blue-green
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
myapp-lan-lv NodePort 10.97.110.87 <none> 80:30062/TCP 13m
# 查看 service 资源详细信息
[root@k8s-master01 ~]# kubectl describe service myapp-lan-lv -n blue-green
在浏览器访问 http://k8s-master节点ip:30062 显示如下:
实验完成之后,把资源先删除,以免影响后面实验:
[root@k8s-master01 ~]# kubectl delete -f lan.yaml
deployment.apps "myapp-v2" deleted
[root@k8s-master01 ~]# kubectl delete -f lv.yaml
deployment.apps "myapp-v1" deleted
[root@k8s-master01 ~]# kubectl delete -f service_lanlv.yaml
service "myapp-lan-lv" deleted
六、通过 k8s 完成线上业务的金丝雀发布
6.1 金丝雀发布简介
金丝雀发布的由来:17 世纪,英国矿井工人发现,金丝雀对瓦斯这种气体十分敏感。空气中哪怕有极其微量的瓦斯,金丝雀也会停止歌唱;当瓦斯含量超过一定限度时,虽然人类毫无察觉,金丝雀却早已毒发身亡。当时在采矿设备相对简陋的条件下,工人们每次下井都会带上一只金丝雀作为瓦斯检测指标,以便在危险状况下紧急撤离。
金丝雀发布(又称灰度发布、灰度更新):金丝雀发布一般先发1台,或者一个小比例,例如2%的服务器,主要做流量验证用,也称为金丝雀 (Canary) 测试 (国内常称灰度测试)。
假如有100个 pod,更新了一个pod:用的新的代码做的镜像,99个pod:没有更新。
简单的金丝雀测试一般通过手工测试验证,复杂的金丝雀测试需要比较完善的监控基础设施配合,通过监控指标反馈,观察金丝雀的健康状况,作为后续发布或回退的依据。 如果金丝测试通过,则把剩余的V1版本全部升级为V2版本。如果金丝雀测试失败,则直接回退金丝雀,发布失败。
- 优点:灵活,策略自定义,可以按照流量或具体的内容进行灰度(比如不同账号,不同参数),出现问题不会影响全网用户。
- 缺点:没有覆盖到所有的用户导致出现问题不好排查。
6.2 在 k8s 中实现金丝雀发布
# 打开另一个会话监测更新过程
[root@k8s-master01 ~]# kubectl get pods -n blue-green -o wide -w
[root@k8s-master01 ~]# kubectl apply -f lv.yaml
deployment.apps/myapp-v1 created
# 使用命令行修改镜像,发布新版服务
[root@k8s-master01 ~]# kubectl set image deployment myapp-v1 myapp=nginx:latest -n blue-green && kubectl rollout pause deployment myapp-v1 -n blue-green
解释说明:把 myapp 这个容器的镜像更新到 nginx:latest ,更新镜像之后,创建一个新的 pod 就立即暂停,这就是我们说的金丝雀发布;如果暂停几个小时之后没有问题,那么取消暂停,就会依次执行后面步骤,把所有 pod 都升级。
我们先访问旧的镜像服务:
绿色背景:
访问新服务 nginx:
金丝雀实验成功,解除暂停,发布更新:
[root@k8s-master01 ~]# kubectl rollout resume deployment myapp-v1 -n blue-green
deployment.apps/myapp-v1 resumed
可以看到如下一些信息,下面过程是把余下的3个 pod 里的容器都更新:
访问下面三个更新后的 pod ip,都是 nginx 访问信息:
上一篇文章:【云原生 | Kubernetes 实战】10、K8s 控制器 Deployment 入门到企业实战应用(上)_Stars.Sky的博客-CSDN博客