小白解说之资源控制技术cgroup

小白解说之资源控制技术cgroup,第1张

大家好,我是小白。今天给大家讲解一下Linux下的资源控制cgroup。

提到cgroup,可能有的同学一时不太清楚做什么用的,但大家应该都用过公有云虚拟机或者容器,套餐1C2G,如何限制资源使用实现的呢,答案就是cgroup啦~

一、何为cgroup

Linux cgroups 的全称是 Linux Control Groups,它是 Linux 内核的特性,主要作用是限制、记录和隔离进程组(process groups)使用的物理资源(cpu、memory、IO 等)。

cgroups 从设计之初使命就很明确,为进程提供资源控制,它主要的功能包括:

目前 cgroups 已经成为很多技术的基础,比如 Openstack、LXC、Docker、Kubernetes、systemd等。

二、Cgroup概念

cgroup 全程control group,除了它本身的概念,还有Task(进程)、 Hierarchy(层级结构) 和 subsystem(子系统) 的概念

1. cgroups子系统

cgroups为每种可以控制的资源定义了一个子系统。典型的子系统介绍如下:

    cpu 子系统,主要限制进程的 cpu 使用率。

    cpuacct 子系统,可以统计 cgroups 中的进程的 cpu 使用报告。

    cpuset 子系统,可以为 cgroups 中的进程分配单独的 cpu 节点或者内存节点。

    memory 子系统,可以限制进程的 memory 使用量。

    blkio 子系统,可以限制进程的块设备 io。

    devices 子系统,可以控制进程能够访问某些设备。

    net_cls 子系统,可以标记 cgroups 中进程的网络数据包,然后可以使用 tc 模块(traffic control)对数据包进行控制。

    freezer 子系统,可以挂起或者恢复 cgroups 中的进程。

    ns 子系统,可以使不同 cgroups 下面的进程使用不同的 namespace。

这里面每一个子系统都需要与内核的其他模块配合来完成资源的控制,比如对 cpu 资源的限制是通过进程调度模块根据 cpu 子系统的配置来完成的;对内存资源的限制则是内存模块根据 memory 子系统的配置来完成的,而对网络数据包的控制则需要 Traffic Control 子系统来配合完成。本文不会讨论内核是如何使用每一个子系统来实现资源的限制,而是重点放在内核是如何把 cgroups 对资源进行限制的配置有效的组织起来的,和内核如何把cgroups 配置和进程进行关联的,以及内核是如何通过 cgroups 文件系统把cgroups的功能暴露给用户态的。

2. cgroups 层级结构(Hierarchy)

内核使用 cgroup 结构体来表示一个 control group 对某一个或者某几个 cgroups 子系统的资源限制。cgroup 结构体可以组织成一颗树的形式,每一棵cgroup 结构体组成的树称之为一个 cgroups 层级结构。cgroups层级结构可以 attach 一个或者几个 cgroups 子系统,当前层级结构可以对其 attach 的 cgroups 子系统进行资源的限制。每一个 cgroups 子系统只能被 attach 到一个 cpu 层级结构中。

3. cgroup概念间的关系

    系统创建hierarchy 之后,所有的进程都会加入这个hierarchy的cgroup的根节点。在这个cgroup根节点是hierarchy默认创建的。

    一个subsystem只能附加到一个hierarchy上面。

    一个进程可以作为多个cgroup的成员,但是cgroup必须在不同的hierarchy中。

    一个进程fork的子进程和父进程在同一个cgroup中也可以根据需要移到其他cgroup中。

三、容器如何使用cgroup的

1. Docker容器和cgroup

Docker 容器的内存限制放在了 /sys/fs/cgroup/memory/docker 目录下,比如:

2. Kubernetes Pod和cgroup

CRI-O 是被设计面向 Kubernetes 的,所以在一些目录名中就有浓浓的 k8s 风格。

CRI-O 容器的内存限制放在了 /sys/fs/cgroup/memory/kubepods.slice 目录下,这一层目录下,又根据 QoS 创建了三个子目录 kubepods-besteffort.slice、kubepods-burstable.slice、kubepods-guaranteed.sice 分别表示三种不同 QoS Class的内存限制。

Kubernete对资源的限制,靠的是cri-o,cri-o对资源的限制,靠的是Linux Cgroup 。

Linux Cgroup 限制资源,是限制进程,只需要在Cgroup配置目录的tasks文件中,添加进程ID,限制立即生效。

Linux Cgroup 不仅仅可以限制CPU,内存,还可以限制磁盘IO等。

说起容器监控,首先会想到通过Cadvisor, Docker stats等多种方式获取容器的监控数据,并同时会想到容器通过Cgroups实现对容器中的资源进行限制。但是这些数据来自哪里,并且如何计算的?答案是Cgroups。最近在写docker容器监控组件,在深入Cadvisor和Docker stats源码发现数据都来源于Cgroups。了解之余,并对Cgroups做下笔记。

01

Cgroups介绍

Cgroups 是 control groups 的缩写,是Linux内核提供的一种可以限制,记录,隔离进程组(process groups)所使用物理资源的机制。最初有google工程师提出,后来被整合进Linux的内核。因此,Cgroups为容器实现虚拟化提供了基本保证,是构建Docker,LXC等一系列虚拟化管理工具的基石。

02

Cgroups作用

资源限制(Resource limiting): Cgroups可以对进程组使用的资源总额进行限制。如对特定的进程进行内存使用上限限制,当超出上限时,会触发OOM。

优先级分配(Prioritization): 通过分配的CPU时间片数量及硬盘IO带宽大小,实际上就相当于控制了进程运行的优先级。

资源统计(Accounting): Cgroups可以统计系统的资源使用量,如CPU使用时长、内存用量等等,这个功能非常适用于计费。

进程控制(ControlCgroups): 可以对进程组执行挂起、恢复等操作。

03

Cgroups 组成

Cgroups主要由task,cgroup,subsystem及hierarchy构成。下面分别介绍下各自的概念。

task: 在Cgroups中,task就是系统的一个进程。

cgroup: Cgroups中的资源控制都以cgroup为单位实现的。cgroup表示按照某种资源控制标准划分而成的任务组,包含一个或多个子系统。一个任务可以加入某个cgroup,也可以从某个cgroup迁移到另外一个cgroup。

subsystem: Cgroups中的subsystem就是一个资源调度控制器(Resource Controller)。比如CPU子系统可以控制CPU时间分配,内存子系统可以限制cgroup内存使用量。

hierarchy: hierarchy由一系列cgroup以一个树状结构排列而成,每个hierarchy通过绑定对应的subsystem进行资源调度。hierarchy中的cgroup节点可以包含零或多个子节点,子节点继承父节点的属性。整个系统可以有多个hierarchy。

组件之间的关系

Subsystems, Hierarchies,Control Group和Tasks之间有许多的规则,下面介绍下:

1、同一个hierarchy能够附加一个或多个subsystem。

如下图,将cpu和memory subsystems(或者任意多个subsystems)附加到同一个hierarchy。

2、一个subsystem只能附加到一个hierarchy上。

如下图,cpu subsystem已经附加到了hierarchy A,并且memory subsystem已经附加到了hierarchy B。因此cpusubsystem不能在附加到hierarchy B。

3、系统每次新建一个hierarchy时,该系统上的所有task默认构成了这个新建的hierarchy的初始化cgroup,这个cgroup也称为root cgroup。对于你创建的每个hierarchy,task只能存在于其中一个cgroup中,即一个task不能存在于同一个hierarchy的不同cgroup中,但是一个task可以存在在不同hierarchy中的多个cgroup中。如果操作时把一个task添加到同一个hierarchy中的另一个cgroup中,则会从第一个cgroup中移除。

如下图,cpu和memory被附加到cpu_mem_cg的hierarchy。而net_cls被附加到net_cls hierarchy。并且httpd进程被同时加到了cpu_mem_cg hierarchy的cg1 cgroup中和net hierarchy的cg3 cgroup中。并通过两个hierarchy的subsystem分别对httpd进程进行cpu,memory及网络带宽的限制。

