date: 2020-08-17title: k8s之名称空间资源限制 #标题
tags: k8s资源限制 #标签
categories: k8s # 分类

默认情况下,容器在 K8s 集群上运行时,不受计算资源的限制。使用 Resource quota,可以针对名称空间限定资源的使用情况。在名称空间内部,一个 Pod(或容器)的资源消耗不受限制。此时的顾虑在于,可能有一个 Pod(或容器)独占了名称空间的大部分资源。Limit Range 是一种用来限定名称空间内 Pod(或容器)可以消耗资源数量的策略(Policy)。

名称空间可以限制的对象

k8s limitrange对象可以:

  • 限制名称空间中每个 Pod 或容器的最小最大计算资源
  • 限制名称空间中每个 PVC 可使用的最小最大存储空间
  • 限制名称空间中计算资源请求request、限定limit之间的比例
  • 设置名称空间中默认的计算资源的 request/limit,并在运行时自动注入到容器中

启用limit range

  1. $ kubectl api-resources | grep limitranges
  2. limitranges limits true LimitRange
  3. # 以上字段为 true,则表示启用
  4. # 通常默认是启用的

配置limit range

limit range基本介绍

  • 集群管理员在名称空间中创建一个limitrange对象。
  • 用户在名称空间中创建工作负载等对象,例如Pod、Container、PVC等。
  • 针对那些没有设置计算资源请求request和限制limit 的 Pod 和容器,LimitRanger 根据名称空间中的 LimitRange 对象为其设定默认的资源请求和响应,并确保 Pod 和容器对计算资源的实际消耗不会超过指定的值
  • 如果创建或更新对象(Pod、Container、PersistentVolumeClaim)的请求与 Limit Range 的限定相冲突,apiserver 将返回 HTTP status 状态码 403 FORBIDDEN,以及相应的错误提示信息
  • 如果名称空间中激活了 limit range 来限定 cpu 和内存等计算资源的使用,则,用户创建 Pod、Container 时,必须指定 cpu 或内存的 request 和 limit,否则系统将拒绝创建 Pod
  • Kubernetes 只在 Pod 创建阶段检查 LimitRange 的限定,而不在 Pod 运行时执行任何检查

limitrange使用场景:

  • 在一个总容量为 8G内存 16核CPU 的 2 节点集群上,限定某个名称空间中的 Pod 使用 100m的CPU请求(request)且不超过 500m的CPU上限(limit),200Mi的内存请求(request)且不超过 600Mi的内存上线(limit)
  • 为没有定义cpu和内存请求的容器,指定默认的 CPU 请求(request)和限制(limit)均为 150m,默认的内存请求为 300Mi

当名称空间总的 limit 小于名称空间中 Pod/Container 的 limit 之和时,将发生资源争夺的现象,容器或者 Pod 将不能创建。

在资源争夺现象发生时,或者修改 limitrange 的时候,这两种情况都不会影响到已经创建的 Pod/Container。

限定容器的计算资源

假设有一个 Pod 包含 4个容器,每个容器都定义了 spec.resource,此时 LimitRanger 管理控制器在处理该 Pod 中的 4个容器时,处理方式是不一样的。

创建limitrange资源对象

  1. # 创建一个名称空间
  2. $ kubectl create namespace limitrange-demo
  3. # 切换至此名称空间
  4. $ kubectl config set-context --current --namespace=limitrange-demo
  5. # limitrange对象的yaml文件如下所示:
  6. $ cat limitrange.yaml
  7. apiVersion: v1
  8. kind: LimitRange
  9. metadata:
  10. name: limit-mem-cpu-per-container
  11. spec:
  12. limits:
  13. - max:
  14. cpu: "800m"
  15. memory: "1Gi"
  16. min:
  17. cpu: "100m"
  18. memory: "99Mi"
  19. default:
  20. cpu: "700m"
  21. memory: "900Mi"
  22. defaultRequest:
  23. cpu: "110m"
  24. memory: "111Mi"
  25. type: Container
  26. # 上述yaml文件定义的内容如下:
  27. # 最大和最小的CPU/内存
  28. # 默认的 CPU/内存限定
  29. # 默认的 CPU/内存请求
  30. $ kubectl apply -f limitrange.yaml # 创建此对象
  31. # 查看此对象的详细信息
  32. $ kubectl describe limitrange/limit-mem-cpu-per-container -n limitrange-demo

查看此对象的详细信息返回结果如下:

k8s之名称空间资源限制 - 图1

