K8S生产化集群运维:节点资源管理(Kubelet)、降本增效

一、Numa Node

Non-Uniform Memory Access中文直译:非统一内存访问,是为多核计算机设计的内存架构。

以下图为例,服务器有多个CPU和内存插槽,Numa Node1和左边的memory是通过FSB(Front Service Bus)直连的。访问是local access,效率会很高。

如果Numa Node1要访问右边的memory,是没有直连的,需要通过QPI(Quick Path Interconnect)的总线,再通过FSB来访问,是remote access,效率很低。
在这里插入图片描述

注意:kubelet其实使用NUMA的特性,对CPU Manager + Topology Manager可以实现让CPU尽量去访问本地的memory。在性能优化时会用到。

参考链接(下面三个都很硬核建议阅读):
Kubelet从入门到放弃:识透CPU管理
Kubelet从入门到放弃:拓扑管理(上)
Kubelet从入门到放弃:拓扑管理(下)
这三篇文章,粗略读了前两篇,最后一章是topologyManager源码解析就不搞了。下面两部分会把两篇中的重点内容提炼出来。

1、cpu管理

默认情况下,kubelet 基于CFS 调度算法来执行Pod的CPU分配。但是当节点上运行了CPU 密集型 Pod 时,应用可能会因抢占等情况导致CPU切换,而上述的切换导致的延时与中断对于业务敏感性Pod是无法接受的。

为了解决上述问题。Kubelet 提供了可选的 CPU 管理策略,以满足不同的业务场景

a. 以API形式向用户提供配置方案

b. 同时支持多种CPU使用场景共存

c. CPU基于亲和性分配时,考虑设备拓扑

处理器SMP架构:
对称多处理器(Symmetric Multi-Processors,简称SMP),其是指在一个计算机上汇集了一组处理器(多CPU),各CPU之间共享内存子系统以及总线结构。共享存储型多处理机有三种模型:均匀存储器存取(Uniform-Memory-Access,简称UMA)模型、非均匀存储器存取(Non-uniform Memory Access,简称NUMA)模型和只用高速缓存的存储器结构(Cache-Only Memory Architecture,简称COMA)模型,这些模型的区别在于存储器和外围资源如何共享或分布
cpuManagerPolicy

(1)cpu管理中相关技术介绍

在CPU管理中,涉及NUMA、HT及cpuset技术,以下为简要介绍。

【1】NUMA内存架构

NUMA,以内存访问的不一致性为代价,减轻对总线和memory的带宽需求。这种结构对进程调度算法的要求较高,尽量减少跨Node的内存访问次数,以提升系统性能。Core之间会共享总线、内存等资源。如果Core的数量较少,则没什么问题,但随着Core的增多,对总线以及内存带宽的需求就会显著增大,最终总线和内存会成为系统性能的瓶颈。

如下图所示,一个NUMA Node包括一个或者多个Socket,以及与之相连的local memory。一个多核的Socket有多个Core。如果CPU支持HT,OS还会把这个Core看成 2个Logical Processor。
在这里插入图片描述

  • Socket是一个物理上的概念,指的是主板上的cpu插槽
  • Node是一个逻辑上的概念,上图中没有提及。由于SMP体系中各个CPU访问内存只能通过单一的通道,导致内存访问成为瓶颈,cpu再多也无用。后来引入了NUMA,通过划分node,每个node有本地RAM,这样node内访问RAM速度会非常快。但跨Node的RAM访问代价会相对高一点,我们用Node之间的距离(Distance,抽象的概念)来定义各个Node之间互访资源的开销。
  • Core就是一个物理cpu,一个独立的硬件执行单元,比如寄存器,计算单元等
  • Thread就是超线程(HyperThreading)的概念,是一个逻辑cpu,共享core上的执行单元
【2】HT超线程技术

