K8S节点本地存储被撑爆问题彻底解决方法

目录
  • 存储的内容
    • 镜像
    • 可写层
    • 日志
    • emptyDir
  • 存储的限制方法
    • K8S的GC
    • 日志总量限制
    • emptyDir Volume 限制
    • 临时数据的总量限制

存储的内容

现在云原生越来越流行,很多企业都上马了K8S,但是这里边也有很多的坑要填,这篇文章就聊一下K8S节点本地存储被撑爆的问题,也就是磁盘被占满的问题。

要解决存储使用过多的问题,就得先了解存储中都保存了些什么内容,否则解决不了问题,还可能带来更多的风险。

镜像

容器要在节点上运行,kubelet 首先要拉取容器镜像到节点本地,然后再根据镜像创建容器。随着Pod的调度和程序的升级,日积月累,节点本地就会保存大量的容器镜像,占用大量存储空间。

如果使用的是Docker容器运行时,这些文件保存在 /var/lib/docker/image/overlay2 目录下。

可写层

关于可写层,了解容器本质的同学应该比较熟悉,容器运行时使用的是一种联合文件系统技术,它把镜像中的多层合并起来,然后再增加一个可写层,容器中写操作的结果会保存在这一层,这一层存在于容器当前节点的本地存储中。虽然镜像中的层是容器实例共享的,但是可写层是每个容器一份。

假如我们有一个名为 mypod 的Pod实例,在其中创建一个文件:/hello.txt,并写入 hello k8s 的字符。

$ kubectl exec mypod -- sh -c 'echo "hello k8s" > /hello.txt'
$ kubectl exec mypod -- cat /k8s/hello.txt
hello k8s

如果使用的是Docker容器运行时,可以在Docker的相关目录中找到可写层以及刚刚创建的这个文件,它们在  /var/lib/docker/overlay2 这个目录下。

如果毫无节制的使用可写层,也会导致大量的本地磁盘空间被占用。

日志

K8S推荐的日志输出方式是将程序日志直接输出到标准输出和标准错误,此时容器运行时会捕捉这些数据,并把它们写到本地存储,然后再由节点上的日志代理或者Pod中的边车日志代理转运到独立的日志处理中心,以供后续分析使用。

这些日志保存在节点本地的  /var/log/container 目录下,我们可以实际创建一个Pod来确认下:

apiVersion: v1
kind: Pod
metadata:
  name: pod-log-stdout
spec:
  containers:
  - name: count
    image: busybox:latest
    args: [/bin/sh, -c,
            'i=0; while true; do echo "$i: $(date) a log entry."; i=$((i+1)); usleep 1000; done']

这个Pod每隔1毫秒会写1条数据到标准输出。要找到容器运行时根据标准输出创建的日志文件,首先要找到这个Pod部署的节点,然后登录到这个节点,就能找到对应的文件了。

如果程序输出的日志很多,占满磁盘空间就是早晚的事。

emptyDir

emptyDir 是一种基于节点本地存储的Volume类型,它通过在本地存储创建一个空目录来实际承载Volume。使用这种存储卷可以在Pod的多个容器之间共享数据,比如一个容器造数据,一个容器消费数据。

看下面这个例子:

apiVersion: v1
kind: Pod
metadata:
  name: pod-vol-empty-dir
spec:
  containers:
  - name: count
    image: busybox:latest
    args: [/bin/sh, -c, 'echo "k8s" > /cache/k8s.txt;sleep 1800']
    volumeMounts:
    - mountPath: /cache
      name: cache-volume
  volumes:
  - name: cache-volume
    emptyDir: {}

在 spec.volumes[] 中只需要添加一个名为 emptyDir 的字段,它的配置都可以使用默认值,然后这个卷会被挂载到容器的 /cache 路径。

容器的启动参数是一个shell命令,它会在容器的 cache 目录下创建1个名为 k8s.txt 的文件。容器创建后稍等一会,使用下面的命令获取这个文件的内容:

