计算资源管理 requests & limits

为pod中的容器申请资源

设置 pod 的容器资源申请量保证每个容器能够获得它所需要资源的最小量。
创建一个 pod 时,可以指定容器对 CPU 和内存的资源请求量(requests),以及资源限制量(limits)。它们并不是在 pod 里定义,而是针对每个容器单独指定。pod 对资源的请求量和限制量是它所包含的所有容器的请求量和限制量之和。

创建包含资源 requests 的 pod

apiVersion: v1 kind: Pod metadata: name: requests-pod spec: containers: - image: busybox command: ["dd", "if=/dev/zero", "of=/dev/null"] name: main resources: requests: cpu: 200m memory: 10Mi

在 pod mainfest 中,声明你一个容器需要 1/5 核 (200 毫核)的 CPU 才能正常运行。换句话说,五个同样的 pod(或容器)可以足够快地运行在一个 CPU 核上。
当我们不指定 CPU requests 时,表示我们并不关心系统为容器内的进程分配了多少 CPU 时间。在最坏情况下进程可能根本分不到 CPU 时间(当其他进程对 CPU 需求量很大时会发生)。这对一些时间不敏感、低优先级的 batch jobs 没有问题,但对于处理用户请求的容器这样配置显然不太合适。
在 pod spec 里,同时为容器申请了 10 MB 的内存,说明期望容器内的进程最大消耗 10MB 的 RAM。它们可能实际占用较小,但在正常情况下我们并不希望它们占用超过这个值。

资源 requests 如何影响调度

通过设置资源 requests 我们指定了 pod 对资源需求的最小值。调度器在将 pod调度到节点的过程中会用到该信息。每个节点可分配给 pod 的 CPU 和内存数量都是一定的 。调度器在调度时只考虑那些未分配资源量满足 pod 需求量的节点。如果节点的未分配资源量小于 pod 需求量,这时节点没有能力提供 pod 对资源需求的最小量,因此Kubernetes不会将该 pod 调度到这个节点。

调度器如何判断一个pod是否适合调度到某个节点
调度器在调度时并不关注各类资源在当前时刻的实际使用量,而只关心节点上部署的所有 pod 的资源申请量之和。尽管现有 pods 的资源实际使用量可能小于它的申请量,但如果使用基于实际资源消耗量的调度算法将打破系统为这些已部署成功的 pods 提供足够资源的保证。

 =1000*

上图中,节点上部署了三个pod。它们共申请了节点80%的 CPU 和60%的内存资源。图右下方的 podD 将无法调度到这个节点上,因为它25%的 CPU requests 大于节点未分配的20% CPU。而实际上,这与当前三个 pods 仅使用70%的 CPU 没有什么关系。

调度器如何利用 pod requests 为其选择最佳节点
调度器首先会对节点列表进行过滤,排除那些不满足需求的节点,然后根据预先配置的优先级函数对其余节点进行排序 。其中有两个基于资源请求量的优先级排序函数: LeastRequestedPriority 和 MostRequestedPriority。前者优先将 pod 调度到请求量少的节点上(也就是拥有更多未分配资源的节点), 而后者相反,优先调度到请求量多的节点(拥有更少未分配资源的节点)。 但是,它们都只考虑资源请求量,而不关注实际使用资源量。
调度器只能配置一种优先级函数。你可能在想为什么有人会使用MostRequestedPriority函数。毕竟如果你有一组节点,通常会使其负载平均分布,但是在随时可以增加或删除节点的云基础设施上运行时并非如此。 配置调度器使用MostRequestedPriority函数, 可以在为每个pod提供足量 CPU/内存资源的同时, 确保Kubernetes使用尽可能少的节点。通过使 pod 紧凑地编排,一些节点可以保待空闲并可随时从集群中移除。由于通常会按照单个节点付费,这样便可以节省一笔开销。

查看节点资源总量