Hyperthreading 使操作系统认为处理器的核心数是实际核心数的2倍,超线程(hyper-threading)本质上就是CPU支持的同时多线程(simultaneous multi-threading)技术,简单理解就是对CPU的虚拟化,一颗物理CPU可以被操作系统当做多颗CPU来使用。Hyper-threading只是一种“欺骗”手段。注意超线程技术其实是会增加上下文切换开销的,所以一般生产环境都不会使用超线程技术,但是超线程技术可以更充分利用cpu资源,类似cpu超售。比如一个物理cpu被分为了两个逻辑cpu,当两个线程调度到这两个逻辑cpu上,同时运行在这一个物理cpu上时,操作系统需要频繁地进行上下文切换,以确保每个线程都能被公平地执行

【2】cpuset绑定技术

cpuset作为cgroup的子系统,主要用于numa架构,用于设置cpu的亲和性,为 cgroup 中的 task 分配独立的 CPU和内存等。

cpuset使用sysfs提供用户态接口,可以通过普通文件读写,工作流程为:cpuset调用sched_setaffinity来设置进程的cpu、内存的亲和性,调用mbind和set_mempolicy来设置内存的亲和性。

(2)查看Numa Node信息

numactl是设定进程NUMA策略的命令行工具,也可以用来查看当前的Numa node:

[root@xxx ~]# numactl -H
available: 1 nodes (0)
node 0 cpus: 0 1 2 3 4 5 6 7
node 0 size: 16047 MB
node 0 free: 3693 MB
node distances:
node   0
  0:  10

从上面可以看出本机有一个Numa node(操作系统配置numa=on效果一样…),如果要进一步知道一个Node包含哪几个CPU,该怎么办?

一种方法是通过查看ls /sys/devices/system/node/目录下的信息,例如:

[root@xxx ~]# ls /sys/devices/system/node/
has_cpu  has_normal_memory  node0  online  possible  power  uevent
[root@xxx ~]# ls /sys/devices/system/node/node0
compact    cpu0       cpu1       cpu2       cpu3       cpu4       cpu5       
cpu6       cpu7       cpulist    cpumap     distance   hugepages  
...
(3)查看物理cpu、逻辑cpu数量

一个Socket对应主板上的一个插槽,在本文中是指一个CPU封装。在/proc/cpuinfo中的physical id就是Socket的ID,可以从中找到本机到底有多少个Socket(物理cpu),并且每个Socket有那几个Processor。

  • 查看Socket数量(cpu插槽)
// 有id为0,1的两个socket
[root@k8s46-prod.nbj03.corp.com ~]# grep 'physical id' /proc/cpuinfo | awk -F: '{print $2 | "sort -un"}'
 0
 1
  • 查看每个Socket有几个Processor(逻辑cpu)
//0,1 socket分别有48个Processor
[root@k8s46-prod.nbj03.corp.yodao.com ~]# grep 'physical id' /proc/cpuinfo | awk -F: '{print $2}' | sort | uniq -c
     48  0
     48  1
  • 查看一个socket有几个core(物理cpu)
// 一个socket有24核,有两个socket,也就是这是个48核的cpu
[root@k8s46-prod.nbj03.corp.yodao.com ~]# cat /proc/cpuinfo | grep 'core'  | sort -u
core id		: 0
core id		: 11
...
core id		: 5
core id		: 9
cpu cores	: 24
(4)CPU Manager

CPU 管理器(CPU Manager)作为 alpha 特性引入 Kubernetes 1.8 版本,Kubernetes 1.12进入beta版本后,默认开启。CPU 管理策略通过 kubelet 参数 --cpu-manager-policy 来指定或者在config.yaml里指定cpuManagerPolicy。支持两种策略:

  • none: 默认策略,保持现有的调度行为,通过 CFS 配额来实现 Guaranteed pods的 CPU 使用限制。
  • static: 节点上满足某些资源特征的 Pod 根据 CPU 亲和性和独占性进行分配。

static 策略针对具有整数型 CPU请求 的 Guaranteed Pod (后续文章介绍),它允许该类 Pod 中的容器独占 CPU 资源。其基于 cpuset cgroup 控制器 实现的

