Kubernetes 零宕机滚动更新(kubernetes deployment滚动升级)
nanshan 2024-10-26 11:14 11 浏览 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 这种长连接应用需要做滚动更新的话目前还没有找到一个很好的解决方案,有的团队是将长连接转换成短连接来进行处理的,我这边还是在应用层面来做的支持,比如客户端增加重试机制,连接断掉以后会自动重新连接,大家如果有更好的办法也可以留言互相讨论下方案。
相关推荐
- 教你一个解决手机卡顿的方法(10秒解决手机卡顿问题)
-
我们的手机天天刷头条,看视频,用了一阶段时间以后,就时不时的发生卡顿现象。昨天我的手机就发现了这个问题。友友们,你们遇到过这样的问题吗?你们都是怎样解决的?我看了一眼我的粉丝情况,头条君给我分析的很精...
- 手机视频缓存清理,3步彻底清空,告别卡顿
-
在我们使用手机观看视频的过程中,经常会产生大量的缓存垃圾,这些垃圾文件不仅占用了手机的存储空间,还可能导致手机卡顿和运行缓慢。然而,你知道如何彻底清空手机的视频缓存,让手机恢复流畅的使用体验吗?在本文...
- 关手机这个开关,轻松提升流畅度!
-
关闭手机这个开关,跟新买的一样流畅。手机不要再清理垃圾了,只要关闭这个开关,手机就会和新买的差不多,丝滑流畅不卡顿。其实抖音里就隐藏着一个小开关,每天刷过的视频都会保存在手机里,如果一直不清理,手机就...
- 如何清理今日头条和西瓜视频的内存,让手机流畅不卡顿?
-
对于老年人而言,今日头条和西瓜视频能带来丰富的资讯与娱乐。然而,随着使用时间的增加,这些应用会占用大量手机内存,致使手机运行卡顿。那该如何解决呢?接下来,我将用最简单易懂的方式教老年人清理今日头条和西...
- 视频在线如何转换格式?好用不卡顿的三种转换办法
-
转换视频格式目前来说已经是很熟练的操作了,但是还有些用户可能还是不知道,小编今天就特意给大家带来一些小众才知道的转换教程,让新手也能快速的上手去转换视频格式,以后获取到视频就不怕内容丢失了,视频的格式...
- 如何把视频慢放处理?这几个慢放方法记得收藏
-
如何把视频慢放处理?如果你想让视频慢放,可能是因为你想放慢一些精彩的瞬间,或者你想制作一个慢动作视频。在这篇文章中,我们将介绍一些调速方法,这些方法可以有效地调整视频速度,一起来学习一下吧。方法一:使...
- 如何清理看过的视频,释放垃圾,让手机更流畅?
-
现在谁的手机上没几个短视频平台,无聊时就会刷别人的视频。可您知道吗?我们看过的内容都会被自动保存在手机里,而且很耗内存。如果长时间不释放,手机就会出现各种问题,其中最突出的就是反应慢。相信很多老年人的...
- 手机掉帧是怎么回事?刷视频的时候经常掉帧卡顿
-
手机掉帧是指在运行应用或视频时,画面出现卡顿、不流畅的现象,通常由硬件性能不足、软件优化不佳、内存占用过高、网络问题或设备过热等因素引起。尤其是在刷视频时,掉帧问题可能更为明显,以下是具体原因及解决方...
- 拍视频画面卡顿不流畅,原来是相机设置错误 #短视频拍摄
-
拍摄视频时,应该选择哪种快门速度?许多新手朋友可能会认为,快门速度越高,画面就越清晰,实则不然。因为拍摄视频时,需要考虑一个问题,即动态模糊。例如,如果设置为24帧/秒,那么每秒钟会拍摄24张图片。如...
- 手机卡顿最大原因#视频太卡怎么变流畅
-
抖音这几个开关是手机卡顿的最大原因。你是不是也会经常遇到刷视频的时候,打开一个视频之后老半天还在那转着圈圈,总觉得手机没有之前流畅了。这就说明你的手机占用的内存太多了,导致手机卡顿,使用不流畅。使用手...
- 为啥你家的玩游戏和刷视频经常性的会卡,那是你不懂这些小妙招
-
本内容来源于@什么值得买APP,观点仅代表作者本人|作者:暴走的黄小猪说到网速有不少的值友都有一个共同点,那就是“卡”,那是你根本没体验过啥叫真正的网速啊,全屋零四条网络报表也花不了几个钱你们的方法...
- 电脑看视频卡顿有什么解决方法?(电脑看视频画面卡顿是什么原因)
-
电脑看视频卡顿的原因可能多种多样,包括硬件性能不足、网络问题、软件设置不当等。以下是一些常见的解决方法,帮助你改善视频播放的流畅度:一、硬件方面1.检查硬件性能:如果电脑配置较低,尤其是CPU、内存或...
- 手机Wi-Fi满格但视频卡顿,你需要这样解决
-
累了一天的打工人回家拿出手机准备玩玩游戏,看看电影时,发现网络异常卡顿,但手机又显示Wi-Fi信号满格,当咱们遇到此类问题时,这些动作能让网络恢复正常,方法如下。一、重启路由器和光猫很多家庭在安装好路...
- 视频越刷越卡?原来是路由器开启了这个功能,关闭方法来了
-
应该很多小伙伴都有过类似的经历,就是在家里长时间刷视频或者看剧的时候,网速好像会越来越慢,视频总是要加载。手机本身可能是一部分原因,但路由器也会影响,你知道吗?当我们在刷视频的,路由器会悄悄地开启大量...
- 一招解决视频卡顿的问题,改变发布渠道后,结果香了
-
最近一段时间拍了很多美景视频,编辑发布到头条后,有时一直显示在缓冲,播放不了,有时打开断断续续的,老是卡顿。导致的后果是:要么展现量很低,要么阅读量寥寥无几,这让我非常苦恼。所以再发布作品时,我只好文...
你 发表评论:
欢迎- 一周热门
-
-
如何在安装前及安装后修改黑群晖的Mac地址和Sn系列号
-
爱折腾的特斯拉车主必看!手把手教你TESLAMATE的备份和恢复
-
极空间如何无损移机,新Z4 Pro又有哪些升级?极空间Z4 Pro深度体验
-
[常用工具] OpenCV_contrib库在windows下编译使用指南
-
10个免费文件中转服务站,分享文件简单方便,你知道几个?
-
Ubuntu系统Daphne + Nginx + supervisor部署Django项目
-
WindowsServer2022|配置NTP服务器的命令
-
UOS服务器操作系统防火墙设置(uos20关闭防火墙)
-
日本海上自卫队的军衔制度(日本海上自卫队的军衔制度是什么)
-
【系统配置】信创终端挂载NAS共享全攻略:一步到位!
-
- 最近发表
- 标签列表
-
- 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)