kubelet版本升级引起的容器重启机制与参考解决方案

简介: 背景 k8s能够帮助我们的服务实现服务高可用,其提供的副本机制能够有效的保证运行实例的副本数,从而当某个实例异常后服务可以重新被自动唤起,但在我们的生产环境中,某些特殊的服务(如广告资金服务或计费服务)因服务重启期间而导致的业务中断,对业务请求的延时响应也是不可忽略的问题;而在kubelet的部分版本升级中,也可能会因版本的升级进而导致已经运行的容器服务发生重启;而在特殊的生产环境中类似的操作直接引起的服务重启是需要我们尽可能去规避的; 此篇内容即是对kubelet版本升级与container自动重启这一关联过程原因分析以及供参考方案的简单介绍。

背景


k8s能够帮助我们的服务实现服务高可用,其提供的副本机制能够有效的保证运行实例的副本数,从而当某个实例异常后服务可以重新被自动唤起,但在我们的生产环境中,某些特殊的服务(如广告资金服务或计费服务)因服务重启期间而导致的业务中断,对业务请求的延时响应也是不可忽略的问题;而在kubelet的部分版本升级中,也可能会因版本的升级进而导致已经运行的容器服务发生重启;而在特殊的生产环境中类似的操作直接引起的服务重启是需要我们尽可能去规避的;

此篇内容即是对kubelet版本升级与container自动重启这一关联过程原因分析以及供参考方案的简单介绍。

环境基本信息:

操作系统: CentOS 7

kubelet当前版本:1.7.4

目标kubelet版本:1.9.1

现象

当前kubelet版本1.7.4中已持续运行一些容器服务,在对kubelet版本升级1.9.1后,所升级机器上已持续运行多天的container服务出现自动重启,重启之后继续提供服务

原因

因为container的自动重启发生在kubelet版本升级后,所以需要沿kubelet启动后的接口函数调用链进行定位,以确认container重启的根本原因.

总体调用链关系图:(右下角computePodActions() 函数中containerChanged()函数即为决定container服务是否重启的判断逻辑)

高清无码图下载(https://pan.baidu.com/s/1dtMmbO

链路跟踪过程:(整体kubelet调用关系比较复杂,后面仅针对问题的场景关键链路进行分析)

@kubernetes-1.9.1/cmd/kubelet/kubelet.go @表示所处的源码文件,后面意义相同)

启动kubelet main()入口,风格上保持主入口代码最小化的设计风格

功能上仅是读取config初始化配置结构后调用真正的server中的Run()

@kubernetes-1.9.1/cmd/kubelet/app/server.go

判断启动模式,同时初始化证书相关和心跳等,以及进行健康度的检查

RunKubelet中启动协程,进入真正的更新处理流程kubelet中的Run主体

@kubernetes-1.9.1/pkg/kubelet­/kubelet.go

与场景现象相关的逻辑处理主入口,依次进行非依赖模块初始化initializeModules(“internal modules that do not require the container runtime to be up”),以及使用kubeClient与APIserver 同步node状态信息和本地网络状态及容器网络状态的检查

statusprobepleg作用如下图示,可参照如上整体的调用链路简图

@kubernetes-1.9.1/pkg/kubelet/kubelet.go

syncLoop(),处理变化的主循环逻辑,监听3种来源的管道:file, apiserver, http;

只要有消息就会进行处理(监听的也是updates消息队列)

在syncLoopIteration迭代过程中,会根据不同的类型(config\pleg\sync…)进行相应的处理,处理是通过调用对应的Handle*()函数实现的

在各自的处理函数中,针对所有的类别,本质都是调用dispatchWork,只是传入的参数分别为不同的类别而已;如果pod已是终止状态了,则需要同时调用statusManager.TerminatePod(pod) 来通知apiserver状态的更新;

在dispatchWork函数中,会调用具体执行单元worker中UpdatePod函数,此时已将变化封装的信息交由执行单元worker。

@kubernetes-1.9.1/pkg/kubelet/pod_workers.go

