k8s(12) — 版本控制和滚动更新(金丝雀部署理念)
金丝雀部署简介:
1、基本概念
金丝雀部署是一种软件开发中的渐进式发布策略,其核心思想是通过将新版本应用逐步发布给一小部分用户(即 “金丝雀” 用户),在真实环境中验证功能稳定性和性能表现,再逐步扩大发布范围,最终完成全量更新。
名称来源:源于煤矿工人用金丝雀检测瓦斯泄漏的做法 —— 通过观察少量样本的反应,提前发现潜在风险。2、核心流程与特点
(一)核心流程
- 准备阶段
- 同时运行 ** 旧版本(稳定版本)和新版本(待发布版本)** 的应用服务。
- 配置路由规则,将少量用户流量(如 5%)导向新版本,其余流量仍指向旧版本。
- 监控与验证
- 实时监控新版本的性能指标(如响应时间、错误率、资源利用率)和用户反馈(如功能异常、界面问题)。
- 若发现严重问题,立即将流量切回旧版本(回滚);若验证通过,逐步增加新版本流量(如 10%、20%……)。
- 全量发布
- 当新版本通过所有验证且流量占比达到 100% 时,完成部署,下线旧版本服务。
(二)关键特点
优点 缺点 1. 风险隔离:仅少量用户受潜在问题影响,降低故障波及范围。
2. 精准验证:在真实环境中验证功能,提前发现兼容性、性能等问题。
3. 灵活回滚:支持快速切换回旧版本,减少停机时间。1. 复杂度高:需维护新旧版本并存的环境,增加部署和监控成本。
2. 流量分配难度大:需精确控制流量比例,避免因流量不均导致验证偏差。
3. 适用场景有限:不适合需要用户状态强一致的场景(如交易系统)。3、适用场景
- 功能迭代验证:如前端界面优化、新功能试点,通过小范围用户反馈迭代改进。
- 性能测试:在生产环境中测试新版本对服务器、数据库的负载影响。
- 灰度发布:与 A/B 测试结合,向不同用户群体展示不同版本,对比效果后再全量发布。
- 微服务架构:在分布式系统中,对单个服务进行金丝雀部署,降低整体变更风险。
部署思路:
在生产上先进行少量更新如有10个v1.0的Pod正在稳定运行,此时设置一个滚动更新为v2.0, 更新之后立马停止更新,此时有11个Pod正在运行,此时如果用户访问正常那么就全量开启滚动更新,否则就进行回退。
一、金丝雀部署-打补丁升级步骤
在 Kubernetes 中,rollout resume
和rollout pause
是用于控制 Deployment、StatefulSet 或 DaemonSet 滚动更新过程的两个重要命令。它们允许你暂停正在进行的更新,进行检查或修改,然后恢复更新过程,提供了对滚动更新的精细控制。
1、滚动更新概念:
(一)、
rollout pause
:暂停滚动更新1. 基本功能
- 暂停当前进行中的滚动更新,使 Deployment 停止创建或更新 Pod。
- 保留已更新的 Pod,但不会继续更新剩余的 Pod。
- 允许修改更新参数(如镜像版本、环境变量),而不会触发新的滚动更新。
2. 适用场景
- 在更新过程中进行中间检查(如验证部分 Pod 的运行状态)。
- 需要临时调整更新策略(如减慢更新速度)。
- 在更新关键应用前,预留时间进行人工确认。
3. 示例命令
bash
kubectl rollout pause deployment/my-app
4. 注意事项
- 暂停后,Deployment 的状态会显示为
Progressing
且Paused: true
。- 只有 Deployment 支持暂停 / 恢复操作, ReplicaSet 和 ReplicationController 不支持。
(二)、
rollout resume
:恢复滚动更新1. 基本功能
- 继续被暂停的滚动更新,按照最新的配置继续创建或更新 Pod。
- 应用暂停期间的配置修改,但不会触发新的滚动更新版本。
2. 适用场景
- 在中间检查完成后,继续更新过程。
- 在调整更新参数(如
maxSurge
、maxUnavailable
)后,恢复更新。3. 示例命令
bash
kubectl rollout resume deployment/my-app
4. 注意事项
- 恢复后,Deployment 会继续使用暂停时的滚动更新策略(如
spec.strategy
)。- 如果在暂停期间修改了不允许的字段(如
selector
),可能导致更新失败。(三)、典型工作流程示例
场景:更新应用并验证中间状态
启动滚动更新:
bash
kubectl set image deployment/my-app app=my-app:v2
暂停更新(例如,当 50% 的 Pod 更新完成时):
bash
kubectl rollout pause deployment/my-app
验证中间状态:
bash
kubectl get pods # 检查已更新Pod的运行状态 kubectl describe deployment/my-app # 查看Deployment状态
调整参数(可选):
bash
kubectl patch deployment/my-app -p '{"spec":{"strategy":{"rollingUpdate":{"maxSurge":1}}}}'
恢复更新:
bash
kubectl rollout resume deployment/my-app
(四)、常见问题与注意事项
1. 暂停后资源占用
- 暂停期间,旧版本和新版本的 Pod 可能同时存在,需确保集群有足够资源。
2. 状态查看
- 使用以下命令查看暂停状态:
bash
kubectl get deployments.apps my-app -o jsonpath='{.status.conditions[?(@.type=="Progressing")].message}'
输出示例:plaintext
Deployment is paused and will not progress further until resumed
3. 版本控制
- 暂停 / 恢复操作不会创建新的 Rollout 版本(
revision
),所有修改会应用到当前进行中的更新。4. 超时处理
- 如果更新长时间暂停,可能触发
ProgressDeadlineExceeded
条件,需通过kubectl rollout restart
重启更新。(五)、与其他 Rollout 命令的对比
命令 功能描述 rollout pause
暂停滚动更新,允许修改配置而不触发新的更新。 rollout resume
恢复被暂停的滚动更新。 rollout status
查看滚动更新的状态(是否完成、进度百分比)。 rollout history
查看滚动更新的历史版本。 rollout undo
回滚到上一个稳定版本或指定版本。 rollout restart
重启 Deployment,触发新一轮滚动更新(常用于配置刷新)。 (六)、总结
rollout pause
和rollout resume
为 Kubernetes 滚动更新提供了灵活的控制机制,特别适合需要精细验证或调整的生产环境。通过暂停更新,你可以在关键阶段进行人工干预,确保变更安全;通过恢复更新,你可以继续完成变更流程,实现平滑过渡。合理使用这两个命令,有助于提升集群稳定性和发布效率。
2、滚动更新实现步骤
步骤一:运行v1.0版本的pod
v1.0版本的yaml
apiVersion: apps/v1
kind: Deployment
metadata:name: nginx-denamespace: delabels:app: nginx-de
spec:replicas: 3selector:matchExpressions:- key: appoperator: Invalues: [nginx-de]template:metadata:name: nginx-denamespace: delabels:app: nginx-despec:containers:- name: nginx-deimagePullPolicy: IfNotPresentimage: registry.cn-hangzhou.aliyuncs.com/yangbin-docker/nginx:v2.0ports:- containerPort: 80startupProbe:httpGet:path: /port: 80successThreshold: 1initialDelaySeconds: 15
步骤二:打补丁修改系统默认的更新策略
可用和不可用都是25%
修改更新策略:
#触发更新就停止滚动更新kubectl patch deploy nginx-de -n de -p '{"spec":{"strategy":{"rollingUpdate":{"maxSurge":1,"maxUnavailable":0}}}}'
修改之后:变成了允许超出预期的Pod数量最大值为1个。
maxSurge: 1
此参数表明在滚动更新期间,允许超出预期 Pod 数量的最大值为 1 个。打个比方,要是预期的 Pod 数量设定为 3 个,那么在更新过程中,最多会有 4 个 Pod 同时运行。maxUnavailable: 0
该参数意味着在滚动更新时,处于不可用状态的 Pod 数量上限为 0。也就是说,在更新期间,所有预期的 Pod 都必须保持可用状态。
步骤三 :执行v2.0版本镜像的更新
kubectl patch deploy nginx-de -n de --patch '{"spec":{"template":{"spec":{"containers":[{"name":"nginx-de","image":"registry.cn-hangzhou.aliyuncs.com/yangbin-docker/nginx:v2.0"}]}}}}' && kubectl rollout pause deploy nginx-de -n de
-
在打补丁时出现异常处理情况:
情况一: 直接回退到上一个版本
此时想回退到上一个版本:
操作步骤一:执行回滚命令会出现报错
kubectl rollout undo deploy nginx-de -n de
此时执行报错rollout undo命令会报错,因为是暂停了滚动更新需要回退之前得开启被暂停掉的更新!!!
操作步骤二:按照提示操作
解决方法:
执行:
#步骤一:先执行被暂停的滚动更新,再执行回滚的动作
kubectl rollout resume deploy nginx-de -n de && kubectl rollout undo deploy nginx-de -n de#步骤二:查看回滚状态是否正常kubectl rollout status deploy nginx-de -n de
情况二:出现报错修改配置参数
上述出现拉取镜像错误的信息,那么我们现在要将正确的镜像信息配置
操作步骤一:先删除之前报错的pod
步骤二:先执行继续回滚的动作再执行修改镜像配置的动作再执行暂停滚动更新动作
#步骤一:删除失败的镜像信息kubectl delete pod nginx-de-bbd87f74d-2s6d5 -n de#步骤二:执行更新镜像信息
kubectl rollout resume deploy nginx-de -n de && \
kubectl patch deploy nginx-de -n de --patch '{"spec":{"template":{"spec":{"containers":[{"name":"nginx-de","image":"registry.cn-hangzhou.aliyuncs.com/yangbin-docker/nginx:v2.0"}]}}}}' && \
kubectl rollout pause deploy nginx-de -n de#步骤三:验证
while true;do curl 10.96.62.230;done
步骤四:配置一个svc用于检测测试结果
apiVersion: v1
kind: Service
metadata:name: nginx-denamespace: de
spec:type: ClusterIPports:- port: 80targetPort: 80selector:app: nginx-de
金丝雀部署打补丁结果:
出现了4个Pod,其中1个为最新的v2.0版本,其他的为v1.0版本
测试:
[root@master deployment]# kubectl get svc -n de
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
nginx-de ClusterIP 10.96.62.230 <none> 80/TCP 3m49s
[root@master deployment]#
[root@master deployment]#
[root@master deployment]# while true;do curl 10.96.62.230;done
步骤五:操作异常回滚
情况一:灰度更新正常(继续开启滚动更新)
停止滚动更新目的是要看生产上有没有出现异常,如果没有异常再继续更新
继续滚动更新:
kubectl rollout resume deploy nginx-de -n de
测试更新结果:
情况二:灰度更新异常(回滚)
停止滚动更新目的是要看生产上有没有出现异常,如果有异常直接进行回滚操作
#回滚到上个版本
kubectl rollout undo deployment/nginx-de -n de
二、历史版本控制与规范
(一)、使用--record参数进行版本记录
1、--record参数使用方法
#执行yaml
kubectl apply -f deployment.yaml --record#打补丁
kubectl patch deploy nginx-de -n de --patch '{"spec":{"template":{"spec":{"containers":[{"name":"nginx-de","image":"registry.cn-hangzhou.aliyuncs.com/yangbin-docker/nginx:v2.0"}]}}}}' --record#查看历史版本
kubectl rollout history deploy nginx-de -n de
2、使用--record参数记录版本号的弊端
注意:如果有一个在版本升级少加了--record,那么记录中会沿用上一个版本的的记录 这样容易在版本回退的时候造成误解。
如:
执行新的更新命令不带--record
#执行命令不带--record
kubectl patch deploy nginx-de -n de --patch '{"spec":{"template":{"spec":{"containers":[{"name":"nginx-de","image":"registry.cn-hangzhou.aliyuncs.com/yangbin-docker/nginx:v1.0"}]}}}}'
(二)、自定义版本更新规范(适用于生产环境的版本控制)
1、操作步骤
将要更新的yaml格式设置为:xx.yaml-年-月-日-姓名-版本,再对这个新的xx.yaml-年-月-日-姓名-版本进行yaml文件进行操作
如下:
cp deployment.yaml deployment.yaml-2025-05-13-yb-nginx:v2.0
kubectl apply -f deployment.yaml-2025-05-13-yb-nginx\:v2.0 --record
(三)、配置deploy.spec.revisionHistoryLimit(保留多少版本的历史记录)
如果使用这种当时可用将etcd中的rs记录给去掉,这个就不会造成资源消耗了。
revisionHistoryLimit 参数配置保留多少版本的历史记录:
kubectl explain deploy.spec.revisionHistoryLimit
三、回滚到指定的版本信息
1、查看版本的历史记录加--record参数
kubectl rollout history deployment/nginx-de -n de
2、添加--to-revision=0参数回退到指定版本
2.1、查看kubectl rollout undo参数
#查看回滚的参数
kubectl rollout undo --help
2.2、--to-revision回退到指定版本
命令格式:
kubectl rollout undo --to-revision=版本编号
目前版本是v2.0,回退到v1.0
步骤一:查看v1.0对应的版本编号
kubectl rollout history deploy nginx-de -n de
步骤二:根据查出来的版本编号回退到指定的版本
#查出来的v1.0对应的历史版本号为3
kubectl rollout undo deploy nginx-de -n de --to-revision=3