Kubernetes 提供了 LimitRange 机制对 Pod 和容器的 Requests 和 Limits 配置做进一步限制。下面的示例中首先如何将 LimitsRange 应用到一个 Kubernetes 的命名空间中,然后说明 LimitRange 的几种限制方式,比如最大及最小范围、Requests 和 Limits 的默认值、Limits 与 Requests 的最大比例上线,等等。下面用过 LimitRange 的设置和应用对其进行说明。

1. 创建一个命名空间

创建一个名为 limit-example 的 Namespace:

[root@master1 ~]# kubectl create namespace limit-example
namespace/limit-example created

2. 为命名空间设置 LimitRange

为命名空间 limit-example 创建一个简单的 LimitRange。创建 limits.yaml 配置文件,内容如下:

apiVersion: v1
kind: LimitRange
metadata:
  name: mylimits
spec:
  limits:
  - max:
      cpu: "4"
      memory: 2Gi
    min:
      cpu: 200m
      memory: 6Mi
    maxLimitRequestRatio:
      cpu: 3
      memory: 2
    type: Pod
  - default:
      cpu: 300m
      memory: 200Mi
    defaultRequest:
      cpu: 200m
      memory: 100Mi
    max:
      cpu: "2"
      memory: 1Gi
    min:
      cpu: 100m
      memory: 3Mi
    maxLimitRequestRatio:
      cpu: 5
      memory: 4
    type: Container

创建该 LimitRange:

[root@master1 ~]# kubectl create -f limits.yaml --namespace=limit-example 
limitrange/mylimits created

查看 namespace limit-example 中的 LimitRange:

[root@master1 ~]# kubectl describe limitranges mylimits --namespace=limit-example 
Name:       mylimits
Namespace:  limit-example
Type        Resource  Min   Max  Default Request  Default Limit  Max Limit/Request Ratio
----        --------  ---   ---  ---------------  -------------  -----------------------
Pod         cpu       200m  4    -                -              3
Pod         memory    6Mi   2Gi  -                -              2
Container   cpu       100m  2    200m             300m           5
Container   memory    3Mi   1Gi  100Mi            200Mi          4

LimitRange 中各项配置的意义和特点如下:

  1. 不论是 CPU 还是内存,在 LimitRange 中,Pod 和 Container 都可以设置 Min、Max 和 Max Limit / Requests Ratio 参数。Container 还可以设置 Default Request 和 Default Limit 参数,而 Pod 不能设置 Default Request 和Default Limit 参数。

  2. 对 Pod 和 Container 的参数解释如下。

    • Container:
      • Container 的 Min(上面的 100m 和 3Mi)是 Pod 中所有容器的 Requests 值下限;
      • Container 的 Max(上面的 2 和 1Gi)是 Pod 中所有容器的 Limits 值上限;
      • Container 的 Default Request(上面的 200m 和 100Mi)是 Pod 中所有未指定 Requests 值的容器的默认 Requests 值;
      • Container 的 Default Limit(上面的300m和200Mi)是 Pod 中所有未指定 Limits 值的容器的默认 Limits 值。
      • 对于同一资源类型,这 4 个参数必须满足以下关系:Min ≤ Default Request ≤ Default Limit ≤ Max。
    • Pod:
      • Pod 的 Min(上面的 200m 和 6Mi)是 Pod 中所有容器的 Requests 值的总和下限;
      • Pod 的 Max(上面的 4 和 2Gi)是 Pod 中所有容器的 Limits 值的总和上限。
      • 容器未指定 Requests 值或者 Limits 值时,将使用 Container 的 Default Request 值或者 Default Limit 值。
    • Container 的 Max Limit/Requests Ratio(上面的 5 和 4)限制了 Pod 中所有容器的 Limits 值与 Requests 值的比例上限;而 Pod 的 Max Limit / Requests Ratio(上面的 3 和 2)限制了 Pod 中所有容器的 Limits 值总和与 Requests 值总和的比例上限。
  3. 如果设置了 Container 的 Max,那么对于该类资源而言,整个集群中的所有容器都必须设置 Limits,否则无法成功创建。Pod 内的容器未配置 Limits 时,将使用 Default Limit 的值(本例中的 300m CPU 和 200MiB 内存),如果也未配置 Default,则无法成功创建。

  4. 如果设置了 Container 的 Min,那么对于该类资源而言,整个集群中的所有容器都必须设置 Requests。如果创建 Pod 的容器时未配置该类资源的 Requests,那么在创建过程中会报验证错误。Pod 里容器的 Requests 在未配置时,可以使用默认值 defaultRequest(本例中的 200m CPU 和 100MiB 内存);如果未配置而且没有使用默认值 defaultRequest,那么默认等于该容器的 Limits;如果容器的 Limits 也未定义,就会报错。

  5. 对于任意一个 Pod 而言,该 Pod 中所有容器的 Requests 总和都必须大于或等于 6MiB,而且所有容器的 Limits 总和都必须小于或等于 1GiB;同样,所有容器的 CPU Requests 总和都必须大于或等于 200m,而且所有容器的 CPU Limits 总和都必须小于或等于 2。

  6. Pod里任何容器的 Limits 与 Requests 的比例都不能超过 Container 的Max Limit / Requests Ratio;Pod 里所有容器的 Limits 总和与 Requests 总和的比例都不能超过 Pod 的 Max Limit / Requests Ratio。