$ kubectl exec pod-vol-empty-dir -- cat /cache/k8s.txt
k8s

可以看到,文件内容正是容器启动命令中写入的 k8s 字符。

K8S会在当前的Node自动创建一个目录来实际承载这个卷,目录的位置在Node的  /var/lib/kubelet/pods 路径下。要查看这个目录中的内容,需要先找到Pod Id和对应的Node,然后登录到这个Node,就能找到这个目录了。minikube中的查找方法如下图所示:

注意用颜色框圈出来的内容,不同的Pod对应的数据不同。查找Pod Id的命令:

kubectl get pods -o custom-columns=PodName:.metadata.name,PodUID:.metadata.uid,PodNode:.spec.nodeName

如果不对 emptyDir Volume 做一些限制,也是有很大的风险会使用过多的磁盘空间。

存储的限制方法

通过上文的介绍,我们可以看到,除了容器镜像是系统机制控制的,其它的内容都跟应用程序有关。

应用程序完全可以控制自己使用的存储空间,比如少写点日志,将数据保存到远程存储,及时删除使用完毕的临时数据,使用LRU等算法控制存储空间的使用量,等等。不过完全依赖开发者的自觉也不是一件很可靠的事,万一有BUG呢?所以K8S也提供了一些机制来限制容器可以使用的存储空间。

K8S的GC

K8S有一套自己的GC控制逻辑,它可以清除不再使用的镜像和容器。这里我们重点看下对镜像的清理。

这个清理工作是 kubelet 执行的,它有三个参数来控制如何执行清理:

  • imageMinimumGCAge 未使用镜像进行垃圾回收时,其存在的时间要大于这个阈值,默认是2分钟。
  • imageGCHighThresholdPercent 镜像占用的磁盘空间比例超过这个阈值时,启动垃圾回收。默认85。
  • ImageGCLowThresholdPercent 镜像占用的磁盘空间比例低于这个阈值时,停止垃圾回收。默认80。

可以根据自己的镜像大小和数量的水平来更改这几个阈值。

日志总量限制

K8S对写入标准输出的日志有一个轮转机制,默认情况下每个容器的日志文件最多可以有5个,每个文件最大允许10Mi,如此每个容器最多保留最新的50Mi日志,再加上Node也可以对Pod数量进行限制,日志使用的本地存储空间就变得可控了。这个控制也是 kubelet 来执行的,有两个参数:

  • containerLogMaxSize 单个日志文件的最大尺寸,默认为10Mi。
  • containerLogMaxFiles 每个容器的日志文件上限,默认为5。

以上文的 pod-log-stdout 这个Pod为例,它的日志输出量很多就会超过10Mi,我们可以实际验证下。

不过如果没有意外,意外将要发生了,K8S的限制不起作用。这是因为我们使用的容器运行时是docker,docker有自己的日志处理方式,这套机制可能过于封闭,K8S无法适配或者不愿意适配。可以更改docker deamon的配置来解决这个问题,在K8S Node中编辑这个文件  /etc/docker/daemon.json (如果没有则新建),增加关于日志的配置:

{
    "log-opts": {
        "max-size": "10m",
        "max-file": "5"
    }
}

然后重启Node上的docker:systemctl restart docker。注意还需要重新创建这个Pod,因为这个配置只对新的容器生效。

在docker运行时下,容器日志实际上位于 /var/lib/docker/containers 中,先找到容器Id,然后就可以观察到这些日志的变化了:

emptyDir Volume 限制

对于emptyDir类型的卷,可以设置 emptyDir.sizeLimit,比如设置为 100Mi。

apiVersion: v1
kind: Pod
metadata:
  name: pod-vol-empty-dir-limit
spec:
  containers:
  - name: count
    image: busybox:latest
    args: [/bin/sh, -c,
            'while true; do dd if=/dev/zero of=/cache/$(date "+%s").out count=1 bs=5MB; sleep 1; done']
    volumeMounts:
    - mountPath: /cache
      name: cache-volume
  volumes:
  - name: cache-volume
    emptyDir:
      sizeLimit: 100Mi