创建包含4个容器的pod

  1. $ cat lr-container-pod.yaml # yaml文件如下
  2. apiVersion: v1
  3. kind: Pod
  4. metadata:
  5. name: busybox1
  6. spec:
  7. containers:
  8. - name: busybox-cnt01
  9. image: busybox
  10. command: ["/bin/sh"]
  11. args: ["-c", "while true; do echo hello from cnt01; sleep 10;done"]
  12. resources:
  13. requests:
  14. memory: "100Mi"
  15. cpu: "100m"
  16. limits:
  17. memory: "200Mi"
  18. cpu: "500m"
  19. - name: busybox-cnt02
  20. image: busybox
  21. command: ["/bin/sh"]
  22. args: ["-c", "while true; do echo hello from cnt02; sleep 10;done"]
  23. resources:
  24. requests:
  25. memory: "100Mi"
  26. cpu: "100m"
  27. - name: busybox-cnt03
  28. image: busybox
  29. command: ["/bin/sh"]
  30. args: ["-c", "while true; do echo hello from cnt03; sleep 10;done"]
  31. resources:
  32. limits:
  33. memory: "200Mi"
  34. cpu: "500m"
  35. - name: busybox-cnt04
  36. image: busybox
  37. command: ["/bin/sh"]
  38. args: ["-c", "while true; do echo hello from cnt04; sleep 10;done"]
  39. $ kubectl apply -f lr-container-pod.yaml # 创建pod

查看容器包含有效的 CPU/内存的requests/limits

  1. # 执行以下命令,查看 busybox-cnt01 的配置信息
  2. # 如果提示没有jq命令,则直接 yum -y install jq 即可
  3. $ kubectl get po/busybox1 -n limitrange-demo -o json | jq ".spec.containers[0].resources"
  4. {
  5. "limits": {
  6. "cpu": "500m",
  7. "memory": "200Mi"
  8. },
  9. "requests": {
  10. "cpu": "100m",
  11. "memory": "100Mi"
  12. }
  13. }
  • busybox Pod 中的容器 busybox-cnt01 定义了 requests.cpu=100m 和 requests.memory=100Mi
  • 100m <= 500m <= 800m 容器的 cpu limit(500m)在名称空间 LimitRange 指定的范围内
  • 99Mi <= 200Mi <= 1Gi 容器的内存 limit(200Mi)在名称空间 LimitRange 指定的范围内
  • 没有为CPU/内存指定 request/limit 比例
  • 此时容器的定义是有效的,将被创建

容器包含有效的 CPU/内存requests且没有指定limits

  1. $ kubectl get po/busybox1 -n limitrange-demo -o json | jq ".spec.containers[1].resources"
  2. {
  3. "limits": {
  4. "cpu": "700m",
  5. "memory": "900Mi"
  6. },
  7. "requests": {
  8. "cpu": "100m",
  9. "memory": "100Mi"
  10. }
  11. }
  • busybox Pod 中的容器 busybox-cnt02 定义了 requests.cpu=100m 和 requests.memory=100Mi,且未指定 CPU/内存的最大限定
  • 由于容器没有定义 limits,则名称空间的 LimitRange 定义的 limits.cpu=700mi 和 limits.memory=900Mi 被注入到该容器
  • 100m <= 700m <= 800m 容器的CPU最大限定(700m)在名称空间 LimitRange 指定的范围内
  • 99Mi <= 900Mi <= 1Gi 容器的内存 limit(900Mi)在名称空间 LimitRange 指定的范围内
  • 没有为CPU/内存指定 request/limit 比例
  • 此时容器的定义是有效的,将被创建

容器包含有效的CPU/内存limits且没有指定requests

  1. $ kubectl get po/busybox1 -n limitrange-demo -o json | jq ".spec.containers[2].resources"
  2. {
  3. "limits": {
  4. "cpu": "500m",
  5. "memory": "200Mi"
  6. },
  7. "requests": {
  8. "cpu": "500m",
  9. "memory": "200Mi"
  10. }
  11. }
  • busybox Pod 中的容器 busybox-cnt03 定义了 limits.cpu=500m 和 limits.memory=200Mi,且没有指定 CPU/内存的 requests
  • 由于容器没有定义 requests,名称空间中 LimitRange 定义的 defaultRequest 并没有注入到容器的 request 字段,反而,容器定义的 limits 被设置到了其 requests 字段: limits.cpu=500m 和 limits.memory=200Mi
  • 100m <= 500m <= 800m 容器的 cpu 最大限定(500m)在名称空间 LimitRange 指定的范围内
  • 99Mi <= 200Mi <= 1Gi 容器的内存最大限定(200Mi)在名称空间 LimitRange 指定的范围内
  • 没有为CPU/内存指定 request/limit 比例
  • 此时容器的定义是有效的,将被创建

