前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >k8s集群内的节点,可能没你想象的那么健壮!(磁盘管理篇)

k8s集群内的节点,可能没你想象的那么健壮!(磁盘管理篇)

作者头像
博文视点Broadview
发布2023-05-19 19:13:57
8830
发布2023-05-19 19:13:57
举报
文章被收录于专栏:博文视点Broadview

节点是组成k8s集群的基本单位,Pod的容器最终是需要在节点上创建并运行起来,因此节点健康状态直接影响到了k8s集群和用户容器的健康。

在每个人入门容器的第一课,都会了解到容器在节点上是基于namespace和cgroup来做隔离,可是仅仅是相互之间做隔离,就足够了吗?

在容器应用落地和长期的运维过程中,会面临比隔离更多的实际需要面对的问题。归结起来,有两大类:

  • 当众多的容器在节点上运行起来,如何能保证容器的行为不会影响到节点的其他容器,或者甚至把节点搞挂? 这个问题,是长期的k8s运维中会经常面对的一个问题,容器的某些行为,会影响到其他的容器和节点,在k8s的版本演进中,有些已经被修复,有些却一直存在并且会长期存在。
  • 如何能保证节点可以承载众多的应用? 在应用独自占用节点的时代,节点的资源属于特定应用独享,所以在大多数时候,系统的默认配置,可以完全满足应用的需要。可是在容器时代,一个节点上会跑各种各样的应用,操作系统面临更复杂的业务情况,很多配置的默认值很已经不能满足需求了,进而影响到应用和节点的稳定性。

在k8s的落地实践中,这两个问题都是不能避免的,有时候甚至是一个问题。上甘岭不是一下子拿下来的,而是一个阵地一个阵地的争夺。节点稳定性维护也类似,不会是个一蹴而就的过程,而是各个细节点的优化再优化,一个点一个点地逐步解决。

本文选自新书《Kubernetes生产化实践之路》,将从节点磁盘这个点来深入探讨。

▊ 磁盘的分区

  • kubelet的工作目录

在kubelet的默认设计上,是使用/var/lib/kubelet作为工作目录的,并且默认使用/var/log作为日志的存储目录,而且默认/var/lib/kubelet 和/var/log是在root分区上的,所以不建议用户将这两个目录使用非root分区。Pod empytDir 的卷,就位于kubelet的工作目录下属于Pod的某个子目录, 例如:

代码语言:javascript
复制
1/var/lib/kubelet/pods/a64f37ba8c5add4c01a106b1680248f9/volumes/kubernetes.io~empty-dir/tmp
  • 运行时工作目录

用户会一般选择docker,或者containerd作为运行时。运行时的工作目录,会存储容器的镜像,还有容器的可写层数据。运行时目录可以同样位于root分区上,也可以单独做个分区,避免容器的数据影响root分区。 

  • 磁盘其他分区

磁盘的其他分区可以作为local volume提供给Pod使用。至于如何有效管理这些磁盘,后面有机会可以再写个文章展开讲解。

▊ 容器的存储驱动

docker和containerd运行时都支持多种的容器存储驱动,例如overlay2,devicemapper等。overlay2是目前广泛推荐的存储驱动,如果没有特殊的需求,基本上用户都会选择overlay2作为存储驱动。因为数据的存储,推荐都放在Pod的外挂卷上,而不要存储在容器的可写层,所以在容器的存储驱动上,稳定性是超过读写性能的更需要考虑的因素。

https://docs.docker.com/storage/storagedriver/select-storage-driver/#docker-engine---community

基于以上两个官方推荐的节点配置,我们来看下磁盘满这个问题。

Kubelet具有针对磁盘的eviction机制,当磁盘root分区和运行时分区(如果存在)的inode或者空间少于一定的门限,会进行相关资源的释放,例如进行镜像的回收,删除已经退出的容器,或者删除相关正在运行的pod。所以如果用户使用磁盘空间或者inode不恰当,可能会造成正在运行的其他pod被删除的情况,这是集群的管理者所不愿意看到的。

容器可以通过多种方式来使用节点上的磁盘空间,主要有emptyDir,容器镜像,容器的可写层,以及容器日志。如果没有对这几种容器使用节点磁盘的方式进行限制,当容器往emptyDir或者容器可写层写大量数据,很容易将节点的root分区和运行时分区(如果存在)磁盘用满,进而导致节点不能正常工作。在kubernetes 1.8之前,这是经常发现的导致磁盘满的原因。尽管可以通过对emptyDir增加sizeLimit来限制对emptyDir的使用,但是因为这样的sizeLimit没有被调度处理,所以依然存在问题。

kubernetes 1.8引入了ephemeral-storage的特性,来针对容器使用磁盘进行管理。emptyDir,容器日志,容器的可写层都被归结为ephemeral-storage。类似CPU,Memory,容器可以通过spec.containers[].resources.limits.ephemeral-storage和spec.containers[].resources.requests.ephemeral-storage来申明对节点磁盘的空间使用。