3. 创建 Pod 时触发 LimitRange 限制

命名空间中的 LimitRange 只会在 Pod 创建或者更新时执行检查。如果手动修改 LimitRange 为一个新的值,那么这个新的值不会去检查或限制之前已经在该命名空间中创建好的 Pod。

如果在创建 Pod 时配置的资源值(CPU 或者内存)超出了 LimitRange 的限制,那么该创建过程会报错,在错误信息中会说明详细的错误原因。

下面通过创建一个单容器 Pod 来展示默认限制是如何被配置到 Pod 上的:

[root@master1 ~]# kubectl run nginx --image=nginx --replicas=1 --namespace=limit-example 
Flag --replicas has been deprecated, has no effect and will be removed in the future.
pod/nginx created

查看已创建的Pod:

[root@master1 ~]# kubectl get pods --namespace=limit-example 
NAME    READY   STATUS    RESTARTS   AGE
nginx   1/1     Running   0          2m8s

查看该 Pod 的 resources 相关信息:

[root@master1 ~]# kubectl get pods nginx --namespace=limit-example -o yaml | grep resource -C 8
  resourceVersion: "489149"
  selfLink: /api/v1/namespaces/limit-example/pods/nginx
  uid: 6836fd71-c59f-40fc-9d86-def510525c6c
spec:
  containers:
  - image: nginx
    imagePullPolicy: Always
    name: nginx
    resources:
      limits:
        cpu: 300m
        memory: 200Mi
      requests:
        cpu: 200m
        memory: 100Mi
    terminationMessagePath: /dev/termination-log
    terminationMessagePolicy: File

由于该 Pod 未配置资源 Requests 和 Limits,所以使用了 namespace limit-example 中的默认 CPU 和内存定义的 Requests 和 Limits 值。

下面通过 invalid-pod.yaml 创建一个超出资源限制的 Pod(使用 3 个 CPU):

apiVersion: v1
kind: Pod
metadata:
  name: invalid-pod
spec:
  containers:
    - name: nginx
      image: nginx
      resources:
        limits:
          cpu: "3"
          memory: 100Mi

创建该 Pod,可以看到系统报错,并且提供的错误原因为超出资源限制:

[root@master1 ~]# kubectl create -f invalid-pod.yaml --namespace=limit-example 
Error from server (Forbidden): error when creating "invalid-pod.yaml": pods "invalid-pod" is forbidden: maximum cpu usage per Container is 2, but limit is 3

通过 limit-test-nginx.yaml 文件的例子展示了 LimitRange 对 maxLimitRequestRatio 的限制过程:

apiVersion: v1
kind: Pod
metadata:
  name: limit-test-nginx
  labels:
    name: limit-test-nginx
spec:
  containers:
  - name: limit-test-nginx
    image: nginx
    resources:
      limits:
        cpu: "1"
        memory: 512Mi
      requests:
        cpu: "0.8"
        memory: 250Mi

由于 limit-test-nginx 这个 Pod 的全部内存 Limits 总和与 Requests 总和的比例为 512:250,大于在 LimitRange 中定义的 Pod 的最大比率为 2(maxLimitRequestRatio.memory=2),因此创建失败:

[root@master1 ~]# kubectl create -f limit-test-nginx.yaml --namespace=limit-example 
Error from server (Forbidden): error when creating "limit-test-nginx.yaml": pods "limit-test-nginx" is forbidden: memory max limit to request ratio per Pod is 2, but provided ratio is 2.048000

通过 valid-pod.yaml 文件的例子为满足 LimitRange 限制的 Pod:

apiVersion: v1
kind: Pod
metadata:
  name: valid-pod
  labels:
    name: valid-pod
spec:
  containers:
  - name: nginx
    image: nginx
    resources:
      limits:
        cpu: "1"
        memory: 512Mi

创建 Pod 将会成功:

[root@master1 ~]# kubectl create -f valid-pod.yaml --namespace=limit-example 
pod/valid-pod created

查看该 Pod 的资源信息:

[root@master1 ~]# kubectl get pods valid-pod --namespace=limit-example -o yaml | grep -C 6 resources
  uid: 3aa42389-ed29-42f9-9ca6-9f6ded0d9c68
spec:
  containers:
  - image: nginx
    imagePullPolicy: Always
    name: nginx
    resources:
      limits:
        cpu: "1"
        memory: 512Mi
      requests:
        cpu: "1"
        memory: 512Mi

可以看到该 Pod 明确的 Limits 和 Requests,因此该 Pod 不会使用在 namespace limit-example 中定义的 default 和 defaultRequests。

需要注意的是,CPU Limits 强制配置这个选项,在 Kubernetes 集群中默认是开启的;除非在部署kubelet服务时通过设置--cpu-cfs-quota=false来关闭该限制。

参考:《Kubernetes权威指南(第五版)》