文章轉載自:https://www.kuboard.cn/learning/k8s-advanced/policy/lr.html
默認情況下,容器在 Kubernetes 集群上運行時,不受 計算資源 的限制。使用 Resource quota,集群管理員可以針對名稱空間限定資源的使用情況。在名稱空間內部,一個 Pod(或容器)的資源消耗不受限制。此時的顧慮在於,可能有一個 Pod(或容器)獨占了名稱空間的大部分資源。Limit Range 是一種用來限定名稱空間內 Pod(或容器)可以消耗資源數量的策略(Policy)。
Kubernetes LimitRange 對象可以:
- 限制名稱空間中每個 Pod 或容器的最小最大計算資源
- 限制名稱空間中每個 PersistentVolumeClaim 可使用的最小最大存儲空間
- 限制名稱空間中計算資源請求request、限定limit之間的比例
- 設置名稱空間中默認的計算資源的 request/limit,並在運行時自動注入到容器中
啟用 Limit Range
執行命令 kubectl api-resources 可查看您的集群是否支持 Limit Range,輸出結果如下所示,通常 LimitRange 是默認啟用的。
NAME SHORTNAMES APIGROUP NAMESPACED KIND
bindings true Binding
componentstatuses cs false ComponentStatus
configmaps cm true ConfigMap
endpoints ep true Endpoints
events ev true Event
limitranges limits true LimitRange
namespaces ns false Namespace
nodes no false Node
persistentvolumeclaims pvc true PersistentVolumeClaim
persistentvolumes pv false PersistentVolume
pods po true Pod
podtemplates true PodTemplate
基本介紹
- 集群管理員在名稱空間中創建一個 LimitRange 對象
- 用戶在名稱空間中創建工作負載等對象,例如 Pod、Container、PersistentVolumeClaim 等
- 針對那些沒有設置 計算資源請求request和限制limit 的 Pod 和容器,LimitRanger 根據名稱空間中的 LimitRange 對象為其設定默認的資源請求和響應,並確保 Pod 和容器對計算資源的實際消耗不會超過指定的值
- 如果創建或更新對象(Pod、Container、PersistentVolumeClaim)的請求與 Limit Range 的限定相沖突,apiserver 將返回 HTTP status 狀態碼 403 FORBIDDEN,以及相應的錯誤提示信息
- 如果名稱空間中激活了 limit range 來限定 cpu 和內存等計算資源的使用,則,用戶創建 Pod、Container 時,必須指定 cpu 或內存的 request 和 limit,否則系統將拒絕創建 Pod
- Kubernetes 只在 Pod 創建階段檢查 LimitRange 的限定,而不在 Pod 運行時執行任何檢查
LimitRange 對象激活后,再創建Pod、Container、PersistentVolumeClaim,必須指定 cpu 或內存的 request 和 limit,否則系統將拒絕創建 Pod
先創建的Pod、Container、PersistentVolumeClaim,然后再創建激活LimitRange 對象。沒有設置 計算資源請求request和限制limit 的 Pod 和容器,LimitRanger 根據名稱空間中的 LimitRange 對象為其設定默認的資源請求和響應
使用 LimitRange 的例子有:
- 在一個總容量為 8G內存 16核CPU 的 2 節點集群上,限定某個名稱空間中的 Pod 使用 100m的CPU請求(request)且不超過 500m的CPU上限(limit),200Mi的內存請求(request)且不超過 600Mi的內存上線(limit)
- 為沒有定義cpu和內存請求的容器,指定默認的 CPU 請求(request)和限制(limit)均為 150m,默認的內存請求為 300Mi
當名稱空間總的 limit 小於名稱空間中 Pod/Container 的 limit 之和時,將發生資源爭奪的現象,容器或者 Pod 將不能創建。
在資源爭奪現象發生時,或者修改 limit range 的時候,這兩種情況都不會影響到已經創建的 Pod/Container。
限定容器的計算資源
假設有一個 Pod 包含 4個容器,每個容器都定義了 spec.resource,此時 LimitRanger 管理控制器在處理該 Pod 中的 4個容器時,處理方式是不一樣的。
演示步驟如下:
1.執行如下命令創建名稱空間 limitrange-demo
kubectl create namespace limitrange-demo
將 kubectl 默認名稱空間切換至 limitrange-demo
kubectl config set-context --current --namespace=limitrange-demo
2.LimitRange 對象的 yaml 文件如下所示:
apiVersion: v1
kind: LimitRange
metadata:
name: limit-mem-cpu-per-container
spec:
limits:
- max:
cpu: "800m"
memory: "1Gi"
min:
cpu: "100m"
memory: "99Mi"
default:
cpu: "700m"
memory: "900Mi"
defaultRequest:
cpu: "110m"
memory: "111Mi"
type: Container
該對象為名稱空間中的容器定義了:
- 最大和最小的CPU/內存
- 默認的 CPU/內存限定
- 默認的 CPU/內存請求
執行命令以創建該對象:
kubectl create -f https://kuboard.cn/statics/learning/policy/lr-container-limit-range.yaml -n limitrange-demo
執行命令查看結果
kubectl describe limitrange/limit-mem-cpu-per-container -n limitrange-demo
Type Resource Min Max Default Request Default Limit Max Limit/Request Ratio
---- -------- --- --- --------------- ------------- -----------------------
Container cpu 100m 800m 110m 700m -
Container memory 99Mi 1Gi 111Mi 900Mi -
3.前面提到的包含 4 個容器的 Pod,其 yaml 文件如下所示:
apiVersion: v1
kind: Pod
metadata:
name: busybox1
spec:
containers:
- name: busybox-cnt01
image: busybox
command: ["/bin/sh"]
args: ["-c", "while true; do echo hello from cnt01; sleep 10;done"]
resources:
requests:
memory: "100Mi"
cpu: "100m"
limits:
memory: "200Mi"
cpu: "500m"
- name: busybox-cnt02
image: busybox
command: ["/bin/sh"]
args: ["-c", "while true; do echo hello from cnt02; sleep 10;done"]
resources:
requests:
memory: "100Mi"
cpu: "100m"
- name: busybox-cnt03
image: busybox
command: ["/bin/sh"]
args: ["-c", "while true; do echo hello from cnt03; sleep 10;done"]
resources:
limits:
memory: "200Mi"
cpu: "500m"
- name: busybox-cnt04
image: busybox
command: ["/bin/sh"]
args: ["-c", "while true; do echo hello from cnt04; sleep 10;done"]
執行命令以創建該 Pod
kubectl apply -f https://kuboard.cn/statics/learning/policy/lr-container-pod.yaml
容器包含有效的 CPU/內存的requests/limits
執行以下命令,查看 busybox-cnt01 的配置信息
kubectl get po/busybox1 -n limitrange-demo -o json | jq ".spec.containers[0].resources"
{
"limits": {
"cpu": "500m",
"memory": "200Mi"
},
"requests": {
"cpu": "100m",
"memory": "100Mi"
}
}
- busybox Pod 中的容器 busybox-cnt01 定義了 requests.cpu=100m 和 requests.memory=100Mi
- 100m <= 500m <= 800m 容器的 cpu limit(500m)在名稱空間 LimitRange 指定的范圍內
- 99Mi <= 200Mi <= 1Gi 容器的內存 limit(200Mi)在名稱空間 LimitRange 指定的范圍內
- 沒有為CPU/內存指定 request/limit 比例
- 此時容器的定義是有效的,將被創建
容器包含有效的 CPU/內存requests且沒有指定limits
執行以下命令,查看 busybox-cnt02 的配置信息
kubectl get po/busybox1 -n limitrange-demo -o json | jq ".spec.containers[1].resources"
{
"limits": {
"cpu": "700m",
"memory": "900Mi"
},
"requests": {
"cpu": "100m",
"memory": "100Mi"
}
}
- busybox Pod 中的容器 busybox-cnt02 定義了 requests.cpu=100m 和 requests.memory=100Mi,且為指定 CPU/內存的最大限定
- 由於容器沒有定義 limits,則名稱空間的 LimitRange 定義的 limits.cpu=700mi 和 limits.memory=900Mi 被注入到該容器
- 100m <= 700m <= 800m 容器的CPU最大限定(700m)在名稱空間 LimitRange 指定的范圍內
- 99Mi <= 900Mi <= 1Gi 容器的內存 limit(900Mi)在名稱空間 LimitRange 指定的范圍內
- 沒有為CPU/內存指定 request/limit 比例
- 此時容器的定義是有效的,將被創建
容器包含有效的CPU/內存limits且沒有指定requests
執行以下命令,查看 busybox-cnt03 的配置信息
kubectl get po/busybox1 -n limitrange-demo -o json | jq ".spec.containers[2].resources"
{
"limits": {
"cpu": "500m",
"memory": "200Mi"
},
"requests": {
"cpu": "500m",
"memory": "200Mi"
}
}
- busybox Pod 中的容器 busybox-cnt03 定義了 limits.cpu=500m 和 limits.memory=200Mi,且沒有指定 CPU/內存的 requests
- 由於容器沒有定義 requests,名稱空間中 LimitRange 定義的 defaultRequest 並沒有注入到容器的 request 字段,反而,容器定義的 limits 被設置到了其 requests 字段: limits.cpu=500m 和 limits.memory=200Mi
- 100m <= 500m <= 800m 容器的 cpu 最大限定(500m)在名稱空間 LimitRange 指定的范圍內
- 99Mi <= 200Mi <= 1Gi 容器的內存最大限定(200Mi)在名稱空間 LimitRange 指定的范圍內
- 沒有為CPU/內存指定 request/limit 比例
- 此時容器的定義是有效的,將被創建
容器不包含CPU/內存的requests/limits
執行以下命令,查看 busybox-cnt04 的配置信息
kubectl get po/busybox1 -n limitrange-demo -o json | jq ".spec.containers[3].resources"
{
"limits": {
"cpu": "700m",
"memory": "900Mi"
},
"requests": {
"cpu": "110m",
"memory": "111Mi"
}
}
- busybox Pod 中的容器 busybox-cnt04 既沒有定義 request,也沒有定義 limits
- 由於容器沒有定義 limits,則名稱空間的 LimitRange 定義的 limits.cpu=700mi 和 limits.memory=900Mi 被注入到該容器
- 由於容器沒有定義 requests,則名稱空間的 LimitRange 定義的 requests.cpu=110m 和 requests.memory=110Mi 被注入到該容器
- 100m <= 700m <= 800m 容器的 cpu 最大限定(700m)在名稱空間 LimitRange 指定的范圍內
- 99Mi <= 900Mi <= 1Gi 容器的內存 limit(900Mi)在名稱空間 LimitRange 指定的范圍內
- 沒有為CPU/內存指定 request/limit 比例
- 此時容器的定義是有效的,將被創建
Pod busybox 中所有的容器都通過了名稱空間的 LimitRange 檢查,此 Pod 將被創建
限定Pod的計算資源
下面是一個用於限定 Pod 資源使用的 LimitRange 對象。
apiVersion: v1
kind: LimitRange
metadata:
name: limit-mem-cpu-per-pod
spec:
limits:
- max:
cpu: "2"
memory: "2Gi"
type: Pod
在開始之前先完成 限定容器 的計算資源,並確保該教程中的 LimitRange limit-mem-cpu-per-container 和 Pod busybox1 都已經創建。
1.執行如下命令,創建 limit-mem-cpu-pod 上面 yaml 中的 LimitRange,該 LimitRange 限定了每一個 Pod 的CPU使用不超過 2 核,內存不超過 2Gi。
kubectl apply -f https://kuboard.cn/statics/learning/policy/lr-pod-limit-range.yaml -n limitrange-demo
執行命令查看 limit-mem-cpu-per-pod 的創建結果:
kubectl describe limitrange/limit-mem-cpu-per-pod -n limitrange-demo
Name: limit-mem-cpu-per-pod
Namespace: limitrange-demo
Type Resource Min Max Default Request Default Limit Max Limit/Request Ratio
---- -------- --- --- --------------- ------------- -----------------------
Pod cpu - 2 - - -
Pod memory - 2Gi - - -
2.創建第二個 Pod,yaml 文件如下:
apiVersion: v1
kind: Pod
metadata:
name: busybox2
spec:
containers:
- name: busybox-cnt01
image: busybox
command: ["/bin/sh"]
args: ["-c", "while true; do echo hello from cnt01; sleep 10;done"]
resources:
requests:
memory: "100Mi"
cpu: "100m"
limits:
memory: "200Mi"
cpu: "500m"
- name: busybox-cnt02
image: busybox
command: ["/bin/sh"]
args: ["-c", "while true; do echo hello from cnt02; sleep 10;done"]
resources:
requests:
memory: "100Mi"
cpu: "100m"
- name: busybox-cnt03
image: busybox
command: ["/bin/sh"]
args: ["-c", "while true; do echo hello from cnt03; sleep 10;done"]
resources:
limits:
memory: "200Mi"
cpu: "500m"
- name: busybox-cnt04
image: busybox
command: ["/bin/sh"]
args: ["-c", "while true; do echo hello from cnt04; sleep 10;done"]
執行如下命令可創建該 Pod
kubectl apply -f https://kuboard.cn/statics/learning/policy/lr-pod-pod.yaml -n limitrange-demo
Pod busybox2 的定義與 busybox1 的定義完全相同,但是執行該創建命令時將碰到如下錯誤,因為Pod可使用的資源現在受到了限制:
Error from server (Forbidden): error when creating "limit-range-pod-2.yaml": pods "busybox2" is forbidden: [maximum cpu usage per Pod is 2, but limit is 2400m., maximum memory usage per Pod is 2Gi, but limit is 2306867200.]
執行命令查看 busybox1 的資源使用
kubectl get po/busybox1 -n limitrange-demo -o json | jq ".spec.containers[].resources.limits.memory"
"200Mi"
"900Mi"
"200Mi"
"900Mi"
Pod busybox2 將不能在集群中創建,因為其中所有容器的內存限制的總和超過了 LimitRange limit-mem-cpu-per-pod 中的限定。 busybox1 將不會被驅逐,因為該 Pod 在創建 LimitRange limit-mem-cpu-per-pod 就已經創建好了。
限定存儲資源
通過 LimitRange 對象,集群管理員可以限定名稱空間中每個 PersistentVolumeClaim(存儲卷聲明)可以使用的最小、最大存儲空間。
請參考下面的例子:
apiVersion: v1
kind: LimitRange
metadata:
name: storagelimits
spec:
limits:
- type: PersistentVolumeClaim
max:
storage: 2Gi
min:
storage: 1Gi
執行命令可創建該 LimitRange:
kubectl create -f https://kuboard.cn/statics/learning/policy/lr-storage-limit.yaml -n limitrange-demo
kubectl describe limits/storagelimits -n limitrange-demo
Name: storagelimits
Namespace: limitrange-demo
Type Resource Min Max Default Request Default Limit Max Limit/Request Ratio
---- -------- --- --- --------------- ------------- -----------------------
PersistentVolumeClaim storage 1Gi 2Gi - - -
現在假設有一個 PVC(存儲卷聲明),定義文件如下所示:
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: pvc-limit-lower
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 500Mi
執行命令創建該 PVC(存儲卷聲明)
kubectl create -f https://kuboard.cn/statics/learning/policy/lr-storage-pvc-lower.yaml -n limitrange-demo
由於 PVC 中定義的字段 requests.storage 比 LimitRange storagelimits 中 limits[0].min.storage 的定義要小,所以創建該 PVC 時將失敗:
Error from server (Forbidden): error when creating "lr-storage-pvc-lower.yaml": persistentvolumeclaims "pvc-limit-lower" is forbidden: minimum storage usage per PersistentVolumeClaim is 1Gi, but request is 500Mi.
如果 PVC 的 requests.storage 大於 LimitRange 中的 limits[0].max.storage,同樣不能創建成功,參考下面的例子:
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: pvc-limit-greater
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 5Gi
執行命令創建該 PVC(存儲卷聲明)
kubectl create -f https://kuboard.cn/statics/learning/policy/lr-storage-pvc-greater.yaml
Error from server (Forbidden): error when creating "lr-storage-pvc-greater.yaml": persistentvolumeclaims "pvc-limit-greater" is forbidden: maximum storage usage per PersistentVolumeClaim is 2Gi, but request is 5Gi.
限定 Limit/Request 比例
如果指定了 LimitRange 對象的 spec.limits.maxLimitRequestRatio 字段,名稱空間中的 Pod/容器的 request 和 limit 都不能為 0,且 limit 除以 request 的結果必須小於或等於 LimitRange 的 spec.limits.maxLimitRequestRatio
下面的例子中 LimitRange 限定了名稱空間中任何 Pod 的最大內存限定(limit)不能超過最小內存請求(request)的兩倍:
apiVersion: v1
kind: LimitRange
metadata:
name: limit-memory-ratio-pod
spec:
limits:
- maxLimitRequestRatio:
memory: 2
type: Pod
執行命令以創建該 LimitRange:
kubectl create -f https://kuboard.cn/statics/learning/policy/lr-ratio-limit-range.yaml -n limitrange-demo
執行命令以查看創建結果:
kubectl describe limitrange/limit-memory-ratio-pod -n limitrange-demo
Name: limit-memory-ratio-pod
Namespace: limitrange-demo
Type Resource Min Max Default Request Default Limit Max Limit/Request Ratio
---- -------- --- --- --------------- ------------- -----------------------
Pod memory - - - - 2
此時,如果我們創建一個 Pod 包含如下屬性 requests.memory=100Mi 和 limits.memory=300Mi:
apiVersion: v1
kind: Pod
metadata:
name: busybox3
spec:
containers:
- name: busybox-cnt01
image: busybox
resources:
limits:
memory: "300Mi"
requests:
memory: "100Mi"
執行命令以創建該 Pod:
kubectl apply -f https://kuboard.cn/statics/learning/policy/lr-ratio-pod.yaml -n limitrange-demo
由於該 Pod 的內存限制請求比例為 3,超過了 LimitRange 中定義的 2,該 Pod 將不能創建成功:
Error from server (Forbidden): error when creating "lr-ratio-pod.yaml": pods "busybox3" is forbidden: memory max limit to request ratio per Pod is 2, but provided ratio is 3.000000.