1. 程式人生 > 其它 >k8s——容器啟動、退出動作+list watch機制+node節點與pod親和/反親和的排程

k8s——容器啟動、退出動作+list watch機制+node節點與pod親和/反親和的排程

目錄

一、啟動、退出動作

vim demo1.yaml
==========================================================
apiVersion: v1
kind: Pod
metadata:
  name: lifecycle-demo
spec:
  containers:
  - name: lifecycle-demo-container
    image: soscscs/myapp:v1
    lifecycle:
      postStart:
        exec:
          command: ["/bin/sh", "-c", " echo '333333' >> /var/log/nginx/message"]
      preStop:
        exec:
          command: ["/bin/sh", "-c", " echo '222222'  >> /var/log/nginx/message"]
    volumeMounts:
    - name: message-log
      mountPath: /var/log/nginx/
      readOnly: false
  initContainers:
  - name: init-myservice
    image: soscscs/myapp:v1
    command: ["/bin/sh", "-c", "echo '111111'   >> /var/log/nginx/message"]
    volumeMounts:
    - name: message-log
      mountPath: /var/log/nginx/
      readOnly: false
  volumes:
  - name: message-log
    hostPath:
      path: /data/volumes/nginx/log/
      type: DirectoryOrCreate
==========================================================
kubectl apply -f demo1.yaml

kubectl get pods -o wide

在node01上節點上檢視
cat /data/volumes/nginx/log/message




二、k8s的List-Watch的機制


1.使用者通過kubectl或其他API客戶端提交請求給APIServer來建立一個 Pod物件副本
2.APIServer 嘗試著將Pod物件的相關元資訊存入etcd中,待寫入操作執行完成,APIServer即會返回確認資訊至客戶端
3.當etcd接受建立Pod資訊以後,會發送一個Create事件給APIServer
4.由於Controller Manager一直在監聽(Watch,通過http的8080埠)APIServer中的事件。此時APIServer接受到了Create事件,又會發送給Controller Manager
5.Controller Manager在接到Create事件以後,呼叫其中的 Replication Controller 來保證Node上面需要建立的副本數量
6.在Controller Manager建立Pod副本以後,APIServer會在etcd中記錄這個Pod的詳細資訊。例如Pod的副本數,Container的資訊
7.同樣的etcd會將建立Pod的資訊通過事件傳送給APIServer
8.由於Scheduler在監聽(Watch)APIServer,並且它在系統中起到了“承上啟下”的作用,“承上”是指它負責接收建立的Pod事件,為其安排 Node;“啟下”是指安置工作完成後,Node上的kubelet程序會接管後繼工作,負責Pod生命週期中的“下半生”。 換句話說,Scheduler的作用是將待排程的Pod按照排程演算法和策略繫結到叢集中Node上
9.Scheduler排程完畢以後會更新Pod的資訊,此時的資訊更加豐富了。除了知道Pod的副本數量,副本內容。還知道部署到哪個Node上面了。並將上面的Pod資訊更新至API Server,由APIServer更新至etcd中,儲存起來
10.etcd將更新成功的事件傳送給APIServer,APIServer也開始反映此 Pod物件的排程結果
11.kubelet是在Node上面執行的程序,它也通過List-Watch的方式監聽(Watch,通過https的6443埠)APIServer傳送的Pod更新的事件。kubelet會嘗試在當前節點上呼叫Docker啟動容器,並將Pod以及容器的結果狀態回送至APIServer
12.APIServer將Pod狀態資訊存入etcd中。在etcd確認寫入操作成功完成後,APIServer將確認資訊傳送至相關的kubelet,事件將通過它被接受
注: kubectl發命令,要擴充Pod副本數量,那麼上面的流程又會觸發一遍,kubelet會根據最新的Pod的部署情況調整Node的資源。又或者Pod 副本數量沒有發生變化,但是其中的映象檔案升級了,kubelet也會自動獲取最新的映象檔案並且載入

三、排程過程

3.1 排程策略

1.Sheduler是作為單獨的程式執行的,啟動之後會一直監聽APIServer,獲取spec.nodeName為空的pod,對每個pod都會建立一個binding,表明該pod應該放到哪個節點上
2.排程分為幾個部分:首先是過濾掉不滿足條件的節點,這個過程稱為預算策略(predicate);然後對通過的節點按照優先順序排序,這個是優選策略(priorities);最後從中選擇優先順序最高的節點。如果中間任何一步驟有錯誤,就直接返回錯誤

