設置資源請求數量
創建Pod的時候,可以為每個容器指定資源消耗的限制。Pod的資源請求限制則是Pod中所有容器請求資源的總和。
apiVersion: v1
kind: Pod
metadata:
name: requests-pod
spec:
containers:
- image: busybox
command: ["dd", "if=/dev/zero", "of=/dev/null"]
name: main
resources:
requests:
cpu: 200m
memory: 10Mi
如果不指定CPU請求資源,表示不關心容器會分到多少CPU資源,有可能會一直分不到而處於等待狀態。指定資源請求表示Pod對資源的最小需求,因此在調度的時候會如果Node剩余的資源不能滿足Pod的需求,則不會調度到對應的Node上。Scheduler調度的時候並不關注在調度時具體的資源使用情況,而是根據現存Pod的資源請求情況來進行調度。這就會有問題,特別是當允許Pod使用超過請求的資源時。下面的圖一看就能理解。

調度判斷首先將不符合請求的Node排除在外,然后將符合要求的Node進行排序。節點排序根據資源請求數量的不同分為兩個策略,LeastRequestPolicy和MostRequestPolicy。從字面上我們可以看到,一個是優先分派到資源請求少的節點,一個是優先分派到資源請求多的節點。一般在生產環境,建議使用LeastRequestPolicy,便於將負載平均的分配到各個機器上。在公有雲的環境中建議使用MostRequestPolicy,提高資源的利用率,減少成本。
在沒有設置資源使用限制的情況下,Pod可能使用超過請求的資源數量。對於CPU資源來說,如果同時有兩個Pod請求剩余的資源,在分配剩余資源時,調度器會根據請求數量的比例在不同的Pod間分配資源。例如Pod A請求100m的CPU,Pod B請求20m的CPU,在兩個Pod中CPU使用超過請求時,會根據5:1的比例分配。

使用kubectl describe nodes命令可以查看Node資源使用的情況。

如果Kubernetes找不到滿足資源請求的Node,則Pod創建會停留在Pending狀態。
設置資源使用上限
Pod創建的時候,可以設置每個容器使用資源的上限,可以限制的資源包括CPU、內存等。如果不設置上限,則理論上可以使用Node的全部資源。如果要防止Node上的各個容器互相影響,最好為Pod指定上限。
CPU是一種可以壓榨的資源,可以用滿並且Pod之間不會互相影響。內存則不一樣,Pod之間分配的內存不能互相使用。requests的資源數量必須與Node容量一樣或者更小,limits資源數量的總和可以超過Node的容量。當節點的資源被全部使用完后,一些容器可能會被殺掉。特別是使用內存超限后,會被Kubernetes進行OOMKilled。如果這個Pod的重啟策略是Always,很可能你都沒注意到Pod被重啟了,但是隨着發生次數的增多,每次重啟delay的時間就會增加。
apiVersion: v1
kind: Pod
metadata:
name: limit-pod
spec:
containers:
- image: busybox
command: ["dd", "if=/dev/zero", "of=/dev/null"]
name: main
resources:
requests:
cpu: 200m
memory: 10Mi
limits:
cpu: 1
memory: 20Mi
容器中運行top命令你會發現,容器中能看到的CPU、內存總量是Node的總量。這樣就會造成一些應用能夠探測到的容量和Limits的限制不一樣,從而造成使用超出請求的情況。

對於CPU、內存來說,可以利用Metadata獲取的三種方式中提到的辦法通過API來獲取限制的大小,也可以在
/sys/fs/cgroup/cpu/cpu.cfs_quota_us、/sys/fs/cgroup/cpu/cpu.cfs_period_us來查看。
QoS:Pod Kill的策略
在Pod使用的資源超過Node容量時,Kubernetes為了保障Node的運行,會選擇其中的一些Pod並殺掉,那么如何確定殺掉哪個Pod呢,這里就需要引入一個QoS的概念。
QoS是 Quality of Service,有三種Quality of Service 策略,Kubernetes依次選擇三種策略的Pod進行Kill。如果兩個的QoS一樣,則選擇資源利用率高的Kill。
- BestEffort 應用到沒有資源限制的Pod上,可以使用盡可能多的資源,也可能第一個被殺死
- Burstable limits超過requests的Pod類型
- Guaranteed 適用於請求和上限一致的Pod(limits默認與requests相同),這種Pod不能使用超額的資源,但是會保證存活
對於單容器的Pod,遵循以下原則

對於多個容器的Pod,如果兩個容器的策略不一致,就使用Burstable策略,一致則使用容器的策略。

設置Pod/Container的默認請求和限制 LimitRange
通過創建LimitRange對象,在一個命名空間內,可以為所有創建的Pod設置一個磨人的requests和limits的限制。
apiVersion: v1
kind: LimitRange
metadata:
name: limitrange-demo
spec:
limits:
- type: Pod
min:
cpu: 50m
meomery: 5Mi
max:
cpu: 1
meomery: 1Gi
- type: Container
defaultRequest:
cpu: 100m
memory: 10Mi
default:
cpu: 200m
memory: 100Mi
min:
cpu: 50m
memory: 5Mi
max:
cpu: 1
memory: 1Gi
maxLimitRequestRatio:
cpu: 4
memory: 10
- type: PersistentVolumeClaim
min:
storage: 1Gi
max:
storage: 10Gi
創建一個不符合LimitRange要求的Pod,則會出現以下報錯。

設置集群的資源Quota
除了設置每個Pod的默認上限外,還可以通過ResourceQuota設置集群的可用資源上限。ResourceQuota可以設置一個集群可用的最大計算資源的數量,也可以設置用戶可以創建的各種對象的數量。
apiVersion: v1
kind: ResourceQuota
metadata:
name: cpu-and-mem
spec:
hard:
requests.cpu: 400m
requests.memory: 200Mi
limits.cpu: 600m
limits.memory: 500Mi
查看當前的資源限制

還可以限制存儲及各種對象的數量,具體參考下面的yaml。
apiVersion: v1
kind: ResourceQuota
metadata:
name: storage-object
spec:
hard:
pods: 10
replicationcontrollers: 5
secrets: 10
configmaps: 10
persistentvolumeclaims: 4
services: 5
services.loadbalancers: 1
services.nodeports: 2
ssd.storageclass.storage.k8s.io/persistentvolumeclaims: 2
設置的Quota默認在命名空間內生效,也可以根據QoS來設定不同的生效范圍。
apiVersion: v1
kind: ResourceQuota
metadata:
name: quota-qos
spec:
scopes:
- BestEffort
- NotTerminating
hard:
pods: 4
一共有四種策略:BestEffort、NotBestEffort、Terminating、NotTerminating。前兩個根據QoS來選擇Pod,后兩個根據Pod是否設置了activeDeadlineSeconds屬性來選擇。看下圖就能夠明白了。

監控
Kubernetes本身包含了cAdvisor來監控容器和節點的運行情況,如果想要從整體上看資源的使用情況需要安裝Heapster組件。但是這兩個
kubectl top node
kubectl top pod
kubectl top pod --container
使用這兩個命令可以查看短時間內的Pod、Node資源使用的情況,也可以查看每個容器資源使用的情況。如果想要將性能數據保存下來,需要安裝heapster\influxdb\grafana。具體不在這篇文章中講解了。
參考資料:
