前面我们介绍了kubernetes的resourceQuota,现在再来介绍下limitRanges。

Resource Quota区分的粒度是namespace,其目的是为了不同namespace之间的公平,防止某些流氓team占用了太多的资源。而limitRange区分的粒度则是container,则是在为了在同一个namespace下,限制container的最大最小值。另外, 在设置了resourceQuota的namespace下,如果用户创建Pod时没有指定limit/request,默认是无法创建的(403 FORBIDDEN),此时可以通过limitRanges来配置该namespace下容器默认的limit/request。

来看下面这个例子。

先创建一个namespace,并切换到该namespace。

kubectl create namespace limit-example
kubens limit-example

如果你没有装kubens,可以装一个,很好用,很方便。

然后apply下面的编排文件。

apiVersion: v1
kind: LimitRange
metadata:
  name: mem-limit-range
spec:
  limits:
  - default:
      memory: 512Mi
      cpu: 1
    defaultRequest:
      memory: 256Mi
      cpu: 0.5
    max:
      memory: 1024Mi
      cpu: 1
    min:
      memory: 128Mi
      cpu: 0.5
    type: Container

说明:

  • default:即该namespace配置resourceQuota时,创建container的默认limit上限
  • defaultRequest:即该namespace配置resourceQuota时,创建container的默认request上限
  • max:即该namespace下创建container的资源最大值
  • min:即该namespace下创建container的资源最小值

其中: min <= defaultRequest <= default <= max

其实我觉得default、defaultRequest应该单独拿出来,他们跟max、min的意义区别还是挺大的。

看一下刚创建的limits。

$ kubectl describe limits
Name:       limit-range
Namespace:  resource-quota
Type        Resource  Min    Max  Default Request  Default Limit  Max Limit/Request Ratio
----        --------  ---    ---  ---------------  -------------  -----------------------
Container   cpu       500m   1    500m             1              -
Container   memory    128Mi  1Gi  256Mi            512Mi          -

我没有配置Max Limit/Request Ratio

先来看看maxmin的效果。

apiVersion: v1
kind: Pod
metadata:
  name: default-cpu-demo-maxmin
spec:
  containers:
  - name: default-cpu-demo-ctr-maxmin
    image: nginx
    resources:
      limits:
        cpu: "1.1"
        memory: 1.1Gi

尝试创建一下,会看到失败信息,提示,超过max啦!

kubectl apply -f nginx-maxmin.yaml 
Error from server (Forbidden): error when creating "nginx-maxmin.yaml": pods "default-cpu-demo-maxmin" is forbidden: [maximum cpu usage per Container is 1, but limit is 1100m., maximum memory usage per Container is 1Gi, but limit is 1181116006400m.]

其他类似,不再赘述。

再看看defaultdefaultRequest

在namespace limit-example下创建下面的Pod。该Pod未指定任何资源信息。

apiVersion: v1
kind: Pod
metadata:
  name: default-cpu-demo
spec:
  containers:
  - name: default-cpu-demo-ctr
    image: nginx

创建后来看看其实际资源的情况,可以看到确实是按照上面的limits配置的。

apiVersion: v1
kind: Pod
spec:
  containers:
  - image: gcr.io/nginx
    imagePullPolicy: Always
    name: default-cpu-demo-ctr
    resources:
      limits:
        cpu: "1"
        memory: 512Mi
      requests:
        cpu: 500m
        memory: 256Mi

注意:如果container只设置了limit,没有设置request,那么最终创建出来的container,其request=limit。而不是想当然的是 default request。

apiVersion: v1
kind: Pod
metadata:
  name: default-cpu-demo-maxmin
spec:
  containers:
  - name: default-cpu-demo-ctr-maxmin
    image: nginx
    resources:
      limits:
        cpu: "1"
        memory: 1Gi

尝试创建,提示request要求为1核1G,超过defaultRequest限制。

kubectl apply -f nginx-maxmin.yaml 
Error from server (Forbidden): error when creating "nginx-maxmin.yaml": pods "default-cpu-demo-maxmin" is forbidden: exceeded quota: compute-resources, requested: requests.cpu=1,requests.memory=1Gi, used: requests.cpu=500m,requests.memory=256Mi, limited: requests.cpu=1,requests.memory=1Gi

为什么要这样设计呢?可能是如果使用defaultRequest,那么必然request<limit,这种container比较容易在节点资源不足的时候被k8s杀死,设计为一致,能更好的提示用户(猜的)。

如果container只设置了request,没设置limit,则最终container的limit为default设置的值。

推荐阅读下 Kubernetes best practices: Resource requests and limits(作者是 Dinesh 哈哈),会对limit、request的设置有更好的理解。

Dinesh

简单来说,request影响的是k8s的调度,也就是说k8s会保证container所request的资源,在调度时会考虑node是否满足request的条件。而limit则是实际运行时k8s的限制,防止container无限制的占用node的资源。显然的,由于调度时更多的考虑了request而不是limit,那么必然会出现某个node上container的limit总和超过该node资源的情况,此时,k8s针对cpu和memory会由不同的处理。

对于cpu,k8s认为cpu是可压缩的,在应用达到limit时,k8s会减少该容器的调度时间,并不会杀死应用。

对于memory,k8s认为memory是无法压缩的,此时k8s会杀死占用资源超过其request的应用(1.9版本之后的版本)。首当其冲的是没有指定request的container,然后是使用资源超过其request更多的container。同等情况下优先级更低的container更容易被杀死。

Ref: