35.B站薪享宏福笔记——第十二章(5)资源限制
12 B站薪享宏福笔记——第十二章
—— Kubernetes 中必备的工具组件
12.5 资源限制
—— 需要多少配多少
12.5.1 资源限制
(1)概念
Kubernetes 对资源的限制实际上是通过 Cgroup 来控制的(底层是 docker ,docker 的资源限制是通过 Cgroup 控制的),Cgroup 是容器的一组用来控制内核运行进程的相关属性的集合,针对内存、CPU 和 各种设备都有对应的 Cgroup
默认情况下,Pod 运行没有 CPU 和 内存的限制。这意味着系统中任何 Pod 将能够运行该节点所有的运算资源,可以消耗足够多的 CPU 和内存,一般会针对某些应用的 Pod 资源进行资源限制,通过 resources 的 requests 和 limits 来实现
(2)特性
调度器在调度时并不关注各类资源在当前时刻的实际使用量,而只关心节点上部署的所有 Pod 的资源申请量之和
在容器内看到的始终是节点的内存,而不是容器本身的内存
在容器内看到的始终是节点所有的 CPU 核心数,而不仅仅只是容器可用的 CPU 核心数
12.5.2 HPA
(1)镜像导入
# HPA 需要能够知道 cpu、内存 的使用量才可以根据cpu、内存进行限制(前面11.3 Prometheus 时 安装了 metrics.server,可以获取资源使用情况 ) [root@k8s-master01 12.5]# kubectl top node NAME CPU(cores) CPU% MEMORY(bytes) MEMORY% k8s-master01 321m 8% 2182Mi 61% k8s-node01 164m 8% 1448Mi 41% k8s-node02 182m 9% 1667Mi 47%
# 上传镜像 [root@k8s-master01 12.5]# rz [root@k8s-master01 12.5]# ls hpav1.tar # 主节点导入,推送到node01、node02 节点,node01、node02节点再倒入镜像 [root@k8s-master01 12.5]# docker load -i hpav1.tar ........ [root@k8s-master01 12.5]# scp hpav1.tar n1:/root root@n1's password: hpav1.tar 100% 482MB 14.2MB/s 00:33 [root@k8s-master01 12.5]# scp hpav1.tar n2:/root root@n2's password: hpav1.tar 100% 482MB 106.8MB/s 00:04 [root@k8s-node01 ~]# docker load -i /root/hpav1.tar ........ [root@k8s-node02 ~]# docker load -i /root/hpav1.tar ........
(2)创建 hpa
[root@k8s-master01 12.5]# cat 1.resources.yaml apiVersion: apps/v1 kind: Deployment metadata: name: my-deployment spec: replicas: 3 selector: matchLabels: app: myapp template: metadata: labels: app: myapp spec: containers: - name: my-container image: wangyanglinux/hpa:v1 resources: requests: cpu: 200m
4.deployment 期望:副本数、选择器:匹配标签:标签、标签值、Pod 模版:元数据:标签、标签值、Pod 期望:容器组:容器名、基于镜像版本、资源限制:初始化:cpu
[root@k8s-master01 12.5]# kubectl apply -f 1.resources.yaml deployment.apps/my-deployment created [root@k8s-master01 12.5]# kubectl get deployment NAME READY UP-TO-DATE AVAILABLE AGE my-deployment 3/3 3 3 6s [root@k8s-master01 12.5]# kubectl get pod -o wide NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES my-deployment-5cd68fd574-cq4bt 1/1 Running 0 2m7s 10.244.85.251 k8s-node01 <none> <none> my-deployment-5cd68fd574-cw2sj 1/1 Running 0 2m7s 10.244.58.221 k8s-node02 <none> <none> my-deployment-5cd68fd574-dkmc6 1/1 Running 0 2m7s 10.244.85.198 k8s-node01 <none> <none>
# hpa 需要接管控制器,目前没有接管任何控制器 [root@k8s-master01 12.5]# kubectl get hpa No resources found in default namespace. # hpa 控制器需要依托别的控制器之上进行管理,管理 deployment、管理的deployment 名称、cpu 使用百分比是 50%(一旦超过50%进行扩容)、最小 保留 2个(防止流量激增,1个 Pod 被访问压死)、最大保留 10个(防止因被攻击,无限扩容) [root@k8s-master01 12.5]# kubectl autoscale deployment my-deployment --cpu-percent=50 --min=2 --max=10 horizontalpodautoscaler.autoscaling/my-deployment autoscaled # hpa 名、管理 deployment 名、目前使用/设置目标扩容值、最小保留、最大保留、副本数、管理时间(hpa的回收很谨慎!) [root@k8s-master01 12.5]# kubectl get hpa NAME REFERENCE TARGETS MINPODS MAXPODS REPLICAS AGE my-deployment Deployment/my-deployment 0%/50% 2 10 3 2m28s # deployment 中定义的是 3 个,hpa 中定义最小值是 2 个,经过长时间没有流量访问,副本数下降,因为 hpa 是控制 deployment 的
[root@k8s-master01 12.5]# kubectl get hpa NAME REFERENCE TARGETS MINPODS MAXPODS REPLICAS AGE my-deployment Deployment/my-deployment 0%/50% 2 10 2 34m
(3)实验验证
[root@k8s-master01 12.5]# kubectl get pod --show-labels NAME READY STATUS RESTARTS AGE LABELS my-deployment-5cd68fd574-5hr4l 1/1 Running 0 17m app=myapp,pod-template-hash=5cd68fd574 my-deployment-5cd68fd574-cw2sj 1/1 Running 0 145m app=myapp,pod-template-hash=5cd68fd574 [root@k8s-master01 12.5]# kubectl create svc clusterip myapp --tcp=80:80 service/myapp created [root@k8s-master01 12.5]# kubectl get svc NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE kubernetes ClusterIP 10.0.0.1 <none> 443/TCP 34d myapp ClusterIP 10.5.168.161 <none> 80/TCP 17s [root@k8s-master01 12.5]# curl 10.5.168.161 OK!
# 新开一个终端,启动 Pod 作为客户端访问经过 hpa 管理的服务端,通过无限循环对服务端进行压测 [root@k8s-master01 ~]# kubectl run -i --tty work1 --image=busybox /bin/sh If you don't see a command prompt, try pressing enter. / # while true;do wget -q -O- http://myapp.default.svc.cluster.local;done
# 再开一个终端,同样无限循环压测 [root@k8s-master01 ~]# kubectl run -i --tty work2 --image=busybox /bin/sh If you don't see a command prompt, try pressing enter. / # while true;do wget -q -O- http://myapp.default.svc.cluster.local;done
# 当使用率超过设定值 50% 会自动扩容,当 pod 达到最大值 10 个,即使再超过设定值,也不会再扩容 [root@k8s-master01 12.5]# kubectl get hpa NAME REFERENCE TARGETS MINPODS MAXPODS REPLICAS AGE my-deployment Deployment/my-deployment 37%/50% 2 10 7 77m [root@k8s-master01 12.5]# kubectl get hpa NAME REFERENCE TARGETS MINPODS MAXPODS REPLICAS AGE my-deployment Deployment/my-deployment 71%/50% 2 10 7 79m [root@k8s-master01 12.5]# kubectl get hpa NAME REFERENCE TARGETS MINPODS MAXPODS REPLICAS AGE my-deployment Deployment/my-deployment 55%/50% 2 10 10 79m [root@k8s-master01 12.5]# kubectl get pod --show-labels NAME READY STATUS RESTARTS AGE LABELS my-deployment-5cd68fd574-5hr4l 1/1 Running 0 33m app=myapp,pod-template-hash=5cd68fd574 my-deployment-5cd68fd574-8qpvc 1/1 Running 0 3m38s app=myapp,pod-template-hash=5cd68fd574 my-deployment-5cd68fd574-cw2sj 1/1 Running 0 161m app=myapp,pod-template-hash=5cd68fd574 my-deployment-5cd68fd574-d4glb 1/1 Running 0 37s app=myapp,pod-template-hash=5cd68fd574 my-deployment-5cd68fd574-fpxx9 1/1 Running 0 3m53s app=myapp,pod-template-hash=5cd68fd574 my-deployment-5cd68fd574-kks52 1/1 Running 0 3m38s app=myapp,pod-template-hash=5cd68fd574 my-deployment-5cd68fd574-ncbm6 1/1 Running 0 3m38s app=myapp,pod-template-hash=5cd68fd574 my-deployment-5cd68fd574-sktxs 1/1 Running 0 37s app=myapp,pod-template-hash=5cd68fd574 my-deployment-5cd68fd574-tkwdm 1/1 Running 0 37s app=myapp,pod-template-hash=5cd68fd574 my-deployment-5cd68fd574-zmmgn 1/1 Running 0 3m53s app=myapp,pod-template-hash=5cd68fd574 work1 1/1 Running 0 5m57s run=work1 work2 1/1 Running 0 79s run=work2
# 将无限循环 while 停止后,没有流量访问,cpu 减少,经过一段时间,hpa 控制减少到最小保留个数 [root@k8s-master01 12.5]# kubectl get hpa NAME REFERENCE TARGETS MINPODS MAXPODS REPLICAS AGE my-deployment Deployment/my-deployment 0%/50% 2 10 2 94m [root@k8s-master01 12.5]# kubectl get pod --show-labels NAME READY STATUS RESTARTS AGE LABELS my-deployment-5cd68fd574-cw2sj 1/1 Running 0 176m app=myapp,pod-template-hash=5cd68fd574 my-deployment-5cd68fd574-fpxx9 1/1 Running 0 18m app=myapp,pod-template-hash=5cd68fd574
# 消除实验影响 [root@k8s-master01 12.5]# kubectl delete hpa,deployment,pod --all horizontalpodautoscaler.autoscaling "my-deployment" deleted deployment.apps "my-deployment" deleted pod "work1" deleted pod "work2" deleted
12.5.3 Pod QoS
(1)Qos 等级
BestEffort(优先级最低) (当抢资源时,最后分配)
Burstable (当抢资源时,其次分配)
Guaranteed(优先级最高)(当抢资源时,优先分配)
(2)BestEffort
会分配给那些没有为任何容器设置 requests 和 limits 的 Pod
最坏情况下,可能分配不到任何资源,同时,在需要为其它 Pod 释放资源时,这些容器会被第一批杀死
因为没有设置资源限制,所以资源在足够使用时,这些容器可以使用任意多的资源量级
(3)Burstable
Burstable QoS 等级基于 BestEffort 和 Guaranteed 之间,只要不归属于 BestEffort 和 Guaranteed 均归于此等级
(4)Guaranteed
会分配给那些有 request 和 limits 资源且相等的 Pod
如果容器资源 requests(软限制) 没有显示设置,默认与 limits(硬限制) 相同
(5)等级对比
注意:不同 Pod 间等级对比