容器不包含CPU/内存的requests/limits

  1. $ kubectl get po/busybox1 -n limitrange-demo -o json | jq ".spec.containers[3].resources"
  2. {
  3. "limits": {
  4. "cpu": "700m",
  5. "memory": "900Mi"
  6. },
  7. "requests": {
  8. "cpu": "110m",
  9. "memory": "111Mi"
  10. }
  11. }
  • busybox Pod 中的容器 busybox-cnt04 既没有定义 request,也没有定义 limits
  • 由于容器没有定义 limits,则名称空间的 LimitRange 定义的 limits.cpu=700mi 和 limits.memory=900Mi 被注入到该容器
  • 由于容器没有定义 requests,则名称空间的 LimitRange 定义的 requests.cpu=110m 和 requests.memory=110Mi 被注入到该容器
  • 100m <= 700m <= 800m 容器的 cpu 最大限定(700m)在名称空间 LimitRange 指定的范围内
  • 99Mi <= 900Mi <= 1Gi 容器的内存 limit(900Mi)在名称空间 LimitRange 指定的范围内
  • 没有为CPU/内存指定 request/limit 比例
  • 此时容器的定义是有效的,将被创建

限制pod的计算资源

参考:kuboard官网

限制存储资源

通过 LimitRange 对象,可以限定名称空间中每个 PVC(存储卷声明)可以使用的最小、最大存储空间。

创建limitrange

  1. $ cat lr-storage-limit.yaml # yaml文件如下
  2. apiVersion: v1
  3. kind: LimitRange
  4. metadata:
  5. name: storagelimits
  6. spec:
  7. limits:
  8. - type: PersistentVolumeClaim
  9. max:
  10. storage: 2Gi
  11. min:
  12. storage: 1Gi
  13. $ kubectl apply -f lr-storage-limit.yaml # 确认
  14. $ kubectl describe limits/storagelimits # 查看详细信息
  15. Name: storagelimits
  16. Namespace: default
  17. Type Resource Min Max Default Request Default Limit Max Limit/Request Ratio
  18. ---- -------- --- --- --------------- ------------- -----------------------
  19. PersistentVolumeClaim storage 1Gi 2Gi - - -

假设现在有一个PVC(存储卷声明),定义文件如下所示:

  1. cat > pvc.yaml << EOF
  2. apiVersion: v1
  3. kind: PersistentVolumeClaim
  4. metadata:
  5. name: pvc-limit-lower
  6. spec:
  7. accessModes:
  8. - ReadWriteOnce
  9. resources:
  10. requests:
  11. storage: 500Mi
  12. EOF
  13. $ kubectl apply -f pvc.yaml # 创建此yaml文件
  14. Error from server (Forbidden): error when creating "pvc.yaml": persistentvolumeclaims "pvc-limit-lower" is forbidden: minimum storage usage per PersistentVolumeClaim is 1Gi, but request is 500Mi

由于 PVC 中定义的字段 requests.storage 比 LimitRange storagelimits 中 limits[0].min.storage 的定义要小,所以创建该 PVC 时将失败。

如果 PVC 的 requests.storage 大于 LimitRange 中的 limits[0].max.storage,同样不能创建成功。

限定limit/request比例

这里记录了如何使用 LimitRange 在名称空间中限制 Limits/Requests 的比例。如果指定了 LimitRange 对象的 spec.limits.maxLimitRequestRatio 字段,名称空间中的 Pod/容器的 request 和 limit 都不能为 0,且 limit 除以 request 的结果必须小于或等于 LimitRange 的 spec.limits.maxLimitRequestRatio

下面的例子中 LimitRange 限定了名称空间中任何 Pod 的最大内存限定(limit)不能超过最小内存请求(request)的两倍:

  1. $ cat limit-memory-ratio-pod.yaml # 查看yaml文件如下
  2. apiVersion: v1
  3. kind: LimitRange
  4. metadata:
  5. name: limit-memory-ratio-pod
  6. spec:
  7. limits:
  8. - maxLimitRequestRatio:
  9. memory: 2
  10. type: Pod
  11. $ kubectl apply -f limit-memory-ratio-pod.yaml # 创建
  12. $ kubectl describe limitrange/limit-memory-ratio-pod # 查看详细信息
  13. Name: limit-memory-ratio-pod
  14. Namespace: default
  15. Type Resource Min Max Default Request Default Limit Max Limit/Request Ratio
  16. ---- -------- --- --- --------------- ------------- -----------------------
  17. Pod memory - - - - 2

创建一个pod,包含如下属性 requests.memory=100Mi 和 limits.memory=300Mi:

  1. $ cat busybox3.yaml
  2. apiVersion: v1
  3. kind: Pod
  4. metadata:
  5. name: busybox3
  6. spec:
  7. containers:
  8. - name: busybox-cnt01
  9. image: busybox
  10. resources:
  11. limits:
  12. memory: "300Mi"
  13. requests:
  14. memory: "100Mi"
  15. $ kubectl apply -f busybox3.yaml # 创建此pod
  16. Error from server (Forbidden): error when creating "busybox3.yaml": pods "busybox3" is forbidden: memory max limit to request ratio per Pod is 2, but provided ratio is 3.000000

如上所示,由于该 Pod 的内存限制请求比例为 3,超过了 LimitRange 中定义的 2,该 Pod 将不能创建成功。