static策略详解:

  • static策略管理一个CPU共享资源池,起初,该资源池包含节点上所有的 CPU 资源。可用且独占的CPU 数量等于节点的CPU总量减去通过 reserved-cpus或--kube-reserved 或 --system-reserved 命令行保留的CPU(其实还有eviction资源,但当前不支持CPU类型,因此省略)。
  • 通过这些参数预留的 CPU 是以整数方式,按物理内核 ID 升序从初始共享池获取的。共享池是 BestEffort 和 Burstable pod 运行的CPU 集合。Guaranteed Pod 中的容器,如果声明了非整数值的 CPU requests ,也将运行在共享池的CPU 上。只有 指定了正整数型的 CPU requests 的Guaranteed Pod ,才能独占 CPU 资源
  • 当 Guaranteed Pod 调度到节点上时,如果其容器符合独占要求, 相应的CPU会从共享池中移除,并放置到容器的cpuset 中。容器cgroup目录的 cpuset文件 中的 CPU 数量与 Pod 中指定的 CPU limit 相等。这种分配增强了CPU亲和性,减少了CPU上下文切换

2、拓扑管理

随着单服务器节点内的处理器数量、硬件加速器及其他外围设备日益增多,越来越多的系统利用 CPU 和硬件加速器的组合来支持对延迟要求较高的任务和高吞吐量的并行计算。这类负载包括电信、科学计算、机器学习、金融服务和数据分析等。如何优化延迟敏感型的高性能并行计算应用的性能成了一个重大的挑战。

在引入拓扑管理器之前,CPU、内存和设备管理器在资源分配决策上彼此独立。这可能导致在多处理系统上出现与期望不符的资源分配,由于这些与期望不一致的分配,对性能或延迟敏感的应用将受到影响,例如, CPU 和设备是从不同的 NUMA 节点分配的,因此会导致额外的延迟。为了获得最佳性能,需要与 CPU 分配、内存和设备局部性等进行亲和性有关的优化

拓扑管理器是Kubelet中ContainerManager组件的一部分,充当存储分配资源信息的角色,以便ContainerManager组件可以做出与拓扑结构相适应的资源分配决策,在资源分配的时候实现拓扑结构上的对齐。注意拓扑管理不是单独起作用的,它和CPU manager、memory manager、Device manager共同为Pod分配资源,优化资源访问

(1)拓扑管理相关配置

注意:为了将 Pod 中的 CPU 与其他请求资源对齐,需要启用CPU 管理并且配置适当的 CPU 管理策略

在Kubernetes 1.18版本之前若需要启用拓扑管理器,需要在Kublet的特性门控处启用该特性。从Kubernetes 1.18 版本开始,这一特性默认启动。–feature-gates=“…,TopologyManager=<true|false>”

为了满足定制对齐方式需求,拓扑管理器提供了两种不同的方式:scopepolicy

1)scope 定义了资源对齐的粒度(当前提供podcontainer 两种级别)。
2)policy 定义了对齐时实际使用的策略(当前提供best-effort、none、restricted、single-numa-node等)。

【1】作用域

正如上文所述,拓扑管理器提供以下两种不同的资源对齐粒度:container (默认)、pod。

在 kubelet 启动时,可以使用 --topology-manager-scope 标志来配置其中任一粒度。

  • Container作用域(defaulted)
    默认使用的是 container 作用域,拓扑管理依次进行一系列的资源对齐, 即对每一个容器(包含在一个 Pod 里)单独计算对齐。拓扑管理会把单个容器任意地对齐到 NUMA 节点上
  • Pod作用域
    在启动 kubelet时,配置 --topology-manager-scope=pod ,即可对齐粒度为 pod 。

重点讲解pod作用域:

该作用域允许把一个 Pod 里的所有容器作为一个分组,分配到一个共同的 NUMA 节点,即拓扑管理会把一个 Pod 当成一个整体, 并且试图把整个 Pod(所有容器)分配到一个单个的 NUMA 节点或者一个共同的 NUMA 节点集。下例说明了拓扑管理器在不同的场景下使用的对齐方式:

1、所有容器可以被分配到一个单一的 NUMA 节点

2、所有容器可以被分配到一个共享的 NUMA 节点集合

整个 Pod 请求的某种资源总量通过 request/limit公式计算, 因此,对某一种资源而言,该总量等于以下数值中的最大值:所有应用容器请求之和、Init容器请求的最大值。然后kubelet根据容器资源需求、容器之间亲和性、系统当前各个NUMA 节点的资源空闲程度等来计算可能的NUMA 节点集合。注意可能两个字,也就是会返回很多集合。

