Kubernetes资源管理
资源requests如何影响调度
调度器如何判断Pod调度到某个节点上
- 通过设置资源requests,可以设置Pod的最小资源分配请求,调度器在调度时只考虑那些未分配资源量满足Pod需求量的节点
- 调度器在调度时并不关心各类资源在当前的实际使用量,而是关注节点上部署所有Pod的资源requests的总和,当一个节点的request > capacity那么调度器将不予Pod分配该节点,否则会启动失败
调度器在调度时如何选择最佳节点
- 二个函数LeastRequestedPriority & MostRequestedPriority
- LeastRequestedPriority 优先将Pod调度到requests相对较少的节点上
- MostRequestedPriority 优质将Pod调度到requests相对较多的节点上
- 但是调度器在调度时只有选择一种函数,那么在什么情况下会使用MostRequestedPriority函数呢,在云计算环境背景下,计算实例是按节点计费的,通过让Pod紧凑型编排,这时就可以使用MostRequestedPriority函数以节省费用的开销
如果查看节点的资源使用状态
- 在Kubernetes集群中调度器apiserver需要知道每个集群节点的资源使用情况,比如有多少CPU & MEM并且已被分配了多少量,在Kubernetes每个节点上都安装一个kubelet的组件,Kubelet会定时向API-server发送节点的资源状态数据,并通过节点资源对外访问(schedule controller通信)
- 查看节点的资源使用情况,如下命令
1 <root@HK-K8S-CP ~># kubectl describe nodes hk-k8s-wn1 2 Name: hk-k8s-wn1 3 Roles: worker 4 Labels: beta.kubernetes.io/arch=amd64 5 beta.kubernetes.io/os=linux 6 kubernetes.io/arch=amd64 7 kubernetes.io/hostname=hk-k8s-wn1 8 kubernetes.io/ingress=pre 9 kubernetes.io/os=linux 10 node-role.kubernetes.io/worker= 11 topology.diskplugin.csi.alibabacloud.com/zone=cn-hongkong-c 12 Annotations: csi.volume.kubernetes.io/nodeid: {"diskplugin.csi.alibabacloud.com":"i-j6cg230darhjdqdf9n75"} 13 io.cilium.network.ipv4-cilium-host: 172.20.0.105 14 io.cilium.network.ipv4-health-ip: 172.20.0.102 15 io.cilium.network.ipv4-pod-cidr: 172.20.0.64/26 16 kubeadm.alpha.kubernetes.io/cri-socket: /var/run/dockershim.sock 17 node.alpha.kubernetes.io/ttl: 0 18 volumes.kubernetes.io/controller-managed-attach-detach: true 19 CreationTimestamp: Tue, 16 Mar 2021 14:04:25 +0800 20 Taints: <none> 21 Unschedulable: false 22 Lease: 23 HolderIdentity: hk-k8s-wn1 24 AcquireTime: <unset> 25 RenewTime: Fri, 13 Aug 2021 15:29:41 +0800 26 Conditions: 27 Type Status LastHeartbeatTime LastTransitionTime Reason Message 28 ---- ------ ----------------- ------------------ ------ ------- 29 NetworkUnavailable False Tue, 16 Mar 2021 23:44:59 +0800 Tue, 16 Mar 2021 23:44:59 +0800 CiliumIsUp Cilium is running on this node 30 MemoryPressure False Fri, 13 Aug 2021 15:28:39 +0800 Tue, 16 Mar 2021 14:04:25 +0800 KubeletHasSufficientMemory kubelet has sufficient memory available 31 DiskPressure False Fri, 13 Aug 2021 15:28:39 +0800 Tue, 16 Mar 2021 14:04:25 +0800 KubeletHasNoDiskPressure kubelet has no disk pressure 32 PIDPressure False Fri, 13 Aug 2021 15:28:39 +0800 Tue, 16 Mar 2021 14:04:25 +0800 KubeletHasSufficientPID kubelet has sufficient PID available 33 Ready True Fri, 13 Aug 2021 15:28:39 +0800 Tue, 16 Mar 2021 23:44:57 +0800 KubeletReady kubelet is posting ready status 34 Addresses: 35 InternalIP: 172.19.1.120 36 Hostname: hk-k8s-wn1 37 Capacity: 38 cpu: 2 39 ephemeral-storage: 41152812Ki 40 hugepages-1Gi: 0 41 hugepages-2Mi: 0 42 memory: 3883608Ki 43 pods: 110 44 Allocatable: 45 cpu: 2 46 ephemeral-storage: 37926431477 47 hugepages-1Gi: 0 48 hugepages-2Mi: 0 49 memory: 3781208Ki 50 pods: 110 51 System Info: 52 Machine ID: 20191225111607875619293640639763 53 System UUID: dcbce1f0-bd51-4124-b199-a0d81cf89874 54 Boot ID: b0ee5748-9383-46a9-91cb-a984f869ed40 55 Kernel Version: 5.11.1-1.el7.elrepo.x86_64 56 OS Image: CentOS Linux 7 (Core) 57 Operating System: linux 58 Architecture: amd64 59 Container Runtime Version: docker://19.3.12 60 Kubelet Version: v1.18.5 61 Kube-Proxy Version: v1.18.5 62 PodCIDR: 172.20.1.0/24 63 PodCIDRs: 172.20.1.0/24 64 Non-terminated Pods: (10 in total) 65 Namespace Name CPU Requests CPU Limits Memory Requests Memory Limits AGE 66 --------- ---- ------------ ---------- --------------- ------------- --- 67 default prometheus-kube-state-metrics-858f88ff6-gb2lh 0 (0%) 0 (0%) 0 (0%) 0 (0%) 56d 68 default prometheus-node-exporter-cq6fp 0 (0%) 0 (0%) 0 (0%) 0 (0%) 56d 69 default rabbitmq-1 1 (50%) 1 (50%) 2Gi (55%) 2Gi (55%) 56d 70 default zk-1 100m (5%) 0 (0%) 128M (3%) 0 (0%) 77d 71 kube-system cilium-operator-789c9b45c9-fvjkx 0 (0%) 0 (0%) 0 (0%) 0 (0%) 149d 72 kube-system cilium-wcrm7 100m (5%) 0 (0%) 100Mi (2%) 0 (0%) 149d 73 kube-system csi-plugin-tsjwb 100m (5%) 500m (25%) 128Mi (3%) 1Gi (27%) 88d 74 kube-system hubble-relay-7995686985-bhp4k 0 (0%) 0 (0%) 0 (0%) 0 (0%) 146d 75 kube-system hubble-ui-769fb95577-kqn7m 0 (0%) 0 (0%) 0 (0%) 0 (0%) 146d 76 kube-system kube-router-njnhh 250m (12%) 0 (0%) 250Mi (6%) 0 (0%) 149d 77 Allocated resources: 78 (Total limits may be over 100 percent, i.e., overcommitted.) 79 Resource Requests Limits 80 -------- -------- ------ 81 cpu 1550m (77%) 1500m (75%) 82 memory 2711624Ki (71%) 3Gi (83%) 83 ephemeral-storage 0 (0%) 0 (0%) 84 hugepages-1Gi 0 (0%) 0 (0%) 85 hugepages-2Mi 0 (0%) 0 (0%) 86 Events: <none>
CPU requests如何影响CPU时间分配
- 比如在一个节点上,创建了二个Pod,一个Pod的CPU是200m;一个Pod是1000m(requests只是在调度分配时指定最小请求值并不能限制Pod实际使用上限)requests不仅在调度时起作用,它还决定Pod是如何请求CPU分配时间,如果二个Pod同时负载情况下消耗CPU时,那么在请求分配CPU时间片时,会按照requests的比例来分配CPU,意味着就是1:5的比例分配CPU
限制容器可用资源
- CPU是一种可压缩的资源,意味着可以在不对容器内运行的进程产生不利的影响的同时,对其进行使用量的限制,而内存明显不同是一种不可压缩的资源,一旦系统为进程分配了一块内存后,在未被进程主动释放前操作系统不会主动回收这部分空间,这就是为什么需要针对内存设置limits
- 如果不对Pod的CPU & MEM设置limits限制,由于Pod是在部署一个共有的节点上,那么在突发事件故障时,由于一个Pod将该节点的资源消耗完,那么势必会造成其它Pod无法正常运行1 resources:
1 resources: 2 limits: 3 cpu: '1' 4 memory: 1Gi 5 requests: 6 cpu: 100m 7 memory: 512Mi
Kubernetes如何处理 overlimits
-
CPU的反应:进程不等待IO操作时消耗所有的CPU时间是非常常见的,如果在Kubernetes集群Pod设置CPU limits值时,如果该Pod遇到CPU负载时, 那么此时该Pod只会被限制在limits值内,不会分配到大于limits的CPU
-
内存的反应:内存则并不相同,当进程尝试申请分配大于limits的值时,此时会触发OOM,kill掉Pod,如果Pod的重启策略是Always或者是OnFailure时,Pod会自动重启,如果反重启则会触发Kubernetes内部策略机制,则增加下次重启的时间间隔(具体时间kubelet在第一次会以10s时间间隔等待,如果反复重启则会以倍数时间增加即20,40,80,160一致至300s,后面会以300s的时间间隔进行重启,直到Pod正常或者被delete),这种情况下就会看到Pod处于CrashLoopBackOff状态
-
定位Pod的crash的原因也很简单,执行kubectl des pod_name
容器中的应用如何看待limits
-
在设置了limits值时,但是exec到容器中top发现实际的内存或是CPU玩玩超出设置的limits值,结论是:在容器中看到的资源始终是节点的,而非Pod本身的资源
-
在java应用时需要注意,在早期的jdk版本时,并不支持 -XX:+UseContainerSupport 参数,这将无法控制ava进程堆外内存,会出现OOM的情况,好在jdk新版本之后1.8_191之后支持该参数以识别Pod的limits值来避免这一类问题
-
CPU的limits并非限制使用几个CPU的核数及其它,而是限制Pod使用所在节点的CPU时间切片,比如一个64C的节点,而为Pod限制了1000m,此Pod只是获得了1/64的CPU时间,但是容器内的进程不会运行在一个核上,而是分散在多个核上执行,但是一些垃圾程序是通过查询系统CPU核数决定启动多少个线程,针对这种情况可以从Pod获取具体CPU的信息如(/sys/fs/cgroup/cpu/cpu.cfs_quota/period_us)或者使用其它方法
Pod QoS等级
背景介绍:在上文已经说明了,CPU可以overlimits,优点就是在一个节点上所有的Pod不可能把所有的CPU消耗完,多个Pod可以共同使用,那么会衍生另一个问题(在资源消耗殆尽时)比如:Pod-A使用了该节点的90%内存,Pod-B突发事件受到内存压力情况下可能会消耗节点的%20的内存乃至需求更多的内存,此时Kubernetes该终结哪一个Pod呢,以释放内存保留其中一个Pod呢,Kubernetes引入了QoS概念,Qos一共分三个等级如下
- BestEffort(优先级最低)
- Burstable
- Guaranteed(优先级最高)
如何定义Pod的Qos等级
先了解一下Qos的等级优势,BestEffort最低等级,优先被Kill掉,最没有资源保障,其次是Burstable,再次Guaranteed,那如何定义Qos的等级,如下
- Pod没有定义requests & limits配置,定义等级就为BestEffort
- Pod定义requests 没有定义limits;或者二者的值不等;或者Pod多容器的状态下(定义,未定义,定义不等)都视为 Burstable等级
- Pod定义了requests & limits值,并且二者相等,定义等级为Guaranteed
资源不足Kill顺序
BestEffort > Burstable > Guaranteed
如果都是Guaranteed 等级的话,就对比进程的OOM分数值,谁高杀谁
CPU requests vs. limits | mem requests vs. limits | Qos level |
none | none | BestEffort |
none | requests < limits | Burstable |
none | requests = limits | Burstable |
requests < limits | none | Burstable |
requests < limits | requests < limits | Burstable |
requests < limits | requests = limits | Burstable |
requests = limits | requests = limits | Guaranteed |