k8s之深入解剖Pod(三)
目錄:
Pod的排程
Pod的擴容和縮容
Pod的滾動升級
一、Pod的排程
Pod只是容器的載體,通常需要通過RC、Deployment、DaemonSet、Job等物件來完成Pod的排程和自動控制功能。
1、RC、Deployment全自動排程
RC的主要功能之一就是自動部署一個容器應用的多份副本,以及持續監控副本的數量,在叢集內始終維持使用者指定的副本數量。
2、NodeSelector:定向排程
Master上的Schedule負責實現Pod的排程,但無法知道Pod會排程到哪個節點上。可以通過Node的標籤(Label)和Pod的nodeSelector屬性相匹配,達到將Pod排程到指定的Node上。
(1)首先通過kubectl label命令給目標Node打上標籤
kubectl label nodes node-name key=value
例如這邊給cnode-2和cnode-3新增標籤
檢視是否已打上標籤可以使用如下命令
kubelct describe nodes node-name
(2)在Pod定義上新增nodeSelector的設定,
apiVersion: v1 kind: ReplicationController metadata: name: nodeselectorrc labels: name: nodeselectorrc spec: replicas: 1 template: metadata: name: nodeselectorrc labels: name: nodeselectorrc spec: containers: - name: nodeselectorrc image: nginx imagePullPolicy: IfNotPresent ports: - containerPort: 80 nodeSelector: name: cnode-2
【注】如果沒有節點有這個標籤,那麼Pod會無法進行排程
3、NodeAffinity:親和性排程
由於NodeSelector通過Node的label進行精確匹配,所以NodeAffinity增加了In,NotIn,Exists、DoesNotExist、Gt、Lt等操作符來選擇Node,能夠使排程更加靈活,同時在NodeAffinity中將增加一些資訊來設定親和性排程策略
(1)RequiredDuringSchedulingIgnoredDuringExecution:必須滿足指定的規則才可以排程Pod到Node上
(2)PreferredDuringSchedulingIngoredDuringExecution:強調優選滿足指定規則,排程器嘗試將Pod排程到Node上,但不強求,多個優先順序規則還可以設定權重,以定義執行的選後順序。
需要在Pod的metadata.annotations中設定NodeAffinity的內容,例如
spec: affinity: nodeAffinity: preferredDuringSchedulingIngoredDuringExecution: - weight: 1 preference: matchExpressions: - key: name operator: In values: ["cnode-1","cnode-2"]
上述yaml指令碼是說明只有Node的label中包含key=name,並且值並非是["cnode-1","cnode-2"]中的一個,才能成為Pod的排程目標,其中操作符還有In,Exists,DoesNotExist,Gt,Lt。
PreferredDuringSchedulingIngoredDuringExecution使用如下:
spec: affinity: nodeAffinity: preferredDuringSchedulingIngoredDuringExecution: - weight: 1 preference: matchExpressions: - key: name operator: In values: ["cnode-1","cnode-2"]
4、DaemonSet:特定場景排程
用於管理在叢集中每個Node上僅執行一份Pod的副本例項
適合以下場景:
1、在每個Node上執行GlusterFS儲存或者Ceph儲存的daemon程序
2、每個Node上執行一個日誌採集程式 ,例如fluentd或者logstach。
3、每個Node上執行一個健康程式,採集該Node的執行效能資料,例如Prometheus node Exporter
排程策略於RC類似,也可使用NodeSelector或者NodeAffinity來進行排程
例如:為每個Node上啟動一個nginx
apiVersion: apps/v1 kind: DaemonSet metadata: name: ds-nginx labels: name: ds-nginx spec: selector: matchLabels: name: ds-nginx template: metadata: name: ds-nginx labels: name: ds-nginx spec: containers: - name: ds-nginx image: nginx imagePullPolicy: IfNotPresent ports: - containerPort: 80
5、Job批處理排程
可通過Job資源物件定義並啟動一個批處理任務,通常並行或序列啟動多個計算程序去處理一批工作任務,處理完成後,整個批處理任務結束。
按照批處理任務實現方式的不同,可分為如下幾種模式 :
1、Job Template Expansion模式:一個Job物件對應一個待處理的Work Item,有幾個Work item就產生幾個獨立的Job,適合Work item少,每個Work item要處理的資料量比較大的場景
例如:定義一個Job模板,job.yaml.txt
apiVersion: batch/v1 kind: Job metadata: name: process-item-$ITEM labels: jobgroup: jobexample spec: template: metadata: name: jobexample labels: jobgroup: jobexample spec: containers: - name: c image: busybox imagePullPolicy: IfNotPresent command: ["sh","-c","echo $Item && sleep 5"] restartPolicy: Never
#使用如下命令生成yaml檔案
for i in a b c; do cat job.yaml.txt | sed "s/\$ITEM/${i}/" > ./job-$i.yaml; done
#檢視執行情況
kubectl get jobs -l jobgroup=jobexample
2、Queue with Pod Per Work Item模式:採用一個任務佇列存放Work Item,一個Job作為消費者去完成這些Work item,此模式下,Job會啟動N個Pod,每個Pod對應一個WorkItem
3、Queue with Variable Pod Count模式:採用一個任務佇列存放Work Item,一個Job作為消費者去完成這些Work item,Job啟動的Pod數量是可變的
4、Single Job with Static Work Assignment模式:一個Job產生多個Pod,採用程式靜態方式分配任務項
考慮到批處理的並行問題,k8s將job分為以下三種類型:
1、Non-parallel Jobs
一個Job只啟動一個Pod,除非Pod異常,才會 重啟該Pod,一旦 Pod正常結束,Job將結束。
2、Parallel Jobs with a fixed completion count
並行job會 啟動多個Pod,需要設定Pod的引數.spec.completions為一個正數,當正常 結束的Pod數量達到此數時,Job結束,同時此引數用於控制並行度,即同時啟動幾個Job來處理Work item
3、Parallel Jobs with a work queue
任務佇列的並行job需要一個獨立的佇列,work item都在一個佇列中存放,不能設定job的 .spec.completions引數,此時job有以下一些特性
(1)每個Pod能獨立判斷和決定是否還有任務項需要儲裡
(2)如果某個Pod能正常結束,則Job不會在啟動新的Pod
(3)如果一個Pod成功結束,則此時應該不存在其他Pod還在幹活 的情況,應該都處於即將結束 、退出的狀態 。
(4)如果 所有Pod都結束了,且至少有一個Pod成功結束,則整個Job才算成功 結束。
另外,k8s從1.12版本後給job加入了ttl控制,當pod完成任務後,自動進行Pod的關閉,資源回收。
6、Cronjob:定時任務
能根據設定的定時表示式定時排程Pod
(1)Cron Job的定時表示式(與Linux的基本相同)
Minutes Hours DayOfMonth Month DayOfWeek Year
其中每個域都可出現的字元如下。
◎ Minutes:可出現【,-*/】這4個字元,有效範圍為0~59的整數。
◎ Hours:可出現【,-*/】這4個字元,有效範圍為0~23的整 數。
◎ DayofMonth:可出現【,-*/?LWC】這8個字元,有效範圍為0~31的整數。
◎ Month:可出現【,-*/】這4個字元,有效範圍為1~12的整數或JAN~DEC。
◎ DayofWeek:可出現【,-*/?LC#】這8個字元,有效範圍為1~7的整數或SUN~SAT。1表示星期天,2表示星期一,以此類推
◎ *:表示匹配該域的任意值,假如在Minutes域使用,則表示每分鐘都會觸發事件。
◎ /:表示從起始時間開始觸發,然後每隔固定時間觸發一次,例如在Minutes域設定為5/20,則意味著第1次觸發在第5min時,接下來每20min觸發一次
◎ -:指定一個整數範圍。譬如,1-4 意味著整數 1、2、3、4。
◎ ,:隔開的一系列值指定一個列表。譬如3, 4, 6, 8 標明這四個指定的整數。
比如需要每分鐘執行一次:
*/1 * * * *
(2)建立Cron Job
使用yaml檔案
apiVersion: batch/v1beta1 kind: CronJob metadata: name: hello spec: schedule: "*/1 * * * *" jobTemplate: spec: template: spec: containers: - name: hello image: busybox command: ["/bin/bash","-c","date;echo Hello"] restartPolicy: OnFailure
7、PodAffinity:Pod親和與互斥排程策略
根據在節點上正在執行的 Pod的標籤而不是節點的標籤進行判斷和排程,要求對節點和Pod兩個條 件進行匹配。這種規則可以描述為:如果在具有標籤X的Node上運行了一個或者多個符合條件Y的Pod,那麼Pod應該(如果是互斥的情況,那麼就變成拒絕)執行在這個Node上。
這裡X指的是一個叢集中的節點、機架、區域等概念,通過 Kubernetes內建節點標籤中的key來進行宣告。這個key的名字為 topologyKey,意為表達節點所屬的topology範圍。
◎ kubernetes.io/hostname
◎ failure-domain.beta.kubernetes.io/zone
◎ failure-domain.beta.kubernetes.io/region
與節點不同的是,Pod是屬於某個名稱空間的,所以條件Y表達的 是一個或者全部名稱空間中的一個Label Selector。
和節點親和相同,Pod親和與互斥的條件設定也是requiredDuringSchedulingIgnoredDuringExecution和 preferredDuringSchedulingIgnoredDuringExecution。
Pod的親和性被定義於PodSpec的affinity欄位下的podAffinity子欄位中。Pod間的互斥性則被定義於同一層次的podAntiAffinity子欄位中。
例如:
參照目標Pod
apiVerison: v1 kind: Pod metadata: name: pod-flag labels: security: s1 app: nginx spec: containers: - name: nginx image: nginx
(1)Pod親和性排程
apiVersion: v1 kind: Pod metadata: name: pod-affinity spec: affinity: podAffinity: requiredDuringSchedulingIgnoredDuringExecution: - labelSelector: matchExpressions: - key: security operator: In values: ["s1"] topologyKey: kubernetes.io/hostname containers: - name: nginx image: nginx
建立之後會發現兩個Pod在同一個節點上
(2)Pod互斥性排程
apiVersion: v1 kind: Pod metadata: name: pod-antiaffinity spec: affinity: podAntiAffinity: requiredDuringSchedulingIgnoredDuringExecution: - labelSelector: matchExpressions: - key: security operator: In values: ["s1"] topologyKey: kubernetes.io/hostname containers: - name: nginx image: nginx
建立之後會發現這個Pod跟參照Pod不在同一個節點上
8、Pod Priority Preemption:Pod優先順序排程
在中大型叢集中,為了儘可能提高叢集的資源利用率,會採用優先順序方案,即不同型別的負載對應不同的優先順序,同時允許叢集中的所有負載所需的資源總量超過叢集可提供的資源,在這種情況下,當發生資源不足的情況時,系統可以選擇釋放一些不重要的負載(優先順序最低的),保障最重要的負載能夠獲取足夠的資源穩定執行。
如果發生了需要搶佔的排程,高優先順序Pod就可能搶佔節點N,並將其低優先順序Pod驅逐出節點N。
(1)首先建立PriorityClasses
apiVersion: v1 kind: scheduling.k8s.io/v1beta1 metadata: name: high-priority value: 10000 globalDefault: false
(2)然後在Pod中引用Pod優先順序
apiVersion: v1 kind: Pod metadata: name: nginx-priority spec: containers: - name: nginx image: nginx priorityClassName: high-priority
二、Pod的擴容和縮容
1、通過kubectl scale
通過kubectl scale進行擴容和縮容,其實就是修改控制器的副本數字段
kubectl scale rc rc-name --replicas=副本數量
比如我將nodeselectorrc擴容為3
縮容也是一樣,將副本數量改小就行
2、Horizontal Pod AutoScale(HPA)
實現基於cpu使用率進行自動Pod擴縮容,HPA控制器基於Master的kube-controller-manager服務啟動引數
--horizontal-pod-authscaler-sync-period
定義的時長(預設為30s),週期性的監測目標pod的cpu使用率,並在滿足條件時對RC或Deployment中的Pod副本數量進行調整,以符合使用者定義的平均Pod CPU使用率
建立HPA時可以使用kubectl autoscale命令進行快速建立或者使用yaml配置檔案進行建立,在建立HPA前,需要已經存在一個RC或者Deployment物件,並且必須定義resources.requests.cpu的資源請求值,如果不設定該值,則heapster將無法採集Pod的cpu使用率
【注】此方式需要安裝heapster進行採集資源的cpu使用率
命令列方式:
kubectl autoscale rc rc-name --min=1 --max=10 --cpu-percent=50
yaml方式:
apiVersion: autoscaling/v1 kind: HorizontalPodAutoscaler metadata: name: hpa-name spec: scaleTargetRef: apiVersion: v1 kind: ReplicationController name: rc-name minReplicas: 1 maxReplicas: 10 targetCPUUtilizationPercentage: 50
上述兩種方式都是在cpu使用率達到50%的時候進行擴縮容,最小副本數為1,最大副本數為10
三、Pod的滾動升級
滾動升級通過kubectl rolling-update命令完成,該命令建立了一個RC,然後自動控制舊的RC中的Pod副本的數量逐漸減少至0,同時新的RC中的Pod副本的數量從0逐步增加至目標值,最終實現了Pod的升級。新舊的RC需要在同一個Namespace下。
1、使用yaml進行升級
比如有一個nginx的v1版本:nginx-v1.yaml
apiVersion: v1 kind: ReplicationController metadata: name: roll-v1 labels: name: roll-v1 version: v1 spec: replicas: 3 selector: name: roll-v1 version: v1 template: metadata: name: roll-v1 labels: name: roll-v1 version: v1 spec: containers: - name: roll-v1 image: nginx imagePullPolicy: IfNotPresent ports: - containerPort: 80
建立之後如下:
需要將其升級為v2版本:nginx-v2.yaml
apiVersion: v1 kind: ReplicationController metadata: name: roll-v2 labels: name: roll-v2 version: v2 spec: replicas: 3 selector: name: roll-v2 version: v2 template: metadata: name: roll-v2 labels: name: roll-v2 version: v2 spec: containers: - name: roll-v2 image: nginx imagePullPolicy: IfNotPresent ports: - containerPort: 8080
使用如下命令進行升級:
kubectl rolling-update roll-v1 -f nginx-v2.yaml
執行之後會逐步替換掉v1版本的pod
需要注意的是:
1、RC的名字不能與舊的RC相同
2、在selector中至少有一個Label與舊的不同,以表示其是新的RC。(其實是必須所有label不一樣)
2、使用命令方式直接升級
也可以使用命令列直接替換掉容器的映象
kubectl rolling-update rc-name --image=image-name:version
3、回滾
當滾動更新出現問題時,可以進行回滾
kubectl rolling-update rc-name --image=image-name:version --rollback
===============================
我是Liusy,一個喜歡健身的程式設計師。
歡迎關注微信公眾號【Liusy01】,一起交流Java技術及健身,獲取更多幹貨,領取Java進階乾貨,領取最新大廠面試資料,一起成為Java大神。
來都來了,關注一波再溜