kubectl describe node master Capacity: cpu: 4 ephemeral-storage: 38774276Ki hugepages-1Gi: 0 hugepages-2Mi: 0 memory: 3799004Ki pods: 110 Allocatable: cpu: 4 ephemeral-storage: 35734372703 hugepages-1Gi: 0 hugepages-2Mi: 0 memory: 3696604Ki pods: 110 ... Non-terminated Pods: (11 in total) Namespace Name CPU Requests CPU Limits Memory Requests Memory Limits Age --------- ---- ------------ ---------- --------------- ------------- --- default kubia-647b7bf689-6whmt 0 (0%) 0 (0%) 0 (0%) 0 (0%) 9d default kubia-647b7bf689-czvnt 0 (0%) 0 (0%) 0 (0%) 0 (0%) 9d default kubia-647b7bf689-jmb4q 0 (0%) 0 (0%) 0 (0%) 0 (0%) 9d kube-system coredns-57d4cbf879-npdf6 100m (2%) 0 (0%) 70Mi (1%) 170Mi (4%) 16d kube-system coredns-57d4cbf879-sbndr 100m (2%) 0 (0%) 70Mi (1%) 170Mi (4%) 16d kube-system etcd-master 100m (2%) 0 (0%) 100Mi (2%) 0 (0%) 16d kube-system kube-apiserver-master 250m (6%) 0 (0%) 0 (0%) 0 (0%) 16d kube-system kube-controller-manager-master 200m (5%) 0 (0%) 0 (0%) 0 (0%) 16d kube-system kube-flannel-ds-7t8fc 100m (2%) 100m (2%) 50Mi (1%) 50Mi (1%) 16d kube-system kube-proxy-bxl8s 0 (0%) 0 (0%) 0 (0%) 0 (0%) 16d kube-system kube-scheduler-master 100m (2%) 0 (0%) 0 (0%) 0 (0%) 16d Allocated resources: (Total limits may be over 100 percent, i.e., overcommitted.) Resource Requests Limits -------- -------- ------ cpu 950m (23%) 100m (2%) memory 290Mi (8%) 390Mi (10%) ephemeral-storage 100Mi (0%) 0 (0%) hugepages-1Gi 0 (0%) 0 (0%) hugepages-2Mi 0 (0%) 0 (0%) ...

