1.1在kubernetes叢集中,為了使得系統能夠穩定的執行,通常會對Pod的資源使用量進行限制。在kubernetes叢集中,如果有一個程式出現異常,並且佔用大量的系統資源,如果沒有對該Pod進行資源限制的話,可能會影響其他的Pod正常執行,從而造成業務的不穩定性。
1.2正常情況下我們在一個宿主機的核心之上,這個宿主機可能管理了一組硬體包括CPU、記憶體。而後在這個宿主機的核心之上,我們可以執行多個容器,這些容器將共用底層的同一個核心,很顯然,硬體是屬於核心的,因此任何容器中的每一個程序預設可以請求佔有這個核心管理的所有的可用硬體資源。
1.3尤其是多租戶的環境當中,有人惡意的執行了一個容器,這個容器可能會大量的佔用CPU和記憶體,進而會導致其他容器無法執行,Docker容器啟動的時候預設是在核心的名稱空間級別進行了隔離,在程序所執行的資源範圍上並沒有做太多的隔離操作。我們應該為每個應用設定內部程序執行最為合理的資源的最小保證量和最大保證量。
1.4官方檔案:https://kubernetes.io/zh-cn/docs/tasks/configure-pod-container/assign-cpu-resource/
spec.containers[].resources.request.cpu # Pod申請時的CPU,如果節點沒有足夠大,則Pod排程失敗
spec.containers[].resources.request.memory # Pod申請時的記憶體
spec.containers[].resource.limits.cpu # Pod最大可使用的CPU
spec.containers[].resource.limits.memory # Pod最大可使用的記憶體
3.1我們為什麼要進行資源限制?
4.1CPU限制單位
1核CPU=1000毫核,當定義容器為0.5時,所需要的CPU資源是1核心CPU的一般,對於CPU單位,表示式0.1等價於表示式100m,可以看作是100millicpu;
1核=1000millicpu (1 Core=1000m)
0.5核=500millicpu (0.5 Core=500m)
4.2記憶體限制單位
記憶體的基本單位是位元組數(Bytes),也可以使用E、P、T、G、M、K作為單位字尾,或Ei、Pi、Ti、Gi、Mi和Ki形式單位字尾;
1MB=1000KB=1000000Bytes
1Mi=1024KB=1048576Bytes
5.1.1設定容器的CPU請求與限制;
需安裝Metrics-Server才能用top命令否則無法使用;
# 建立一個具有一個容器的Pod,容器將請求0.5個CPU,最多限制1個CPU;
root@kubernetes-master01:~# cat cpu-requests-limits.yaml
apiVersion: v1
kind: Pod
metadata:
name: cpu-test-cpu-limits
spec:
containers:
- name: cpu-test-stress
image: registry.cn-hangzhou.aliyuncs.com/lengyuye/stress:latest
args:
- -cpus # 容器嘗試使用2核CPU
- "2"
resources:
requests: # 限制Pod最多可申請0.5核CPU
cpu: "500m"
limits: # 限制Pod最大可使用1核CPU
cpu: "1000m"
root@kubernetes-master01:~# kubectl apply -f cpu-requests-limits.yaml
pod/cpu-test-cpu-limits created
# 檢視資源限制情況,容器設定去嘗試使用2個CPU,但是容器只能被允許使用1個CPU;
root@kubernetes-master01:~# kubectl top pods cpu-test-cpu-limits
NAME CPU(cores) MEMORY(bytes)
cpu-test-cpu-limits 999m 1Mi
5.1.2建立一個Pod,設定該Pod中容器請求為100核,這個值會大於叢集中所有記憶體的總和;
root@kubernetes-master01:~# cat cpu-requests-limits.yaml
apiVersion: v1
kind: Pod
metadata:
name: cpu-test-cpu-limits
spec:
containers:
- name: cpu-demo-ctr
image: registry.cn-hangzhou.aliyuncs.com/lengyuye/stress:latest
args:
- -cpus
- "2"
resources:
requests:
cpu: "100" # 設定Pod申請100GB,我們叢集上沒有100GB的資源
limits:
cpu: "100" # 最大使用100GB,叢集資源不足,無法建立;
root@kubernetes-master01:~# kubectl apply -f cpu-requests-limits.yaml
pod/cpu-test-cpu-limits created
# 檢視Pod的狀態,為Pending,Pod未被排程到任何節點上;
root@kubernetes-master01:~# kubectl get pods
cpu-test-cpu-limits 0/1 Pending 0 4s
# 檢視Events,輸出顯示由於3節點的CPU資源不足,無法進行排程;
root@kubernetes-master01:~# kubectl describe pods cpu-test-cpu-limits
Type Reason Age From Message
---- ------ ---- ---- -------
Warning FailedScheduling 113s default-scheduler 0/3 nodes are available: 3 Insufficient cpu.
Warning FailedScheduling 113s default-scheduler 0/3 nodes are available: 3 Insufficient cpu.
5.1.3如果不指定CPU的Limits?
如果沒有為容器設定CPU限制,那麼容器在可以使用的CPU資源是沒有上限的,因而可以使用所在節點上的所有可用CPU資源,這樣會造成某一個Pod佔用了大量的CPU,可能會影響其他Pod的正常允許,從而造成業務的不穩定性。
5.2.1設定容器的記憶體請求與限制;
建立一個1個容器Pod,容器會將請求100MB記憶體,並且最大可用記憶體為200MB以內;
root@kubernetes-master01:~# cat memory-requests-limits.yaml
apiVersion: v1
kind: Pod
metadata:
name: pod-memory-resource
spec:
containers:
- name: momory-demo-stress
image: registry.cn-hangzhou.aliyuncs.com/lengyuye/stress:latest
command: ["stress"]
args: ["--vm", "1", "--vm-bytes", "150M", "--vm-hang", "1" ]
resources:
requests:
memory: "100Mi" # 設定最小請求為100Mi
limits:
memory: "200Mi" # 最大可使用200Mi
root@kubernetes-master01:~# kubectl apply -f memory-requests-limits.yaml
pod/pod-memory-resource created
# 獲取Pod的記憶體使用資訊,輸出結果顯示Pod正在使用的記憶體約為150Mi,大於Pod請求的100Mi,但是在Pod限制的200Mi之內。
root@kubernetes-master01:~# kubectl top po pod-memory-resource
NAME CPU(cores) MEMORY(bytes)
pod-memory-resource 43m 151Mi
# 也可用通過Yaml檔案的方式來看limits最大可使用為200Mi
resources:
limits:
memory: 200Mi
requests:
memory: 100Mi
5.2.2執行超過容器記憶體限制的應用
當節點擁有足夠的可用記憶體時,容器可用使用其請求的記憶體,但是,容器不允許使用超過其限制的記憶體。如果容器分配的記憶體超過其限制,該容器會成為被終止的候選容器。如果容器繼續消耗超過其限制的記憶體,則終止容器。如果終止的容器可以被重啟,則kubelet會重新啟動它。
5.2.2.1建立一個Pod,擁有一個Containers,該容器的記憶體請求為100Mi,記憶體限制為200Mi,嘗試分配超出其限制的記憶體;
root@kubernetes-master01:~# cat memory-requests-limits.yaml
apiVersion: v1
kind: Pod
metadata:
name: pod-memory-resource
spec:
containers:
- name: momory-demo-ctr
image: registry.cn-hangzhou.aliyuncs.com/lengyuye/stress:latest
command: ["stress"]
args: ["--vm", "1", "--vm-bytes", "250M", "--vm-hang", "1" ] # 強行分配250M
resources:
requests:
memory: "100Mi"
limits:
memory: "200Mi" # 我們上限不能超過200,超過200Mi會發生OOM Kill
root@kubernetes-master01:~# kubectl apply -f memory-requests-limits.yaml
# 檢視Pod,此時容器被殺死;
root@kubernetes-master01:~# kubectl get pods -w
pod-memory-resource 0/1 OOMKilled 0 9s
pod-memory-resource 0/1 OOMKilled 1 11s
pod-memory-resource 0/1 CrashLoopBackOff 1 12s
# 檢視更詳細的資訊,顯示為OOMKilled;
root@kubernetes-master01:~#kubectl get pod pod-memory-resource -o yaml
lastState:
terminated:
containerID: docker://3d6e53a12a101f474d24c00b8e9c5b1e6da2ef26735b6e2cb6790184c6d69cfa
exitCode: 1
finishedAt: "2022-07-27T06:40:07Z"
reason: OOMKilled
5.2.3超過節點的記憶體分配
Pod的排程基於請求,只有當前節點擁有足夠滿足Pod記憶體請求的記憶體時,才會將Pod排程至該節點執行;
5.2.3.1建立一個Pod,其擁有一個請求1000GB記憶體的容器,超出了叢集任何一個節點所擁有的記憶體;
root@kubernetes-master01:~/cloud-Native/resource# cat memory-requests-limits.yaml
apiVersion: v1
kind: Pod
metadata:
name: pod-memory-resource
spec:
containers:
- name: momory-demo-ctr
image: registry.cn-hangzhou.aliyuncs.com/lengyuye/stress:latest
command: ["stress"]
args: ["--vm", "1", "--vm-bytes", "250M", "--vm-hang", "1" ]
resources:
requests:
memory: "100Gi"
limits:
memory: "200Gi"
root@kubernetes-master01:~# kubectl apply -f memory-requests-limits.yaml
# 檢視Pod狀態,發現處於pending,這意味著該Pod未被排程至任何節點;
root@kubernetes-master01:~# kubectl get pods -w
pod-memory-resource 0/1 Pending 0 6s
# 通過describe檢視更詳細資訊;顯示為由於節點記憶體不足,該容器無法被排程;
root@kubernetes-master01:~# kubectl describe pods pod-memory-resource
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Warning FailedScheduling 2m21s default-scheduler 0/3 nodes are available: 3 Insufficient memory.
Warning FailedScheduling 2m20s default-scheduler 0/3 nodes are available: 3 Insufficient memory.
5.2.4如果沒有指定記憶體限制;
如果為容器指定記憶體限制,容器可以無限的使用其所在節點的所有可用記憶體,進而可能導致該節點呼叫OOM Killer。此外如果發生OOM Kill,沒有設定資源限制的容器將被殺死的可能性會更大。
kubernetes允許節點資源對limits的過載使用,這意味著節點無法同時滿足其上的所有Pod物件以資源滿載的方式執行,於是在記憶體資源緊缺時,應該以何種次序先後終止哪些Pod物件?
kubernetes無法自行對此做出決策,它需要藉助於Pod物件的優先順序判定,根據Pod物件的Requests和Limits屬性,kubernetes將Pod物件歸類到BestEffort、Burstable和Guaranteed三個服務質量(Quality of Service,QOS);
6.1.1Guaranteed: Pod物件為每個容器都設定了CPU資源需求和資源限制,且兩者的值相同,還同時為每個容器設定了記憶體需求與記憶體限制,並且兩者的值相同,這類Pod物件具有最高階別服務質量。
6.1.2Burstable: 至少有一個容器設定了CPU或記憶體資源Requests屬性,但不滿足Guaranteed,這類Pod具有中級服務質量;
6.1.3BestEffort: 沒有為任何容器設定Requests和Limits屬性,這類Pod物件服務質量是最低階別。
1.當kubernetes叢集記憶體資源緊缺,優先殺死BestEffort類別的容器,因為系統不為該類資源提供任何服務保證,但是此類資源最大的好處就是能夠儘可能的使用資源。
2.如果系統中沒有BestEffort類別的容器,接下來就輪到Burstable類別的容器,如果有多個Burstable類別的容器,就看誰的資源佔用多就優先殺死誰。對於Guaranteed類別的容器擁有最高優先順序,他們不會被殺死,除非其記憶體需求超限,或OMM時沒有其他更低優先順序的Pod物件存在,才幹掉Guaranteed類容器;