1. 程式人生 > >k8s之深入解剖Pod(三)

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大神。

來都來了,關注一波再溜