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.phase 是 Failed, 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
物件用來定義某個名稱空間
下某種資源物件
的使用限額,其中資源物件包括:Pod
、Container
、PersistentVolumeClaim
。
2.1. 為namespace配置CPU和記憶體的預設值
如果在一個擁有預設記憶體或CPU限額的名稱空間中建立一個容器,並且這個容器未指定它自己的記憶體或CPU的limit
, 它會被分配這個預設的記憶體或CPU的limit
。既沒有設定pod的limit
和request
才會分配預設的記憶體或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 說明
- 如果沒有指定pod的
request
和limit
,則建立的pod會使用LimitRange
物件定義的預設值(request和limit) - 如果指定pod的
limit
但未指定request
,則建立的pod的request
值會取limit
的值,而不會取LimitRange物件定義的request預設值。 - 如果指定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級別的request
和limit
是其所有容器的request和limit之和。
3.2. Requests and Limits
Pod可以指定request
和limit
資源。其中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
所有的容器的limit
和request
值都沒有配置。
例如:
containers:
name: foo
resources:
name: bar
resources:
參考: