1. 程式人生 > >Kubernetes基本概念(四)之資源配額詳解

Kubernetes基本概念(四)之資源配額詳解

1. 資源配額(ResourceQuota)

ResourceQuota物件用來定義某個名稱空間下所有資源的使用限額,其實包括:

  • 計算資源的配額
  • 儲存資源的配額
  • 物件數量的配額

如果叢集的總容量小於名稱空間的配額總額,可能會產生資源競爭。這時會按照先到先得來處理。
資源競爭和配額的更新都不會影響已經建立好的資源。

1.1. 啟動資源配額

Kubernetes 的眾多發行版本預設開啟了資源配額的支援。當在apiserver的--admission-control配置中新增ResourceQuota引數後,便啟用了。 當一個名稱空間中含有ResourceQuota物件時,資源配額將強制執行。

1.2. 計算資源配額

可以在給定的名稱空間中限制可以請求的計算資源(compute resources)的總量。

資源名稱 描述
cpu 非終止態的所有pod, cpu請求總量不能超出此值。
limits.cpu 非終止態的所有pod, cpu限制總量不能超出此值。
limits.memory 非終止態的所有pod, 記憶體限制總量不能超出此值。
memory 非終止態的所有pod, 記憶體請求總量不能超出此值。
requests.cpu 非終止態的所有pod, cpu請求總量不能超出此值。
requests.memory 非終止態的所有pod, 記憶體請求總量不能超出此值。

1.3. 儲存資源配額

可以在給定的名稱空間中限制可以請求的儲存資源(storage resources)的總量。

資源名稱 描述
requests.storage 所有PVC, 儲存請求總量不能超出此值。
persistentvolumeclaims
.storageclass.storage.k8s.io/requests.storage 和該儲存類關聯的所有PVC, 儲存請求總和不能超出此值。
.storageclass.storage.k8s.io/persistentvolumeclaims

1.4. 物件數量的配額

資源名稱 描述
congfigmaps 名稱空間中可以存在的配置對映的總數。
persistentvolumeclaims 名稱空間中可以存在的PVC總數。
pods 名稱空間中可以存在的非終止態的pod總數。如果一個pod的status.phaseFailed, Succeeded, 則該pod處於終止態。
replicationcontrollers 名稱空間中可以存在的rc總數。
resourcequotas
services 名稱空間中可以存在的服務總數量。
services.loadbalancers 名稱空間中可以存在的服務的負載均衡的總數量。
services.nodeports 名稱空間中可以存在的服務的主機介面的總數量。
secrets 名稱空間中可以存在的secrets的總數量。

例如:可以定義pod的限額來避免某使用者消耗過多的Pod IPs。

1.5. 限額的作用域

作用域 描述
Terminating 匹配 spec.activeDeadlineSeconds >= 0 的pod
NotTerminating 匹配 spec.activeDeadlineSeconds is nil 的pod
BestEffort 匹配具有最佳服務質量的pod
NotBestEffort 匹配具有非最佳服務質量的pod

1.6. request和limit

當分配計算資源時,每個容器可以為cpu或者記憶體指定一個請求值和一個限度值。可以配置限額值來限制它們中的任何一個值。
如果指定了requests.cpu 或者 requests.memory的限額值,那麼就要求傳入的每一個容器顯式的指定這些資源的請求。如果指定了limits.cpu或者limits.memory,那麼就要求傳入的每一個容器顯式的指定這些資源的限度。

1.7. 檢視和設定配額

# 建立namespace
$ kubectl create namespace myspace

# 建立resourcequota
$ cat <<EOF > compute-resources.yaml
apiVersion: v1
kind: ResourceQuota
metadata:
  name: compute-resources
spec:
  hard:
    pods: "4"
    requests.cpu: "1"
    requests.memory: 1Gi
    limits.cpu: "2"
    limits.memory: 2Gi
EOF
$ kubectl create -f ./compute-resources.yaml --namespace=myspace

# 查詢resourcequota
$ kubectl get quota --namespace=myspace
NAME                    AGE
compute-resources       30s

# 查詢resourcequota的詳細資訊
$ kubectl describe quota compute-resources --namespace=myspace
Name:                  compute-resources
Namespace:             myspace
Resource               Used Hard
--------               ---- ----
limits.cpu             0    2
limits.memory          0    2Gi
pods                   0    4
requests.cpu           0    1
requests.memory        0    1Gi

1.8. 配額和叢集容量

資源配額物件與叢集容量無關,它們以絕對單位表示。即增加節點的資源並不會增加已經配置的namespace的資源。

2. Pod限額(LimitRange)

ResourceQuota物件是限制某個namespace下所有Pod(容器)的資源限額

LimitRange物件是限制某個namespace單個Pod(容器)的資源限額

LimitRange物件用來定義某個名稱空間下某種資源物件的使用限額,其中資源物件包括:PodContainerPersistentVolumeClaim

2.1. 為namespace配置CPU和記憶體的預設值

如果在一個擁有預設記憶體或CPU限額的名稱空間中建立一個容器,並且這個容器未指定它自己的記憶體或CPU的limit, 它會被分配這個預設的記憶體或CPU的limit。既沒有設定pod的limitrequest才會分配預設的記憶體或CPU的request

2.1.1. namespace的記憶體預設值

# 建立namespace
$ kubectl create namespace default-mem-example

# 建立LimitRange
$ cat memory-defaults.yaml
apiVersion: v1
kind: LimitRange
metadata:
  name: mem-limit-range
spec:
  limits:
  - default:
      memory: 512Mi
    defaultRequest:
      memory: 256Mi
    type: Container

$ kubectl create -f https://k8s.io/docs/tasks/administer-cluster/memory-defaults.yaml --namespace=default-mem-example

# 建立Pod,未指定記憶體的limit和request
$ cat memory-defaults-pod.yaml
apiVersion: v1
kind: Pod
metadata:
  name: default-mem-demo
spec:
  containers:
  - name: default-mem-demo-ctr
    image: nginx

$ kubectl create -f https://k8s.io/docs/tasks/administer-cluster/memory-defaults-pod.yaml --namespace=default-mem-example

# 檢視Pod
$ kubectl get pod default-mem-demo --output=yaml --namespace=default-mem-example
containers:
- image: nginx
  imagePullPolicy: Always
  name: default-mem-demo-ctr
  resources:
    limits:
      memory: 512Mi
    requests:
      memory: 256Mi

2.1.2. namespace的CPU預設值

# 建立namespace
$ kubectl create namespace default-cpu-example

# 建立LimitRange
$ cat cpu-defaults.yaml 
apiVersion: v1
kind: LimitRange
metadata:
  name: cpu-limit-range
spec:
  limits:
  - default:
      cpu: 1
    defaultRequest:
      cpu: 0.5
    type: Container

$ kubectl create -f https://k8s.io/docs/tasks/administer-cluster/cpu-defaults.yaml --namespace=default-cpu-example    

# 建立Pod,未指定CPU的limit和request
$ cat cpu-defaults-pod.yaml
apiVersion: v1
kind: Pod
metadata:
  name: default-cpu-demo
spec:
  containers:
  - name: default-cpu-demo-ctr
    image: nginx

$ kubectl create -f https://k8s.io/docs/tasks/administer-cluster/cpu-defaults-pod.yaml --namespace=default-cpu-example

# 檢視Pod
$ kubectl get pod default-cpu-demo --output=yaml --namespace=default-cpu-example
containers:
- image: nginx
  imagePullPolicy: Always
  name: default-cpu-demo-ctr
  resources:
    limits:
      cpu: "1"
    requests:
      cpu: 500m

2.1.3 說明

  1. 如果沒有指定pod的requestlimit,則建立的pod會使用LimitRange物件定義的預設值(request和limit)
  2. 如果指定pod的limit但未指定request,則建立的pod的request值會取limit的值,而不會取LimitRange物件定義的request預設值。
  3. 如果指定pod的request但未指定limit,則建立的pod的limit值會取LimitRange物件定義的limit預設值。

預設Limit和request的動機