命令的输出展示了节点可用资源相关的两组数量:节点资源总量(Capacity #F44336)和可分配资源量(Allocatable #F44336)。资源总量代表节点所有的资源总和,包括那些可能对 pod 不可用的资源。有些资源会为 Kubemetes或者系统组件预留。调度器的决策仅仅基于可分配资源量。

Non-terminated Pods : 展示查询节点下所有名称空间下每个容器创建时资源申请情况

kubectl get pod etcd-master -n kube-system -o yaml ... name: etcd resources: requests: cpu: 100m ephemeral-storage: 100Mi memory: 100Mi ... kubectl get pod coredns-57d4cbf879-sbndr -n kube-system -o yaml resources: limits: memory: 170Mi requests: cpu: 100m memory: 70Mi

Allocated resources: (分配的资源) 查询节点下已占用的资源量,是节点上所有容器申请资源之和。

CPU requests如何影响 CPU 时间分配

CPU requests不仅仅在调度时起作用,它还决定着剩余(未使用)的 CPU 时间如何在 pod 之间分配。如图描绘的那样,因为第一个 pod 请求了200毫核,另一个请求了1000毫核,所以未使用的 CPU 将按照 1:5 的比例来划分给这两个 pod。如果两个 pod 都全力使用 CPU, 第一个 pod 将获得16.7%的 CPU 时间,另一个将获得83.3%的 CPU 时间。
 =1000*
另一方面,如果一个容器能够跑满 CPU, 而另一个容器在该时段处于空闲状态,那么前者将可以使用整个 CPU 时间(当然会减掉第二个容器消耗的少量时间)。毕竟当没有其他入使用时提高整个 CPU 的利用率也是有意义的,对吧?当然 ,第二个容器需要 CPU 时间的时候就会获取到,同时第一个容器会被限制回来。

定义和申请自定义资源

限制容器的可用资源

容器可以消耗资源的最大量

设置容器可使用资源量的硬限制

当其他进程处于空闲状态时容器可以被允许使用所有 CPU 资源。但是你可能想防止一些容器使用超过指定数量的 CPU ,而且经常会希望限制容器的可消耗内存数量。

CPU 是一种可压缩资源 #F44336,意味着我们可以在不对容器内运行的进程产生不利响的同时,对其使用量进行限制。
内存不是一种不可压缩资源 #F44336,一旦系统为进程分配了一块内存,这块内存在进程主动释放之前将无法被回收。这就是为什么需要限制容器的最大内存分配的根本原因。

如果不对内存进行限制,工作节点上的容器(或者 pod )可能会吃掉所有可用内存,会对该节点上所有其他 pod 任何新调度上来的 pod (记住新调度的 pod 是基于内存的申请量 而不是实际使用量的)造成影响。单个故障 pod 或恶意 pod 几乎可以导致整个节点不可用。

创建一个带有资源 limits pod

apiVersion: v1 kind: Pod metadata: name: limited-pod spec: containers: - image: busybox command: ["dd", "if=/dev/zero", "of=/dev/null"] name: main resources: limits: cpu: 1 memory: 20Mi

这个 pod 容器包含了 CPU 和内存资源 limit 配置。 容器内的进程不允许消耗超过 CPU 20MB 内存。
注意:因为没有指定资源 requests ,它将被设置为与资源 limits 相同的值。

可超卖的 limits
与资源 requests 不同的是,资源 limits 不受节点可分配资源量的约束。所有 limits 总和允许超过节点资源总量的 100% 。 换句话说,资源 limits 可以超卖。 果节点资源使用 超过 100% ,一些容器将被杀掉, 这是一个很重要的结果。
 =1000*

超过 limits

CPU 是可压缩资源,当进程不等待 IO 操作时消耗所有的 CPU 时间是非常常见的,正如我们所知道的,对一个进程的 CPU 使用率可以进行限制,因此当为一个容器设置 CPU 限额时,该进程只会分不到比限额更多的 CPU 而己。
而内存却有所不同,当进程尝试申请分配比限额更多的内存时会被杀掉(我们会说这个容器被 OOMKilled 了, OOM是 Out Of Memory 的缩写)。
如果 pod 的重启策略为 Always 或 OnFailure ,进程将会立即重启,因此用户可能根本察觉不到它被杀掉。但是如果它继续超限并被杀死, Kubernetes 会再次尝试重启,并开始增加下次重启的间隔时间。 这种情况下用户会看到 pod CrashLoopBackOff 状态。
CrashLoopBackOff 状态表示 Kubelet 还没有放弃,它意味着在每次崩溃之后,Kubelet 会增加下次重启之前的间隔时间 。第一次崩渍之后,Kubelet 立即重启容器,如果容器再次崩溃, Kubelet 会等待 10 秒钟后再重启。随着不断崩溃,延迟时间也会按照 20、 40、 80、 160 秒以几何倍数增长,最终收敛在 300 。一 间隔时间达300 秒, Kubelet 将以5分钟为间隔时间对容器进行无限重启,直到容器正常运行或被删除。

kubectl describe pod Name: memoryhog ... State: Resaon: OOMKilled # 当前容器因为OOM被杀死 ... Last State: Resaon: OOMKilled # 上一个容器同样因为OOM被杀死 ...

*如果你不希望容器被杀掉,重要的一点就是不要将内存 limits 设置得很低,而容器有时即使没有超限也依然会被 OOMKilled *

容器中的应用如何看待 limits

在容器内看到的始终是节点的内存, 而不是容器本身的内存
即使你为容器设置了最大可用内存的限额, top 命令显示的是运行该容器的节点的内存数,而容器无法感知到此限制。
这对任何通过查看系统剩余可用内存数量,并用这些信息来决定自己该使用多少内存的应用来说具有非常不利的影响。
在 Kubemetes 发集群运行 Java 容器化应用(比如在笔记本电脑上运行)时,因为内存 limis 和笔记本电脑总内存差距不是很大,这个问题还不太明显。
但是如果 pod 部署在拥有更大物理内存的生产系统中, JVM 将迅速超过预先配置的内存限额,然后被 OOM 杀死。

容器内同样可以看到节点所有的 CPU
与内存完全一样,无论有没有配置 CPU limits 容器内也会看到节点所有的 CPU 。将 CPU 限额配置为 1,并不会神奇地只为容器暴露一个核。 CPU limits 做的只是限制容器使用的 CPU 时间。
因此如果一个拥有1核 CPU 限额的容器运行在 64核 CPU 上,只能获得 1/64的全部 CPU 时间。而且即使限额设置为1核, 容器进程也不会只运行在一个核上,不同时刻,代码还是会在多个核上执行。
一些程序通过查询系统 CPU 核数来决定启动工作线程的数量。 同样在开发环境的笔记本电脑上运行良好,但是部署在拥有更多数量 CPU 的节点上,程序将快速启动大量线程,所有线程都会争夺(可能极其)有限的 CPU 时间。同时每个线程通常都需要额外的内存资源,导致应用的内存用量急剧增加。
不要依赖应用程序从系统获取的 CPU 数量,你可能需要使用 Downward API 将 CPU 限额传递至容器并使用这个值。也可以通过 cgroup 系统直接获取配置的 CPU 限制,查看下面的文件

/sys/fs/cgroup/cpu/cpu.cfs_quota_us /sys/fs/cgroup/cpu/cpu.cfs_period_us

__EOF__

本文作者何时&明月
本文链接https://www.cnblogs.com/kiyalone/p/15956371.html
关于博主:当你发现自己的才华支撑不起野心时,就请安静下来学习吧!
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   何时&明月  阅读(498)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· DeepSeek “源神”启动!「GitHub 热点速览」
· 微软正式发布.NET 10 Preview 1:开启下一代开发框架新篇章
· 我与微信审核的“相爱相杀”看个人小程序副业
· C# 集成 DeepSeek 模型实现 AI 私有化(本地部署与 API 调用教程)
· DeepSeek R1 简明指南:架构、训练、本地部署及硬件要求
点击右上角即可分享
微信分享提示