pod 计算资源管理

简述

为一个 pod 配置资源的预期使用量和最大使用量是 pod 定义中的重要组成部分。 通过设置这两组参数, 可以确保 pod 公平地使用 Kubemetes集群资源, 同时也影响着整个集群pod的调度方式。 

为Pod中的容器申请资源

 我们创建 一 个pod 时,可以指定容器对CPU 和内存的资源请求量(即requests), 以及资源限制量(即Limt)。它们并不在 pod 里定义, 而是针对每个容器单独指定。pod 对资源的请求量和限制量是它所包含的所有容器的请求量和限制量之和。

创建包含资源 requests 的 pod
apiVersion: vl 
kind: Pod 
metadata: 
  name: requests-pod 
spec: 
  containers: 
  - image: busybox
    command: ["dd", "if=/dev/zero", "of=/dev/null"]
    name: main
    resources:                    #我们为主容器指定了资源请求
      requests:
        cpu: 200m                 #容器申请200毫核(即一个CPU核心的1/5)
        memory: lOMi              #容器申请了10M 内存
View Code
当我们不指定CPU requests时,表示我们并不关心系统为容器内的进程分配了多少CPU时间。在最坏情况下进程可能根本分不到CPU时间(当其他进程对CPU需求量很大时会发生)。这对一些时间不敏感、低优先级的batch jobs没有问题,但对于处理用户请求的容器这样配置显然不太合适。 
 
资源 requests 影响调度
通过设置资源requests我们指定了pod对资源需求的最小值。调度器在将pod调度到节点的过程中会用到该信息。调度器在调度时只考虑那些未分配资源量满足pod 需求量的节点。如果节点的未分配资源量小于pod 需求量,这时节点没有能力提供pod对资源需求的最小量,因此Kubemetes不会将该pod调度到这个节点。 
调度器在调度时并不关注各类资源在当前时刻的实际使用量,而只关心节点上部署的所有pod 的资源申请(request)量之和。尽管现有pods 的资源实际使用量 可能小于它 的 申请量,但如果使用基于 实际资源消耗量 的调度算法将打破系统为这些已部署成功的pods提供足够资源的保证。 
 
查看资源分配情况
kubectl describe node node-name

#整个节点总体资源
Capacity:
 cpu:                4
 ephemeral-storage:  515922800Ki
 hugepages-1Gi:      0
 hugepages-2Mi:      0
 memory:             15732704Ki
 pods:               23
#整个节点可以对外分配的资源
Allocatable:
 cpu:                4
 ephemeral-storage:  475474451693
 hugepages-1Gi:      0
 hugepages-2Mi:      0
 memory:             14708704Ki
 pods:               23

...                

#各个命名空间实际requests分配的情况,会有kube-system 下的系统级别的Pod申请了资源。
Non-terminated Pods:         (15 in total)            
  Namespace                  Name                                       CPU Requests  CPU Limits  Memory Requests  Memory Limits  AGE
  ---------                  ----                                       ------------  ----------  ---------------  -------------  ---
  default                    jianwei-k8s-3afe2134-3b6f-43a6-a473-ce4    0 (0%)        0 (0%)      1Gi (7%)         0 (0%)         58d
  filebeat                   filebeat-fdasd                             250m (6%)     500m (12%)  500Mi (3%)       1Gi (7%)       21d
  kube-system                flexvolume-dfhjj                           100m (2%)     1 (25%)     100Mi (0%)       1000Mi (6%)    58d
  kube-system                kube-proxy-worker-bqcmk                    0 (0%)        0 (0%)      0 (0%)           0 (0%)         58d
  kube-system                terway-eniip-fffvg                         250m (6%)     0 (0%)      0 (0%)           0 (0%)         58d
  monitoring                 ack-prometheus-operator-adapter-7c      0 (0%)        0 (0%)      0 (0%)           0 (0%)         23d
  monitoring                 ack-prometheus-operator-grafana-5b      0 (0%)        0 (0%)      0 (0%)           0 (0%)         23d
  monitoring                 ack-prometheus-operator-kube-state      0 (0%)        0 (0%)      0 (0%)           0 (0%)         23d
  monitoring                 ack-prometheus-operator-operator-8      0 (0%)        0 (0%)      0 (0%)           0 (0%)         23d
  monitoring                 ack-prometheus-operator-prometheus-node  0 (0%)        0 (0%)      0 (0%)           0 (0%)         23d
  monitoring                 alertmanager-ack-prometheus-operator     100m (2%)     100m (2%)   225Mi (1%)       25Mi (0%)      23d
  monitoring                 prometheus-ack-prometheus-operator-      150m (3%)     150m (3%)   75Mi (0%)        75Mi (0%)      23d
  ad1                        payshop-85dasdbcd4749-h625m               500m (12%)    2 (50%)     1Gi (7%)         4Gi (28%)      24d
  ad3                        fdaf-supply-chain-go-64988c99d8-ppv2v     500m (12%)    1 (25%)     1Gi (7%)         2Gi (14%)      16d
  ad6                        k8s-admin-soul-85d5945974-lxjh4           500m (12%)    2 (50%)     1Gi (7%)         4Gi (28%)      24d