BestEffort:Requests 和 Limits 都没有设置
Burstable:Requests 和 Limits 都设置了,但 Limits 比 Requests 设置的值更多
Guaranteed:Requests 和 Limits 都设置且设置的值相等
(6)单容器 Pod
| CPU requests VS limits | 内存 requests VS limits | 容器的 QoS 等级 |
| 未设置 | 未设置 | BestEffort |
| 未设置 | Requests < Limits | Burstable |
| 未设置 | Requests = Limits | Burstable |
| Requests < Limits | 未设置 | Burstable |
| Requests < Limits | Requests < Limits | Burstable |
| Requests < Limits | Requests = Limits | Burstable |
| Requests = Limits | Requests = Limits | Guaranteed |
BestEffort:CPU 、内存的 Requests 和 Limits 都没有设置
Burstable:CPU 、内存的 Requests 和 Limits 至少有一个设置了,或 Limits 比 Requests 设置的值不相等
Guaranteed:CPU 、内存的 Requests 和 Limits 都设置且设置的值相等
(7)多容器 Pod
| 容器1 的 QoS 等级 | 容器2 的 QoS 等级 | Pod 的 QoS 等级 |
| BestEffort | BestEffort | BestEffort |
| BestEffort | Burstable | Burstable |
| BestEffort | Guaranteed | Burstable |
| Burstable | Burstable | Burstable |
| Burstable | Guaranteed | Burstable |
| Guaranteed | Guaranteed | Guaranteed |
通过 单容器 Pod 知道 QoS 等级,低、中、优,低 x 低 = 低,优 x 优 =优,其余相乘都是中
(8)案例等级 释放资源顺序
注意:当以下 4 个 Pod 在同一服务器内,需要释放资源时,释放顺序

