当前位置:   article > 正文

Kubernetes基础(二十九)-资源预留

Kubernetes基础(二十九)-资源预留

kubelet中有几个参数,通过这几个参数可以为系统进程预留资源,不至于pod把计算资源耗尽,而导致系统操作都无法正常进行。

  1. --enforce-node-allocatable
  2. --system-reserved
  3. --system-reserved-cgroup
  4. --kube-reserved
  5. --kube-reserved-cgroup
  6. --eviction-hard

Allocatable

在kubernetes 1.6版本后,引入了Node的Allocatable特性,通过该特性我们可以控制每个节点可分配的资源。
借用官网的图如下:

  1. capacity
  2. -----------------------------
  3. | kube-reserved |
  4. ------------------------------
  5. | system-reserved |
  6. ------------------------------
  7. | eviction-threshhold |
  8. ------------------------------
  9. | allocatable |
  10. | (available for pods) |
  11. ------------------------------

Capacity是指Node的容量,allocatable的值为

allocatable = capacity - kube_reserved - system_reserved - eviction_threshhold

当kubelet启动后,Node的allocatable就是固定的,不会因为pod的创建与销毁而改变。

  • allocatable vs requests vs limits

在pod的yaml文件中,可以为pod设置requests与limits。其中limits与allocatable没有什么关系。但requests与allocatable关系紧密。

调度到某个节点上的Pod的requests总和不能超过该节点的allocatable。limits的总和没有上限。

比如某个节点的内存的allocatable为10Gi,有三个Pod(requests.memory=3Gi)已经调度到该节点上,那么第4个Pod就无法调度到该节点上,即使该Node上的空闲内存大于3Gi。

资源预留 - 不设cgroup

假设我们现在需要为系统预留一定的资源,那么我们可以配置如下的kubelet参数(在这里我们不设置对应的cgroup参数):

  1. --enforce-node-allocatable=pods
  2. --kube-reserved=memory=...
  3. --system-reserved=memory=...
  4. --eviction-hard=...

在上面提到,节点上Pod的requests总和不能超过allocatable。
当我们设置了以上的四个参数时,节点上所有Pod实际使用的资源总和不会超过capacity - kube_reserved - system_reserved

我们可以通过实验进行验证。

1、参数设置
kubelet的启动参数如下:

/usr/bin/kubelet --address=0.0.0.0 --allow-privileged=true --cluster-dns=10.254.0.10 --cluster-domain=kube.local --fail-swap-on=true --hostname-override=192.168.1.101 --kubeconfig=/etc/kubernetes/kubeconfig --pod-infra-container-image=10.142.232.115:8021/library/pause:latest --port=10250 --enforce-node-allocatable=pods --kube-reserved=memory=1Gi --system-reserved=memory=1Gi --cgroup-driver=cgroupfs --eviction-hard=memory.available<100Mi

2、查看capacity及allocatable

查看到Node的capacity及allocatable的值如下:

  1. Capacity:
  2. cpu: 2
  3. memory: 4016436Ki (约3.83Gi)
  4. pods: 110
  5. Allocatable:
  6. cpu: 2
  7. memory: 1816884Ki (约1.73Gi)
  8. pods: 110

我们可以计算出allocatable的值,刚好与上面的一致:

  1. allocatale = capacity - kube_reserved - system_reserved - eviction_hard
  2. 1816884Ki = 4016436Ki - 1*1024*1024Ki - 1*1024*1024Ki - 100*1024Ki

我们可以通过free命令来查看Node的total值,与capacity一致:

  1. $ free -k
  2. total used free shared buff/cache available
  3. Mem: 4016436 1224372 2234872 17100 557192 2453156
  4. Swap: 0 0 0

3、查看kubepods控制组

查看kubepods控制组中对内存的限制,该值决定了Node上所有的Pod能使用的资源上限:

  1. $ cat /sys/fs/cgroup/memory/kubepods/memory.limit_in_bytes
  2. 1965346816

1965346816 Bytes = 1919284Ki = allocatable + 100Mi

根据上面的计算可知,Node上Pod能实际使用的资源上限值为:

kubepods/memory.limit_in_bytes = capacity - kube_reserved - system_reserved

注意:根据上面的公式,我们可以知道,一个节点上所有Pod能使用的内存总和,与eviction-hard无关

4、查看内存的空闲情况

查看内存的使用情况,发现空闲内存为 2.3Gi

  1. $ free -h
  2. total used free shared buff/cache available
  3. Mem: 3.8G 1.2G 2.1G 16M 544M 2.3G
  4. Swap: 0B 0B 0B

5、创建pod

此时内存的空闲值为2.3Gi,allocatable为1.73Gi,kubepod.limit为1.83Gi。
我们创建一个Pod,pod.request为0.1Gi,pod.limit为20Gi,Pod实际消耗内存1Gi。理论上该Pod能创建成功,实际也成功了,如下:
备注:yaml文件消耗内存的脚本见本文附录

  1. $ kubectl get pod
  2. NAME READY STATUS RESTARTS AGE
  3. centos-659755bf78-jdlrc 1/1 Running 0 44s

查看Node的内存使用情况:

  1. $ free -h
  2. total used free shared buff/cache available
  3. Mem: 3.8G 2.2G 1.1G 16M 546M 1.3G
  4. Swap: 0B 0B 0B