#整个节点汇总后实际requests分配的情况,k8s根据分配后的剩余量来调度pod 
Allocated resources:
  (Total limits may be over 100 percent, i.e., overcommitted.)
  Resource           Requests      Limits
  --------           --------      ------
  cpu                2350m (58%)   6750m (168%)
  memory             4996Mi (34%)  12364Mi (86%)
  ephemeral-storage  0 (0%)        0 (0%)
...
View Code
 
CPU requests影响CPU时间分配
现在有两个pod运行在集群中(暂且不理会那些系统pod 因为它们大部分时间都是空闲的)。 一个请求了200毫核,另一个是前者的5倍。我们还没有定义任何limts, 因此每个pod 分别可以消耗多少CPU并没有做任何限制。那么假设每个pod内的进程都尽情消耗CPU时间,每个pod最终能分到多少CPU时间呢?CPU requests不仅仅在调度时起作用,它还决定着剩余(未使用) 的CPU时间如何在pod之间分配。第一个pod 请求了200毫核,另 一个请求了1000毫核,所以未使用的CPU将按照1:5的比例来划分给这两个
pod。如果两个pod 都全力使用CPU, 第一个pod 将获得16.7%的CPU时间,另 一个将获得83.3%的CPU时间。 
 
另一方面,如果一个容器能够跑满CPU,而另 一个容器在该时段处于空闲状态,那么前者将可以使用整个CPU时间(当然会减掉第二个容器消耗的少量时间)。毕竟当没有其他人使用时提高整个CPU的利用率也是有意义的,对吧?当然 ,第二个容器需要CPU时间的时候就会获取到,同时第一个容器会被限制回来。 
 