3.2 預算策略常見的演算法

1.PodFitsResources:節點上剩餘的資源是否大於pod請求的資源
2.PodFitsHost:如果pod指定了NodeName,檢查節點名稱是否和 NodeName匹配
3.PodFitsHostPorts:節點上已經使用的port是否和pod申請的port衝突
4.PodSelectorMatches:過濾掉和pod指定的label不匹配的節點
5.NoDiskConflict:已經mount的volume和pod指定的volume不衝突,除非它們都是隻讀

3.3 優先順序的確立

1.如果在predicate過程中沒有合適的節點,pod會一直在pending狀態,不斷重試排程,直到有節點滿足條件。 經過這個步驟,如果有多個節點滿足條件,就繼續 priorities過程:按照優先順序大小對節點排序
2.優先順序由一系列鍵值對組成,鍵是該優先順序項的名稱,值是它的權重(該項的重要性)。有一系列的常見的優先順序選項包括:
1)LeastRequestedPriority:通過計算CPU和Memory的使用率來決定權重,使用率越低權重越高。也就是說,這個優先順序指標傾向於資源使用比例更低的節點
2)BalancedResourceAllocation:節點上 CPU 和 Memory 使用率越接近,權重越高。這個一般和上面的一起使用,不單獨使用。比如 node01 的 CPU 和 Memory 使用率 20:60,node02 的 CPU 和 Memory 使用率 50:50,雖然 node01 的總使用率比 node02 低,但 node02 的 CPU 和 Memory 使用率更接近,從而排程時會優選 node02
3)ImageLocalityPriority:傾向於已經有要使用映象的節點,映象總大小值越大,權重越高
3.通過演算法對所有的優先順序專案和權重進行計算,得出最終的結果

四、指定排程節點

4.1 指定nodeName

#pod.spec.nodeName 將 Pod 直接排程到指定的 Node 節點上,會跳過 Scheduler 的排程策略,該匹配規則是強制匹配
vim demo2.yaml
==========================================================
apiVersion: extensions/v1beta1  
kind: Deployment  
metadata:
  name: myapp
spec:
  replicas: 3
  template:
    metadata:
      labels:
        app: myapp
    spec:
      nodeName: node01
      containers:
      - name: myapp
        image: nginx
        ports:
        - containerPort: 80
==========================================================
kubectl apply -f demo2.yaml

kubectl get pods -owide

kubectl describe pod myapp-86c89df7fc-6glj6


4.2 指定nodeSelector

pod.spec.nodeSelector:通過 kubernetes 的 label-selector 機制選擇節點,由排程器排程策略匹配 label,然後排程 Pod 到目標節點,該匹配規則屬於強制約束
//給對應的 node 設定標籤分別為gxd=111和gxd=222
kubectl label nodes node01 gxd=111
kubectl label nodes node02 gxd=222
//檢視標籤
kubectl get nodes --show-labels
//修改成nodeSelector排程方式
vim demo3.yaml
==========================================================
apiVersion: extensions/v1beta1  
kind: Deployment  
metadata:
  name: myapp1
spec:
  replicas: 3
  template:
    metadata:
      labels:
        app: myapp1
    spec:
      nodeSelector:
	    gxd: "111"
      containers:
      - name: myapp1
        image: nginx
        ports:
        - containerPort: 80
==========================================================
kubectl apply -f demo3.yaml 

kubectl get pods -o wide

#檢視詳細事件(通過事件可以發現要先經過scheduler排程分配)
kubectl describe pod myapp1-55c6cc597c-8xw9x


//修改一個 label 的值,需要加上 --overwrite 引數
kubectl label nodes node02 gxd=a --overwrite
kubectl get nodes --show-labels
//刪除一個 label,只需在命令列最後指定 label 的 key 名並與一個減號相連即可:
kubectl label nodes node02 gxd-
指定標籤查詢 node 節點
kubectl get node -l gxd=111

五、親和性

5.1 分類

官方文件:https://kubernetes.io/zh/docs/concepts/scheduling-eviction/assign-pod-node/

1.節點親和性
pod.spec.nodeAffinity
●preferredDuringSchedulingIgnoredDuringExecution:軟策略
●requiredDuringSchedulingIgnoredDuringExecution:硬策略
2.Pod 親和性
pod.spec.affinity.podAffinity/podAntiAffinity
●preferredDuringSchedulingIgnoredDuringExecution:軟策略
●requiredDuringSchedulingIgnoredDuringExecution:硬策略

