在ACK集群中配置工作負載(Deployment、StatefulSet、DaemonSet、Job、CronJob等)時,您需考慮多種因素,以確保應用可以穩定、可靠地運行。
聲明每個Pod的resource(Request和Limit)
在使用Kubernetes集群時,經常會遇到在一個節點上調度了太多的Pod,導致節點負載過高,無法正常對外提供服務的問題。
為避免上述問題,在Kubernetes集群中部署Pod時,您可以指定該Pod所需的Request及Limit資源,Kubernetes在部署這個Pod的時候,就會根據Pod的需求找一個具有充足空閑資源的節點部署這個Pod。下面的例子中,聲明Nginx這個Pod需要1核CPU,1024MB的內存,運行中實際使用不能超過2核CPU和4096MB內存。
apiVersion: v1
kind: Pod
metadata:
name: nginx
spec:
containers:
- name: nginx
image: nginx
resources: # 資源聲明
requests:
memory: "1024Mi"
cpu: "1000m"
limits:
memory: "4096Mi"
cpu: "2000m"
Kubernetes采用靜態資源調度方式,對于每個節點上的剩余資源的計算為節點剩余資源=節點總資源-已經分配出去的資源
,并不是實際使用的資源。如果您自己手動運行一個資源消耗較大的程序,Kubernetes并不能感知到。
此外,所有Pod都要聲明resources
。沒有聲明resources
的Pod被調度到某個節點后,Kubernetes不會在對應節點上減去這個Pod使用的資源,繼而可能導致該節點上被調度過多Pod。
您可以使用ACK提供的資源畫像功能,基于資源使用量的歷史數據獲得容器粒度的資源規格推薦,簡化為容器配置Request和Limit的復雜度。更多信息,請參見資源畫像。
啟動時等待下游服務,不要直接退出
有些應用可能會有一些外部依賴,例如需要從數據庫(DB)讀取數據或者依賴另外一個服務的接口。應用啟動時,外部依賴未必都能滿足。手動運維時,通常采用依賴不滿足立即退出的方式,也就是所謂的failfast,但在Kubernetes中,這種策略不再適用。這是因為Kubernetes中多數運維操作都是自動操作,無需人工介入。例如,部署應用時,無需自己選擇節點,再到節點上啟動應用;應用fail時,也無需手動重啟,Kubernetes會自動重啟應用;負載增高時,還可以通過HPA自動擴容。
啟動時依賴不滿足的場景下,可以假設有兩個應用A和B,A依賴B且運行在同一個節點上,此節點因為某些原因重啟,重啟后,A首先啟動,B還沒啟動,對于A來說就是依賴不滿足。如果A還是按照傳統的方式直接退出,當B啟動之后,A也不會再啟動,必須人工介入處理。
在Kubernetes集群中,推薦您啟動時檢查依賴,如果不滿足,則進行輪詢等待,而不是直接退出。可以通過 Init Container完成這個功能。
配置restart policy
Pod運行過程中進程退出十分常見。代碼中存在Bug、占用內存太多等,都會導致應用進程退出,繼而導致Pod退出。您可在Pod上配置restartPolicy,實現Pod退出后自動啟動。
apiVersion: v1
kind: Pod
metadata:
name: tomcat
spec:
containers:
- name: tomcat
image: tomcat
restartPolicy: OnFailure
restartPolicy有三個可選值:
Always
:總是自動重啟。OnFailure
:異常退出時自動重啟(進程退出狀態非0)。Never
:從不重啟。
配置Liveness Probe和Readiness Probe
Pod處于Running狀態和Pod能正常提供服務是完全不同的概念。一個Running狀態的Pod,里面的進程可能發生了死鎖而無法提供服務。但是因為Pod還是Running的,Kubernetes也不會自動重啟這個Pod。所以我們要在所有Pod上配置Liveness Probe,探測Pod是否真的存活,是否還能提供服務。如果Liveness Probe發現了問題,Kubernetes會重啟Pod。
Readiness Probe用于探測Pod是否可以對外提供服務。應用啟動過程中需要一些時間完成初始化,在這個過程中是無法對外提供服務的,通過Readiness Probe,可以告訴Ingress或者Service是否可以將流量轉發到這個Pod上。當Pod出現問題時,Readiness Probe可以避免新流量繼續轉發到這個Pod。
apiVersion: v1
kind: Pod
metadata:
name: tomcat
spec:
containers:
- name: tomcat
image: tomcat
livenessProbe:
httpGet:
path: /index.jsp
port: 8080
initialDelaySeconds: 3
periodSeconds: 3
readinessProbe:
httpGet:
path: /index.jsp
port: 8080
每個進程一個容器
很多剛剛接觸容器的人喜歡按照舊習慣把容器當作虛擬機(VM)使用,在一個容器里放置多個進程:監控進程、日志進程、sshd進程,甚至整個Systemd。這樣操作存在兩個問題:
判斷Pod整體的資源占用會變復雜,不方便實施Pod Resource涉及到的Request和Limit。
容器內只有一個進程的情況下,如果進程中斷,外部的容器引擎可以清楚地感知到,并且重啟容器。如果容器內有多個進程,某個進程掛了,容器未必受影響,外部的容器引擎無法感知到容器內有進程退出,也不會對容器做任何操作,但是實際上容器已經不能正常工作了。
如果有幾個進程需要協同工作,在Kubernetes里也可以實現,例如:nginx和php-fpm,通過Unix domain socket通信,我們可以用一個包含兩個容器的Pod,將Unix socket放在兩個容器的共享Volume中。
確保不存在SPOF(Single Point of Failure)
如果應用只有一個實例,當實例失敗的時候,雖然Kubernetes能夠重啟實例,但是中間不可避免地存在一段時間的不可用。甚至更新應用,發布一個新版本的時候,也會出現這種情況。在Kubernetes里,盡量避免直接使用Pod,盡可能使用Deployment/StatefulSet,并且讓應用的Pod在兩個以上。
相關文檔
ACK可實現應用灰度發布、藍綠發布等,請參見應用部署。
關于應用管理的最佳實踐,請參見應用管理最佳實踐。