稍等几分钟,然后查询Pod的事件:

可以看到 kubelet 发现 emptyDir volume 超出了100Mi的限制,然后就把 Pod 关掉了。

临时数据的总量限制

对于所有类型的临时性本地数据,包括 emptyDir 卷、容器可写层、容器镜像、日志等,K8S也提供了一个统一的存储请求和限制的设置,如果使用的存储空间超过限制就会将Pod从当前Node逐出,从而避免磁盘空间使用过多。

然后我们创建一个Pod,它会每秒写1个5M的文件,同时使用 spec.containers[].resources.requests.limits 给存储资源设置了一个限制,最大100Mi。

apiVersion: v1
kind: Pod
metadata:
  name: pod-ephemeral-storage-limit
spec:
  containers:
  - name: count
    image: busybox:latest
    args: [/bin/sh, -c,
            'while true; do dd if=/dev/zero of=$(date "+%s").out count=1 bs=5MB; sleep 1; done']
    resources:
      requests:
        ephemeral-storage: "50Mi"
      limits:
        ephemeral-storage: "100Mi"

稍等几分钟,然后查询Pod的事件:

kubectl describe pod pod-ephemeral-storage-limit

可以看到 kubelet 发现Pod使用的本地临时存储空间超过了限制的100Mi,然后就把 Pod 关掉了。

通过这些存储限制,基本上就可以说是万无一失了。当然还要在节点预留足够的本地存储空间,可以根据Pod的数量和每个Pod最大可使用的空间进行计算,否则程序也会因为总是得不到所需的存储空间而出现无法正常运行的问题。

以上就是K8S节点本地存储被撑爆问题彻底解决方法的详细内容,更多关于K8S节点本地存储被撑爆的资料请关注我们其它相关文章!

(0)

