如何限制Kubernetes本地临时存储的容量

栏目: 编程工具 · 发布时间: 5年前

内容简介:作为Kubernetes平台的提供方,必须要对某些“流氓”应用做出一些限制,防止它们滥用平台的CPU、内存、磁盘、网络等资源。例如,Kubernetes提供了对CPU,内存的限制,可以防止应用无限制的使用系统的资源;Kubernetes提供的PVC,如CephFS、RBD,也支持容量的限制。但是,早期Kubernetes版本并没有限制container的rootfs的容量,由于默认容器使用的log存储空间是在 /var/lib/kubelet/ 下,rootfs在/var/lib/docker下,而这两个目

介绍

作为Kubernetes平台的提供方,必须要对某些“流氓”应用做出一些限制,防止它们滥用平台的CPU、内存、磁盘、网络等资源。

例如,Kubernetes提供了对CPU,内存的限制,可以防止应用无限制的使用系统的资源;Kubernetes提供的PVC,如CephFS、RBD,也支持容量的限制。

但是,早期Kubernetes版本并没有限制container的rootfs的容量,由于默认容器使用的log存储空间是在 /var/lib/kubelet/ 下,rootfs在/var/lib/docker下,而这两个目录默认就在宿主机Node的根分区,如果应用恶意攻击,可以通过在容器内大量dd从而迅速造成宿主机Node根分区文件系统满。我们知道,当 Linux 根分区使用达到100%的时候,通常会很危险。

Kubernetes在1.8版本引入了一种新的resource:local ephemeral storage(临时存储),用来管理本地临时存储,对应特性 LocalStorageCapacityIsolation。从1.10开始该特性转为beta状态,默认开启。 如果你想和更多 Kubernetes 技术专家交流,可以加我微信liyingjiese,备注『加群』。群里每周都有全球各大公司的最佳实践以及行业最新动态

临时存储,如emptyDir volumes, container logs,image layers and container writable layers,默认它们使用的是 /var/lib/kubelet,通过限制临时存储容量,也就可以保护Node的root分区了。

本地临时存储管理只对root分区有效,如果你定制了相关的参数,例如 --root-dir,则不会生效。

配置

我的集群版本是1.14,默认开启了 local ephemeral storage 的特性,只需要配置Pod即可。

Pod的每个container都可以配置:

  • spec.containers[].resources.limits.ephemeral-storage
  • spec.containers[].resources.requests.ephemeral-storage

单位是byte,可以直接配置,也可以按E/P/T/G/M/K或者Ei, Pi, Ti, Gi, Mi, Ki.为单位来配置,例如 128974848, 129e6, 129M, 123Mi 表示的是同一个容量。

下面创建一个Deployment,设置其使用的临时存储最大为2Gi。

apiVersion: extensions/v1beta1

kind: Deployment

metadata:

name: nginx

namespace: default

spec:

selector:

matchLabels:

  run: nginx

template:

metadata:

  labels:

    run: nginx

spec:

  containers:

  - image: nginx

    name: nginx

    resources:

      limits:

        ephemeral-storage: 2Gi

      requests:

        ephemeral-storage: 2Gi

Pod启动后,进入容器,执行dd if=/dev/zero of=/test bs=4096 count=1024000 ,尝试创建一个4Gi的文件,可以发现在执行一段时间后,Pod被 Evict,controller重新创建了新的Pod。

nginx-75bf8666b8-89xqm                    1/1     Running             0          1h

nginx-75bf8666b8-pm687                    0/1     Evicted             0          2h

实现

Evict Pod动作是由kubelet完成的。每个节点上的kubelet会启动一个evict manager,每10秒种(evictionMonitoringPeriod)进行一次检查,ephemeral storage的检查也是在这个阶段完成的。

evict manager可以对pod和container来检查超额应用。

func (m *managerImpl) localStorageEviction(summary *statsapi.Summary, pods []*v1.Pod) []*v1.Pod {

statsFunc := cachedStatsFunc(summary.Pods)

evicted := []*v1.Pod{}

for _, pod := range pods {

    podStats, ok := statsFunc(pod)

    if !ok {

        continue

    }



    if m.emptyDirLimitEviction(podStats, pod) {

        evicted = append(evicted, pod)

        continue

    }



    if m.podEphemeralStorageLimitEviction(podStats, pod) {

        evicted = append(evicted, pod)

        continue

    }



    if m.containerEphemeralStorageLimitEviction(podStats, pod) {

        evicted = append(evicted, pod)

    }

}



return evicted

} 

