文章转载自:https://www.kuboard.cn/learning/k8s-advanced/policy/lr.html
默认情况下,容器在 Kubernetes 集群上运行时,不受 计算资源 的限制。使用 Resource quota,集群管理员可以针对名称空间限定资源的使用情况。在名称空间内部,一个 Pod(或容器)的资源消耗不受限制。此时的顾虑在于,可能有一个 Pod(或容器)独占了名称空间的大部分资源。Limit Range 是一种用来限定名称空间内 Pod(或容器)可以消耗资源数量的策略(Policy)。
Kubernetes LimitRange 对象可以:
- 限制名称空间中每个 Pod 或容器的最小最大计算资源
- 限制名称空间中每个 PersistentVolumeClaim 可使用的最小最大存储空间
- 限制名称空间中计算资源请求request、限定limit之间的比例
- 设置名称空间中默认的计算资源的 request/limit,并在运行时自动注入到容器中
启用 Limit Range
执行命令 kubectl api-resources 可查看您的集群是否支持 Limit Range,输出结果如下所示,通常 LimitRange 是默认启用的。
NAME SHORTNAMES APIGROUP NAMESPACED KIND
bindings true Binding
componentstatuses cs false ComponentStatus
configmaps cm true ConfigMap
endpoints ep true Endpoints
events ev true Event
limitranges limits true LimitRange
namespaces ns false Namespace
nodes no false Node
persistentvolumeclaims pvc true PersistentVolumeClaim
persistentvolumes pv false PersistentVolume
pods po true Pod
podtemplates true PodTemplate
基本介绍
- 集群管理员在名称空间中创建一个 LimitRange 对象
- 用户在名称空间中创建工作负载等对象,例如 Pod、Container、PersistentVolumeClaim 等
- 针对那些没有设置 计算资源请求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 对象激活后,再创建Pod、Container、PersistentVolumeClaim,必须指定 cpu 或内存的 request 和 limit,否则系统将拒绝创建 Pod
先创建的Pod、Container、PersistentVolumeClaim,然后再创建激活LimitRange 对象。没有设置 计算资源请求request和限制limit 的 Pod 和容器,LimitRanger 根据名称空间中的 LimitRange 对象为其设定默认的资源请求和响应
使用 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 将不能创建。
在资源争夺现象发生时,或者修改 limit range 的时候,这两种情况都不会影响到已经创建的 Pod/Container。
限定容器的计算资源
假设有一个 Pod 包含 4个容器,每个容器都定义了 spec.resource,此时 LimitRanger 管理控制器在处理该 Pod 中的 4个容器时,处理方式是不一样的。
演示步骤如下:
1.执行如下命令创建名称空间 limitrange-demo
kubectl create namespace limitrange-demo
将 kubectl 默认名称空间切换至 limitrange-demo
kubectl config set-context --current --namespace=limitrange-demo
2.LimitRange 对象的 yaml 文件如下所示:
apiVersion: v1
kind: LimitRange
metadata:
name: limit-mem-cpu-per-container
spec:
limits:
- max:
cpu: "800m"
memory: "1Gi"
min:
cpu: "100m"
memory: "99Mi"
default:
cpu: "700m"
memory: "900Mi"
defaultRequest:
cpu: "110m"
memory: "111Mi"
type: Container
该对象为名称空间中的容器定义了:
- 最大和最小的CPU/内存
- 默认的 CPU/内存限定
- 默认的 CPU/内存请求
执行命令以创建该对象:
kubectl create -f https://kuboard.cn/statics/learning/policy/lr-container-limit-range.yaml -n limitrange-demo
执行命令查看结果
kubectl describe limitrange/limit-mem-cpu-per-container -n limitrange-demo
Type Resource Min Max Default Request Default Limit Max Limit/Request Ratio
---- -------- --- --- --------------- ------------- -----------------------
Container cpu 100m 800m 110m 700m -
Container memory 99Mi 1Gi 111Mi 900Mi -
3.前面提到的包含 4 个容器的 Pod,其 yaml 文件如下所示:
apiVersion: v1
kind: Pod
metadata:
name: busybox1
spec:
containers:
- name: busybox-cnt01
image: busybox
command: ["/bin/sh"]
args: ["-c", "while true; do echo hello from cnt01; sleep 10;done"]
resources:
requests:
memory: "100Mi"
cpu: "100m"
limits:
memory: "200Mi"
cpu: "500m"
- name: busybox-cnt02
image: busybox
command: ["/bin/sh"]
args: ["-c", "while true; do echo hello from cnt02; sleep 10;done"]
resources:
requests:
memory: "100Mi"
cpu: "100m"
- name: busybox-cnt03
image: busybox
command: ["/bin/sh"]
args: ["-c", "while true; do echo hello from cnt03; sleep 10;done"]
resources:
limits:
memory: "200Mi"
cpu: "500m"
- name: busybox-cnt04
image: busybox
command: ["/bin/sh"]
args: ["-c", "while true; do echo hello from cnt04; sleep 10;done"]
执行命令以创建该 Pod
kubectl apply -f https://kuboard.cn/statics/learning/policy/lr-container-pod.yaml
容器包含有效的 CPU/内存的requests/limits
执行以下命令,查看 busybox-cnt01 的配置信息
kubectl get po/busybox1 -n limitrange-demo -o json | jq ".spec.containers[0].resources"
{
"limits": {
"cpu": "500m",
"memory": "200Mi"
},
"requests": {
"cpu": "100m",
"memory": "100Mi"
}
}
- 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
执行以下命令,查看 busybox-cnt02 的配置信息
kubectl get po/busybox1 -n limitrange-demo -o json | jq ".spec.containers[1].resources"
{
"limits": {
"cpu": "700m",
"memory": "900Mi"
},
"requests": {
"cpu": "100m",
"memory": "100Mi"
}
}
- 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
执行以下命令,查看 busybox-cnt03 的配置信息
kubectl get po/busybox1 -n limitrange-demo -o json | jq ".spec.containers[2].resources"
{
"limits": {
"cpu": "500m",
"memory": "200Mi"
},
"requests": {
"cpu": "500m",
"memory": "200Mi"
}
}
- 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
执行以下命令,查看 busybox-cnt04 的配置信息
kubectl get po/busybox1 -n limitrange-demo -o json | jq ".spec.containers[3].resources"
{
"limits": {
"cpu": "700m",
"memory": "900Mi"
},
"requests": {
"cpu": "110m",
"memory": "111Mi"
}
}
- 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 busybox 中所有的容器都通过了名称空间的 LimitRange 检查,此 Pod 将被创建
限定Pod的计算资源
下面是一个用于限定 Pod 资源使用的 LimitRange 对象。
apiVersion: v1
kind: LimitRange
metadata:
name: limit-mem-cpu-per-pod
spec:
limits:
- max:
cpu: "2"
memory: "2Gi"
type: Pod
在开始之前先完成 限定容器 的计算资源,并确保该教程中的 LimitRange limit-mem-cpu-per-container 和 Pod busybox1 都已经创建。
1.执行如下命令,创建 limit-mem-cpu-pod 上面 yaml 中的 LimitRange,该 LimitRange 限定了每一个 Pod 的CPU使用不超过 2 核,内存不超过 2Gi。
kubectl apply -f https://kuboard.cn/statics/learning/policy/lr-pod-limit-range.yaml -n limitrange-demo
执行命令查看 limit-mem-cpu-per-pod 的创建结果:
kubectl describe limitrange/limit-mem-cpu-per-pod -n limitrange-demo
Name: limit-mem-cpu-per-pod
Namespace: limitrange-demo
Type Resource Min Max Default Request Default Limit Max Limit/Request Ratio
---- -------- --- --- --------------- ------------- -----------------------
Pod cpu - 2 - - -
Pod memory - 2Gi - - -
2.创建第二个 Pod,yaml 文件如下:
apiVersion: v1
kind: Pod
metadata:
name: busybox2
spec:
containers:
- name: busybox-cnt01
image: busybox
command: ["/bin/sh"]
args: ["-c", "while true; do echo hello from cnt01; sleep 10;done"]
resources:
requests:
memory: "100Mi"
cpu: "100m"
limits:
memory: "200Mi"
cpu: "500m"
- name: busybox-cnt02
image: busybox
command: ["/bin/sh"]
args: ["-c", "while true; do echo hello from cnt02; sleep 10;done"]
resources:
requests:
memory: "100Mi"
cpu: "100m"
- name: busybox-cnt03
image: busybox
command: ["/bin/sh"]
args: ["-c", "while true; do echo hello from cnt03; sleep 10;done"]
resources:
limits:
memory: "200Mi"
cpu: "500m"
- name: busybox-cnt04
image: busybox
command: ["/bin/sh"]
args: ["-c", "while true; do echo hello from cnt04; sleep 10;done"]
执行如下命令可创建该 Pod
kubectl apply -f https://kuboard.cn/statics/learning/policy/lr-pod-pod.yaml -n limitrange-demo
Pod busybox2 的定义与 busybox1 的定义完全相同,但是执行该创建命令时将碰到如下错误,因为Pod可使用的资源现在受到了限制:
Error from server (Forbidden): error when creating "limit-range-pod-2.yaml": pods "busybox2" is forbidden: [maximum cpu usage per Pod is 2, but limit is 2400m., maximum memory usage per Pod is 2Gi, but limit is 2306867200.]
执行命令查看 busybox1 的资源使用
kubectl get po/busybox1 -n limitrange-demo -o json | jq ".spec.containers[].resources.limits.memory"
"200Mi"
"900Mi"
"200Mi"
"900Mi"
Pod busybox2 将不能在集群中创建,因为其中所有容器的内存限制的总和超过了 LimitRange limit-mem-cpu-per-pod 中的限定。 busybox1 将不会被驱逐,因为该 Pod 在创建 LimitRange limit-mem-cpu-per-pod 就已经创建好了。
限定存储资源
通过 LimitRange 对象,集群管理员可以限定名称空间中每个 PersistentVolumeClaim(存储卷声明)可以使用的最小、最大存储空间。
请参考下面的例子:
apiVersion: v1
kind: LimitRange
metadata:
name: storagelimits
spec:
limits:
- type: PersistentVolumeClaim
max:
storage: 2Gi
min:
storage: 1Gi
执行命令可创建该 LimitRange:
kubectl create -f https://kuboard.cn/statics/learning/policy/lr-storage-limit.yaml -n limitrange-demo
kubectl describe limits/storagelimits -n limitrange-demo
Name: storagelimits
Namespace: limitrange-demo
Type Resource Min Max Default Request Default Limit Max Limit/Request Ratio
---- -------- --- --- --------------- ------------- -----------------------
PersistentVolumeClaim storage 1Gi 2Gi - - -
现在假设有一个 PVC(存储卷声明),定义文件如下所示:
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: pvc-limit-lower
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 500Mi
执行命令创建该 PVC(存储卷声明)
kubectl create -f https://kuboard.cn/statics/learning/policy/lr-storage-pvc-lower.yaml -n limitrange-demo
由于 PVC 中定义的字段 requests.storage 比 LimitRange storagelimits 中 limits[0].min.storage 的定义要小,所以创建该 PVC 时将失败:
Error from server (Forbidden): error when creating "lr-storage-pvc-lower.yaml": persistentvolumeclaims "pvc-limit-lower" is forbidden: minimum storage usage per PersistentVolumeClaim is 1Gi, but request is 500Mi.
如果 PVC 的 requests.storage 大于 LimitRange 中的 limits[0].max.storage,同样不能创建成功,参考下面的例子:
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: pvc-limit-greater
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 5Gi
执行命令创建该 PVC(存储卷声明)
kubectl create -f https://kuboard.cn/statics/learning/policy/lr-storage-pvc-greater.yaml
Error from server (Forbidden): error when creating "lr-storage-pvc-greater.yaml": persistentvolumeclaims "pvc-limit-greater" is forbidden: maximum storage usage per PersistentVolumeClaim is 2Gi, but request is 5Gi.
限定 Limit/Request 比例
如果指定了 LimitRange 对象的 spec.limits.maxLimitRequestRatio 字段,名称空间中的 Pod/容器的 request 和 limit 都不能为 0,且 limit 除以 request 的结果必须小于或等于 LimitRange 的 spec.limits.maxLimitRequestRatio
下面的例子中 LimitRange 限定了名称空间中任何 Pod 的最大内存限定(limit)不能超过最小内存请求(request)的两倍:
apiVersion: v1
kind: LimitRange
metadata:
name: limit-memory-ratio-pod
spec:
limits:
- maxLimitRequestRatio:
memory: 2
type: Pod
执行命令以创建该 LimitRange:
kubectl create -f https://kuboard.cn/statics/learning/policy/lr-ratio-limit-range.yaml -n limitrange-demo
执行命令以查看创建结果:
kubectl describe limitrange/limit-memory-ratio-pod -n limitrange-demo
Name: limit-memory-ratio-pod
Namespace: limitrange-demo
Type Resource Min Max Default Request Default Limit Max Limit/Request Ratio
---- -------- --- --- --------------- ------------- -----------------------
Pod memory - - - - 2
此时,如果我们创建一个 Pod 包含如下属性 requests.memory=100Mi 和 limits.memory=300Mi:
apiVersion: v1
kind: Pod
metadata:
name: busybox3
spec:
containers:
- name: busybox-cnt01
image: busybox
resources:
limits:
memory: "300Mi"
requests:
memory: "100Mi"
执行命令以创建该 Pod:
kubectl apply -f https://kuboard.cn/statics/learning/policy/lr-ratio-pod.yaml -n limitrange-demo
由于该 Pod 的内存限制请求比例为 3,超过了 LimitRange 中定义的 2,该 Pod 将不能创建成功:
Error from server (Forbidden): error when creating "lr-ratio-pod.yaml": pods "busybox3" is forbidden: memory max limit to request ratio per Pod is 2, but provided ratio is 3.000000.