对于延迟敏感或者 IPC 高吞吐量工作负载,在配置Pod 作用域及 single-numa-node 拓扑管理策略时,可以把一个 Pod 里的所有容器都放到单一 NUMA 节点, 使得该 Pod 消除了 NUMA 之间的通信开销

在 single-numa-node 策略下,只有当可能的分配方案中存在合适的 NUMA 节点集时,Kubelet才会准入该Pod。如下述的示例:

1、当所有分配方案中,存在节点集只包含单个 NUMA 节点时,Pod 就会被准入

2、当所有分配方案中,只存在节点集包含多个 NUMA 节点时,Pod 会被拒绝

简而言之,拓扑管理器首先计算出所有可能的 NUMA 节点集合,然后使用拓扑管理策略来测试所有集合是否可行, 从而决定拒绝或者接受 Pod。

【2】策略

拓扑管理支持四种分配策略,在 Kubelet 启动时,可以通过 Kubelet命令行 --topology-manager-policy 设置。当前支持的策略有四种:

  • none (默认)
    这是默认策略,不执行任何拓扑对齐。
  • best-effort
    对于 Guaranteed 类Pod 中的每个容器,配置 best-effort 拓扑管理策略的 kubelet 将调用每个Hint Provider以确定资源可用性。使用此信息,拓扑管理器存储该容器的首选亲和性NUMA 节点。如果亲和性不是首选,则拓扑管理器将存储该亲和性,并且无论如何都将 Pod 接纳到该节点,之后Hint Provider在进行资源分配决策时使用该信息。
  • restricted
    对于 Guaranteed 类 Pod 中的每个容器, 配置了 restricted 拓扑管理策略的 Kubelet 调用每个Hint Provider以确定其资源可用性。使用此信息,拓扑管理器存储该容器的首选亲和性 NUMA 节点。如果亲和性不是首选,则拓扑管理器将从节点中拒绝此 Pod 。这将导致 Pod 处于 Terminated 状态。Pod调度失败,Kubernetes 调度器不会尝试重新调度该 Pod,建议使用 ReplicaSet 或者 Deployment部署 Pod。如果 Pod 被允许运行在某节点,则 Hint Provider 可以在做出资源分配决策时使用此信息。
  • single-numa-node
    对于 Guaranteed 类 Pod 中的每个容器, 配置了 single-numa-node 拓扑管理策略的 Kubelet 调用每个Hint Provider以确定其资源可用性。使用此信息,拓扑管理器确定单一 NUMA 节点亲和性是否可能。如果是这样,则拓扑管理器将存储此信息,然后Hint Provider可以在做出资源分配决定时使用此信息。如果不满足,则拓扑管理器将拒绝该Pod ,这将导致 Pod 处于 Terminated 状态。一旦 Pod 处于 Terminated 状态,Kubernetes 调度器将不会尝试重新调度该 Pod。建议使用 ReplicaSet 或者 Deployment 来重新部署 Pod。
(2)cpu管理与拓扑管理总结(目前没看懂)

没有指定资源 requests 或limits,该 Pod 以 BestEffort QoS 运行。
requests少于 limits,该 Pod 以 Burstable QoS 运行。
requests 值等于 limits 值 ,因此以 Guaranteed QoS 运行。

1、对于 Guaranteed Pod, 如果CPU 请求数为整数,CPU 管理器策略为static 时,将返回与 CPU 请求有关的提示, 而设备管理器将返回有关所请求设备的提示。对于 Guaranteed 类的 CPU 请求可共享的 Pod(非整数CPU),CPU 管理器策略为static 时,将返回默认的拓扑提示,因为没有排他性的 CPU 请求,而设备管理器则针对所请求的设备返回有关提示。在上述两种Guaranteed Pod 的情况中,CPU 管理器策略为none时, 返回默认的拓扑提示

2、对于Burstable Pod,如果选择的策略是 none 以外的任何其他策略,拓扑管理器都会评估这些 Pod 的资源使用。拓扑管理器会调用每个Hint Provider,获得拓扑结果。当策略为 static,且Hint Provider为 CPU时,不进行分配记录。