如果名稱空間具有資源配額(ResourceQuota), 它為記憶體限額(CPU限額)設定預設值是有意義的。 以下是資源配額對名稱空間施加的兩個限制:

  • 在名稱空間執行的每一個容器必須有它自己的記憶體限額(CPU限額)。
  • 在名稱空間中所有的容器使用的記憶體總量(CPU總量)不能超出指定的限額。

如果一個容器沒有指定它自己的記憶體限額(CPU限額),它將被賦予預設的限額值,然後它才可以在被配額限制的名稱空間中執行。

2.2. 為namespace配置CPU和記憶體的最大最小值

2.2.1. 記憶體的最大最小值

建立LimitRange

# 建立namespace
$ kubectl create namespace constraints-mem-example

# 建立LimitRange
$ cat memory-constraints.yaml
apiVersion: v1
kind: LimitRange
metadata:
  name: mem-min-max-demo-lr
spec:
  limits:
  - max:
      memory: 1Gi
    min:
      memory: 500Mi
    type: Container

$ kubectl create -f https://k8s.io/docs/tasks/administer-cluster/memory-constraints.yaml --namespace=constraints-mem-example

# 檢視LimitRange
$ kubectl get limitrange cpu-min-max-demo --namespace=constraints-mem-example --output=yaml
...
  limits:
  - default:
      memory: 1Gi
    defaultRequest:
      memory: 1Gi
    max:
      memory: 1Gi
    min:
      memory: 500Mi
    type: Container
...
# LimitRange設定了最大最小值,但沒有設定預設值,也會被自動設定預設值。

建立符合要求的Pod

# 建立符合要求的Pod
$ cat memory-constraints-pod.yaml
apiVersion: v1
kind: Pod
metadata:
  name: constraints-mem-demo
spec:
  containers:
  - name: constraints-mem-demo-ctr
    image: nginx
    resources:
      limits:
        memory: "800Mi"
      requests:
        memory: "600Mi"

$ kubectl create -f https://k8s.io/docs/tasks/administer-cluster/memory-constraints-pod.yaml --namespace=constraints-mem-example

# 檢視Pod
$ kubectl get pod constraints-mem-demo --output=yaml --namespace=constraints-mem-example
...
resources:
  limits:
     memory: 800Mi
  requests:
    memory: 600Mi
...

建立超過最大記憶體limit的pod

$ cat memory-constraints-pod-2.yaml
apiVersion: v1
kind: Pod
metadata:
  name: constraints-mem-demo-2
spec:
  containers:
  - name: constraints-mem-demo-2-ctr
    image: nginx
    resources:
      limits:
        memory: "1.5Gi"  # 超過最大值 1Gi
      requests:
        memory: "800Mi"

$ kubectl create -f https://k8s.io/docs/tasks/administer-cluster/memory-constraints-pod-2.yaml --namespace=constraints-mem-example

# Pod建立失敗,因為容器指定的limit過大
Error from server (Forbidden): error when creating "docs/tasks/administer-cluster/memory-constraints-pod-2.yaml":
pods "constraints-mem-demo-2" is forbidden: maximum memory usage per Container is 1Gi, but limit is 1536Mi.

建立小於最小記憶體request的Pod

$ cat memory-constraints-pod-3.yaml
apiVersion: v1
kind: Pod
metadata:
  name: constraints-mem-demo-3
spec:
  containers:
  - name: constraints-mem-demo-3-ctr
    image: nginx
    resources:
      limits:
        memory: "800Mi"
      requests:
        memory: "100Mi"   # 小於最小值500Mi

$ kubectl create -f https://k8s.io/docs/tasks/administer-cluster/memory-constraints-pod-3.yaml --namespace=constraints-mem-example         

# Pod建立失敗,因為容器指定的記憶體request過小
Error from server (Forbidden): error when creating "docs/tasks/administer-cluster/memory-constraints-pod-3.yaml":
pods "constraints-mem-demo-3" is forbidden: minimum memory usage per Container is 500Mi, but request is 100Mi.

建立沒有指定任何記憶體limit和request的pod

$ cat memory-constraints-pod-4.yaml
apiVersion: v1
kind: Pod
metadata:
  name: constraints-mem-demo-4
spec:
  containers:
  - name: constraints-mem-demo-4-ctr
    image: nginx

