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
$ kubectl api-resources | grep limitranges
limitranges limits true LimitRange
# 以上字段为 true,则表示启用
# 通常默认是启用的
配置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资源对象
# 创建一个名称空间
$ kubectl create namespace limitrange-demo
# 切换至此名称空间
$ kubectl config set-context --current --namespace=limitrange-demo
# limitrange对象的yaml文件如下所示:
$ cat 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
# 上述yaml文件定义的内容如下:
# 最大和最小的CPU/内存
# 默认的 CPU/内存限定
# 默认的 CPU/内存请求
$ kubectl apply -f limitrange.yaml # 创建此对象
# 查看此对象的详细信息
$ kubectl describe limitrange/limit-mem-cpu-per-container -n limitrange-demo
查看此对象的详细信息返回结果如下:
创建包含4个容器的pod
$ cat lr-container-pod.yaml # 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"]
$ kubectl apply -f lr-container-pod.yaml # 创建pod
查看容器包含有效的 CPU/内存的requests/limits
# 执行以下命令,查看 busybox-cnt01 的配置信息
# 如果提示没有jq命令,则直接 yum -y install jq 即可
$ 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
$ 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
$ 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
$ 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的计算资源
参考:kuboard官网
限制存储资源
通过 LimitRange 对象,可以限定名称空间中每个 PVC(存储卷声明)可以使用的最小、最大存储空间。
创建limitrange
$ cat lr-storage-limit.yaml # yaml文件如下
apiVersion: v1
kind: LimitRange
metadata:
name: storagelimits
spec:
limits:
- type: PersistentVolumeClaim
max:
storage: 2Gi
min:
storage: 1Gi
$ kubectl apply -f lr-storage-limit.yaml # 确认
$ kubectl describe limits/storagelimits # 查看详细信息
Name: storagelimits
Namespace: default
Type Resource Min Max Default Request Default Limit Max Limit/Request Ratio
---- -------- --- --- --------------- ------------- -----------------------
PersistentVolumeClaim storage 1Gi 2Gi - - -
假设现在有一个PVC(存储卷声明),定义文件如下所示:
cat > pvc.yaml << EOF
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: pvc-limit-lower
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 500Mi
EOF
$ kubectl apply -f pvc.yaml # 创建此yaml文件
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)的两倍:
$ cat limit-memory-ratio-pod.yaml # 查看yaml文件如下
apiVersion: v1
kind: LimitRange
metadata:
name: limit-memory-ratio-pod
spec:
limits:
- maxLimitRequestRatio:
memory: 2
type: Pod
$ kubectl apply -f limit-memory-ratio-pod.yaml # 创建
$ kubectl describe limitrange/limit-memory-ratio-pod # 查看详细信息
Name: limit-memory-ratio-pod
Namespace: default
Type Resource Min Max Default Request Default Limit Max Limit/Request Ratio
---- -------- --- --- --------------- ------------- -----------------------
Pod memory - - - - 2
创建一个pod,包含如下属性 requests.memory=100Mi 和 limits.memory=300Mi:
$ cat busybox3.yaml
apiVersion: v1
kind: Pod
metadata:
name: busybox3
spec:
containers:
- name: busybox-cnt01
image: busybox
resources:
limits:
memory: "300Mi"
requests:
memory: "100Mi"
$ kubectl apply -f busybox3.yaml # 创建此pod
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 将不能创建成功。