但是这个特性直接打开就可以了吗?这个特性的使能,是有前提条件的。因为emptyDir,日志,和容器可写层都被归结为统一的ephemeral-storage,因此这三者需要在同一个磁盘分区(推荐是root分区)上才可以被统一管理。

当你费了九牛二虎之力将集群上的机器的磁盘分区都更改为支持该特性的模式,是否意味着全部解决问题了呢?用户的这些使用本地磁盘的行为,真的都能被限制住吗?

我们可以看kubelet如何来检测下emptyDir,容器的可写层,和容器日志的使用率的,都采用了du或者类似du的方式。

当我们将一个文件打开,然后再将文件删除,因为文件描述符被打开,所以文件并不会真正删除,依旧占用磁盘空间,而du却检测不出来。因此如果有用户通过不断打开文件并删除的方式来占用磁盘空间,是可以导致节点的磁盘被写满,可是kubelet并不能进行有效控制。另外通过du的计算方式在文件大量存在的情况下非常低效,有时候当计算结果还没出来,磁盘就已经满了。

既然问题来了,聪明的开发者想到,可以通过文件系统的quota特性来对emptyDir卷的使用率进行监控,该方式可以检测到真正的磁盘使用率。而容器的可写层(只针对overlayfs),如果是使用docker作为运行时,也是可以通过文件系统的quota来进行限制的(https://docs.docker.com/engine/reference/commandline/run/#set-storage-driver-options-per-container)。如果使用containerd作为运行时,那么目前还是不支持。 

于是你需要将节点相关磁盘的mount option修改为支持文件系统的quota特性,然后在kubelet,docker上使能quota相关的特性,辛苦一番后,我们能翘起二郎腿,觉得万事大吉了吗?

当然还是不能,难道容器只能通过这三种方式往磁盘上写数据吗?

在Dockerfile中,我们能看到一条指令,叫VOLUME 。

(https://docs.docker.com/engine/reference/builder/#volume)

意思是给容器提供一个卷来使用。很多开源的镜像,为了支持多种部署方式,都会在Dockerfile里面定义这样都卷来存储数据。当将这样的容器部署到集群里后,如果没有在Pod Spec里指定特定的卷mount到容器内VOLUME指令指定的目录,那么运行时会在运行时的工作目录下,创建一个本地目录,然后再mount给容器使用。当用户往该目录写数据使用磁盘,而该行为并不会被kubelet监控到。因此你只能修改相关的运行时代码,将该行为在相关节点上禁掉。

当经过了前面的阶段,磁盘的问题算彻底解决了吗?很明显,还是不能,因为磁盘不仅仅是空间占用问题,还有inode资源,IO资源等问题。 

① 当某个容器往emptyDir里面创建大量的问题,是否可以将磁盘的根分区的inode耗尽?

目前对容器inode资源的使用,并没有做相应的限制。

② 当某个容器往emptyDir里面大量读写数据,是否会将磁盘的IO耗尽,影响其他用户或者系统进程对磁盘的使用?

目前容器普遍使用的cgroup v1 版本,还只能限制direct IO,而无法限制buffer IO。理论上cgroup V2可以解决这个问题。目前各大社区也在推进cgroup v2版本的支持工作,但是还并没有大规模使用。另外cgroup V2目前也才刚开始支持XFS。

上面我们讲了emptyDir和容器可写层的限制,那么日志呢?

在我们的长期实践中,日志也是经常会导致节点空间被占用的原因之一,这里的日志包含系统服务的日志和容器的日志。日志的控制,非常依赖于节点logrotate服务。可是你节点上的logrotate服务真的配置正确了?更多内容《Kubernetes生产化实践之路》一书中详细讲解。

▊ 图书推荐

▊《Kubernetes生产化实践之路》

孟凡杰 等著

  • 规模化K8s生产最佳实践
  • 基于K8s 1.18,所有案例来自eBay一线实践

本书从设计层面剖析了Kubernetes的设计原理,并阐述了其设计背后的生产系统问题。从互联网公司的视角出发,分享了如何构建高可用的多租户集群,如何确保集群的稳定性和高性能。

此外,本书阐述了数据面优化的重要性,并介绍了各个关键点,以确保使用物理机或虚拟机的应用在迁移至容器平台后能够获得最佳性能。

(扫码获取详情)

如果喜欢本文

欢迎 在看留言分享至朋友圈 三连

热文推荐 


▼点击阅读原文,获取本书详情~

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2020-12-09,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 博文视点Broadview 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
容器服务
腾讯云容器服务(Tencent Kubernetes Engine, TKE)基于原生 kubernetes 提供以容器为核心的、高度可扩展的高性能容器管理服务,覆盖 Serverless、边缘计算、分布式云等多种业务部署场景,业内首创单个集群兼容多种计算节点的容器资源管理模式。同时产品作为云原生 Finops 领先布道者,主导开源项目Crane,全面助力客户实现资源优化、成本控制。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档