Pod1:定义了 Requests、Limit ,且两者相等,QoS 为 Guaranteed
Pod2:定义了 Requests、Limit ,但两者不相等,QoS 为 Burstable ,实际使用量 90%
Pod3:没有定义 Requests、Limit ,QoS 为 BestEffort
Pod4:定义了 Requests、Limit ,但两者不相等,QoS 为 Burstable ,实际使用量 70%
资源释放由等级低到高,先释放 BestEffort,再 Burstable ,最后 Guaranteed,当 Burstable 等级相同时,因为是服务器资源不够需要释放,实际使用量越多被认为资源消耗越严重,比相同 QoS 等级释放的更早
释放资源的顺序:Pod3 > Pod2 > Pod4 > Pod1
12.5.4 LimitRange(作用在 Pod)
(1)概念
通过创建一个 LimitRange 资源来避免必须配置每个容器的资源限制,LimitRange 资源不仅允许用户(为每个命名空间)指定能给容器配置的每种资源的最小和最大限额,还支持在没有显示指定资源 request 时为容器设置默认值
(2)实验验证
[root@k8s-master01 12.5]# cat 2.limit_range.yaml apiVersion: v1 kind: LimitRange metadata: name: example-limit-range spec: limits: - type: Pod max: cpu: "1" memory: 1Gi min: cpu: "200m" memory: 100Mi - type: Container max: cpu: "500m" memory: 512Mi min: cpu: "100m" memory: 64Mi defaultRequest: cpu: "200m" memory: 128Mi default: cpu: "300m" memory: 200Mi maxLimitRequestRatio: cpu: "2" memory: "4"
1.接口组版本:核心组 v1 版 2.类别:limitRange 类别 3.元数据:limitRange 名称 4.期望:最大限制:类型:Pod:最大值:cpu、内存、最小值:cpu、内存(定义 Pod 时,cpu、内存所在区间) 类型:容器:最大值:cpu、内存、最小值:cpu、内存(定义 容器 时,cpu、内存所在区间)、 容器默认初始值:cpu、内存(在容器下,当cpu 、内存未定义时采用默认值)、默认最大值:cpu、内存、最大值与初始值的比值:cpu 比值、内存比值
[root@k8s-master01 12.5]# kubectl apply -f 2.limit_range.yaml limitrange/example-limit-range created
[root@k8s-master01 12.5]# kubectl get limitranges
NAME CREATED AT
example-limit-range 2025-08-26T03:48:37Z
# 验证当 pod 中未定义资源使用情况时,会因为 limitRange 定义后默认添加,limit 和 requests 中 cpu 和 内存 被定义默认值 [root@k8s-master01 12.5]# cat 3.pod.yaml apiVersion: v1 kind: Pod metadata: name: resource-limited-default-pod spec: containers: - name: my-container image: myapp:v1.0 [root@k8s-master01 12.5]# kubectl apply -f 3.pod.yaml pod/resource-limited-default-pod created [root@k8s-master01 12.5]# kubectl get pod -o wide NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES resource-limited-default-pod 1/1 Running 0 7s 10.244.85.205 k8s-node01 <none> <none> [root@k8s-master01 12.5]# kubectl get pod resource-limited-default-pod -o yaml .......... spec: containers: - image: myapp:v1.0 imagePullPolicy: IfNotPresent name: my-container resources: limits: cpu: 300m memory: 200Mi requests: cpu: 200m memory: 128Mi ..........
# 超出默认限制会创建失败,cpu 的 最大值与初始值的比值 比设定的 2 大,比值为 2.5
[root@k8s-master01 12.5]# cat 4.out_limit.yaml apiVersion: v1 kind: Pod metadata: name: resource-limited-pod spec: containers: - name: my-container image: myapp:v1.0 resources: requests: cpu: "200m" memory: "128Mi" limits: cpu: "500m" memory: "256Mi" [root@k8s-master01 12.5]# kubectl apply -f 4.out_limit.yaml Error from server (Forbidden): error when creating "4.out_limit.yaml": pods "resource-limited-pod" is forbidden: cpu max limit to request ratio per Container is 2, but provided ratio is 2.500000
# 消除实验影响 [root@k8s-master01 12.5]# kubectl delete limitranges example-limit-range limitrange "example-limit-range" deleted [root@k8s-master01 12.5]# kubectl delete pod --all pod "resource-limited-default-pod" deleted
12.5.5 ResourceQuota(作用在 namespace)
注意:当特定资源配置了配额,在 pod 中必须为这些资源指定 request 和 limits ,否则 apiServer 不会接受创建 Pod 的请求,即使删除限制,也需要重新创建才能成功
(1)概念
LimitRange 只应用于单独的 Pod,而集群需要一种手段可以限制命名空间中的可用资源总量,这个就是 ResourceQuota
ResourceQuota 限制了一个命名空间中 pod 和 PVC 存储最多可以使用的资源总量,同时也可以限制用户允许在该命名空间中创建 pod、PVC 以及其它 API 对象的数量
(2)实验
[root@k8s-master01 12.5]# cat 5.resource_quota.yaml apiVersion: v1 kind: ResourceQuota metadata: name: test-resources-rq namespace: test spec: hard: requests.cpu: "20" requests.memory: 100Gi limits.cpu: "40" limits.memory: 200Gi pods: "1" configmaps: "10" persistentvolumeclaims: "4" replicationcontrollers: "20" secrets: "10" services: "10" services.loadbalancers: "2"
1.接口组版本:核心组 v1 版 2.类别:ResourceQuota 类别 3.元数据:ResourceQuota 名称、所在名称空间(限制的名称空间) 4.期望:固定资源:cpu初始值、内存初始值、cpu最大值、内存最大值、pod总量、configmap 总量、pvc 总量、RC 控制器总量、secrets 总量、svc 总量、svc 的 loadbalancers 总量
# 可以看到各类资源在名称空间下 创建的个数/可创建总个数 [root@k8s-master01 12.5]# kubectl apply -f 5.resource_quota.yaml resourcequota/test-resources-rq created [root@k8s-master01 12.5]# kubectl get resourcequotas -n test NAME AGE REQUEST LIMIT test-resources-rq 112s configmaps: 1/10, persistentvolumeclaims: 0/4, pods: 0/1, replicationcontrollers: 0/20, requests.cpu: 0/20, requests.memory: 0/100Gi, secrets: 0/10, services: 0/10, services.loadbalancers: 0/2 limits.cpu: 0/40, limits.memory: 0/200Gi # 没有定义 deployment 可创建个数,虽然显示创建了,但是没有成功 # 注意,如果在限制之前创建,不会因限制删除原资源,但是将无法增加 [root@k8s-master01 12.5]# kubectl create deployment myapp --image=myapp:v1.0 --replicas=3 -n test deployment.apps/myapp created [root@k8s-master01 12.5]# kubectl get deployment -n test NAME READY UP-TO-DATE AVAILABLE AGE myapp 0/3 0 0 70s [root@k8s-master01 12.5]# kubectl get pod -n test No resources found in test namespace.
# 消除实验影响 [root@k8s-master01 12.5]# kubectl delete resourcequotas,deployment --all -n test resourcequota "test-resources-rq" deleted deployment.apps "myapp" deleted
———————————————————————————————————————————————————————————————————————————
无敌小马爱学习
浙公网安备 33010602011771号