定义和申请自定义资源
Kubemetes允许用户为节点添加属于自己的自定义资源,同时支持在pod资源 requests里申请这种资源。因为目前是一个alpha特性,所以不打算描述其细节,而 只会简短地介绍一下。 首先, 需要通过将自定义资源加入节点API对象的capacity属性让 Kubemetes知道它的存在。这可以通过执行HTTP的PATCH请求来完成。资源名 称可以是不以 kubernetes.io 域名开头的任 意值,例如 example.org/my resource ,数量必须是整数(例如不能设为 lOOm ,因为 0.1 不是整数;但是可以 设置为 l000m、 2000m ,或者简单地设为1和2 。这个值将自动从 capacity 复制到 allocatable字段。
 
创建 pod 时只要简单地在容器 spec resources requests 宇段下,或者像之前例子那样使用带 requests 参数的 kubectl run 命令来指定自定义资源名称和申请 ,调度器就可以确保这个 pod 只能部署到满足自定义资源申的节点,同时每个己部署的 pod 会减少节点的这类可分配资源数量。
 
一个自定义资源的例子就是节点上可用的 GPU 单元数量。如果pod 要使用GPU ,只 要简单指定其 requests 调度器就会保证这个 pod 只能调度到至少拥有一 个未分配 GPU 单元的节点上。

限制容器的可用资源

设置 pod 的容器资源申请量保证了每个容器能够获得它所需要资源的最小量。现在我们再看看硬币的另一面一一容器可以消耗资源的最大量。

CPU与内存的区别

CPU 是一种可压缩资源,意味着我们可 在不对容器内运行的进程产生不利影响的同时,对其使用量进行限制而内存明显不同一一是一种不可压缩资源。一旦系统为进程分配了 块内存,这块内存在进程主动释放之前将无法被回收。这就是为什么需要限制容器的最大内存分配的根本原因。
如果不对内存进行限制, 工作节点上的容器(或者 pod )可能会吃掉所有可用内存,会对该节点上所有其他 po 任何新调度上来的pod (记住新调度的 pod基于内存的申请量而不是实际使用量的)造成影响。单个故障 pod 或恶意 pod 几乎可以导致整个节点不可用。 
 
创建一个带有资源 limits 的pod
apiVersion: vl 
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
View Code
可超卖的 limits
与资源 requests 不同的是,资源 limits 不受节点可分配资源量的约束所有limits 总和允许超过节点资源总量的 100%。 换句话说,资源 limits 以超卖。 如果节点资源使用超过 100% ,一些容器将被杀掉, 这是一个很重要的 结果 。
 
超过 limits
当容器内运行的进程尝试使用比限额更多的资源时会发生什么呢?
我们己经了解了 CPU 是可压缩资源,当进程不等待 IO 操作时消耗所有的 CPU 时间是非常常见的。 正如我们所知道的,对一个进程的 CPU 使用率可以进行限制,因此当为一个容器设置 CPU 限额时,该进程只会分不到比限额更多的 CPU 而己。
而内存却有所不同 当进程尝试申请分配比限额更多的内存时会被杀掉(我们会说这个容器被 OOMKilled 了, OMM是Out Of Memory 的缩写〉 如果 pod 的重 启策略为 Always 或 OnFailure ,进程将会立即重启,因此用户可能根本察觉不 到它被杀掉。但是如果它继续超限并被杀死, kubernetes 会再次尝试重启,并开始 增加下次重启的间隔时间。这种情况下用户会看到 pod CrashLoopBackOff  状态。

关于 CrashLoopBackOf

CrashLoopBackOf 状态表示 Kubelet 还没有放弃,它 味着在每次崩溃之后,Kubelet 会增加下次重启之前的间隔时间 次崩渍之后, kubelet 立即重启容器,如果容器再次崩溃, kubelet 会等待 10 秒钟后再重启,随着不断崩溃,延迟时间也会按照 20 40 80 160 秒以几何倍数增长,最终收敛在 300s  。一旦间隔时间达300 秒, kubelet 将以5分钟为间隔时间对容器进行无限重启,直到容器正常运行或被删除。
  要定位容器 crash 原因,可以通过查看 pod 日志以及 kubectl describe pod 命令
View Code
在容器内看到的始终是节点的内存, 而不是容器本身的内存
kubectl exec -it limited-pod top     #此命令查看到的是整个节点的资源
即使你为容器设置了最大可用内存的限额, top 命令显示的是运行该容器的节点的内存数 ,而容器无法感知到此限制。 这对任何通过查看系统剩余可用内存数量,并用这些信息来决定自己该使用多 少内存的应用来说具有非常不利的影响。
对于 Java 程序来说这是个很大的问题,尤其是不使用一Xmx 选项指定虚拟机的最大堆大小时, JVM 会将其设置为主机总物理内存的百分值。在 kubemetes 开发集群运行 Java 容器化应用(比如在笔记本电脑上运行)时,因为内存 limit 和笔记本电脑总内存差距不是很大,这个问题还不太明显但是如果 pod 部署在拥有更大物理内存的生产系统中, JVM 将迅速超过预先配置的内存限额,然后被 OOM 杀死也许你觉得可以简单地设 Xmx 选项就可以解决这个问题,那么你就错了,很遗憾。 Xmx 选项仅仅限制了堆大小,并不管其他 off heap 内存,好在新版本的Java 会考虑到容器 limits 缓解这个问题
 
容器内同样可感知的是节点所有的 CPU
与内存完全一样,无论有没有配置 CPU limits 容器内也会看到节点所有的CPU 。将 CPU 限额配置为1 ,并不会神奇地只为容器暴露一个核。 CPU limit 做的只是限制容器使用的 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 
 

猜你喜欢

转载自www.cnblogs.com/fanggege/p/12273009.html
pod