4、系统中的任何一个task(Linux中的进程)fork自己创建一个子task(子进程)时,子task会自动的继承父task cgroup的关系,在同一个cgroup中,但是子task可以根据需要移到其它不同的cgroup中。父子task之间是相互独立不依赖的。

如下图,httpd进程在cpu_and_mem hierarchy的/cg1 cgroup中并把PID 4537写到该cgroup的tasks中。之后httpd(PID=4537)进程fork一个子进程httpd(PID=4840)与其父进程在同一个hierarchy的统一个cgroup中,但是由于父task和子task之间的关系独立不依赖的,所以子task可以移到其它的cgroup中。

04

Cgroups使用

我们直接使用shell 命令直接操作hierarchy并设置cgroup参数。在centos6上也可以直接使用libcgroup提供的工具可简化对cgroup的使用。

Create a Hierarchy

使用shell命令创建hierarchy并附加subsystems到该hierarchy上。 作为root为hierarchy创建一个mount point。并且在mount point中包含cgrou的名字。

例如:

接下来使用mount命令去挂载hierarchy并附加一个或多个subsystem到该hierarchy上。

例如:

如果想在已有的hierarchy上attch或detach subsystem,可以使用remount操作,例如我们想detach掉memory subsystem。

Unmounting a Hierarchy

可以直接用umount命令来unmount一个已有的Hierarchy:

例如:

Creating Control Groups

直接使用shell命令mkdir创建一个子cgroup:

例如:

Setting Control Cgroup Parameters

在group1中使用echo命令插入0-1到cpuset.cpus,来限制该cgroup中的tasks只能跑在0和1的cpu core上。如下:

Moving a Process to a Control Group

只要将想要限制的进程PID,追加到想要的cgroup的tasks文件中就可以了。例如:将PID=1701的进程放到“/cgroup/cpu_and_mem/group1/”的cgroup中。

05

Subsystem 介绍

blkio: blkio 子系统控制并监控cgroup中的task对块设备的I/O的访问。如:限制访问及带宽等。

cpu: 主要限制进程的cpu使用率。

cpuacct: 可以统计cgroup中进程的cpu使用报告。

cpuset: 可以为cgroup中的进程分配独立的cpu和内存节点。

memory: 自动生成cgroup中task使用的内存资源报告,并对该cgroup的task进行内存使用限制。

devices: 可以控制进程能否访问某些设备。

net_cls: 使用等级标识符(clssid)标记网络数据包,可允许Linux流量控制程序(tc)识别从具体cgroup中生成的数据包。

freezer: 可以挂起或回复cgroup中的进程。

ns: 可以使不同cgroup中的进程使用不同的namespace。

06

容器使用Cgroups进行资源限制

无论是使用docker run方式直接创建容器,还是通过各类容器编排工具(如:Kubernetes)创建容器,对于容器的限制本质都是通过Cgroups。我们分别使用这两种方式来创建容器并观察cgroups:

测试环境:

使用docker run方式创建容器

1、限制CPU share,创建两个容器,则会在运行该容器宿主的/sys/fs/cgroup/cpu/docker/ 下分别创建两个子cgroup,格式如下。

2、创建一个容器,并设置--cpu-shares参数为:1024*10。

查看该容器cgroup的cpu.shares文件内容如下。

3、创建一个容器,并设置--cpu-shares参数为: 1024*14。

查看该容器cgroup的cpu.shares文件内容如下。

4、两个容器使用cpu的stats,一个容器分到14核的相对cpu计算时间,另一个容器分到10核的相对cpu计算时间:

限制容器内存使用量

1、创建一个容器,限制容器能使用的内存上限为1024M。

2、查看容器memory的stats,内存使用率100%。

3、当容器使用的内存量超过1024M,则容器会被kill -9掉。

使用Kubenetes容器编排工具创建容器

