前言
在我之前的项目中,对微服务升级采用的做法是删除整个namespace, 再重新应用所有yaml。 这种方式简单粗暴,但是不可避免的导致服务中断,影响了用户体验
为了解决更新服务导致的服务中断问题, Kubernetes提供了一种有效的服务升级方式 —— 滚动更新(Rolling Update)
什么是滚动更新(RollingUpdate)
滚动更新是一种部署策略。 允许用户逐步替换旧的Pod实例为新版本,而不是一次性替换所有Pod,从而实现零停机时间的部署更新。 解决了如下问题:
- 最小化停机时间, 滚动更新可以在不完全停止服务情况下进行,提高用户体验
- 故障恢复, 如果新版本出现问题,可以迅速回滚到之前的稳定版本
- 平滑流量迁移, 避免瞬间全部更新导致的流量冲击和服务中断
RollingUpdate策略有两个重要参数:
- maxUnavailable, 滚动更新时最多可以有多少个Pod不可用。 默认值为25%,这意味着如果有一个包含4个Pod的服务, 更新期间至少有3个Pod可用
- maxSurge, 滚动更新时可以临时超出期望副本数的额外Pod数, 默认值为25%
说明: 对于关键业务, 可以用保守的设置, 比如maxUnavailable=0, maxSurge=1; 较大的maxSurge可以加快更新速度,但增加了集群压力; 根据实际情况调整这两个参数
实践案例
写一个简单的微服务, Pod副本数设置为5, 观察Kubernetes滚动更新过程
1、首先创建一个简单微服务
创建Flask的app.py
1 | from flask import Flask |
写一个Dockerfile
1 | FROM python:3.9-slim |
构建镜像
1 | docker build -t flask-app:1.0 . |
2、 微服务部署到k8s
创建一个Deployment
1 | apiVersion: apps/v1 |
创建Service
1 | apiVersion: v1 |
3、 执行滚动更新
改一下第一步的app.py, 构建第二个镜像, 用于测试滚动更新
1 | docker build -t flask-app:2.0 . |
执行滚动更新
1 | kubectl set image deployment/flask-app flask-app=docker.io/library/flask-app:2.0 |
4、 观察滚动更新过程
1 | kubectl rollout status deployment/flask-app |
同时, 用watch查看滚动更新过程, 可以看出Pod是一边创建一边删除的
1 | watch kubectl get pods |
5、 滚动回滚
1 | kubectl rollout undo deployment/flask-app |
注: 除了改变镜像, 如果对deployment其他部分做了修改, 同样可以触发滚动更新。 通过kubectl apply更新Deployment, 再watch kubectl get pods
观察滚动更新过程
参考
https://kubernetes.io/docs/tutorials/kubernetes-basics/update/update-intro/