3、对于 BestEffort Pod,由于没有 CPU 请求,CPU 管理器策略为static时, 将发送默认提示, 而设备管理器将为每个请求的设备发送提示。基于此信息,拓扑管理器将为 Pod 计算最佳提示并存储该信息,为 Hint Provider在进行资源分配时使用。

二、节点状态上报

kubelet 周期性地向API Server进行汇报,并更新节点的相关健康状态和资源使用信息。

节点基础信息:包括IP地址、操作系统、内核、运行时、kubelet、kube-proxy版本信息。
节点资源信息: CPU、内存、HugePage、临时存储、GPU 等注册设备,以及这些资源中可以分配给容器使用的部分。
状态信息
在这里插入图片描述

注意:上面三种信息都是调度器在为pod选择节点时需要的依据。

1、Lease对象

早期版本,kubelet的状态上报直接更新node对象,而上报的信息包含状态信息和资源信息,因此需要传输的数据包较大,给APIServer和etcd造成的压力较大。
在这里插入图片描述

后期版本,kube-node-lease ns下的 Lease对象用来保存健康状态信息,在默认40s的nodeLeaseDurationSeconds 周期内,若对应的node Lease对象没有被更新,则对应节点可以被判定为不健康
在这里插入图片描述

三、资源预留

  • 计算节点除用户容器外,还存在很多支撑系统运行的基础服务,譬如 systemd、 journald、 sshd、dockerd、containerd、 kubelet 等。
  • 为了使服务能够正常运行,要确保它们在任何时候都可以获取足够的系统资源,所以我们要为这些系统进程预留资源
  • kubelet 可以通过众多启动参数为系统预留 CPU、内存、PID 等资源,比如 SystemReservedKubeReserved 等。

1、Capacity and Allocatable

容量资源(Capacity)是指 kubelet 获取的计算节点当前的资源信息。
在这里插入图片描述

  • CPU 是从 /proc/cpuinfo 文件中获取的节点 CPU 核数;
    在这里插入图片描述
  • memory 是从 /proc/memoryinfo 中获取的节点内存大小;
    在这里插入图片描述
  • ephemeral-storage 是指节点根分区的大小。
    在这里插入图片描述
    资源可分配额(Allocatable)是用户 Pod 可用的资源,是资源容量减去分配给系统的资源的剩余部分。
    在这里插入图片描述
    Capacity包括k8s,系统使用,驱逐阈值和Allocatable。
    在这里插入图片描述

2、节点磁盘管理

其实我们要剖析的就是容器运行时的存储目录:
在这里插入图片描述
在这里插入图片描述
cri、containers:容器的工作目录,容器日志的存放、挂载信息
overlayfs、overlay2:存储的是imagefs的镜像分层(镜像只读层、init层、容器读写层COW),用于镜像层之间的overlay2的联合挂载,可能有人会问image是干什么的呢,其实它是用于存储镜像元数据的。

四、驱逐管理

kubelet 会在不可压缩资源:内存、磁盘不够时会中止一些容器进程,以空出系统资源,保证节点的稳定性。

但由 kubelet 发起的驱逐只停止 Pod 的所有容器进程,并不会直接删除 Pod。

  • status.phase 会被标记为 Failed
  • status.reason 会被设置为 Evicted
  • status.message 则会记录被驱逐的原因

1、节点可用额监控

  • kubelet 依赖内嵌的开源软件 cAdvisor,周期性检查节点资源使用情况。
  • CPU 是可压缩资源,根据不同进程分配时间配额和权重分时复用
  • 驱逐策略是基于磁盘和内存资源用量进行的,因为两者属于不可压缩的资源,当此类资源使用耗尽时将无法再申请。
  • 在这里插入图片描述
    驱逐策略:
  • kubelet 获得节点的可用额信息后,会结合节点的容量信息来判断当前节点运行的 Pod 是否满足驱逐条件。
  • 驱逐条件(evictionHard),当监控资源的可使用额少于设定的数值或百分比时,kubelet就会发起驱逐操作。
  • kubelet 参数 evictionMinimumReclaim 可以设置每次回收的资源的最小值,以防止小资源的多次回收。

