Kubernetes 零宕机滚动更新(kubernetes deployment滚动升级)
nanshan 2024-10-26 11:14 12 浏览 0 评论
软件世界的发展比以往任何时候都快,为了保持竞争力需要尽快推出新的软件版本,而又不影响在线得用户。许多企业已将工作负载迁移到了 Kubernetes 集群,Kubernetes 集群本身就考虑到了一些生产环境的实践,但是要让 Kubernetes 实现真正的零停机不中断或丢失请求,我们还需要做一些额外的操作才行。
滚动更新
默认情况下,Kubernetes 的 Deployment 是具有滚动更新的策略来进行 Pod 更新的,该策略可以在任何时间点更新应用的时候保证某些实例依然可以正常运行来防止应用 down 掉,当新部署的 Pod 启动并可以处理流量之后,才会去杀掉旧的 Pod。
在使用过程中我们还可以指定 Kubernetes 在更新期间如何处理多个副本的切换方式,比如我们有一个3副本的应用,在更新的过程中是否应该立即创建这3个新的 Pod 并等待他们全部启动,或者杀掉一个之外的所有旧的 Pod,或者还是要一个一个的 Pod 进行替换?下面示例是使用默认的滚动更新升级策略的一个 Deployment 定义,在更新过程中最多可以有一个超过副本数的容器(maxSurge),并且在更新过程中没有不可用的容器。
apiVersion: apps/v1
kind: Deployment
metadata:
name: zero-downtime
labels:
app: zero-downtime
spec:
replicas: 3
selector:
matchLabels:
app: zero-downtime
strategy:
type: RollingUpdate
rollingUpdate:
maxSurge: 1
maxUnavailable: 0
template:
# with image nginx
# ...
上面的 zero-downtime 这个应用使用 nginx 这个镜像创建3个副本,该 Deployment 执行滚动更新的方式:首先创建一个新版本的 Pod,等待 Pod 启动并准备就绪,然后删除一个旧的 Pod,然后继续下一个新的 Pod,直到所有副本都已替换完成。为了让 Kubernetes 知道我们的 Pod 何时可以准备处理流量请求了,我们还需要配置上 liveness 和 readiness 探针。下面展示的就是新旧 Pod 替换的输出信息:
$ kubectl get pods
NAME READY STATUS RESTARTS AGE
zero-downtime-d449b5cc4-k8b27 1/1 Running 0 3m9s
zero-downtime-d449b5cc4-n2lc4 1/1 Running 0 3m9s
zero-downtime-d449b5cc4-sdw8b 1/1 Running 0 3m9s
...
zero-downtime-d449b5cc4-k8b27 1/1 Running 0 3m9s
zero-downtime-d449b5cc4-n2lc4 1/1 Running 0 3m9s
zero-downtime-d449b5cc4-sdw8b 1/1 Running 0 3m9s
zero-downtime-d569474d4-q9khv 0/1 ContainerCreating 0 12s
...
zero-downtime-d449b5cc4-n2lc4 1/1 Running 0 3m9s
zero-downtime-d449b5cc4-sdw8b 1/1 Running 0 3m9s
zero-downtime-d449b5cc4-k8b27 1/1 Terminating 0 3m29s
zero-downtime-d569474d4-q9khv 1/1 Running 0 1m
...
zero-downtime-d449b5cc4-n2lc4 1/1 Running 0 5m
zero-downtime-d449b5cc4-sdw8b 1/1 Running 0 5m
zero-downtime-d569474d4-q9khv 1/1 Running 0 1m
zero-downtime-d569474d4-2c7qz 0/1 ContainerCreating 0 10s
...
...
zero-downtime-d569474d4-2c7qz 1/1 Running 0 40s
zero-downtime-d569474d4-mxbs4 1/1 Running 0 13s
zero-downtime-d569474d4-q9khv 1/1 Running 0 67s
可用性检测
如果我们从旧版本到新版本进行滚动更新,只是简单的通过输出显示来判断哪些 Pod 是存活并准备就绪的,那么这个滚动更新的行为看上去肯定就是有效的,但是往往实际情况就是从旧版本到新版本的切换的过程并不总是十分顺畅的,应用程序很有可能会丢弃掉某些客户端的请求。
为了测试是否存在请求被丢弃,特别是那些针对即将要退出服务的实例的请求,我们可以使用一些负载测试工具来连接我们的应用程序进行测试。我们需要关注的重点是所有的 HTTP 请求,包括 keep-alive 的 HTTP 连接是否都被正确处理了,所以我们这里可以使用 Apache Bench(AB Test) 或者 Fortio(Istio 测试工具) 这样的测试工具来测试。
我们使用多个线程以并发的方式去连接到正在运行的应用程序,我们关心的是响应的状态和失败的连接,而不是延迟或吞吐量之类的信息。我们这里使用 Fortio 这个测试工具,比如每秒 500 个请求和 8 个并发的 keep-alive 连接的测试命令如下所示(使用域名zero.qikqiak.com代理到上面的3个 Pod):
$ fortio load -a -c 8 -qps 500 -t 60s "http://zero.qikqiak.com/"
关于 fortio 的具体使用可以查看官方文档:https://github.com/fortio/fortio
使用 -a 参数可以将测试报告保存为网页的形式,这样我们可以直接在浏览器中查看测试报告。如果我们在进行滚动更新应用的过程中启动测试,则可能会看到一些请求无法连接的情况:
Starting at 1000 qps with 8 thread(s) [gomax 2] for 1m0s : 7500 calls each (total 60000)
Ended after 1m0.006243654s : 5485 calls. qps=91.407
Aggregated Sleep Time : count 5485 avg -17.626081 +/- 15 min -54.753398956 max 0.000709054 sum -96679.0518
[...]
Code 200 : 5463 (99.6 %)
Code 502 : 20 (0.4 %)
Response Header Sizes : count 5485 avg 213.14166 +/- 13.53 min 0 max 214 sum 1169082
Response Body/Total Sizes : count 5485 avg 823.18651 +/- 44.41 min 0 max 826 sum 4515178
[...]
从上面的输出可以看出有部分请求处理失败了(502),我们可以运行几种通过不同方式连接到应用程序的测试场景,比如通过 Kubernetes Ingress 或者直接从集群内部通过 Service 进行连接。我们会看到在滚动更新过程中的行为可能会有所不同,具体的还是需要取决于测试的配置参数,和通过 Ingress 的连接相比,从集群内部连接到服务的客户端可能不会遇到那么多的失败连接。
原因分析
现在的问题是需要弄明白当应用在滚动更新期间重新路由流量时,从旧的 Pod 实例到新的实例究竟会发生什么,首先让我们先看看 Kubernetes 是如何管理工作负载连接的。如果我们执行测试的客户端直接从集群内部连接到 zero-downtime 这个 Service,那么首先会通过 集群的 DNS 服务解析到 Service 的 ClusterIP,然后转发到 Service 后面的 Pod 实例,这是每个节点上面的 kube-proxy 通过更新 iptables 规则来实现的。
Kubernetes 会根据 Pods 的状态去更新 Endpoints 对象,这样就可以保证 Endpoints 中包含的都是准备好处理请求的 Pod。
但是 Kubernetes Ingress 连接到实例的方式稍有不同,这就是为什么当客户端通过 Ingresss 连接到应用程序的时候,我们会在滚动更新过程中查看到不同的宕机行为。
大部分 Ingress Controller,比如 nginx-ingress、traefik 都是通过直接 watch Endpoints 对象来直接获取 Pod 的地址的,而不用通过 iptables 做一层转发了。
无论我们如何连接到应用程序,Kubernetes 的目标都是在滚动更新的过程中最大程度地减少服务的中断。一旦新的 Pod 处于活动状态并准备就绪后,Kubernetes 就将会停止就的 Pod,从而将 Pod 的状态更新为 “Terminating”,然后从 Endpoints 对象中移除,并且发送一个 SIGTERM 信号给 Pod 的主进程。SIGTERM 信号就会让容器以正常的方式关闭,并且不接受任何新的连接。Pod 从 Endpoints 对象中被移除后,前面的负载均衡器就会将流量路由到其他(新的)Pod 中去。这个也是造成我们的应用可用性差距的主要原因,因为在负责均衡器注意到变更并更新其配置之前,终止信号就会去停用 Pod,而这个重新配置过程又是异步发生的,所以并不能保证正确的顺序,所以就可能导致很少的请求会被路由到终止的 Pod 上去。
零宕机
那么如何增强我们的应用程序以实现真正的零宕机迁移呢?
首先,要实现这个目标的先决条件是我们的容器要正确处理终止信号,在 SIGTERM 信号上实现优雅关闭。下一步需要添加 readiness 可读探针,来检查我们的应用程序是否已经准备好来处理流量了。
可读探针只是我们平滑滚动更新的起点,为了解决 Pod 停止的时候不会阻塞并等到负载均衡器重新配置的问题,我们需要使用 preStop 这个生命周期的钩子,在容器终止之前调用该钩子。
生命周期钩子函数是同步的,所以必须在将最终终止信号发送到容器之前完成,在我们的示例中,我们使用该钩子简单的等待,然后 SIGTERM 信号将停止应用程序进程。同时,Kubernetes 将从 Endpoints 对象中删除该 Pod,所以该 Pod 将会从我们的负载均衡器中排除,基本上来说我们的生命周期钩子函数等待的时间可以确保在应用程序停止之前重新配置负载均衡器。
这里我们在 zero-downtime 这个 Deployment 中添加一个 preStop 钩子:
apiVersion: apps/v1
kind: Deployment
metadata:
name: zero-downtime
labels:
app: zero-downtime
spec:
replicas: 3
selector:
matchLabels:
app: zero-downtime
template:
spec:
containers:
- name: zero-downtime
image: nginx
livenessProbe:
# ...
readinessProbe:
# ...
lifecycle:
preStop:
exec:
command: ["/bin/bash", "-c", "sleep 20"]
strategy:
# ...
我们这里使用 preStop 设置了一个 20s 的宽限期,Pod 在真正销毁前会先 sleep 等待 20s,这就相当于留了时间给 Endpoints 控制器和 kube-proxy 更新去 Endpoints 对象和转发规则,这段时间 Pod 虽然处于 Terminating 状态,即便在转发规则更新完全之前有请求被转发到这个 Terminating 的 Pod,依然可以被正常处理,因为它还在 sleep,没有被真正销毁。
现在,当我们去查看滚动更新期间的 Pod 行为时,我们将看到正在终止的 Pod 处于 Terminating 状态,但是在等待时间结束之前不会关闭的,如果我们使用 Fortio 重新测试下,则会看到零失败请求的理想行为:
Starting at 1000 qps with 8 thread(s) [gomax 2] for 1m0s : 7500 calls each (total 60000)
Ended after 1m0.091439891s : 10015 calls. qps=166.66
Aggregated Sleep Time : count 10015 avg -23.316213 +/- 14.52 min -50.161414028 max 0.001811225 sum -233511.876
[...]
Code 200 : 10015 (100.0 %)
Response Header Sizes : count 10015 avg 214 +/- 0 min 214 max 214 sum 2143210
Response Body/Total Sizes : count 10015 avg 826 +/- 0 min 826 max 826 sum 8272390
Saved result to data/2020-02-12-162008_Fortio.json
All done 10015 calls 47.405 ms avg, 166.7 qps
总结
Kubernetes 在考虑到生产就绪性方面已经做得很好了,但是为了在生产环境中运行我们的企业级应用,我们就必须了解 Kubernetes 是如何在后台运行的,以及我们的应用程序在启动和关闭期间的行为。而且上面的方式是只适用于短连接的,对于类似于 websocket 这种长连接应用需要做滚动更新的话目前还没有找到一个很好的解决方案,有的团队是将长连接转换成短连接来进行处理的,我这边还是在应用层面来做的支持,比如客户端增加重试机制,连接断掉以后会自动重新连接,大家如果有更好的办法也可以留言互相讨论下方案。
相关推荐
- 三种自建KMS激活系统自动激活windows方法
-
第一种:在windows服务器上搭建主要针对vol版本(win7、win10、win20xx、win2012等等)平台:我自己搭建的windows虚拟机,windows2016的操作系统软件:...
- 重装系统被收98元?避开Windows付费陷阱的实用指南
-
重装系统被收98元?避开Windows付费陷阱的实用指南有网友反映,在重装Windows系统后,屏幕突然弹出“激活系统需支付98元服务费”的提示,疑惑自己是不是遭遇了付费陷阱。事实上,微软官方的Wi...
- Windows Server2012远程桌面服务配置和授权激活
-
安装:注意:安装完毕之后需手动重启一下计算机配置终端服务管理工具---远程桌面服务---RD授权诊断程序,查看当前服务器有没有授权授权:运行—>gpedit.msc->计算机配置---管理...
- 新书速览|Windows Server 2022 系统与网站配置实战
-
讲述桌面体验、ServerCore/NanoServer,容器与云系统的配置1本书内容《WindowsServer2022系统与网站配置实战》秉持作者一贯理论兼具实践的写作风格,以新版的Wi...
- Windows激活全攻略:KMS神钥与专业工具的完美结合!
-
对于许多Windows用户来说,系统的激活是一个必经的过程。虽然Windows操作系统在未经激活的状态下也可以使用一段时间,但长期来看,未激活的系统会限制某些功能并频繁提示用户激活。以下是两种流行的激...
- 微软Win9全新激活技术曝光(微软系统激活有什么用)
-
2014-07-0905:46:00作者:徐日俄罗斯Wzor日前披露了更多关于Windows9的最新消息,据悉,Windows9将会在今年秋季亮相,其宣传口号是“想要开始按钮和开始菜单?如你所...
- 快速激活Windows 10/11:CMD命令详细教程
-
#记录我的2024#激活Windows操作系统是确保系统功能和安全更新正常运行的重要步骤。本文将为您分享如何使用命令提示符(CMD)在Windows10和Windows11上进行激活的详细步骤。...
- Wndows 2019 RDS应用发布部署(rds的安装和应用程序的发布)
-
安装前的准备1、需要提供服务器作为应用中心,应用中心的推荐配置如下表所示。规格建议1-10人11-20人21-50人51-100人100+人CPU4核8核16核内存8GB16GB32GB64GB系统盘...
- 解决 Windows 系统激活难题(如何解决windows激活问题)
-
今天,一位朋友给我说,他手头有三台电脑,均同时弹出系统未激活的提示。他对此毫无头绪,便急忙将电脑上出现的激活提示信息一股脑发给了我。我看到其中一台显示的是“Windows10企业版LTSC尚...
- 自建KMS激活服务器(自建kms激活服务器的风险)
-
自建KMS激活服务器Win10和office安装后,都需要激活才可以使用,一般可以输入购买的MAK激活码进行在线激活,也可以通过KMS激活,网上也有很多激活工具,但这些工具一般都含有病毒或木马程序,容...
- 30秒免费激活windows和office亲测有效!
-
“第三方工具有病毒?”“KMS服务器激活总失效?”今天给大家分享一个开源激活工具——MicrosoftActivationScripts(MAS),无需密钥、不装软件,30秒永久激活Window...
- 「操作系统」Windows 10 LTSC 2019 企业版C大集成更新版
-
Windows10LTSC企业版CHIANNET集成更新优化整合多镜像版,CHIANNET,是USBOS超级PE维护盘工具箱作者,长久以来一直默默的更新着,USBOSPE软件,电脑城装机及...
- 一文看懂Windows激活:自查方法+授权类型科普(Win7/Win10通用)
-
一、如何判断Windows是否永久激活?无论是Win7还是Win10,均可通过以下方法快速验证:命令提示符法(通用):按下Win+R,输入slmgr.vbs/xpr并按回车键运行即可查看是否...
- 部分Windows Server 2019/2022用户反馈无法运行微软Teams应用
-
IT之家7月2日消息,科技媒体borncity今天(7月2日)发布博文,报道称在多个WindowsServer版本上,MicrosoftTeams应用近期出现了运行故障。用...
- 这种Windows激活方式已有20年...(windows现在激活)
-
2006年微软正式发布WindowsVista,随之而来引入了一项新的激活机制「OEM激活」,这项机制在Vista和Win7上最为流行。其实WindowsServer自2008开始至2025版本一...
你 发表评论:
欢迎- 一周热门
-
-
UOS服务器操作系统防火墙设置(uos20关闭防火墙)
-
极空间如何无损移机,新Z4 Pro又有哪些升级?极空间Z4 Pro深度体验
-
NAS:DS video/DS file/DS photo等群晖移动端APP远程访问的教程
-
如何在安装前及安装后修改黑群晖的Mac地址和Sn系列号
-
手机如何设置与显示准确时间的详细指南
-
如何修复用户配置文件服务在 WINDOWS 上登录失败的问题
-
一加手机与电脑互传文件的便捷方法FileDash
-
日本海上自卫队的军衔制度(日本海上自卫队的军衔制度是什么)
-
10个免费文件中转服务站,分享文件简单方便,你知道几个?
-
爱折腾的特斯拉车主必看!手把手教你TESLAMATE的备份和恢复
-
- 最近发表
-
- 三种自建KMS激活系统自动激活windows方法
- 重装系统被收98元?避开Windows付费陷阱的实用指南
- Windows Server2012远程桌面服务配置和授权激活
- 新书速览|Windows Server 2022 系统与网站配置实战
- Windows激活全攻略:KMS神钥与专业工具的完美结合!
- 微软Win9全新激活技术曝光(微软系统激活有什么用)
- 快速激活Windows 10/11:CMD命令详细教程
- Wndows 2019 RDS应用发布部署(rds的安装和应用程序的发布)
- 解决 Windows 系统激活难题(如何解决windows激活问题)
- 自建KMS激活服务器(自建kms激活服务器的风险)
- 标签列表
-
- linux 查询端口号 (58)
- docker映射容器目录到宿主机 (66)
- 杀端口 (60)
- yum更换阿里源 (62)
- internet explorer 增强的安全配置已启用 (65)
- linux自动挂载 (56)
- 禁用selinux (55)
- sysv-rc-conf (69)
- ubuntu防火墙状态查看 (64)
- windows server 2022激活密钥 (56)
- 无法与服务器建立安全连接是什么意思 (74)
- 443/80端口被占用怎么解决 (56)
- ping无法访问目标主机怎么解决 (58)
- fdatasync (59)
- 405 not allowed (56)
- 免备案虚拟主机zxhost (55)
- linux根据pid查看进程 (60)
- dhcp工具 (62)
- mysql 1045 (57)
- 宝塔远程工具 (56)
- ssh服务器拒绝了密码 请再试一次 (56)
- ubuntu卸载docker (56)
- linux查看nginx状态 (63)
- tomcat 乱码 (76)
- 2008r2激活序列号 (65)