資源類型
在 Kubernetes 中,Node 提供資源,而 Pod 使用資源。其中資源分為計算(CPU、Memory、GPU)、存儲(Disk、SSD)、網(wǎng)絡(luò)(Network Bandwidth、IP、Ports)。這些資源提供了應(yīng)用運行的基礎(chǔ),正確理解這些資源以及集群調(diào)度如何使用這些資源,對于大規(guī)模的 Kubernetes 集群來說至關(guān)重要,不僅能保證應(yīng)用的穩(wěn)定性,還可以提高資源的利用率。在日常工作中,我們一般比較關(guān)心其中的計算資源,包括CPU和內(nèi)存。CPU 的單位是 core,memory 的單位是 byte。
可壓縮資源
目前kubernetes支持的可壓縮資源是CPU。它的特點是,當可壓縮資源不足時,Pod 只會饑餓少用,但不會退出。CPU 資源的限制和請求以cpu為單位。Kubernetes 中的一個 cpu 就是一個核,就是一個邏輯CPU。一個核相當于1000個微核,即1=1000m,0.5=500m。
不可壓縮資源
目前kubernetes支持的不可壓縮資源是內(nèi)存。它的特點是,當不可壓縮資源不足時,Pod 就會因為 OOM被內(nèi)核殺掉。內(nèi)存的限制和請求以字節(jié)為單位??梢允褂靡韵潞缶Y之一作為平均整數(shù)或定點整數(shù)表示內(nèi)存:E,P,T,G,M,K。還可以使用兩個字母的等效的冪數(shù):Ei,Pi,Ti ,Gi,Mi,Ki。
POD中的資源請求和資源限制
requests 資源請求 pod最低需求(表示Pod對資源的最小需求,因此在調(diào)度的時候會如果Node剩余的資源不能滿足Pod的需求,則不會調(diào)度到對應(yīng)的Node上。Scheduler調(diào)度的時候并不關(guān)注在調(diào)度時具體的資源使用情況,而是根據(jù)現(xiàn)存Pod的資源請求情況來進行調(diào)度。調(diào)度器首先將不符合請求的Node排除在外,然后在執(zhí)行優(yōu)選策略最后在選定pod)
由于 Pod 可以由多個 Container 組成,所以 CPU 和內(nèi)存資源的限額,是要配置在每個Container的定義上的。這樣,Pod 整體的資源配置,就由這些 Container的配置值累加得到。
示例
執(zhí)行下面yaml的內(nèi)容:
[root@k8s-m1 k8s-resource]# cat resource-limit-pod.yaml
apiVersion: v1
kind: Pod
metadata:
name: resource-limit-pod
namespace: default
labels:
name: myapp
spec:
containers:
- name: myapp
image: ikubernetes/stress-ng
command: ["/usr/bin/stress-ng","-c 1","--metrics-brief"]
ports:
- name: http
containerPort: 80
resources:
requests:
memory: "128Mi"
cpu: "200m"
limits:
memory: "512Mi"
cpu: "500m"
[root@k8s-m1 k8s-resource]# kubectl apply -f resource-limit-pod.yaml
pod/resource-limit-pod created
查看結(jié)果:
[root@k8s-m1 k8s-resource]# kubectl exec -it resource-limit-pod -- top
Mem: 7805096K used, 202092K free, 6444K shrd, 2104K buff, 4575292K cached
CPU: 3% usr 1% sys 0% nic 88% idle 6% io 0% irq 0% sirq
Load average: 0.14 0.55 0.71 3/1509 33
PID PPID USER STAT VSZ %VSZ CPU %CPU COMMAND
6 1 root R 6892 0% 15 2% {stress-ng-cpu} /usr/bin/stress-ng -c 1 --metrics-brief
1 0 root S 6244 0% 9 0% /usr/bin/stress-ng -c 1 --metrics-brief
29 0 root R 1500 0% 9 0% top
我們看到CPU占用是3%,為什么呢?因為我的集群node都是是16個core。我們最大限制是0.5核。所以應(yīng)該是0.5/16≈3.1%。
Request和Limits
基于Requests和Limits的Pod調(diào)度機制
- 調(diào)度器在調(diào)度時,首先要確保調(diào)度后該節(jié)點上所有Pod的CPU和內(nèi)存的Requests總和,不超過該節(jié)點能提供給Pod使用的CPU和Memory的最大容量值;
- 即使某節(jié)點上的實際資源使用量非常低,但是已運行Pod配置的Requests值的總和非常高,再加上需要調(diào)度的Pod的Requests值,會超過該節(jié)點提供給Pod的資源容量上限,這時Kubernetes仍然不會將Pod調(diào)度到該節(jié)點上。如果Kubernetes將Pod調(diào)度到該節(jié)點上,之后該節(jié)點上運行的Pod又面臨服務(wù)峰值等情況,就可能導(dǎo)致Pod資源短缺;
Requests和Limits的背后機制
kubelet在啟動Pod的某個容器時,會將容器的Requests和Limits值轉(zhuǎn)化為相應(yīng)的容器啟動參數(shù)傳遞給容器執(zhí)行器。如果是docker 容器:
- spec.container[].resources.requests.cpu: 轉(zhuǎn)化為docker 的–cpu-share;
- spec.container[].resources.limits.cpu: 轉(zhuǎn)為docker的–cpu-quota;
- spec.container[].resources.requests.memory: 提供給Kubernetes調(diào)度器作為調(diào)度和管理的依據(jù),不會作為任何參數(shù)傳遞給Docker;
- spec.container[].resources.limits.memory: 會轉(zhuǎn)為–memory;
QoS(服務(wù)質(zhì)量等級)
Kubernetes是根據(jù)Pod的Requests和Limits配置來實現(xiàn)針對Pod的不同級別的資源服務(wù)質(zhì)量控制。當 Kubernetes 創(chuàng)建一個 Pod 時,它就會給這個 Pod 分配一個 QoS 等級。
QoS分類
- Guaranteed:pod里的每一個container都同時設(shè)置了CPU和內(nèi)存的requests和limits 而且值必須相等。(這類的pod是最高優(yōu)先級)
- Burstable:pod至少有一個container設(shè)置了cpu或內(nèi)存的requests和limits,且不滿足 Guarantee 等級的要求。即內(nèi)存或CPU的值設(shè)置的不同。(中等優(yōu)先級)
- BestEffort:沒有任何一個容器設(shè)置了requests或limits的屬性。(最低優(yōu)先級)
應(yīng)用場景:當宿主機資源緊張的時候,kubelet會根據(jù)服務(wù)質(zhì)量等級對pod進行eviction,即驅(qū)逐pod進行資源回收。
Requests和Limits資源配置特點
- 如果Pod配置的Requests值等于Limits值,那么該Pod可以獲得的資源是完全可靠的;
- 如果Pod的Requests值小于Limits值,那么該Pod獲得的資源可分成兩部分;
完全可靠的資源,資源量的大小等于Requests值;
不可靠的資源,資源量最大等于Limits與 Requests的差額,這份不可靠的資源能夠申請到多少,取決于當時主機上容器可用資源的余量;通過這種機制,Kubernetes可以實現(xiàn)節(jié)點資源的超售(Over Subscription),超售機制能有效提高資源的利用率,同時不會影響容器申請的完全可靠資源的可靠性。
調(diào)度策略的影響
- Kubernetes的kubelet通過計算Pod中所有容器的Requests的總和來決定對Pod的調(diào)度;
- 不管是CPU還是內(nèi)存,Kubernetes調(diào)度器和kubelet都會確保節(jié)點上所有Pod的Requests的總和不會超過在該節(jié)點上可分配給容器使用的資源容量上限;
示例
https://www.cnblogs.com/wtzbk/p/15816291.html
Guaranteed樣例
[root@k8s-m1 k8s-resource]# cat guaranteed-pod.yaml
apiVersion: v1
kind: Pod
metadata:
name: guaranteed-pod
labels:
name: nginx
spec:
containers:
- name: myapp
image: nginx
ports:
- name: http
containerPort: 80
resources:
requests:
memory: "512Mi"
cpu: "500m"
limits:
memory: "512Mi"
cpu: "500m"
[root@k8s-m1 k8s-resource]# kubectl apply -f guaranteed-pod.yaml
pod/guaranteed-pod created
結(jié)果:
[root@k8s-m1 k8s-resource]# kubectl describe po guaranteed-pod
......
Volumes:
default-token-glxls:
Type: Secret (a volume populated by a Secret)
SecretName: default-token-glxls
Optional: false
QoS Class: Guaranteed
Node-Selectors: <none>
.....
更詳細檢查
1)查看該pod被分配到的節(jié)點
[root@k8s-m1 k8s-resource]# kubectl get pod -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
guaranteed-pod 1/1 Running 0 8s 10.244.11.39 k8s-m3 <none> <none>
2)然后到k8s-m3上去查看這個pod里面啟動的容器的資源限制是否生效
[root@k8s-m3 ~]# docker ps |grep guaranteed
434a95e67849 nginx "/docker-entrypoint.…" 6 minutes ago Up 6 minutes k8s_myapp_guaranteed-pod_default_7095c77a-7c31-4a0a-ba1c-c347c690cfe8_0
32a0053da67b registry.aliyuncs.com/google_containers/pause:3.2 "/pause" 6 minutes ago Up 6 minutes k8s_POD_guaranteed-pod_default_7095c77a-7c31-4a0a-ba1c-c347c690cfe8_0
#查看主容器的信息
[root@k8s-m3 ~]# docker inspect 434|egrep -i 'cpu|mem'
"CpuShares": 512,
"Memory": 536870912,
"NanoCpus": 0,
"CpuPeriod": 100000,
"CpuQuota": 50000,
"CpuRealtimePeriod": 0,
"CpuRealtimeRuntime": 0,
"CpusetCpus": "",
"CpusetMems": "",
"KernelMemory": 0,
"KernelMemoryTCP": 0,
"MemoryReservation": 0,
"MemorySwap": 536870912,
"MemorySwappiness": null,
"CpuCount": 0,
"CpuPercent": 0,
關(guān)注Memory、CpuPeriod、CpuQuota這三個值
3)通過cgroup的相關(guān)信息查看
從上面的結(jié)果實際上我們就可以看到這個容器的一些資源情況,Pod 上的資源配置最終也還是通過底層的容器運行時去控制 CGroup 來實現(xiàn)的,我們可以進入如下目錄查看 CGroup 的配置,該目錄就是 CGroup 父級目錄,而 CGroup 是通過文件系統(tǒng)來進行資源限制的,所以我們上面限制容器的資源就可以在該目錄下面反映出來:
##查看CPU的限制##
[root@k8s-m3 ~]# docker exec -it 434 /bin/bash
root@guaranteed-pod:/# cd /sys/fs/cgroup/cpu/
root@guaranteed-pod:/sys/fs/cgroup/cpu# cat cpu.cfs_period_us
100000
root@guaranteed-pod:/sys/fs/cgroup/cpu# cat cpu.cfs_quota_us
50000
root@guaranteed-pod:/sys/fs/cgroup/cpu#
#反向計算出--cpus參數(shù)
#cpu.cfs_quota_us / cpu.cfs_period_us = cpu的限制
50000/100000=0.5核(也就是500m)
##查看內(nèi)存的限制##
root@guaranteed-pod:/sys/fs/cgroup/cpu# cd /sys/fs/cgroup/memory/
root@guaranteed-pod:/sys/fs/cgroup/memory# cat memory.limit_in_bytes
536870912
root@guaranteed-pod:/sys/fs/cgroup/memory#
內(nèi)存的計算方法為:536870912÷1024÷1024÷1024 = 0.5(G)
Burstable樣例
[root@k8s-m1 k8s-resource]# cat burstable-pod.yaml
apiVersion: v1
kind: Pod
metadata:
name: burstable-pod
labels:
name: nginx
spec:
containers:
- name: myapp
image: nginx
ports:
- name: http
containerPort: 80
resources:
requests:
memory: "256Mi"
cpu: "200m"
limits:
memory: "512Mi"
cpu: "500m"
[root@k8s-m1 k8s-resource]# kubectl apply -f burstable-pod.yaml
pod/burstable-pod created
結(jié)果:
[root@k8s-m1 k8s-resource]# kubectl describe po burstable-pod
......
Volumes:
default-token-glxls:
Type: Secret (a volume populated by a Secret)
SecretName: default-token-glxls
Optional: false
QoS Class: Burstable
Node-Selectors: <none>
......
上面Burstable的示例中,可以看到limit和Request都設(shè)置了的,且limit大于Request。大家可以自行測試只設(shè)置其中一個的Qos等級。當只設(shè)置Request時,系統(tǒng)是不會補全limit的相關(guān)配置,也是Burstable。而當只設(shè)置limit時,系統(tǒng)會自動補全Request的相關(guān)配置和limit一樣,Qos是Guaranteed類型。
BestEffort樣例
[root@k8s-m1 k8s-resource]# cat besteffort-pod.yaml
apiVersion: v1
kind: Pod
metadata:
name: besteffort-pod
labels:
name: myapp
tier: appfront
spec:
containers:
- name: http
image: nginx
ports:
- name: http
containerPort: 80
[root@k8s-m1 k8s-resource]# kubectl apply -f besteffort-pod.yaml
kupod/besteffort-pod created
結(jié)果:
[root@k8s-m1 k8s-resource]# kubectl describe po besteffort-pod
......
Volumes:
default-token-glxls:
Type: Secret (a volume populated by a Secret)
SecretName: default-token-glxls
Optional: false
QoS Class: BestEffort
Node-Selectors: <none>
.....
總結(jié):
CPU是可以壓縮資源,所以在CPU不夠的時候會壓縮限流。而內(nèi)存是不可壓縮資源,所以QoS主要用于內(nèi)存限制。
- BestEffort Pod的優(yōu)先級最低,在這類Pod中運行的進程會在系統(tǒng)內(nèi)存緊缺時被第一優(yōu)先殺掉。當然,從另外一個角度來看,BestEffort Pod由于沒有設(shè)置資源Limits,所以在資源充足時,它們可以充分使用所有的閑置資源;
- Burstable Pod的優(yōu)先級居中,這類Pod初始時會分配較少的可靠資源,但可以按需申請更多的資源。當然,如果整個系統(tǒng)內(nèi)存緊缺,又沒有BestEffort容器可以被殺掉以釋放資源,那么這類Pod中的進程可能會被殺掉;
- Guaranteed Pod的優(yōu)先級最高,而且一般情況下這類Pod只要不超過其資源Limits的限制就不會被殺掉。當然,如果整個系統(tǒng)內(nèi)存緊缺,又沒有其他更低優(yōu)先級的容器可以被殺掉以釋放資源,那么這類Pod中的進程也可能會被殺掉;
OOM計分系統(tǒng)
如果kubelet無法在系統(tǒng)OOM之前回收足夠的內(nèi)存,則oom_killer 會根據(jù)內(nèi)存使用比率來計算oom._score, 將得出的結(jié)果和oom_score_adj相加,最后得分最高的Pod會被首先驅(qū)逐。這個策略的思路是,QoS最低且相對于調(diào)度的Request來說消耗最多內(nèi)存的Pod會被首先清除,來保障內(nèi)存的回收。這意味著與Burstable或Guaranteed QoS類別的容器相比,BestEffort這種類別的容器被殺死的可能性更高。
與Pod驅(qū)逐不同,如果一個Pod的容器被oom殺掉,是可能被 kubelet根據(jù)restartpolicy重啟的。
容器中的JVM資源限制
在Kubernetes環(huán)境中部署Java程序不一會就重啟了,這意味著你的pod是不健康的。然后我們可以通過describe去查看一下重啟的原因。發(fā)現(xiàn)是因為Pod超出了資源限制被kill掉,在日志最后一行會出現(xiàn)一個kill的字段。為什么Kubernetes會kill掉,因為它超出了Kubernetes對Pod的資源限制。默認情況下Docker容器會使用宿主機所有的資源,但如果不做資源限制,會影響整個宿主機。然后整個宿主機資源不夠會實現(xiàn)飄移,會轉(zhuǎn)移到其他主機上,然后再異常,可能會起到一種雪崩的效應(yīng),所以一般我們都是要做Pod資源限制。如果Java容器中未設(shè)置JVM的-Xmx(最大的堆內(nèi)存使用)參數(shù),一旦這個Pod的使用內(nèi)存超出Kubernetes的limits限制,Kubernetes就會把它殺掉并重啟一個新的Pod。所以在實際使用中,JVM中的這個值建議要比limits要小一點,小個10%左右,因為超過這個limits限制就可能會被殺死掉再重新起一個Pod。文章來源:http://www.zghlxwxcb.cn/news/detail-583876.html
更多關(guān)于kubernetes的知識分享,請前往博客主頁。編寫過程中,難免出現(xiàn)差錯,敬請指出文章來源地址http://www.zghlxwxcb.cn/news/detail-583876.html
到了這里,關(guān)于【kubernetes系列】kubernetes之計算資源管理的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!