此时,空闲内存为1.3Gi,Node剩余的request为1.63Gi,Node的kubepods.limit还剩0.83Gi。
我们再创建一个同样的Pod,根据推测,Pod可以调度成功,但是由于要消耗1Gi的实际内存,超过了0.83Gi,那么该Pod会出现OOM。实验结果也的确如此:

  1. $ kubectl get pod
  2. NAME READY STATUS RESTARTS AGE
  3. centos-659755bf78-j8wjv 0/1 OOMKilled 0 5s
  4. centos-659755bf78-jdlrc 1/1 Running 1 1m

资源预留 - 设置对应的cgroup

如果还设置了对应的 --system-reserved-cgroup 和 --kube-reserved-cgroup参数,Pod能实际使用的资源上限不会改变(即kubepods.limit_in_bytes不变),但系统进程与kube进程也会受到资源上限的限制。如果系统进程超过了预留资源,那么系统进程会被cgroup杀掉。
但是如果不设这两个参数,那么系统进程可以使用超过预留的资源上限。

配置建议

为kubelet设置以下四个参数即可:

  1. --enforce-node-allocatable=pods
  2. --kube-reserved=cpu=xx,memory=xx,ephemeral-storage=xx
  3. --system-reserved=cpu=xx,memory=xx,ephemeral-storage=xx
  4. --eviction-hard=memory.available<10%,nodefs.available<10%

一般来说,我们不希望资源的使用率超过70%,所以kube-reserved、system-reserved、eviction-hard都应该设为10%。但由于kube-reserved与system-reserved不能设置百分比,所以它们要设置为绝对值。

总结

  • Node的allocatable在kubelet启动后是一个固定的值,不会因为pod的创建与删除而改变
  • 当我们为Pod设置了resources.requests时,调度到Node上的Pod的resources.requests的总和不会超过Node的allocatable。但Pod的resources.limits总和可以超过Node的allocatable
  • 一个Pod能否成功调度到某个Node,关键看该Pod的resources.request是否小于Node剩下的request,而不是看Node实际的资源空闲量。即使空闲资源小于Pod的requests,Pod也可以调度到该Node上
  • 当Pod的内存资源实际使用量超过其limits时,docker(实际是cgroup)会把该Pod内超出限额的进程杀掉(OOM);如果CPU超过,不会杀掉进程,只是进程会一直等待CPU。
  • 当我们只设置如下四个参数时,可以达到为系统预留资源的效果,即Pod的资源实际使用量不会超过allocatable的值(因为kubepods控制组中memory.limit_in_bytes的值就为allocatable的值)。即使系统本身没有使用完预留的那部分资源,Pod也无法使用。当系统超出了预留的那部分资源时,系统进程可以抢占allocatable中的资源,即对系统使用的资源没有限制。
  1. --enforce-node-allocatable=pods
  2. --kube-reserved=memory=...
  3. --system-reserved=memory=...
  4. --eviction-hard=...
  • 当除了设置了以上四个参数,还设置了对应的cgroup时(如下),那么除了Pod使用的资源上限不会超过allocatable外,系统使用的资源上限也不会超过预留资源。当系统进程超过预留资源时,系统进程也会被cgroup杀掉。所以推荐使用上面的设置方法
  1. --enforce-node-allocatable=pods,kube-reserved,system-reserved
  2. --kube-reserved=memory=...
  3. --kube-reserved-cgroup=...
  4. --system-reserved=memory=...
  5. --system-reserved-cgroup=...
  6. --eviction-hard=...
  • allocatable与kubepods.limit的值不一样,它们之间相差一个 eviction_hard
  1. allocatable = capacity - kube_reserved - system_reserved - eviction_hard
  2. kubepods.limit = capacity - kube_reserved - system_reserved

附录

  • centos.yaml
  1. apiVersion: apps/v1beta2
  2. kind: Deployment
  3. metadata:
  4. name: centos
  5. namespace: default
  6. spec:
  7. replicas: 1
  8. selector:
  9. matchLabels:
  10. name: centos
  11. template:
  12. metadata:
  13. labels:
  14. name: centos
  15. spec:
  16. volumes:
  17. - name: volume1
  18. hostPath:
  19. path: /home/docker/yaml/mem.py
  20. containers:
  21. - name: centos
  22. image: 10.142.232.115:8021/library/centos:centos7
  23. command:
  24. - python
  25. - /mem.py
  26. - 1GB
  27. volumeMounts:
  28. - mountPath: /mem.py
  29. name: volume1
  30. resources:
  31. requests:
  32. memory: 0.1Gi
  33. limits:
  34. memory: 20Gi
  1. import sys
  2. import re
  3. import time
  4. def print_help():
  5. print 'Usage: '
  6. print ' python mem.py 100MB'
  7. print ' python mem.py 1GB'
  8. if __name__ == "__main__":
  9. if len(sys.argv) == 2:
  10. pattern = re.compile('^(\d*)([M|G]B)$')
  11. match = pattern.match(sys.argv[1].upper())
  12. if match:
  13. num = int(match.group(1))
  14. unit = match.group(2)
  15. if unit == 'MB':
  16. s = ' ' * (num * 1024 * 1024)
  17. else:
  18. s = ' ' * (num * 1024 * 1024 * 1024)
  19. time.sleep(10000)
  20. else:
  21. print_help()
  22. else:
  23. print_help()
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/很楠不爱3/article/detail/543160
推荐阅读
  

闽ICP备14008679号