2、软驱逐与硬驱逐

软驱逐就是给pod一个优雅终止的机会。当软驱逐后又达到了硬驱逐的阈值就执行硬驱逐。
在这里插入图片描述

修改kubelet配置文件:

cat /var/lib/kubelet/config.yaml
# 添加配置
# 指定硬驱逐
evictionHard:
  memory.available: '500Mi'
  nodefs.available: '1Gi'
  imagefs.available: '100Gi'
# 指定每次最少驱逐资源
evictionMinimumReclaim:
  memory.available: '0Mi'
  nodefs.available: '500Mi'
  imagefs.available: '2Gi'

3、驱逐顺序

驱逐示例讲解:

  • memory.available 表示当前系统的可用内存情况。kubelet默认设置了 memory.avaiable小于100Mi的硬驱逐条件。
  • 当 kubelet 检测到当前节点可用内存资源紧张并满足驱逐条件时,会将节点的 MemoryPressure状态设置为True调度器会阻止 BestEffort Pod 调度到内存承压的节点

如果磁盘压力,驱逐之前会尝试回收存储资源:

  • 有容器运行时分区
    🔥nodefs(即containers目录) 达到驱逐阈值,那么kubelet 删除已经退出的容器。
    🔥Imagefs(即overlay2) 达到驱逐阈值,那么 kubelet 删除所有未使用的镜像。
  • 无容器运行时分区
    🔥kubelet 同时删除未运行的容器和未使用的镜像。

kubelet 启动对内存不足的驱逐操作时,会依照如下的顺序选取目标 Pod:

  • 判断 Pod 所有容器的内存使用量总和是否超出了请求的内存量,超出请求资源的 Pod 会成为备选目标
  • 查询 Pod 的调度优先级(priority class,不是QOS),低优先级的 Pod 被优先驱逐
  • 计算 Pod 所有容器的内存使用量与 Pod 请求的内存量越接近, 越容易被驱逐

五、QOS在资源管理中的作用

针对不同 Qos Class 的 Pod, Kubneretes 按如下 Hierarchy 组织不同QOS的Pod的Cgroup
在这里插入图片描述

1、不同QOS的Cgroup配置

内存Cgroup配置:
在这里插入图片描述
CPU Cgroup配置:
在这里插入图片描述

2、OOM killer

  • 系统的 OOM killer 根据进程的 oom score 来进行优先级排序,选择待终止的进程,且进程的 oom score越高,越容易被终止
  • 进程的 oom_score 是根据当前进程使用的内存占节点总内存的比例值乘以10,再加上oom_score_adj 综合得到的。
  • 而容器进程的 oom_score_adj 是 kubelet 根据 memory.request 进行设置的。
    在这里插入图片描述
    在这里插入图片描述
# 查看pod的id
crictl pods --namespace default
# 查看pod的容器进程
crictl ps | grep a04cabae42e13
# 查看进程的pid
crictl inspect 5ed0e8a0350fb | grep pid
# 查看进程的oom_score是1000
cat /proc/30626/oom_score
# 查看进程的oom_score_adj也是1000
cat /proc/30626/oom_score_adj

六、其他资源管理

1、日志管理

节点上需要通过运行 logrotate 的定时任务对系统服务日志进行 rotate 清理,以防止系统服务日志占用大量的磁盘空间。

配置日志原则:

  • logrotate 的执行周期不能过长,以防日志短时间内大量增长。
  • 同时配置日志的 rotate 条件,在日志不占用太多空间的情况下,保证有足够的日志可供查看。

Docker:

  • 除了基于系统 logrotate 管理日志,还可以依赖 Docker 自带的日志管理功能来设置容器日志的数量和每个日志文件的大小。
  • Docker 写入数据之前会对日志大小进行检查和 rotate 操作,确保日志文件不会超过配置的数量和大小。

Containerd:

  • 日志的管理是通过 kubelet 定期(默认为10s)执行 du命令,来检查容器日志的数量和文件的大小的。
  • 每个容器日志的大小和可以保留的文件个数,可以通过 kubelet 的配置参数 container-log-max-size
    和container-log-max-files 进行调整。