其中Pod为GetActivePods获取的本节点所有非Terminated状态的Pod。

kubelet会依此检查Pod的emptyDir、Pod级临时存储、container级临时存储,若Pod需要被evict,则加到evicted数组,之后会将evicted的Pod挤出。

contaier级检查比较简单,因为ephemeral storage设置的就是在container上,依次检查container的使用情况和设置的limits,如果超过了limits,则要加入到evicted pods列表中。

相关代码在 containerEphemeralStorageLimitEviction 中。

而Pod级别的检查会复杂一点。

首先是限制值的计算。

kubelet会统计Pod所有container(但不包括init container)的ephemeral storage limits之和。init container指定的是Pod的配额最低需求(有点像最低工资标准,用于生活保障),当所有container指定的配额,超过init container指定的配额时,将忽略init container指定的配额。数学描述如下。

max(sum(containers), initContainer1, initContainer2, ...)

而实际临时存储用量的计算,除了会计算指定过ephemeral storage的container的使用量,还会统计未指定过ephemeral storage的container,以及emptyDir的使用量。

当实际临时存储用量,超过了限制值时,kubelet会将该Pod Evict,然后等待controller重新创建新的Pod并重新调度。

相关代码在 podEphemeralStorageLimitEviction 中。

requests

注意,设置的local ephemeralstorage requests在evict manager处理过程中没有用到。但是它不是没用的。

创建Pod后,scheduler会将该Pod调度到集群中某个node上。由于每个node所能承载的local ephemeral storage是有上限的,所以scheduler会保证该node上所有Pod的 local ephemeralstorage requests 总和不会超过node的根分区容量。

inode 保护

有的时候,我们会发现磁盘写入时会报磁盘满,但是df查看容量并没有100%使用,此时可能只是因为inode耗尽造成的。因此,对平台来说,inode的保护也是需要的。

其中,podLocalEphemeralStorageUsage 也统计了container或者pods使用的inode的数量。

但是当前Kubernetes并不支持对Pod的临时存储设置inode的limits/requests。

当然了,如果node进入了inode紧缺的状态,kubelet会将node设置为 under pressure,不再接收新的Pod请求。

emptyDir

emptyDir也是一种临时存储,因此也需要限制使用。

在Pod级别检查临时存储使用量时,也会将emptyDir的使用量计算在内,因此如果对emptyDir使用过量后,也会导致该Pod被kubelet Evict。

另外,emptyDir本身也可以设置容量上限。如下所摘录编排文件片段,我指定了emptyDir使用内存作为存储介质,这样用户可以获得极好的读写性能,但是由于内存比较珍贵,我只提供了64Mi的空间,当用户在 /cache 目录下使用超过64Mi后,该Pod会被kubelet evict。

volumeMounts:

    - mountPath: /cache

      name: cache-volume

  volumes:

  - emptyDir:

      medium: Memory

      sizeLimit: 64Mi

    name: cache-volume

相关代码在 emptyDirLimitEviction 中。

原文链接: https://ieevee.com/tech/2019/0 ... .html


以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

STL源码剖析

STL源码剖析

侯捷 / 华中科技大学出版社 / 2002-6 / 68.00元

学习编程的人都知道,阅读、剖析名家代码乃是提高水平的捷径。源码之前,了无秘密。大师们的缜密思维、经验结晶、技术思路、独到风格,都原原本本体现在源码之中。 这本书所呈现的源码,使读者看到vector的实现、list的实现、heap的实现、deque的实现、Red Black tree的实现、hash table的实现、set/map的实现;看到各种算法(排序、查找、排列组合、数据移动与复制技术......一起来看看 《STL源码剖析》 这本书的介绍吧!

JS 压缩/解压工具
JS 压缩/解压工具

在线压缩/解压 JS 代码

Base64 编码/解码
Base64 编码/解码

Base64 编码/解码

HSV CMYK 转换工具
HSV CMYK 转换工具

HSV CMYK互换工具