使用Kubernetes
去創建Deployment, StatefulSet和DaemonSet等controller
,或直接創建pod
時,可設置內部容器的Requests
和Limits
,這裏有不少地方需要注意,以下作記錄和總結。
-
Requests
用於pod的調度, kube scheduller在一系列條件篩選後(taints 和 affinity等),當然也有predicate預選和priority等過濾過程, 最後使用round robin
算法將pod
調度到滿足Requests
資源要求的Node上。 -
Limits
用於限制pod
的資源使用量。 -
若
pod
包含多個container
,則該pod
的調度和資源限制分別由pod
內container
的Requests
總量和Limits
總量來決定。 -
Limits
的值不能低於Requests
的值,否則apiserver
會報錯。 -
Limits
中,CPU
和Memory
某一項超過kubernetes
集羣內最大節點配置,則該pod
將永遠不會被調度到Node
上。除非一些雲服務商會配置vm
伸縮策略去實時增加vm
到kubernetes
集羣上,如GKE。 -
除非部署的
app
使用多線程模型,能利用多cpu
核操作,否則建議使用1核或以下配置,並配合多實例使用。 -
當某
containe
r對CPU
的使用量超過Limits
時,由於CPU
是可壓縮資源,kubernetes
會限制該container
的CPU
使用量, 導致container
的性能下降, 但contianer
不會退出或停止。可使用liveness health check 對container
進行健康檢查。 -
當某
container
對Memory
的使用量超過Limits
時,kubernetes
不能限制Memory
的使用,但是會讓container
停止,若該container
對應的pod
是由deployment
來控制的話,則會使得pod
不斷地重啓。系統傾向於在其原所在的機器上重啓該container
。 -
當某節點內所有的
containers
的Limits
總量超過該節點的可用資源capacity
時,這時候kubernetes進入overcommitted 狀態:- 節點的
Memory
使用量用滿時,kubernetes
會啓動算法去刪除超出Request
申請量的container
。若存在多個這樣的container
, 則根據priority
和Request
的超出量來決定。 - 按照Qos的規範,刪除的順序爲
Best-Effort pods -> Burstable pods -> Guaranteed pods
。源碼kubernetes\pkg\kubelet\qos\policy.go
- 節點的
cpu
使用量用滿時,kubernetes
壓縮各container
的cpu
使用量,同時會確保各container
能使用其在Requests
指定的使用量。
- 節點的
-
DaemonSet
不適合創建BestEffort
類型的Pods
,而通常應該爲Guaranteed
類型Pods
更爲恰當。因爲當節點資源緊張時,BestEffort
類型的Pods
會被優先驅散,但是由於DaemonSet
的特性,Pod
在驅散後仍會在原節點啓動。 -
可以通過設置ResourceQuotas對象來限制命名空間下的所有
container
的Requests
和Limits
的總量。 -
可以通過設置LimitRanges來限制(或提供默認值)每一個
container
的Requests
和Limits
-
關於kube scheduller的調度原理及其源碼分析,參見此文章足矣。
-
關於
Requests
和Limits
的底層實現機制:
-
pod
被刪除的過程,過程分爲若干階段:pod
首先進入默認的30sgrace period
,可通過pod
的terminationGracePeriodSeconds
調整grace period
的大小。pod.state
=Terminating
,service
對應的endpoint
會被清理,pod
不再接收訪問流量。此過程是滾動式的,保證服務的可用性。此時pod
內的container
運行不會受影響。kubernetes
同時執行preStop Hook 指定的指令。若app
中已有邏輯捕獲SIGTERM
信號(在golang
開發的web service
的場景中,程序中利用signal
庫實現SIGTERM
信號的捕獲並實施一些列的回收釋放操作(數據庫連接池回收,日誌服務回收等,同時調用net/http
中的Shutdown
方法,使得web service
同樣能夠gracefully shut down
),則可不指定preStop Hook
。SIGTERM
信號同時傳輸到pod
內的container
的pid
爲1
的進程。- 若在
terminationGracePeriodSeconds
未執行完preStop Hook
或app
捕獲SIGTERM
信號後的清理邏輯,SIGKILL
則會發送到container
。同時kubernetes
會清理所有container
所涉及到的Object
。此後不能從apiserver
查詢到該pod
。
-
對於
Golang
編寫的app
而言, 當其用容器環境部署的時候,會默認設置P
(GOMAXPROCS
)的個數爲CPU
核數,而一般docker
容器內沒有屏蔽cpu
信息, 會導致GOMAXPROCS
數量大於實際可用值, 這時可依賴第三方包從cgroup
中獲取正確的cpu
份額信息, 如https://godoc.org/go.uber.org/automaxprocs
。 否則會導致app
性能下降, 過多的P
導致過多的上下文切換context switch
。
Reference:
https://cloud.google.com/blog/products/gcp
https://www.gnu.org/software/libc/manual/html_node/Termination-Signals.html
https://medium.com/@betz.mark/understanding-resource-limits-in-kubernetes-cpu-time-9eff74d3161b
https://kubernetes.io/docs/tasks/administer-cluster/out-of-resource/