使用kubernetes编排工具创建的容器,则与容器关联的cgroup均在运行该容器宿主机的/sys/fs/cgroup/cpu/kubepods/下,具体的格式如下所示:

使用Pod创建一个容器,对应的yaml文件内容如下:

在运行该容器的宿主机上查看该容器的cgroup信息,会观察到cpu.shares为1核,memory.limit_in_bytes为2G。

相关文章

https://access.redhat.com/documentation/en-us/red_hat_enterprise_linux/6/html/resource_management_guide/ch01

https://www.kernel.org/doc/Documentation/cgroup-v1/cgroups.txt

http://www.infoq.com/cn/articles/docker-kernel-knowledge-cgroups-resource-isolation

cgroups的一个设计目标是为不同的应用情况提供统一的接口,从控制单一进程到操作系统层虚拟化(像OpenVZ,Linux-VServer,LXC)。cgroups提供:

每个 cgroup 子系统代表一种资源,如针对某个 cgroup 的处理器时间或者 pid 的数量,也叫进程数。Linux 内核提供对以下 12 种 cgroup 子系统的支持:

这里面每一个子系统都需要与内核的其他模块配合来完成资源的控制,比如对 cpu 资源的限制是通过进程调度模块根据 cpu 子系统的配置来完成的;对内存资源的限制则是内存模块根据 memory 子系统的配置来完成的,而对网络数据包的控制则需要 Traffic Control 子系统来配合完成。本文不会讨论内核是如何使用每一个子系统来实现资源的限制,而是重点放在内核是如何把 cgroups 对资源进行限制的配置有效的组织起来的,和内核如何把cgroups 配置和进程进行关联的,以及内核是如何通过 cgroups 文件系统把cgroups的功能暴露给用户态的。

cpu子系统用于控制cgroup中所有进程可以使用的cpu时间片。

cpu子系统主要涉及5个参数: cpu.cfs_period_us,cpu.cfs_quota_us,cpu.shares,cpu.rt_period_us,cpu.rt_runtime_us 。cfs表示Completely Fair Scheduler完全公平调度器,是Linux内核的一部分,负责进程调度。

cpu.cfs_quota_us/cpu.cfs_period_us决定cpu控制组中所有进程所能使用CPU资源的最大值,而cpu.shares决定了cpu控制组间可用CPU的相对比例,这个比例只有当主机上的CPU完全被打满时才会起作用。

cpuacct子系统(CPU accounting)会自动生成报告来显示cgroup中任务所使用的CPU资源。报告有两大类: cpuacct.stat和cpuacct.usage。

cpuset主要是为了numa使用的,numa技术将CPU划分成不同的node,每个node由多个CPU组成,并且有独立的本地内存、I/O等资源(硬件上保证)。可以使用numactl查看当前系统的node信息。

memory 子系统 自动生成 cgroup 任务使用内存资源的报告,并限定这些任务所用内存的大小。

容器可以通过设置 memory.swappiness 参数来决定是否使用 swap 空间。

Linux通过文件的方式,将cgroups的功能和配置暴露给用户,这得益于Linux的虚拟文件系统(VFS)。VFS将具体文件系统的细节隐藏起来,给用户态提供一个统一的文件系统API接口,cgroups和VFS之间的链接部分,称之为cgroups文件系统。

比如挂在 cpu、cpuset、memory 三个子系统到 /cgroups/cpu_mem 目录下:

其中-t选项指定文件系统类型为cgroup类型,-o指定本次创建的cgroup实例与cpu和momory子系统(或资源)关联,cpu_momory指定了当前cgroup实例在整个cgroup树中所处的层级名称,最后的路径为文件系统挂载点。

runtime 有两种 cgroup 驱动:一种是 systemd ,另外一种是 cgroupfs :

kubernetes 中默认 kubelet 的 cgroup 驱动就是 cgroupfs,若要使用 systemd,则必须将 kubelet 以及 runtime 都需要配置为 systemd 驱动。

由于 kubeadm 把 kubelet 视为一个系统服务来管理,所以对基于 kubeadm 的安装, 我们推荐使用 systemd 驱动,不推荐 cgroupfs 驱动。

