Quota and Limits学习参考资源配额限制范围为 Pod 和容器管理资源环境准备创建一个独立的名字空间quota并切换到该nsrootmaster30:~# kubectl create ns quotarootmaster30:~# kubectl config set-context --current --namespace quota提前部署好 Metric ServerResourceQuota**问题**当多个用户或团队共享Kubernetes集群时有人会使用超过其基于公平原则所分配到的资源量。**解决**可以使用资源配额限制 Namespace 使用的资源。资源配额通过ResourceQuota对象来定义对每个命名空间的资源消耗总量提供限制。资源配额的工作方式如下不同的团队在不同的命名空间下工作。这可以通过 RBAC 强制执行。集群管理员可以为每个命名空间创建一个或多个 ResourceQuota 对象。当用户在命名空间下创建资源如 Pod、Service 等时Kubernetes 的配额系统会跟踪集群的资源使用情况 以确保使用的资源用量不超过 ResourceQuota 中定义的硬性资源限额。如果资源创建或者更新请求违反了配额约束那么该请求会报错HTTP 403 FORBIDDEN 并在消息中给出有可能违反的约束。如果命名空间下的计算资源 如cpu和memory的配额被启用 则用户必须为这些资源设定请求值request和约束值limit否则配额系统将拒绝 Pod 的创建。提示: 可使用LimitRanger准入控制器来为没有设置计算资源需求的 Pod 设置默认值。启用资源配额Kubernetes 默认启用了资源配额功能 。 当 API 服务器 的命令行标志--enable-admission-plugins中包含ResourceQuota时 资源配额会被启用。当命名空间中存在一个ResourceQuota对象时对于该命名空间而言资源配额就是开启的。配额类型Kubernetes可以限制两种类型资源对象数量Kubernetes 资源数量例如podsservices等。实施资源数量配额可以提高kubernetes稳定性避免Etcd数据库无限增长还可以避免占用node中其他功能资源例如ip地址服务。计算资源物理或者虚拟资源容量例如 CPUmemory 和存储容量。实施计算资源配额可以避免消耗 kubernetes 集群中单个node所有计算资源避免单个namespace中应用消耗所有集群资源导致其他namespace中应用无法正常运行。**kubernetes 通过ResourceQuota类型资源实施配额。**一个namespace可以包含多个ResourceQuota对象这些限制是累加的一般情况多个ResourceQuota对象不会限定同一个资源。对象数量persistentvolumeclaimsservicessecretsconfigmapsreplicationcontrollersdeployments.appsreplicasets.appsstatefulsets.appsjobs.batchcronjobs.batch计算资源资源名称描述limits.cpu在所有处于非终止状态的 Pod 中CPU限制的总和不能超过此值。limits.memory在所有处于非终止状态的 Pod 中内存限制的总和不能超过这个值。requests.cpu在所有处于非终止状态的 Pod 中CPU请求的总和不能超过此值。requests.memory在所有处于非终止状态的 Pod 中内存请求的总和不能超过这个值。requests.storage在所有持久卷声明中存储请求的总和不能超过此值。cpu与requests.cpu一样memory与requests.memory一样单位说明CPU1 cpu等于1000 m默认单位是 cpu核心数量。memory支持两种格式。Ki | Mi | Gi | Ti | Pi | Ei进制是1024例如1024 1Kik | M | G | T | P | E进制是1000例如1000 1k默认单位是 G例如1.5代表1500M。配额管理重要说明如果项目级别配额限定了request和limit那么创建pod的时候必须指定request和limit。创建 ResourceQuota 对象rootmaster30:~# kubectl create quota myquota --hardpods2,services3,secrets5,persistentvolumeclaims10rootmaster30:~# kubectl get resourcequotasNAME AGE REQUEST LIMIT my-quota 10s persistentvolumeclaims:0/10, pods:0/2, secrets:1/5, services:0/3 rootmaster30:~# kubectl describe quota myquotaName: myquota Namespace:quotaResource Used Hard -------- ---- ---- persistentvolumeclaims010pods02secrets15services03通过 yaml 文件创建apiVersion:v1kind:ResourceQuotametadata:name:myquotaspec:hard:persistentvolumeclaims:10pods:2secrets:5services:3测试配额rootmaster30:~# kubectl create deployment web --imagenginx --replicas3rootmaster30:~# kubectl get allNAME READY STATUS RESTARTS AGE pod/web-96d5df5c8-dl7qk1/1 Running040s pod/web-96d5df5c8-j7fhh1/1 Running040s NAME READY UP-TO-DATE AVAILABLE AGE deployment.apps/web2/32240s NAME DESIRED CURRENT READY AGE replicaset.apps/web-96d5df5c832240s rootmaster30:~# kubectl describe rs web-96d5df5c8LAST SEEN TYPE REASON OBJECT MESSAGE......33s Warning FailedCreate replicaset/web-96d5df5c8 Error creating: podsweb-96d5df5c8-xg6c9is forbidden: exceeded quota: myquota, requested:pods1, used:pods2, limited:pods22s Warning FailedCreate replicaset/web-96d5df5c8(combined from similar events): Error creating: podsweb-96d5df5c8-89p7jis forbidden: exceeded quota: myquota, requested:pods1, used:pods2, limited:pods225s Normal SuccessfulCreate replicaset/web-96d5df5c8 Created pod: web-96d5df5c8-bkzmd 34s Normal ScalingReplicaSet deployment/web Scaled up replicasetweb-96d5df5c8 to3# 超过配额创建失败# 修改配额 pod数量为10rootmaster30:~# kubectl patch resourcequotas myquota -p {spec:{hard:{pods:10}}}# 此时重新扩展rsrootmaster30:~# kubectl scale rs web-96d5df5c8 --replicas 3# 再次验证pod数量rootmaster30:~# kubectl get podsNAME READY STATUS RESTARTS AGE pod/web-96d5df5c8-ajcz21/1 Running02s pod/web-96d5df5c8-dl7qk1/1 Running060s pod/web-96d5df5c8-j7fhh1/1 Running060s# 清理环境rootmaster30:~# kubectl delete deployments.apps webrootmaster30:~# kubectl delete resourcequotas myquota思考如果一个用户可以管理多个 namespace能否限定该用户配额呢Request 和 Limits如果命名空间下的计算资源 如cpu和memory的配额被启用 则用户必须为这些资源设定请求值request和约束值limit否则配额系统将拒绝 Pod 的创建。pod.containers.resources定义包含两部分requests指明pod运行需要的最少计算资源调度器查找具有充足计算资源的nodes。limits指明pod运行可以获得节点最多计算资源用于阻止pod占用node太多计算资源。node使用Linux内核功能cgroup限制pod资源使用。测试-不指定计算资源配额示例rootmaster30:~# vim resourcequota.yamlapiVersion:v1kind:ResourceQuotametadata:name:myquotaspec:hard:persistentvolumeclaims:10pods:2secrets:5services:3requests.cpu:1000mrequests.memory:2048Milimits.cpu:1000mlimits.memory:2048Mirootmaster30:~# kubectl apply -f resourcequota.yamlpod 示例rootmaster30:~# vim pod-without-quota.yamlapiVersion:v1kind:Podmetadata:name:weblabels:app:webspec:containers:-name:webimage:httpdimagePullPolicy:IfNotPresentports:-name:webcontainerPort:80protocol:TCProotmaster30:~# kubectl apply -f pod-without-quota.yamlError from server(Forbidden): error when creatingpod-without-quota.yaml:podswebis forbidden: failed quota: myquota: must specify limits.cpu for: web;limits.memory for: web;requests.cpu for: web;requests.memory for: web# 清理环境rootmaster30:~# kubectl delete resourcequotas myquota测试-Request配额示例rootmaster30:~# vim resourcequota.yamlapiVersion:v1kind:ResourceQuotametadata:name:myquotaspec:hard:requests.cpu:1000mrequests.memory:2048Mirootmaster30:~# kubectl apply -f resourcequota.yamlpod 示例1超上限rootmaster30:~# vim pod-request-1.yamlapiVersion:v1kind:Podmetadata:name:weblabels:app:webspec:containers:-name:webimage:httpdimagePullPolicy:IfNotPresentresources:requests:cpu:2000mmemory:4096Miports:-name:webcontainerPort:80protocol:TCProotmaster30:~# kubectl apply -f pod-request-1.yamlError from server(Forbidden): error when creatingpod-request-1.yaml:podswebis forbidden: exceeded quota: myquota, requested:requests.cpu2,requests.memory4Gi, used:requests.cpu0,requests.memory0, limited:requests.cpu1,requests.memory2Gipod 示例2未超上限rootmaster30:~# vim pod-request-2.yamlapiVersion:v1kind:Podmetadata:name:weblabels:app:webspec:containers:-name:webimage:httpdimagePullPolicy:IfNotPresentresources:requests:cpu:200mmemory:1024Miports:-name:webcontainerPort:80protocol:TCProotmaster30 ~# kubectl apply -f pod-request-2.yamlrootmaster30:~# kubectl get podNAME READY STATUS RESTARTS AGE web1/1 Running043s# 验证使用情况rootmaster30:~# kubectl describe resourcequotas myquotaName: myquota Namespace:quotaResource Used Hard -------- ---- ---- requests.cpu 200m1requests.memory 1Gi 2Gi# 删除pod和quotarootmaster30:~# kubectl delete pod webrootmaster30:~# kubectl delete resourcequotas myquota测试-Limits压力测试镜像可以直接使用镜像 hub.gsb.cloud/progrium/stress 进行压力测试该镜像中运行stress命令。找讲师索取镜像。Usage: stress[OPTION[ARG]]... -?,--helpshow thishelpstatement--versionshow version statement -v,--verbosebe verbose -q,--quietbe quiet -n, --dry-run show what would have beendone-t,--timeoutNtimeoutafter N seconds--backoffNwaitfactor of N microseconds before work starts -c,--cpuN spawn N workers spinning on sqrt()-i,--ioN spawn N workers spinning on sync()-m,--vmN spawn N workers spinning on malloc()/free()--vm-bytes B malloc B bytes per vm worker(default is 256MB)--vm-stride Btoucha byte every B bytes(default is4096)--vm-hang NsleepN secs beforefree(default none,0is inf)--vm-keep redirty memory instead of freeing and reallocating -d,--hddN spawn N workers spinning on write()/unlink()--hdd-bytes BwriteB bytes per hdd worker(default is 1GB)Example: stress--cpu8--io4--vm2--vm-bytes 128M--timeout10s Note: Numbers may be suffixed with s,m,h,d,y(time)or B,K,M,G(size).常用选项-c, --cpu N spawn N workers spinning on sqrt()-m, --vm N spawn N workers spinning on malloc()/free() --vm-bytes B malloc B bytes per vm worker (default is 256MB)-d, --hdd N spawn N workers spinning on write()/unlink()–hdd-bytes B write B bytes per hdd worker (default is 1GB)示例# 压力测试内存$dockerrun--namestress hub.gsb.cloud/progrium/stress-m1--vm-bytes 512M# 压力测试CPU$dockerrun--namestress hub.gsb.cloud/progrium/stress-c1# 压力测试IO$dockerrun--namestress hub.gsb.cloud/progrium/stress –d1--hdd-bytes 3G对于 podapiVersion:v1kind:Podmetadata:name:stressspec:containers:-name:stressimage:hub.gsb.cloud/progrium/stressimagePullPolicy:IfNotPresentcommand:[sh,-c,sleep 3600]# 或者不用command而是使用args作为参数传递给镜像的Entrypoint。#args: [-m,1,--vm-bytes,512M]#args: [-c,1]#args: [-d,1,--hdd-bytes,3G]配额示例rootmaster30:~# vim resourcequota.yamlapiVersion:v1kind:ResourceQuotametadata:name:myquotaspec:hard:limits.cpu:1000mlimits.memory:2048Mirootmaster30:~# kubectl apply -f resourcequota.yaml测试 CPU 资源pod示例rootmaster30:~# vim pod-limit-cpu.yamlapiVersion:v1kind:Podmetadata:name:stressspec:containers:-name:stressimage:hub.gsb.cloud/progrium/stressimagePullPolicy:IfNotPresentargs:[-c,1]resources:limits:cpu:200mmemory:256Mirootmaster30:~# kubectl apply -f pod-limit-cpu.yaml打开一个终端监控kubectl top 命令需要提前部署Metrics-Serverrootmaster30:~# kubectl top podsNAME CPU(cores)MEMORY(bytes)stress 201m 0Mi**可以发现**CPU 使用率维持在 200m 左右。# 删除 podrootmaster30:~# kubectl delete pod stress --force测试 MEMORY 资源pod示例rootmaster30:~# vim pod-limit-memory.yamlapiVersion:v1kind:Podmetadata:name:stressspec:containers:-name:stressimage:hub.gsb.cloud/progrium/stressimagePullPolicy:IfNotPresentargs:[-m,1,--vm-bytes,512M]resources:limits:cpu:200mmemory:256Mirootmaster30:~# kubectl apply -f pod-limit-memory.yaml打开一个终端监控rootmaster30:~# kubectl get pods -wNAME READY STATUS RESTARTS AGE stress0/1 OOMKilled1(2s ago)3s stress0/1 CrashLoopBackOff1(2s ago)4s可以发现Pod 状态为 OOMKilled并进行restart。# 删除 pod herootmaster30:~# kubectl delete pod stress --forcerootmaster30:~# kubectl delete resourcequotas myquota总结计算资源的 limits 总和是否会超过节点上资源总和答案可能会。假设 node可用MEMORY为1G。每个pod内存 requests是256Mlimit是512M。创建5个podpod实际占用内存也为256M有可能小于256M。node上大概可以创建4个pod而此时的limits总和是2G。当计算资源的limits总和超过节点上资源总和时kubernetes如何处理对于 cpukubernetes 认为cpu 是可被压缩的资源在应用达到limits时减少该容器的调度时间并不会杀死应用。对于 memorykubernetes 认为memory 是无法被压缩的资源此时k8s会杀死占用资源超过其request的应用1.9版本之后的版本。首当其冲的是没有指定request的container然后是使用资源超过其request更多的container。同等情况下优先级更低的container更容易被杀死。