$ kubectl create -f https://k8s.io/docs/tasks/administer-cluster/memory-constraints-pod-4.yaml --namespace=constraints-mem-example

# 檢視Pod
$ kubectl get pod constraints-mem-demo-4 --namespace=constraints-mem-example --output=yaml
...
resources:
  limits:
    memory: 1Gi
  requests:
    memory: 1Gi
...

容器沒有指定自己的 CPU 請求和限制,所以它將從 LimitRange 獲取預設的 CPU 請求和限制值。

2.2.2. CPU的最大最小值

建立LimitRange

# 建立namespace
$ kubectl create namespace constraints-cpu-example

# 建立LimitRange
$ cat cpu-constraints.yaml
apiVersion: v1
kind: LimitRange
metadata:
  name: cpu-min-max-demo-lr
spec:
  limits:
  - max:
      cpu: "800m"
    min:
      cpu: "200m"
    type: Container

$ kubectl create -f https://k8s.io/docs/tasks/administer-cluster/cpu-constraints.yaml --namespace=constraints-cpu-example

# 檢視LimitRange
$ kubectl get limitrange cpu-min-max-demo-lr --output=yaml --namespace=constraints-cpu-example
...
limits:
- default:
    cpu: 800m
  defaultRequest:
    cpu: 800m
  max:
    cpu: 800m
  min:
    cpu: 200m
  type: Container
...

建立符合要求的Pod

$ cat cpu-constraints-pod.yaml
apiVersion: v1
kind: Pod
metadata:
  name: constraints-cpu-demo
spec:
  containers:
  - name: constraints-cpu-demo-ctr
    image: nginx
    resources:
      limits:
        cpu: "800m"
      requests:
        cpu: "500m"

$ kubectl create -f https://k8s.io/docs/tasks/administer-cluster/cpu-constraints-pod.yaml --namespace=constraints-cpu-example

# 檢視Pod
$ kubectl get pod constraints-cpu-demo --output=yaml --namespace=constraints-cpu-example
...
resources:
  limits:
    cpu: 800m
  requests:
    cpu: 500m
...

建立超過最大CPU limit的Pod

$ cat cpu-constraints-pod-2.yaml
apiVersion: v1
kind: Pod
metadata:
  name: constraints-cpu-demo-2
spec:
  containers:
  - name: constraints-cpu-demo-2-ctr
    image: nginx
    resources:
      limits:
        cpu: "1.5"
      requests:
        cpu: "500m"

$ kubectl create -f https://k8s.io/docs/tasks/administer-cluster/cpu-constraints-pod-2.yaml --namespace=constraints-cpu-example

# Pod建立失敗,因為容器指定的CPU limit過大
Error from server (Forbidden): error when creating "docs/tasks/administer-cluster/cpu-constraints-pod-2.yaml":
pods "constraints-cpu-demo-2" is forbidden: maximum cpu usage per Container is 800m, but limit is 1500m.

建立小於最小CPU request的Pod

$ cat cpu-constraints-pod-3.yaml
apiVersion: v1
kind: Pod
metadata:
  name: constraints-cpu-demo-4
spec:
  containers:
  - name: constraints-cpu-demo-4-ctr
    image: nginx
    resources:
      limits:
        cpu: "800m"
      requests:
        cpu: "100m"

$ kubectl create -f https://k8s.io/docs/tasks/administer-cluster/cpu-constraints-pod-3.yaml --namespace=constraints-cpu-example

# Pod建立失敗,因為容器指定的CPU request過小
Error from server (Forbidden): error when creating "docs/tasks/administer-cluster/cpu-constraints-pod-3.yaml":
pods "constraints-cpu-demo-4" is forbidden: minimum cpu usage per Container is 200m, but request is 100m.

建立沒有指定任何CPU limit和request的pod

$ cat cpu-constraints-pod-4.yaml
apiVersion: v1
kind: Pod
metadata:
  name: constraints-cpu-demo-4
spec:
  containers:
  - name: constraints-cpu-demo-4-ctr
    image: vish/stress

$ kubectl create -f https://k8s.io/docs/tasks/administer-cluster/cpu-constraints-pod-4.yaml --namespace=constraints-cpu-example    