5.2 鍵值運算關係

1.In:label 的值在某個列表中
2.NotIn:label 的值不在某個列表中
3.Gt:label 的值大於某個值
4.Lt:label 的值小於某個值
5.Exists:某個 label 存在
6.DoesNotExist:某個 label 不存在

5.3 node節點親和性+硬策略例項

vim demo4.yaml
==========================================================
apiVersion: v1
kind: Pod
metadata:
  name: affinity
  labels:
    app: node-affinity-pod
spec:
  containers:
  - name: with-node-affinity
    image: nginx
  affinity:
    nodeAffinity:
      requiredDuringSchedulingIgnoredDuringExecution:
        nodeSelectorTerms:
        - matchExpressions:
          - key: gxd    #指定node的標籤
            operator: NotIn     #設定Pod安裝到kubernetes.io/hostname的標籤值不在values列表中的node上
            values:
            - "111"
==========================================================
kubectl apply -f demo4.yaml

kubectl get pods -o wide

如果硬策略不滿足條件,Pod 狀態一直會處於 Pending 狀態
把標籤值改為gxd=222,所有節點都不滿足,建立pod檢視狀態


5.4 node節點親和性+軟策略例項

vim demo5.yaml
==========================================================
apiVersion: v1
kind: Pod
metadata:
  name: affinity
  labels:
    app: node-affinity-pod
spec:
  containers:
  - name: with-node-affinity
    image: nginx
  affinity:
    nodeAffinity:
      preferredDuringSchedulingIgnoredDuringExecution:
      - weight: 1   #如果有多個軟策略選項的話,權重越大,優先順序越高
        preference:
          matchExpressions:
          - key: gxd
            operator: In
            values:
            - "111"
==========================================================
kubectl apply -f demo5.yaml

kubectl get pods -o wide

5.5 node節點親和性+軟策略+硬策略例項

vim demo6.yaml
==========================================================
apiVersion: v1
kind: Pod
metadata:
  name: affinity
  labels:
    app: node-affinity-pod
spec:
  containers:
  - name: with-node-affinity
    image: nginx
  affinity:
    nodeAffinity:
      requiredDuringSchedulingIgnoredDuringExecution:   #先滿足硬策略,排除有kubernetes.io/hostname=node02標籤的節點
        nodeSelectorTerms:
        - matchExpressions:
          - key: kubernetes.io/hostname
            operator: NotIn
            values:
            - node02
      preferredDuringSchedulingIgnoredDuringExecution:  #再滿足軟策略,優先選擇有gxd=111標籤的節點
	  - weight: 1
        preference:
          matchExpressions:
          - key: gxd
            operator: In
            values:
            - "111"
==========================================================
kubectl apply -f demo6.yaml

kubectl get pods -o wide

六、pod親和性與反親和性

6.1 建立一個標籤為app=myapp01的Pod

vim demo7.yaml
==========================================================
apiVersion: v1
kind: Pod
metadata:
  name: myapp01
  labels:
    app: myapp01
spec:
  containers:
  - name: with-node-affinity
    image: nginx
=========================================================
kubectl apply -f pod3.yaml

kubectl get pods --show-labels -o wide

6.2 使用Pod親和性排程

vim demo8.yaml
==========================================================
apiVersion: v1
kind: Pod
metadata:
  name: myapp02
  labels:
    app: myapp02
spec:
  containers:
  - name: myapp02
    image: nginx
  affinity:
    podAffinity:
      requiredDuringSchedulingIgnoredDuringExecution:
      - labelSelector:
          matchExpressions:
          - key: app
            operator: In
            values:
            - myapp01
        topologyKey: kubernetes.io/hostname
==========================================================
kubectl apply -f demo8.yaml

