k8s系列文章:
Pod是k8s中最小的排程單元,包含了一個“根容器”和其它使用者業務容器。
如果你使用過k8s的話,當然會瞭解pod的基本使用,但是為了更好的應用,你需要深入瞭解pod的配置、排程、升級和擴縮容等。本文將會更進一步的介紹pod。
基礎
為什麼需要pod?
pod包含一個或多個相對緊密耦合的容器,處於同一個pod中的容器共享同樣的儲存空間、IP地址和Port埠。
為什麼k8s要設計出Pod這個概念並作為最小排程單元呢?
直接部署一個容器可能會更加容易,每個容器都有不同的配置和功能,k8s需要對這些容器進行管理(重啟、檢測等),那麼為了避免在容器這個實體上增加更多的屬性,就產生了pod這個概念。
並且,Pod中的多個業務容器共享Pause容器的IP,共享Pause容器掛接的Volume,這樣既簡化了密切關聯的業務容器的通訊問題,也很好的解決了它們之間的檔案共享問題。
容器配置
pod可以由一個或多個容器組合而成,也就是說, 在建立pod時可以給一個pod配置多個container,一般情況下,建議將應用緊耦合的容器打包為一個pod,原則上一個容器一個程式。
共享Volume
同一個pod中的多個容器能夠共享pod級別的儲存卷Volume,多個容器各自掛載,將一個volume掛載為容器內部需要的目錄。
Pod通訊
k8s為每個pod都分配了唯一的IP地址,稱之為pod IP,一個pod中的多個容器共享Pod IP地址,屬於同一個pod的多個應用之間相互訪問時僅通過localhost就可以通訊。
k8s底層支援叢集內任意兩個pod之間的TCP/IP直接通訊,因此,在k8s中,一個pod中的容器可以與另外主機上的pod裡的容器直接通訊。
容器限制
需要注意的是:pod中長時間執行的容器需保證其主程式一直在前臺執行。比如建立docker映象時啟動命令是通過nohup在後臺執行的:
nohup ./start.sh &
那麼kubelet建立了包含這個容器的pod之後執行完這個命令,則會根據配置發生兩種情況:
- 如果pod未配置RC,則認為該pod執行結束,將立刻銷燬該pod。
- 如果pod配置了RC,該pod終止以後,k8s會根據RC的數量生成新的pod,會陷入一個 銷燬-> 建立的無限迴圈中。
如果無法前臺執行,只能後端執行的話,該怎麼辦呢?
可以藉助supervisor。
配置管理
應用部署的一個最佳實踐就是將配置資訊和程式進行分離,在k8s中可以使用configmap實現。
詳細使用可參考:K8S configmap使用
生命週期和重啟策略
在建立pod出錯了,通常會看到pending狀態,而你使用 kubectl get pods 時,也偶爾會看到重啟這個欄位,那麼pod的生命週期和重啟策略具體是怎麼實現的呢?
一個pod的狀態資訊是儲存在PodStatus物件中的,phase欄位用來描述pod在其生命週期中的不同狀態,包括:
狀態 | 說明 |
---|---|
Pending | 掛起。有一個或多個容器未被建立,可以通過kubectl get po ** 檢視原因。 |
running | 執行中。所有容器已被建立,至少有一個是執行狀態,可通過kubectl logs -f ** 檢視日誌 |
succeeded | 成功。所有容器執行成功並終止,不會再次重啟。 |
failed | 失敗。所有容器都已終止,至少有一個容器以失敗的方式終止。 |
unknown | 未知。一般是因為通訊問題無法獲取pod的狀態 |
Pod通常使用探針來檢測容器內的應用是否正常,有兩類探針:
- LivenessProbe探針:判斷容器是否存活(Running狀態)
- ReadinessProbe探針:判斷容器是否可用(Ready狀態)
在Pod發生故障時對Pod進行重啟(僅在Pod所處的Node上操作),具體的方式包括:
操作方式 | 說明 |
---|---|
Always | 容器失效時,自動重啟 |
OnFailure | 容器以不為0的狀態碼終止,自動重啟 |
Never | 無論何種狀態,都不會重啟 |
其中,Pod的重啟策略與控制方式息息相關,不同的控制器對pod的重啟策略要求不一樣:
- RC和DaemonSet:必須設定為Always,需要保證容器持續執行
- Job:onfailure或者Never,保證容器執行完成後不再重啟。
Pod排程
在使用K8S時,我們很少直接建立Pod,大多數情況都是會通過RC、Deployment、DaemonSet、Job等控制器來實現對一組Pod副本的建立、排程和全生命週期的自動控制。
官方建議:不應該使用底層的ReplicaSet來控制Pod副本,推薦直接使用管理ReplicaSet的Deployment物件來控制Pod副本。
全自動排程
Deployment或RC的主要功能之一就是自動部署一個容器應用的多份副本,持續監控副本的數量,保證叢集內始終維持指定的副本數量。建立的pod完全由系統自動完成排程,pod各自執行在哪個節點上,完全由master scheduler計算出一個最佳的目標節點進行分配,使用者無法干預。
舉個例子:
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx
spec:
replicas: 3
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:1.0
ports:
- containerPort: 80
使用kubectl create -f **.yaml建立該Deployment。
使用kubectl get deployments,就會發現剛才建立的deployment有三個副本。
使用kubectl get rs和kubectl get pods可檢視已建立的RS和pod,使用kubectl get pod -o wide可以檢視pod的分配情況。
定向排程
在實際應用中,經常會需要將Pod排程到指定的一些Node節點上,這時候可配置NodeSelector或者NodeAffinity來進行定向排程。
NodeSelector
具體的使用:
- 通過kubectl label命令給目標Node打上標籤,可通過kubectl label nodes命令檢視所有節點的標籤;
- 在Pod的定義中加上NodeSelector的設定
- 執行kubectl create -f 命令建立Pod時,scheduler就會將pod自動排程指定標籤的Node上。
NodeAffinity(節點親和力排程)
NodeSelector通過標籤機制,簡單的限制了Pod所在節點的方法,親和力排程機制則更好擴充套件了Pod的排程能力,可以使用軟限制,支援In、NotIn、Exists、DoesNotExist、Gt、LT等操作符。
- 可依據節點上正在執行的其它Pod的標籤來進行限制,而非節點本身的標籤。
需要注意以下幾點:
- 如果同時定義了nodeSelector和nodeAffinity,則必須兩個條件都滿足
- 如果nodeAffinity指定了多個nodeSelectorTerms,則其中一個匹配成功即可。
- 如果nodeSelectorTerms中有多個matchExpressions。則一個節點必須滿足所有matchExpressions才能執行該Pod
PodAffinity(Pod親和與互斥排程)
根據節點上正在執行的Pod標籤而非節點的標籤進行判斷和排程,對節點和Pod兩個條件進行匹配。
具體的使用:
- 建立一個名為pod-flag的pod,設定標籤
- 親和性排程:建立pod-flag在同一個Node節點的pod
- 互斥性排程:可建立與pod-flag不在同一個Node節點的pod
DaemonSet
用於管理在叢集的每個Node上僅執行一份pod的副本例項。適用場景:日誌採集、效能監控等。
優先排程
為了提高資源利用率,我們通常會採用優先順序方案,即不同型別的負載對應不同的優先順序,並且當發生資源不足時,系統可以選擇釋放一些不重要的負載,保障最重要的負載以獲取足夠的資源穩定執行。
優先順序搶佔排程策略的有兩個核心點:
- 驅逐(Eviction):kubelet的行為,當一個Node發生資源不足時,該結點上的kubelet程式會綜合考慮優先順序、資源申請量和實際資源使用等進行驅逐
- 搶佔(Preemption):scheduler的行為,當一個新的pod因資源無法滿足而不能排程時,scheduler可能會選擇(跨節點或本節點)驅逐部分低優先順序的pod例項來滿足排程
批處理排程 Job
可以通過Job來定義並啟動一個批處理任務(並行啟動多個程式去處理一些工作項),處理完成後,整個批處理任務結束。
定時任務 Cronjob
類似Linux Cron的定時任務Cron Job。
除此以外,你還可以自定義排程器。
升級和回滾
為了保證服務的高可用,k8s提供了滾動升級功能。主要介紹下deployment。
Deployment
升級
更新映象名的話,有以下方法進行更新:
- 通過
kubectl set image
命令設定新的映象名 - 使用
kubectl edit
命令修改Deployment的配置,根據yaml的結構更新(比如:將spec.template.spec.containers[0].image從nginx:1.0改為nginx:1.1)。
對於RC的滾動升級,可以使用kubectl rolling-update
命令,該命令會建立一個新的RC,自動控制舊的RC中pod副本數量逐漸減少到0,新的RC中的Pod副本數量從0逐步增加到目標值。
一旦pod的定義發生了修改,則將觸發系統完成Deployment中所有pod的滾動操作,可使用kubectl rollout status
檢視滾動更新過程。
在升級過程中,deployment能夠保證服務不中斷,並且副本數量始終維持在使用者指定數量。可在Deployment定義中,通過spec.strategy指定pod的更新策略,包括:
- Recreate 重建
- RollingUpdate 滾動更新
回滾
服務穩定性或者配置錯誤等原因會使得我們需要進行回滾,Deployment的所有釋出歷史記錄都被保留在系統中,所以回滾是很方便的。具體操作:
- 用kubectl rollout history檢視deployment的部署歷史記錄,確定要回退的版本,可以加上--revision=
引數檢視特定版本詳情 - 回退到上一個版本或者指定版本
- kubectl describe deployment檢視操作過程
對於相對複雜的配置修改,為了避免頻繁大量觸發更新操作,可使用kubectl rollout pause
命令暫停更新操作,然後進行配置修改,最後恢復deployment,一次性觸發完整的更新操作。
擴縮容
伴隨著資源的使用情況,常需要對pod進行擴縮容,可以利用Deployment/RC的Scale機制來實現,分為手動和自動兩種模式。
手動
通過kubectl scale deployment *** --replicas 3
命令更新Pod副本數量,將--replicas設定比當前pod副本數量更小的數字的話,系統會kill一些正在執行的pod。
自動
使用者指定pod副本的數量範圍,設定依據的效能指標或者自定義業務指標,系統將自動的在這個範圍內根據效能指標變化調整pod副本數量。
k8s 1.1版本開始新增了HPA控制器,基於Master的kube-controller-manager服務啟動引數--horizontal-pod-autoscal-sync-period定義的探測週期,週期性檢測目標pod的資源效能指標。並與設定的擴容條件進行對比,進行pod副本數量的自動調整。
以上。