在UpdatePod中,主要是启动持续处理逻辑managePodLoop(),此函数只运行一次,执行后会启动一个循环来处理syncPodFn指向函数。如果希望退出循环则如下2个函数被调用时会中止这个循环:ForgetWorker()与 ForgetNonExistingPodWorkers();控制这2个函数是否被调用则依赖于housekeepingCh 消息队列的处理。

managePodLoop会调用syncPodFn函数

syncPodFn指向kubelet.go中的syncPod处理函数。

@kubernetes-1.9.1/pkg/kubelet/kubelet.go

对于status, mkdir与volume简述如下

最后调用容器运行时的SyncPod函数,以便对POD中容器进行操作。

@ kubernetes-1.9.1/pkg/kubelet/container/runtime.go

containerRuntime.SyncPod进而调用

@ kubernetes-1.9.1/pkg/kubelet/kuberuntime/kuberuntime_manager.go

调用computePodActions()判断哪些container发生了变化,以便后面对变化的container进行处理(如重启等)

在computePodAction()中会对POD中运行的container进行判断,以此为基础来决定后面是否对这个运行的container进行重启(即决定是否重启container的入口判断逻辑)

检查运行时container与pod.spec中是否Hash一致,如果发生变化,则在changes结构中ContainersToStart 加入这个container,以便统一对ContainersToStart数组中的容器进行重启

@ kubernetes-1.9.1/pkg/kubelet/container/helpers.go

container进行深层次HASH计算

@ kubernetes-1.9.1/pkg/util/hash/hash.go

使用spewcontainer对象元素进行字符拼接(github.com/davecgh/go-spew/spew

由此可见,在版本升级启动后,定时触发的containerChanged()函数对container结构元素进行了内容上的HASH比对校验,从而将变化的container加入到ContainersToStart列表。

syncPodFnDeepHashObject链路如下所示:

由于DeepHashObject是对container结构的序列化进行HASH计算,所以对比升级前后版本Container结构不难发现,成员增了VolumeDevices等新成员。

所以在对container进行HASH计算时出现了新旧版本计算HASH值的不一致进而引起重启container服务。

方案

由于重启container是基于container HASH值的比较来判定的,所以可以将kubelet版本信息与启动时间记录并持久化,当container变化后计算HASH的时候,参考持久化的信息辅助决定是否忽略重启的条件。基本参考方案示例流图如下

更新源代码的补丁文件@ https://github.com/cloudusers/UpdateKubeletVersionIgnoreContainerRestart

适用场景及注意事项

适用于在kubelet版本升级情况下,container服务持续运行不希望重启的业务场景;同时因对源码的改动也引入了如下的注意事项或复杂点:

1)版本升级前对比不同版本container结构的变化情况以便了解是否升级对容器HASH计算产生影响;

2)目前采用的记录并缓存kubelet版本及启动时间信息至checkpoint持久化本地文件,所以版本升级前文件的损坏可能使得容器服务依旧会重新启动(因checkpoint内容较少,可以临时手动生成);

3)在每次版本升级前需要对新版本进行源码更新重新编译生成二进制执行文件,过程稍显复杂。

综上所述,简单介绍了自kubelet启动至container服务重启的链路调用关系,同时确认版本升级后引起容器重启的判断条件及处理逻辑,以及提供可参考的避免因版本升级引起重启容器的解决方案;

另一方面简单说明了源码修改后所适用的场景及注意事项。因目前还处在研发阶段,但是我们可以发现,通过规避容器服务因版本升级导致的重启可以解决生产环境中的关键业务无服务中断的问题。

本文转自kubernetes中文社区-kubelet版本升级引起的容器重启机制与参考解决方案

