k8s 学习笔记 - LimitRange 限制范围
前情提要
- 在当前工作经验中,从未限制过
namespace的资源,这次的实施工作中,使用的是第三方定制的 k8s 集群,在namespace被创建时,因为yaml文件没有配置limits和requests两个参数,当yaml文件被apply后,自动对pod配置了LimitRange中定义的limits和requests,结果资源不够使用,导致容器启动过程中出现OOMKilled报错- 后续在
yaml中加上limits和requests依然有报错,导致控制器无法创建pod,原因是LimitRange中的limits.maxLimitRequestRatio配置,对于limits和requests的比例有限制
开始复盘
下面两个是 k8s 官方文档
借用一下官方文档
什么是限制范围
LimitRange是限制namespace(命名空间)内可为每个适用的对象类别 (例如Pod或PersistentVolumeClaim)指定的资源分配量(limits和requests)的策略对象- 一个
LimitRange(限制范围)对象提供的限制能够做到:- 在一个
namespace(命名空间)中实施对每个Pod或Container最小和最大的资源使用量的限制。 - 在一个
namespace(命名空间)中实施对每个PersistentVolumeClaim能申请的最小和最大的存储空间大小的限制。 - 在一个
namespace(命名空间)中实施对一种资源的requests(申请值)和limits(限制值)的比值的控制。 - 设置一个
namespace(命名空间)中对计算资源的默认requests(申请值) / limits(限制值),并且自动的在运行时注入到多个 Container 中。
- 在一个
- 当某
namespace(命名空间)中有一个LimitRange对象时,将在该namespace(命名空间)中实施LimitRange限制 LimitRange的名称必须是合法的DNS 子域名
资源限制和请求的约束
- 管理员在一个
namespace(命名空间)内创建一个LimitRange对象。 - 用户在此
namespace(命名空间)内创建(或尝试创建)Pod和PersistentVolumeClaim等对象。 - 首先,
LimitRanger准入控制器对所有没有设置计算资源需求的所有 Pod(及其容器)设置默认请求值与限制值。 - 其次,
LimitRange跟踪其使用量以保证没有超出命名空间中存在的任意LimitRange所定义的最小、最大资源使用量以及使用量比值。 - 若尝试创建或更新的对象(
Pod和PersistentVolumeClaim)违反了LimitRange的约束, 向 API 服务器的请求会失败,并返回 HTTP 状态码403 Forbidden以及描述哪一项约束被违反的消息。 - 若你在
namespace(命名空间)中添加LimitRange启用了对cpu和memory等计算相关资源的限制, 你必须指定这些值的请求使用量与限制使用量。否则,系统将会拒绝创建 Pod。 LimitRange的验证仅在Pod 准入阶段进行,不对正在运行的 Pod进行验证。 如果你添加或修改LimitRange,namespace(命名空间)中已存在的Pod将继续不变。- 如果命名空间中存在两个或更多
LimitRange对象,应用哪个默认值是不确定的
实践出真知
- 这里图省事,就直接拿 k8s 自带的
default这个namespace来做演示- 这里图省事,就直接部署
pod,没有使用任何控制器(deployment,statefulset,daemonset这一类)
- 如果是控制器启动的,以下创建
pod失败的场景,通过kubectl get pod命令会查看不到pod被创建的,使用kubectl describe <控制器名称>命令能查看到同理的报错- 以下的示例都是拿
cpu做演示,内存是同理的
场景1
pod配置的requests超出了LimitRange配置的limits
cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: LimitRange
metadata:
name: cpu-resource-constraint
spec:
limits:
- default: # 此处定义默认限制值(limits)
cpu: 500m
defaultRequest: # 此处定义默认请求值(requests)
cpu: 500m
type: Container
EOF
可以通过
kubectl get limitrange命令查看是否创建成功
创建一个 pod 来验证
cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: Pod
metadata:
name: busybox
namespace: default
spec:
containers:
- name: busybox
image: busybox:1.28.3
command:
- sleep
- "36000"
imagePullPolicy: IfNotPresent
resources:
requests:
cpu: 700m
restartPolicy: Always
EOF
- 这个时候就会有报错出现
The Pod "busybox" is invalid: spec.containers[0].resources.requests: Invalid value: "700m": must be less than or equal to cpu limit- 只需要把
cpu: 700m调小一点,低于limitrange里面配置的default就可以重新运行 pod 了
场景2
继续使用
场景1的limitrange,但是创建的pod同时配置了limits和requests,并且均超过limitrange里面配置的资源限制
cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: Pod
metadata:
name: busybox-resource-limits-requests
namespace: default
spec:
containers:
- name: busybox
image: busybox:1.28.3
command:
- sleep
- "36000"
imagePullPolicy: IfNotPresent
resources:
limits:
cpu: 700m
requests:
cpu: 700m
restartPolicy: Always
EOF
此时,pod 是可以被创建的
场景3
继续使用
场景1的limitrange,但是创建的pod没有配置limits和requests
cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: Pod
metadata:
name: busybox-no-resource-set
namespace: default
spec:
containers:
- name: busybox
image: busybox:1.28.3
command:
- sleep
- "36000"
imagePullPolicy: IfNotPresent
restartPolicy: Always
EOF
pod是肯定可以创建的,并且会自动给pod赋值limits和requests
kubectl get pod busybox-no-resource-set -o yaml | grep 'resources' -A 4
可以看出来,
limits和requests都是limitrange内配置的500m
resources:
limits:
cpu: 500m
requests:
cpu: 500m
场景4
继续使用
场景1的limitrange,但是创建的pod只配置了limits,并且比limitrange里面的值要高
cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: Pod
metadata:
name: busybox-just-limits
namespace: default
spec:
containers:
- name: busybox
image: busybox:1.28.3
command:
- sleep
- "36000"
imagePullPolicy: IfNotPresent
resources:
limits:
cpu: 700m
restartPolicy: Always
EOF
pod可以被成功创建,且requests被赋值和limits的值一致
kubectl get pod busybox-just-limits -o yaml | grep 'resources' -A 4
resources:
limits:
cpu: 700m
requests:
cpu: 700m
场景5
- 这里图省事,就拿内存来做示例了
limitrange配置了maxLimitRequestRatio,创建的pod的limits/requests的值不等于 1
cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: LimitRange
metadata:
name: cpu-resource-constraint
spec:
limits:
- default: # 此处定义默认限制值(limits)
memory: 256Mi
defaultRequest: # 此处定义默认请求值(requests)
memory: 256Mi
maxLimitRequestRatio: # 此处定义 limits/requests 的值必须等于 1
memory: 1
type: Container
EOF
创建一个
pod来验证
cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: Pod
metadata:
name: busybox-ratio-ne-one
namespace: default
spec:
containers:
- name: busybox
image: busybox:1.28.3
command:
- sleep
- "36000"
imagePullPolicy: IfNotPresent
resources:
limits:
memory: 700Mi
requests:
memory: 70Mi
restartPolicy: Always
EOF
- 这个
pod是无法被创建的,会返回Error from server (Forbidden): error when creating "STDIN": pods "busybox-ratio-ne-one" is forbidden: memory max limit to request ratio per Container is 1, but provided ratio is 10.000000这样的报错- 这个
10.000000就是700/70=10得来的- 只需要把
limits和requests的值改成一样的,就可以成功启动pod了
学习总结
- 当
namespace配置了limitrange,并且pod创建时没有指明limits或/和requests时,pod被创建后由limitrang的配置来指明pod的limits或/和requests - 当
namespace配置了limitrange,并且pod创建时的requests超出了limitrange配置的limits时,会有报错must be less than or equal to xxx limit - 当
namespace配置了limitrange以及maxLimitRequestRatio,并且pod创建时的limits/requests值大于maxLimitRequestRatio配置的值,会有报错is forbidden: xxx max limit to request ratio per Container is xxx, but provided ratio is xxx
关于
limits,requests,maxLimitRequestRatio的取值,主要是围绕cpu和memroy的单位来的
- 在 k8s 中,
数量(Quantity)是数字的定点表示,没有数量可以表示大于2的63次方-1的数,也不可能超过3 个小数位;更大或更精确的数字将被截断或向上取整(只会显示整数)- 在 k8s 中,
cpu的单位为m,1000m=1核0.1m将向上取整为1m
- 在 k8s 中,
memory的单位为k | M | G | T | P | E或者Ki | Mi | Gi | Ti | Pi | Ei- 区别在于换算不同,一个是
1:1000,另一个是1:1024:1m表示1000k1Mi表示1024k- 程序员眼中的整数,必须是
1024
- 区别在于换算不同,一个是
最后,大家也可以去验证,当 memory 这里写 1.5 的时候,pod 创建完,再去 get -o yaml,就会发现 1.5 变成了 1500m
- 在 k8s 中,

浙公网安备 33010602011771号