配置 cgroup 驱动

kubelet作为kubernetes中的node agent,所有cgroup的操作都由其内部的containerManager模块实现,containerManager会通过cgroup将资源使用层层限制: container->pod->qos ->node 。每一层都抽象出一种资源管理模型,通过这种方式提供了一种稳定的运行环境。如下图所示:

kubernetes对于容器级别的隔离其实是交由底层的runtime来负责的,例如docker, 当我们指定运行容器所需要资源的request和limit时,docker会为容器设置进程所运行cgroup的cpu.share, cpu.quota, cpu.period, mem.limit等指标来。

首先是 CPU 资源,我们先看一下 CPU request。CPU request 是通过 cgroup 中 CPU 子系统中的 cpu.shares 配置来实现的。当你指定了某个容器的 CPU request 值为 x millicores 时,kubernetes 会为这个 container 所在的 cgroup 的 cpu.shares 的值指定为 x * 1024 / 1000。即:

举个例子,当你的 container 的 CPU request 的值为 1 时,它相当于 1000 millicores,所以此时这个 container 所在的 cgroup 组的 cpu.shares 的值为 1024。

这样做希望达到的最终效果就是:即便在极端情况下,即所有在这个物理机上面的 pod 都是 CPU 繁忙型的作业的时候(分配多少 CPU 就会使用多少 CPU),仍旧能够保证这个 container 的能够被分配到 1 个核的 CPU 计算量。其实就是保证这个 container 的对 CPU 资源的最低需求。

而针对 CPU limit,Kubernetes 是通过 CPU cgroup 控制模块中的 cpu.cfs_period_us , cpu.cfs_quota_us 两个配置来实现的。kubernetes 会为这个 container cgroup 配置两条信息:

在 cgroup 的 CPU 子系统中,可以通过这两个配置,严格控制这个 cgroup 中的进程对 CPU 的使用量,保证使用的 CPU 资源不会超过 cfs_quota_us/cfs_period_us ,也正好就是我们一开始申请的 limit 值。

对于cpu来说,如果没有指定 limit 的话,那么 cfs_quota_us 将会被设置为 -1 ,即没有限制。而如果 limit 和 request 都没有指定的话,cpu.shares 将会被指定为 2 ,这个是 cpu.shares 允许指定的最小数值了。可见针对这种 pod,kubernetes 只会给他分配最少的 CPU 资源。

针对内存资源,其实 memory request 信息并不会在 container level cgroup 中有体现。kubernetes 最终只会根据 memory limit 的值来配置 cgroup 的。

在这里 kubernetes 使用的 memory cgroup 子系统中的 memory.limit_in_bytes 配置来实现的。配置方式如下:

memory 子系统中的 memory.limit_in_bytes 配置,可以限制一个 cgroup 中的所有进程可以申请使用的内存的最大量,如果超过这个值,那么根据 kubernetes 的默认配置,这个容器会被 OOM killed,容器实例就会发生重启。

对于内存来说,如果没有 limit 的指定的话,memory.limit_in_bytes 将会被指定为一个非常大的值,一般是 2^64 ,可见含义就是不对内存做出限制。

一个pod中往往有一个或者有多个容器,但是如果我们将这些容器的资源使用进行简单的加和并不能准确的反应出整个pod的资源使用,因为每个pod都会有一些overhead的资源,例如sandbox容器使用的资源,docker的containerd-shim使用的资源,此外如果指定memory类型的volume时,这部分内存资源也是属于该pod占用的。因为这些资源并不属于某一个特定的容器,我们无法仅仅通过容器的资源使用量简单累加获取到整个pod的资源,为了方便统计一个pod所使用的资源(resource accounting),并且合理的将所有使用到的资源都纳入管辖范围内,kubernetes引入了pod level Cgroup,会为每个pod创建一个cgroup。该特性通过指定 --cgroups-per-qos=true 开启, 在1.6+版本中是默认开启。kubelet会为每个pod创建一个 pod<pod.UID>的cgroup,该cgroup的资源限制取决于pod中容器的资源request,limit值。

其实上面三种设置方式对应的就是三种QoS pod。这样设置pod level cgourp可以确保在合理指定容器资源时能够防止资源的超量使用,如果未指定则可以使用到足够多的可用资源。 每次启动pod时kubelet就会同步对应的pod level cgroup。

kubernetes中会将所有的pod按照资源request, limit设置分为不同的QoS classes, 从而拥有不同的优先级。QoS(Quality of Service) 即服务质量,QoS 是一种控制机制,它提供了针对不同用户或者不同数据流采用相应不同的优先级,或者是根据应用程序的要求,保证数据流的性能达到一定的水准。kubernetes 中有三种 QoS,分别为:

三者的优先级如下所示,依次递增:

BestEffort ->Burstable ->Guaranteed

如果指定了 --cgroups-per-qos 也会为每个QoS也会对应一个cgroup,该功能默认开启,这样就可以利用cgroup来做一些QoS级别的资源统计,必要时也可以通过该cgroup限制某个QoS级别的pod能使用的资源总和。此时每个QoS cgroup相当于一个资源pool, 内部的pod可以共用pool中的资源,但是对于整个pool会进行一些资源的限制,避免在资源紧张时低优先级的pod抢占高优先级的pod的资源。

对于guaranteed级别的pod,因为pod本身已经指定了request和limit,拥有了足够的限制,无需再增加cgroup来约束。但是对于Burstable和BestEffort类型的pod,因为有的pod和容器没有指定资源限制,在极端条件下会无限制的占用资源,所以我们需要分别设置Burstable和BestEffort cgroup, 然后将对应的pod都创建在该cgroup下。kubelet希望尽可能提高资源利用率,让Burstable和BestEffort类型的pod在需要的时候能够使用足够多的空闲资源,所以默认并不会为该QoS设置资源的limit。但是也需要保证当高优先级的pod需要使用资源时,低优先级的pod能够及时将资源释放出来:对于可压缩的资源例如CPU, kubelet会通过 cpu.shares 来控制,当CPU资源紧张时通过 cpu.shares 来将资源按照比例分配给各个QoS pod,保证每个pod都能够得到其所申请的资源。具体来说, 对于cpu的设置,besteffort和burstable的资源使用限制如下:

对于不可压缩资源内存,要满足“高优先级pod使用资源时及时释放低优先级的pod占用的资源”就比较困难了,kubelet只能通过资源预留的机制,为高优先级的pod预留一定的资源,该特性默认关闭,用户可以通过开启 QOSReserved 特征门控(默认关闭),并设置 --qos-reserved 参数来预留的资源比例,例如 --qos-reserved=memory=50% 表示预留50%高优先级request的资源值,当前只支持memory , 此时qos cgroups的限制如下:

同时根据 cpu.shares 的背后实现原理,位于不同层级下面的 cgroup,他们看待同样数量的 cpu.shares 配置可能最终获得不同的资源量。比如在 Guaranteed 级别的 pod cgroup 里面指定的 cpu.shares=1024,和 burstable 下面的某个 pod cgroup 指定 cpu.shares=1024 可能最终获取的 cpu 资源并不完全相同。所以每次创建、删除pod都需要根据上述公式动态计算cgroup值并进行调整。此时kubelet先会尽力去更新低优先级的pod,给高优先级的QoS预留足够的资源。因为memory是不可压缩资源,可能当pod启动时,低优先级的pod使用的资源已经超过限制了,如果此时直接设置期望的值会导致失败,此时kubelet会尽力去设置一个能够设置的最小值(即当前cgroup使用的资源值),避免资源使用进一步增加。通过设置qos资源预留能够保障高优先级的资源可用性,但是对低优先级的任务可能不太友好,官方默认是关闭该策略,可以根据不同的任务类型合理取舍。

对于node层面的资源,kubernetes会将一个node上面的资源按照使用对象分为三部分:

通常情况下,我们为提高集群资源利用率,会进行适当超配资源,如果控制不当,业务进程可能会占用完整个node的资源,从而使的第二,三部分核心的程序所使用的资源受到压制,从而影响到系统稳定性,为避免这样的情况发生,我们需要合理限制pods的资源使用,从而 为系统组件等核心程序预留足够的资源 ,保证即使在极端条件下有充足的资源来使用。

kubelet会将所有的pod都创建一个 kubepods 的cgroup下,通过该cgroup来限制node上运行的pod最大可以使用的资源。该cgroup的资源限制取值为:

其中 kube-reserved 是为kubernetes组件提供的资源预留, system-reserved 是为系统组件预留的资源,分别通过 --kube-reserved , --system-reserved 来指定,例如--kube-reserved=cpu=100m,memory=100Mi。

除了指定预留给系统运行的资源外,如果要限制系统运行的资源,可以通过 --enforce-node-allocatable 来设置,该flag指定需要执行限制的资源类型,默认值为pods,即通过上述kubepods来限制pods的使用资源,此外还支持限制的资源类型有:

如果需要指定多种类型,通过逗号分割枚举即可,注意如果开启了 system-reserved 和 kube-reserved 的限制,则意味着将限制这些核心组件的资源使用,以上述--kube-reserved=cpu=100m,memory=100Mi为例,所有的kubernetes组件最多可以使用cpu: 100m,memory: 100Mi。

除非已经很了解自己的资源使用属性,否则并不建议对这两种资源进行限制,避免核心组件CPU饥饿或者内存OOM。

默认情况下该 --enforce-node-allocatable 的值为pods,即只限制容器使用的资源,但不限制系统进程和kubernetes进程的资源使用量。

kubelet会在资源紧张的时候主动驱逐低优先级的pod,可以指定 hard-eviction-threshold 来设置阈值,这样一个node真正可以为pod使用的资源量为:

这也是调度器进行调度时所使用的资源值。

除了上述提到的cgroup设置外,kubelet中还有一些对于单个组件的cgroup设置, 例如:

以上runtime-cgroups,system-cgroups,kubelet-cgoups的设置都是 可选的 ,如果不进行指定也可以正常运行。但是如果显式指定后就需要与前面提到的 --kube-reserved-cgroup 和 --system-reserved-cgroup 搭配使用,如果配置不当难以达到预期效果:

如果在 --enforce-node-allocatable 参数中指定了 kube-reserved 来限制kubernetes组件的资源限制后,kube-reserved-cgroup的应该是:runtime-cgroups, kubelet-cgoups的父cgroup。只有对应的进程都应该运行该cgroup之下,才能进行限制,kubelet会设置 kube-reserved-cgroup 的资源限制但并不会将这些进程加入到该cgroup中,我们要想让该配置生效,就必须让通过制定 --runtime-cgroups , --kubelet-cgoups 来将这些进程加入到该cgroup中。同理如果上述 --enforce-node-allocatable 参数中指定了 system-reserved 来限制系统进程的资源,则 --system-reserved-cgroup 的参数应该与 --system-cgroups 参数相同,这样系统进程才会运行到 system-reserved-cgroup 中起到资源限制的作用。

最后整个整个cgroup hierarchy 如下:

上述所有的操作在 kubelet 中是通过 containerManager 来实现的, containerManager 启动的时候首先会 setupNode 初始化各种cgroup,具体包括:

上述所有更新cgroup的操作都会利用一个 cgroupManager 来实现。

三种 Qos 在调度和底层表现上都不一样:

Linux资源管理之cgroups简介

kubernetes 中 Qos 的设计与实现

Cgroup中的CPU资源控制

重学容器29: 容器资源限制之限制容器的CPU

深入解析 kubernetes 资源管理


欢迎分享,转载请注明来源:夏雨云

原文地址:https://www.xiayuyun.com/zonghe/23741.html

(0)
打赏 微信扫一扫微信扫一扫 支付宝扫一扫支付宝扫一扫
上一篇 2023-02-16
下一篇2023-02-16

发表评论

登录后才能评论

评论列表(0条)

    保存