相关实践学习
使用ACS算力快速搭建生成式会话应用
阿里云容器计算服务 ACS(Container Compute Service)以Kubernetes为使用界面,采用Serverless形态提供弹性的算力资源,使您轻松高效运行容器应用。本文将指导您如何通过ACS控制台及ACS集群证书在ACS集群中快速部署并公开一个容器化生成式AI会话应用,并监控应用的运行情况。
深入解析Docker容器化技术
Docker是一个开源的应用容器引擎,让开发者可以打包他们的应用以及依赖包到一个可移植的容器中,然后发布到任何流行的Linux机器上,也可以实现虚拟化,容器是完全使用沙箱机制,相互之间不会有任何接口。Docker是世界领先的软件容器平台。开发人员利用Docker可以消除协作编码时“在我的机器上可正常工作”的问题。运维人员利用Docker可以在隔离容器中并行运行和管理应用,获得更好的计算密度。企业利用Docker可以构建敏捷的软件交付管道,以更快的速度、更高的安全性和可靠的信誉为Linux和Windows Server应用发布新功能。 在本套课程中,我们将全面的讲解Docker技术栈,从环境安装到容器、镜像操作以及生产环境如何部署开发的微服务应用。本课程由黑马程序员提供。     相关的阿里云产品:容器服务 ACK 容器服务 Kubernetes 版(简称 ACK)提供高性能可伸缩的容器应用管理能力,支持企业级容器化应用的全生命周期管理。整合阿里云虚拟化、存储、网络和安全能力,打造云端最佳容器化应用运行环境。 了解产品详情: https://www.aliyun.com/product/kubernetes
相关文章
|
9月前
|
监控 Linux 调度
【赵渝强老师】Docker容器的资源管理机制
本文介绍了Linux CGroup技术及其在Docker资源管理中的应用。通过实例演示了如何利用CGroup限制应用程序的CPU、内存和I/O带宽使用,实现系统资源的精细化控制,帮助理解Docker底层资源限制机制。
846 6
|
关系型数据库 MySQL API
|
Docker 容器
Docker网关冲突导致容器启动网络异常解决方案
当执行`docker-compose up`命令时,服务器网络可能因Docker创建新网桥导致IP段冲突而中断。原因是Docker默认的docker0网卡(172.17.0.1/16)与宿主机网络地址段重叠,引发路由异常。解决方法为修改docker0地址段,通过配置`/etc/docker/daemon.json`调整为非冲突段(如192.168.200.1/24),并重启服务。同时,在`docker-compose.yml`中指定网络模式为`bridge`,最后通过检查docker0地址、网络接口列表及测试容器启动验证修复效果。
1889 39
|
Kubernetes 开发者 容器
"Kubernetes的生死抉择:揭秘Pod容器重启策略如何决定应用命运的惊天大戏"
【8月更文挑战第20天】Kubernetes (k8s) 是一个强大的容器编排平台,其中Pod是最小的运行单元。Pod的重启策略确保服务连续性,主要有Always(总是重启)、OnFailure(失败时重启)和Never(从不重启)。默认策略为Always。根据不同场景,如Web服务、批处理作业或一次性任务,可以选择合适的策略。K8s还支持健康检查等高级机制来控制容器重启。合理配置这些策略对维护应用稳定性至关重要。
495 4
|
监控 关系型数据库 MySQL
zabbix7.0.9安装-以宝塔安装形式-非docker容器安装方法-系统采用AlmaLinux9系统-最佳匹配操作系统提供稳定运行环境-安装教程完整版本-优雅草卓伊凡
zabbix7.0.9安装-以宝塔安装形式-非docker容器安装方法-系统采用AlmaLinux9系统-最佳匹配操作系统提供稳定运行环境-安装教程完整版本-优雅草卓伊凡
1148 30
|
弹性计算 运维 Kubernetes
容器化管理云上应用解决方案评测
容器化管理云上应用解决方案评测
211 10
|
Docker 容器
docker 容器重启
【10月更文挑战第30天】docker 容器重启
4264 0
|
Docker 容器
Docker启动的容器如何做到自动重启?
【8月更文挑战第19天】Docker启动的容器如何做到自动重启?
2182 1
|
网络协议 Linux 网络安全
遇到Docker容器网络隔断?揭秘六种超级实用解决方案,轻松让Docker容器畅游互联网!
【8月更文挑战第18天】Docker容器内网络不通是开发者常遇问题,可能因网络配置错、Docker服务异常或防火墙阻碍等原因引起。本文提供六种解决策略:确认Docker服务运行状态、重启Docker服务、检查与自定义Docker网络设置、验证宿主机网络连接、临时禁用宿主机IPv6及检查防火墙规则。通过这些步骤,多数网络问题可得以解决,确保容器正常联网。
5667 1