2、存储卷管理

  • 在构建容器镜像时,可以在 Dockerfile 中通过 VOLUME 指令声明一个存储卷,目前Kubernetes 尚未将其纳入管控范围,不建议使用
  • 如果容器进程在可写层或 emptyDir 卷进行大量读写操作,就会导致磁盘IO过高,因为多个emptyDir共享一个nodefs,从而影响其他容器进程甚至系统进程
  • Docker 和 Containerd 运行时都基于 Cgroup v1。对于块设备,只支持对 Direct IO限速,而对于 Buffer IO还不具备有效的支持。因此,针对设备限速的问题,目前还没有完美的解决方案,对于有特殊IO需求的容器,建议使用独立的磁盘空间。

3、网络管理

由网络插件通过 Linux Traffic Control 为 Pod 限制带宽。可利用 CNI 社区提供的 bandwidth 插件
在这里插入图片描述
设置pod带宽限制:

 metadata:
      annotations:
        kubernetes.io/ingress-bandwidth: 10M
        kubernetes.io/egress-bandwidth: 10M

4、进程数管理(pod、node)

pod可创建子进程数管理:kubelet 默认不限制 Pod 可以创建的子进程数量,但可以通过启动参数 podPidsLimit 开启限制,还可以由 reserved 参数为系统进程预留进程数。

节点系统进程数管理:

  • kubelet 通过系统调用周期性地获取当前系统的 PID 的使用量,并读取/proc/sys/kernel/pid_max,获取系统支持的PID 上限。
    在这里插入图片描述
  • 如果当前的可用进程数少于设定阈值,那么 kubelet 会将节点对象的 PIDPressure 标记为True。
  • kube-scheduler 在进行调度时,会从备选节点中过滤掉处于 NodeUnderPIDPressure 状态的节点

七、节点异常检测

当 Kubernetes 中节点发生如下问题时,在整个集群中,K8S 服务组件并不会感知这些问题,就会导致 Pod 仍会调度至问题节点。所以就需要一个检测机制来检测上述问题。

基础服务问题:NTP 服务挂了;
硬件问题:CPU,内存或磁盘损坏;
内核问题:内核死锁,文件系统损坏;
容器运行时问题:运行时守护程序无响应。

1、node-problem-detector

node-problem-detector是集群节点的健康监测组件。以 DaemonSet 方式运行,帮助用户实时检测节点上的各种异常情况,并将检测结果报告给上游的 Kube-apiserver

  • 故障种类
    在这里插入图片描述
  • 故障上报,node-problem-detector 通过设置 NodeCondition 或者创建 Event 对象来汇报问题。
    🔥 Nodecondition:针对永久性故障,会通过设置NodeCondition 来改变节点状态。
    🔥 Event:临时故障通过 Event 来提醒相关对象,比如通知当前节点运行的所有 Pod。

2、自定义npd插件

创建 node-strick-detector.yaml,并在控制平面节点上保存配置到插件 Pod 的目录 /etc/kubernetes/addons/node-problem-detector。这样在集群引导时pod就会自动加载出来了。

npd的异常处理行为:

  • NPD 只负责获取异常事件,并修改 node condition,不会对节点状态和调度产生影响
lastHeartbeatTime: "2022-04-02T15:44:46Z"
lastTransitionTime: "2022-04-02T15:29:43Z"
message: 'kernel: INFO: task docker:20744 blocked for more than 120 seconds."
reason: DockerHung
status: "True"
type: KernelDeadlock
  • 需要自定义控制器,监听 NPD 汇报的 condition,taint node,阻止 Pod 调度到故障节点。
  • 问题修复后,重启 NPD pod 来清理错误事件

首先安装node-problem-detector,这个请参照官网安装方法,现在我们就来实践一下:

# 添加kernel bug到/dev/kmsg
sudo sh -c "echo 'kernel: BUG: unable to handle kernel NULL pointer dereference at TESTING' >> /dev/kmsg"
cat /dev/kmsg
# 查看当前node情况,event中显示了添加的kernel bug。
k describe node node1
# 通过KernelOops的event上报给了apiserver。