相关推荐

  • Kubernetes集群模拟删除k8s重装详解

    目录 一.系统环境 二.前言 三.重装Kubernetes集群 3.1 环境介绍 3.2 删除k8s所有节点(node) 3.3 kubeadm初始化 3.4 添加worker节点到k8s集群 3.5 安装calico 一.系统环境 服务器版本 docker软件版本 CPU架构 CentOS Linux release 7.4.1708 (Core) Docker version 20.10.12 x86_64 二.前言 当我们安装部署好一套Kubernetes集群,使用一段时间之后可能会有重新

  • Kubernetes k8s configmap 容器技术解析

    目录 1.什么是 ConfigMap? 2.ConfigMap 能带来什么好处? 3.ConfigMap 三种创建方式 4.ConfigMap 作为环境变量三种使用方式 单个引用 多个引用 args 方式传递环境变量 5.挂载 volume 6.Secret 使用 7.应用程序怎么做到不重启情况下读取最新配置 总结 1.什么是 ConfigMap? ConfigMap 是用来存储配置文件的 Kubernetes 资源对象,配置对象存储在 Etcd 中,配置的形式可以是完整的配置文件.key/va

  • go语言K8S 的 informer机制浅析

    目录 正文 使用方法 创建Informer工厂 创建对象Informer结构体 注册事件方法 启动Informer 机制解析 Reflector Controller Processer & Listener Indexer 总结 正文 Kubernetes的控制器模式是其非常重要的一个设计模式,整个Kubernetes定义的资源对象以及其状态都保存在etcd数据库中,通过apiserver对其进行增删查改,而各种各样的控制器需要从apiserver及时获取这些对象,然后将其应用到实际中,即将这

  • Centos7 安装部署Kubernetes(k8s)集群实现过程

    目录 一.系统环境 二.前言 三.Kubernetes 3.1 概述 3.2 Kubernetes 组件 3.2.1 控制平面组件 3.2.2 Node组件 四.安装部署Kubernetes集群 4.1 环境介绍 4.2 配置节点的基本环境 4.3 节点安装docker,并进行相关配置 4.4 安装kubelet,kubeadm,kubectl 4.5 kubeadm初始化 4.6 添加worker节点到k8s集群 4.7 部署CNI网络插件calico 4.8 配置kubectl命令tab键自

  • Go语言k8s kubernetes使用leader election实现选举

    目录 一.背景 二.官网代码示例 三.锁的实现 一.背景 在kubernetes的世界中,很多组件仅仅需要一个实例在运行,比如controller-manager或第三方的controller,但是为了高可用性,需要组件有多个副本,在发生故障的时候需要自动切换.因此,需要利用leader election的机制多副本部署,单实例运行的模式.应用程序可以使用外部的组件比如ZooKeeper或Etcd等中间件进行leader eleaction, ZooKeeper的实现是采用临时节点的方案,临时节

  • k8s node节点重新加入master集群的实现

    1.删除node节点 执行kubectl delete node node01 2.这时如果直接执行加入,会报错.如下: [root@k8s-node02 pki]# kubeadm join 192.168.140.128:6443 --token abcdef.0123456789abcdef --discovery-token-ca-cert-hash sha256:a3d9827be411208258aea7f3ee9aa396956c0a77c8b570503dd677aa3b6eb6

  • 理解k8s控制器DaemonSet创建及使用场景

    目录 DaemonSet 简介 DaemonSet 使用场景 DaemonSet 创建 查看 DaemonSet 更新 DaemonSet 删除 DaemonSet 其它使用场景 容忍性 Toleration 使用 节点亲和性 nodeAffinity 使用 总结 DaemonSet 简介 DaemonSet 的主要作用,是在 Kubernetes 集群里,运行一个 Daemon Pod. DaemonSet 只管理 Pod 对象,然后通过 nodeAffinity 和 Toleration 这

  • MySQL on k8s 云原生环境部署

    目录 一.概述 二.开始部署(一主两从) 1)添加源 2)修改配置 3)开始安装 4)测试验证 5)Prometheus监控 6)卸载 一.概述 MySQL是一个关系型数据库管理系统,由瑞典MySQL AB 公司开发,属于 Oracle 旗下产品.MySQL 是最流行的关系型数据库管理系统之一,在 WEB 应用方面,MySQL是最好的 RDBMS (Relational Database Management System,关系数据库管理系统) 应用软件之一.这里主要讲mysql部署在k8s上,

  • K8S节点本地存储被撑爆问题彻底解决方法

    目录 存储的内容 镜像 可写层 日志 emptyDir 存储的限制方法 K8S的GC 日志总量限制 emptyDir Volume 限制 临时数据的总量限制 存储的内容 现在云原生越来越流行,很多企业都上马了K8S,但是这里边也有很多的坑要填,这篇文章就聊一下K8S节点本地存储被撑爆的问题,也就是磁盘被占满的问题. 要解决存储使用过多的问题,就得先了解存储中都保存了些什么内容,否则解决不了问题,还可能带来更多的风险. 镜像 容器要在节点上运行,kubelet 首先要拉取容器镜像到节点本地,然后再

  • mysql本地登录无法使用端口号登录的解决方法

    最近在使用linux上进行本地登录时,发现既然无法正常登录 , 报如下错误信息: [root@xxxx ~]# mysql -h localhost -u root -p -P 3306 Enter password: ERROR 2002 (HY000): Can't connect to local MySQL server through socket '/tmp/mysql.sock' (2) 分析:使用mysql --verbose --help进行分析,才发现原来port和socke

  • 纯js实现无限空间大小的本地存储

    好久没有写博客了,想到2年前答应要放出源代码的也没放出来,最近终于有空先把纯js实现无限空间大小的本地存储的功能开源了, 项目地址https://github.com/xueduany/localstore, demo见http://xueduany.github.io/localstore/, 下面给大家简单说说大概原理,具体细节和异常处理后面有机会在单独说 先说下突破本地localStorage的原理,官方原话是这么说的http://www.w3.org/TR/2013/PR-webstor

  • jQuery访问浏览器本地存储cookie、localStorage和sessionStorage的基本用法

    前言:cookie,localStorage和sessionStorage都是浏览器本地存储数据的地方,其用法不尽相同:总结一下基本的用法. 一.cookie 定义: 存储在本地,容量最大4k,在同源的http请求时携带传递,损耗带宽: 可设置访问路径,只有此路径及此路径的子路径才能访问此cookie,存在有效的时间. 注意点: cookie的访问需要服务器环境,直接在本地文件访问无效: cookie的访问和设置需要导入jquery.cookie.js文件: 浏览器对每一个访问的地址下可添加的c

  • AngularJS之ionic 框架下实现 Localstorage本地存储

    前言: 我们前台用的是ionic+AngularJS,做的是混合模式移动应用.最近有一个需求是,我在页面A上面滑动的时候,跳入页面B,页面B需要加载页面A的数据,这样的页面传值如何实现呢?那就需要用到LocalStorage本地存储了. Ionic Ionic是目前最有潜力的一款HTML5手机应用开发框架.通过SASS构架应用程序,他提供了很多UI控件来帮助开发者开发强大的应用.加上angularjs可以让ionic应用体验度增强.代码也非常简单.angularjs可以提供数据的双向绑定,使用它

  • 微信小程序 本地存储及登录页面处理实例详解

    实例内容 登陆界面 处理登陆表单数据 处理登陆表单数据(异步) 清除本地数据 登录界面: 在app.json中添加登陆页面pages/login/login,并设置为入口. 保存后,自动生成相关文件(挺方便的). 修改视图文件login.wxml <!--pages/login/login.wxml--> <view class="container"> <form bindsubmit="formSubmit"> <vie

  • 本地存储localStorage用法详解

    一.什么是localStorage? 在HTML5中,新加入了一个localStorage特性,这个特性主要是用来作为本地存储来使用的,解决了cookie存储空间不足的问题(cookie中每条cookie的存储空间为4k),localStorage中一般浏览器支持的是5M大小,这个在不同的浏览器中localStorage会有所不同. 二.localStorage的优势与局限 localStorage的优势 1.localStorage拓展了cookie的4K限制 2.localStorage会可

  • js仿微博实现统计字符和本地存储功能

    随着移动设备和Web应用的普及,为了更好的便于用户的使用,对于网页或应用程序的用户体验要求就越来越高,确实是这样,作为用户更喜欢选择用户体验效果好的网站或应用程序,所以作为开发者的我们就需要开发出更人生化的应用程序了. 相信许多人有使用微博的经验,像微博这样的社交平台,好的用户体验就变得尤其重要了. 例如:我们在发微博时,文本框会实时地提示我们剩余字符数,这样人性化的提示方便了用户知道微博字数的限制,同时也限制了用户的输入字数. 有一句话我们要牢记在心的是:凡是输入,必有限制:凡是输入,必须校验

  • js浏览器本地存储store.js介绍及应用

    store.js - 轻松实现本地存储(LocalStorage) store.js 是一个兼容所有浏览器的 LocalStorage 包装器,不需要借助 Cookie 或者 Flash.store.js 会根据浏览器自动选择使用 localStorage.globalStorage 或者 userData 来实现本地存储功能. store.js 提供非常简洁的 API 来实现跨浏览器的本地存储功能: 复制代码 代码如下: store.set('username', 'marcus') stor

  • JS实现本地存储信息的方法(基于localStorage与userData)

    本文实例讲述了JS实现本地存储信息的方法.分享给大家供大家参考,具体如下: WEB应用的快速发展,是的本地存储一些数据也成为一种重要的需求,实现的方案也有很多,最普通的就是cookie了,大家也经常都用,但是cookie的缺点是显而易见的,其他的方案比如:IE6以上的userData,Firefox下面的globalStorage,以及Flash的本地存储,除了Flash之外,其他的几个都有一些兼容性的问题. sessionStorage与localStorage Web Storage实际上由

随机推荐