kubectl get pods --show-labels -o wide
==========================================================
#僅當節點和至少一個已執行且有鍵為“app”且值為“myapp01”的標籤 的 Pod 處於同一拓撲域時,才可以將該 Pod 排程到節點上。 (更確切的說,如果節點 N 具有帶有鍵 kubernetes.io/hostname 和某個值 V 的標籤,則 Pod 有資格在節點 N 上執行, 以便叢集中至少有一個節點具有鍵 kubernetes.io/hostname 和值為 V 的節點正在執行具有鍵“app”和值 “myapp01”的標籤的 pod。)
#topologyKey 是節點標籤的鍵。如果兩個節點使用此鍵標記並且具有相同的標籤值,則排程器會將這兩個節點視為處於同一拓撲域中。 排程器試圖在每個拓撲域中放置數量均衡的 Pod。
#如果kubernetes.io/hostname對應的值不一樣就是不同的拓撲域。比如 Pod1 在kubernetes.io/hostname=node01的 Node 上,Pod2 在kubernetes.io/hostname=node02的 Node 上,Pod3 在kubernetes.io/hostname=node01的 Node 上,則 Pod2 和 Pod1、Pod3 不在同一個拓撲域,而Pod1 和 Pod3在同一個拓撲域

6.2 Pod反親和性排程

vim demo9.yaml
==========================================================
apiVersion: v1
kind: Pod
metadata:
  name: myapp03
  labels:
    app: myapp03
spec:
  containers:
  - name: myapp03
    image: nginx
  affinity:
    podAntiAffinity:
      preferredDuringSchedulingIgnoredDuringExecution:
      - weight: 100
        podAffinityTerm:
          labelSelector:
            matchExpressions:
            - key: app
              operator: In
              values:
              - myapp01
          topologyKey: kubernetes.io/hostname
==========================================================
kubectl apply -f demo9.yaml

kubectl get pods --show-labels -o wide
==========================================================
#如果節點處於 Pod 所在的同一拓撲域且具有鍵“app”和值“myapp01”的標籤, 則該 pod 不應將其排程到該節點上。 (如果 topologyKey 為 kubernetes.io/hostname,則意味著當節點和具有鍵 “app”和值“myapp01”的 Pod 處於相同的區域,Pod 不能被排程到該節點上。)

七、總結

7.1 親和

1.node節點親和:排程到滿足 Node 節點 的標籤條件的Node節點   nodeAffinity
硬策略:必須滿足條件   requiredDuringSchedulingIgnoredDuringExecution
軟策略:儘量滿足條件,滿足不了也沒關係   preferredDuringSchedulingIgnoredDuringExecution
2.pod親和:排程到滿足pod的標籤條件所對應的node節點   podAffinity
3.pod反親和:不排程到滿足pod的標籤條件所對應的node節點
排程策略 匹配標籤 操作符 拓撲域支援 排程目標
nodeAffinity 主機 In, NotIn, Exists,DoesNotExist, Gt, Lt 指定主機
podAffinity Pod In, NotIn, Exists,DoesNotExist Pod與指定Pod同一拓撲域
podAntiAffinity Pod In, NotIn, Exists,DoesNotExist Pod與指定Pod不在同一拓撲域

7.2 node節點硬策略配置

spec:
  affinity:
    nodeAffinity:
      requiredDuringSchedulingIgnoredDuringExecution:
        nodeSelectorTerms:
        - matchExpressions:
          - key: KEY_NAME
            operator: In/NotIn/Exists/DoesNotExist/Gt/Lt
            values:
            - KEY_VALUE

7.3 node節點軟策略配置

spec:
  affinity:
    nodeAffinity:
      preferredDuringSchedulingIgnoredDuringExecution:
      - weight: WEIGHT_VALUE
        preference:
          matchExpressions:
          - key: KEY_NAME
            operator: In/NotIn/Exists/DoesNotExist
            values:
            - KEY_VALUE

7.4 pod節點(親和/反親和)硬策略配置

spec:
  affinity:
    podAffinity/podAnitAffinity:
      requiredDuringSchedulingIgnoredDuringExecution:
      - labelSelector:
          matchExpressions:
          - key: KEY_NAME
            operator: In/NotIn/Exists/DoesNotExist/Gt/Lt
            values:
            - KEY_VALUE
         topologyKey: kubernetes.io/hostname 

7.5 pod節點(親和/反親和)軟策略配置

spec:
  affinity:
    podAffinity/podAnitAffinity:
      preferredDuringSchedulingIgnoredDuringExecution:
      - weight: WEIGHT_VALUE
        podAffinityTerm:
          labelSelector:
            matchExpressions:
            - key: KEY_NAME
              operator: In/NotIn/Exists/DoesNotExist
              values:
              - KEY_VALUE
           topologyKey: kubernetes.io/hostname