在这里插入图片描述

八、基于extended resource扩展节点资源

扩展资源是 kubernetes.io 域名之外的标准资源名称,自定义扩展资源无法使用 kubernetes.io 作为资源域名。它们使得集群管理员能够颁布非Kubernetes 内置资源,而用户可以使用他们。

管理扩展资源:

  • 节点级扩展资源,节点级扩展资源绑定到节点.
  • 设备插件管理的资源, 发布在各节点上由设备插件所管理的资源,如 GPU(GPU manager),智能网卡等。

1、为节点配置资源

  • 集群管理员可以向apierver提交 PATCH的HTTP 请求,然后在节点status.capacity 中为其配置资源。
  • kubelet 会异步地对 status.allocatable 字段执行自动更新操作,使之包含新资源。
  • 调度器在评估 Pod 是否适合在某节点上执行时会使用节点的 status.allocatable 值,在更新节点资源情况使之包含新资源和请求该资源的第一个 Pod 被调度到该节点之间,可能会有短暂的延迟。

集群层面的扩展资源:

  • 可选择由默认调度器像管理其他资源一样管理扩展资源。
  • Request 与 Limit 必须一致,因为 Kubernetes无法确保扩展资源的超售。
  • 更常见的场景是,由调度器扩展程序(Scheduler Extenders)管理,这些程序处理资源消耗和资源配额。
  • 修改调度器策略配置 ignored ByScheduler 字段
  • 可配置调度器不要检查自定义资源。
    在这里插入图片描述

2、添加自定义资源实践

  • 查看当前环境的kubeconfig
cat ~/.kube/config
  • 解码并生成证书
echo LS0tL...== | base64 -d > admin.crt
echo LS0tL...== | base64 -d > admin.key
  • 执行patch命令添加资源
curl --key admin.key --cert admin.crt --header "Content-Type: application/json-patch+json" --request PATCH -k --data '[{"op": "add", "path": "/status/capacity/extended-cpu", "value": "2"}]' https://192.168.0.6:6443/api/v1/nodes/node1/status

这里会报错,因为匿名用户没有patch的权限,需要授权。
在这里插入图片描述

  • 授权
k create clusterrolebinding test:anonymous --clusterrole=cluster-admin --user=system:anonymous

现在再patch就ok了。

  • 查看node的资源信息。
    在这里插入图片描述
    现在你就可以部署带额外资源的pod。

3、自定义扩展资源的意义、降本增效

做完实践你会发现,上面演示的自定义扩展资源,其实没啥用,一是这个资源的多少,应该由插件去管理,而不是我们去patch。二是这个资源不应该说说而已,应该在节点上实际存在,且能去使用,

  • 比如gpu卡的实现。其实就是通过一个gpu device manager plugin ds去实时汇报当前节点gpu卡数,然后某pod使用此资源之后,节点allocatable会扣除相应卡数,然后调度到某节点之后,gpu device manager plugin会将pod调度到相应的gpu卡。这样自定义资源才是有实际意义的。
  • reclaim-cpu实现。背景:其实我们k8s集群的cpu使用率是非常低的,一般可能不足10%。这样我们就可以自定义一个reclaim-cpu资源,然后把节点上空闲的cpu,进行二次售卖,这样就能提高cpu使用率,当然一般使用reclaim-cpu资源的服务,最好是离线服务,不稳定也是能接受的。

其实reclaim-cpu这种是一种降本增效的思想,最近几年的k8s其实就是在降本增效的。还有其他的降本增效技术,比如在离线混布,还有在公有云中,你竞价购买的低价云服务器(比如腾讯云竞价低价云服务器),其实原理就是,k8s中一般资源使用率不可能用的很满,总是有20%以上的资源是处于一个闲置的(后备应急、某些情况支持大量弹性伸缩)性质,比如跨机房灾备、双11等。那么平时这些闲置的资源就以低价卖出去,按时间计费,弊端就是当云厂商需要紧急使用这个资源时,就必须要回收这部分资源,你就不能用了

  • 2
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

凤求凰的博客

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值