# 檢視Pod
kubectl get pod constraints-cpu-demo-4 --namespace=constraints-cpu-example --output=yaml
...
resources:
  limits:
    cpu: 800m
  requests:
    cpu: 800m
...

容器沒有指定自己的 CPU 請求和限制,所以它將從 LimitRange 獲取預設的 CPU 請求和限制值。

2.2.3. 說明

LimitRange 在 namespace 中施加的最小和最大記憶體(CPU)限制只有在建立和更新 Pod 時才會被應用。改變 LimitRange 不會對之前建立的 Pod 造成影響。

Kubernetes 都會執行下列步驟:

  • 如果容器沒有指定自己的記憶體(CPU)請求(request)和限制(limit),系統將會為其分配預設值。
  • 驗證容器的記憶體(CPU)請求大於等於最小值。
  • 驗證容器的記憶體(CPU)限制小於等於最大值。

3. Resource Quality of Service

3.1. 資源QoS簡介

request值表示容器保證可被分配到資源。limit表示容器可允許使用的最大資源。Pod級別的requestlimit是其所有容器的request和limit之和。

3.2. Requests and Limits

Pod可以指定requestlimit資源。其中0 <= request <=Node Allocatable & request <= limit <= Infinity。排程是基於request而不是limit,即如果Pod被成功排程,那麼可以保證Pod分配到指定的 request的資源。Pod使用的資源能否超過指定的limit值取決於該資源是否可被壓縮。

3.2.1. 可壓縮的資源

  • 目前只支援CPU
  • pod可以保證獲得它們請求的CPU數量,它們可能會也可能不會獲得額外的CPU時間(取決於正在執行的其他作業)。因為目前CPU隔離是在容器級別而不是pod級別。

3.2.2. 不可壓縮的資源

  • 目前只支援記憶體
  • pod將獲得它們請求的記憶體數量,如果超過了它們的記憶體請求,它們可能會被殺死(如果其他一些pod需要記憶體),但如果pod消耗的記憶體小於請求的記憶體,那麼它們將不會被殺死(除非在系統任務或守護程序需要更多記憶體的情況下)。

3.3. QoS 級別

在機器資源超賣的情況下(limit的總量大於機器的資源容量),即CPU或記憶體耗盡,將不得不殺死部分不重要的容器。因此對容器分成了3個QoS的級別:Guaranteed,Burstable, Best-Effort,三個級別的優先順序依次遞減。

當CPU資源無法滿足,pod不會被殺死可能被短暫控制。

記憶體是不可壓縮的資源,當記憶體耗盡的情況下,會依次殺死優先順序低的容器。Guaranteed的級別最高,不會被殺死,除非容器使用量超過limit限值或者資源耗盡,已經沒有更低級別的容器可驅逐。

3.3.1. Guaranteed

所有的容器的limit值和request值被配置且兩者相等(如果只配置limit沒有request,則request取值於limit)。

例如:

# 示例1
containers:
  name: foo
    resources:
      limits:
        cpu: 10m
        memory: 1Gi
  name: bar
    resources:
      limits:
        cpu: 100m
        memory: 100Mi
# 示例2
containers:
  name: foo
    resources:
      limits:
        cpu: 10m
        memory: 1Gi
      requests:
        cpu: 10m
        memory: 1Gi

  name: bar
    resources:
      limits:
        cpu: 100m
        memory: 100Mi
      requests:
        cpu: 100m
        memory: 100Mi

3.3.2. Burstable

如果一個或多個容器的limit和request值被配置且兩者不相等。

例如:

# 示例1
containers:
  name: foo
    resources:
      limits:
        cpu: 10m
        memory: 1Gi
      requests:
        cpu: 10m
        memory: 1Gi

  name: bar

# 示例2
containers:
  name: foo
    resources:
      limits:
        memory: 1Gi

  name: bar
    resources:
      limits:
        cpu: 100m

# 示例3
containers:
  name: foo
    resources:
      requests:
        cpu: 10m
        memory: 1Gi

  name: bar

3.3.3. Best-Effort

所有的容器的limitrequest值都沒有配置。

例如:

containers:
  name: foo
    resources:
  name: bar
    resources:

參考: