1. 程式人生 > 其它 >k8s入坑之路(14)scheduler排程 kubelet管理及健康檢查

k8s入坑之路(14)scheduler排程 kubelet管理及健康檢查

kubelet 主要功能

Pod 管理

在 kubernetes 的設計中,最基本的管理單位是 pod,而不是 container。pod 是 kubernetes 在容器上的一層封裝,由一組執行在同一主機的一個或者多個容器組成。如果把容器比喻成傳統機器上的一個程序(它可以執行任務,對外提供某種功能),那麼 pod 可以類比為傳統的主機:它包含了多個容器,為它們提供共享的一些資源。

之所以費功夫提供這一層封裝,主要是因為容器推薦的用法是裡面只執行一個程序,而一般情況下某個應用都由多個元件構成的。

pod 中所有的容器最大的特性也是最大的好處就是共享了很多資源,比如網路空間。pod 下所有容器共享網路和埠空間,也就是它們之間可以通過localhost訪問和通訊,對外的通訊方式也是一樣的,省去了很多容器通訊的麻煩。

除了網路之外,定義在 pod 裡的 volume 也可以 mount 到多個容器裡,以實現共享的目的。

最後,定義在 pod 的資源限制(比如 CPU 和 Memory) 也是所有容器共享的。

容器健康檢查

建立了容器之後,kubelet 還要檢視容器是否正常執行,如果容器執行出錯,就要根據設定的重啟策略進行處理。檢查容器是否健康主要有三種方式:執行命令,http Get,和tcp連線。

不管用什麼方式,如果檢測到容器不健康,kubelet 會刪除該容器,並根據容器的重啟策略進行處理(比如重啟,或者什麼都不做)。

容器監控

kubelet 還有一個重要的責任,就是監控所在節點的資源使用情況,並定時向 master 報告。知道整個叢集所有節點的資源情況,對於 pod 的排程和正常執行至關重要。

kubelet 使用cAdvisor進行資源使用率的監控。cAdvisor 是 google 開源的分析容器資源使用和效能特性的工具,在 kubernetes 專案中被整合到 kubelet 裡,無需額外配置。預設情況下,你可以在localhost:4194地址看到 cAdvisor 的管理介面。

除了系統使用的 CPU,Memory,儲存和網路之外,cAdvisor 還記錄了每個容器使用的上述資源情況。

kubelet建立pod啟動過程

流程圖:

流程內容分析
  1. kubelet通過gRPC呼叫dockershim發起建立容器,CRI即容器執行時介面(container runtime interface),目前dockershim的程式碼內嵌在kubele中,所以接受建立容器的就是kubelet程序。

  2. dockershim把建立容器的命令轉換成docker daemon可以識別的命令,之後傳送給docker daemon建立容器。

  3. docker daemon在1.12版本之後就會把建立容器的命令分發給另一個程序: comtainerd。

  4. containerd收到建立容器的命令後,建立另一個程序:containerd-shim程序,由該程序執行具體的建立命令,containerd程序做為父程序存在。

  5. 建立容器的時候需要namespace隔離容器啟動和建立需要的資源,cgroup限制容器可以使用資源的大小等操作,這些事情該怎麼做已經有看公開的規範OCI(open container initivtive 開放容器標準),它的一個參考實現叫做runc。於是containerd--shim在這一步需要呼叫runc命令,來啟動容器。

  6. runc啟動容器之後就直接退出,containerd-shim則會成為容器程序的父程序,收集容器程序的狀態,上報給contanierd,並在容器種pid為1的程序退出後接管容器中的子程序進行清理,確保不會出現殭屍程序。

pod生命週期:

連結:https://kubernetes.io/zh/docs/concepts/workloads/pods/pod-lifecycle/

  • 1.pod生命週期排程只有一次,scheduler排程到node會為pod打上node uid全域性唯一,當pod重啟時不會改變node。更新後pod名字可以不變uid會改變。
  • 2.當節點失效或資源緊缺被驅逐後才會重新排程。
  • 3.service-api向kubelet傳送停止指令,pod會終止。 #pod停止為優雅停止,在kill之前會給定寬容期,與微服務優雅停止相近都是給容器或服務傳送TERM訊號拒絕接受新的請求,並在寬容期後停止容器。

這其中有兩個名詞概念容易混淆

CRI:容器執行時介面 container runtime interface

其主要的作用:

  1. 針對容器操作的介面,包括容器的建立、啟動和停止等
  2. 針對映象的操作,拉去、刪除映象等
  3. 針對podsandbox(容器沙箱環境)

OCI:開放容器標準 open container initiative

主要作用,製作容器

  1. 容器映象製作內容,即imagespec

  2. 容器需要接收哪些指令,即runtimespec

kubelet pod健康檢查

kubelet預設對於容器檢查非常的簡單粗暴,就是對於入口程式pid為1的程式,只要監測是否存活即為容器正常。

kubelet對於容器資源的監控主要使用cAdvisor,cAdvisor是用於針對於docker stats介面的採集工具。kubelet內部集成了cAdvisor,內部函式中定義了定時器及監控採集,1秒鐘就會去採集彙報。

  • 健康檢查三種機制
    • 通過命令返回值來判斷 (執行命令後返回值非0則為失敗)
    • 通過tcp埠是否開啟來判斷容器是否正常
    • 通過http rest請求來判斷是否正常

      #rest簡單描述為前後臺通訊GET/POST,客戶端與服務端通訊,使用者通過socket傳送請求後選擇子標籤,服務端返回子標籤json,客戶端在傳送請求加上子標籤,對應的呼叫標籤對應的介面或功能。rest也是無狀態統一介面,客戶端負責使用者使用者狀態維持。

基於cmd 健康檢查

apiVersion: apps/v1
kind: Deployment
metadata:
  name: web-demo
  namespace: dev
spec:
  selector:
    matchLabels:
      app: web-demo
  replicas: 1
  template:
    metadata:
      labels:
        app: web-demo
    spec:
      containers:
      - name: web-demo
        image: hub.mooc.com/kubernetes/web:v1
        ports:
        - containerPort: 8080
        livenessProbe:
          exec:
            command:
            - /bin/sh
            - -c
            - ps -ef|grep java|grep -v grep
          initialDelaySeconds: 10 #等待容器啟動時間
          periodSeconds: 10 #監控檢查等待時間間隔
          failureThreshold: 2 #健康檢查連續失敗次數
          successThreshold: 1 #健康檢查從錯誤到正常次數
          timeoutSeconds: 5 #執行命令超時時間
pod-cmd.yaml

#pod建立後,會在配置檔案中新增liveness exec [具體命令及執行時間,判斷返回值等]。本質是容器啟動時kubelet為容器新增預設執行命令。判斷命令執行返回值,echo $? 上次命令執行返回值檢視。

基於http健康檢查

apiVersion: apps/v1
kind: Deployment
metadata:
  name: web-demo
  namespace: dev
spec:
  selector:
    matchLabels:
      app: web-demo
  replicas: 1
  template:
    metadata:
      labels:
        app: web-demo
    spec:
      containers:
      - name: web-demo
        image: hub.mooc.com/kubernetes/web:v1
        ports:
        - containerPort: 8080
        livenessProbe:
          httpGet:
            path: /examples/index.html
            port: 8080
            scheme: HTTP
          initialDelaySeconds: 10 #等待容器啟動時間 
          periodSeconds: 5 #檢查等待時間 間隔
          failureThreshold: 1 #健康檢查連續失敗次數
          successThreshold: 1 #從失敗到成功的次數
          timeoutSeconds: 5 #執行命令超時時間
pod-http.yaml

#http健康檢查通過http返回值200來判斷,300 400 500等都為失敗,使用一定要通過一個穩定靜態檔案來獲取。service新增後端pod時是根據後端pod埠是否啟動進行判斷,本質是tcp判斷。http服務一定要注意。

基於tcp埠健康檢查

apiVersion: apps/v1
kind: Deployment
metadata:
  name: web-demo
  namespace: dev
spec:
  selector:
    matchLabels:
      app: web-demo
  replicas: 1
  template:
    metadata:
      labels:
        app: web-demo
    spec:
      containers:
      - name: web-demo
        image: hub.mooc.com/kubernetes/web:v1
        ports:
        - containerPort: 8080
        livenessProbe:
          tcpSocket:
            port: 8080
          initialDelaySeconds: 20 #等待容器啟動時間
          periodSeconds: 10 #檢查隔間時間
          failureThreshold: 2 #連續失敗次數
          successThreshold: 1 #失敗到成功次數
          timeoutSeconds: 5 #超時時間
pod-tcp.yaml

基於http狀態向service傳送就緒狀態

apiVersion: apps/v1
kind: Deployment
metadata:
  name: web-demo
  namespace: dev
spec:
  selector:
    matchLabels:
      app: web-demo
  replicas: 1
  template:
    metadata:
      labels:
        app: web-demo
    spec:
      containers:
      - name: web-demo
        image: hub.mooc.com/kubernetes/web:v1
        ports:
        - containerPort: 8080
        livenessProbe:
          tcpSocket:
            port: 8080
          initialDelaySeconds: 20
          periodSeconds: 10
          failureThreshold: 2
          successThreshold: 1
          timeoutSeconds: 5
        readlinessProbe: #用於向service傳送狀態
          httpGet:
            path: /examples/index.html
            port: 8080
            scheme: HTTP
          initialDelaySeconds: 10 #等待容器啟動時間 
          periodSeconds: 5 #檢查等待時間 間隔
          failureThreshold: 1 #健康檢查連續失敗次數
          successThreshold: 1 #從失敗到成功的次數
          timeoutSeconds: 5 #執行命令超時時間  

tcp-http.yaml

用tcp去探測啟動探針與存活探針,用http返回去向service傳送就緒狀態值。通過改變容器狀態值為read。

###當容器restart,檢查時可以將Pod 的spec中包含一個restartPolicy欄位修改,取值包括 Always、OnFailure 和 Never。預設值是 Always。也可以修改探針策略把探針修改為肯定可以成功的值。

Scheduler--- 玩轉pod排程

Scheduler排程過程

流程圖:

1.kubectl向api-service傳送建立指令。api-service將建立指令轉換為yaml存入etcd中。

2.informer reflector watch api-service 通過pod資訊中是否繫結nodename。將請求分配給scheduler。

3.scheduler將pod放入優先順序佇列中,通過informer store取出node節點資訊(node節點資訊由kubelet通過定時器定時向apiserver上報 寫入etcd中)

4.執行預選策略,查詢是否繫結label,埠是否存在,cpu及記憶體等是否超過resouce限定,掛載檔案型別是否匹配,nodeselect規則匹配,節點狀態是否正常。篩選出符合的node。

5.執行優選策略,通過cpu及記憶體平衡性(pod limit總的值剩餘量及當前執行狀態),node中是否預先存在執行映象,同一deployment pod是否排程在同一node中等對其進行評分,分值最高的為選中節點。

6.scheduler將該pod繫結node,賦予一個nodename,並生成全域性唯一uid,上傳到apiservice,寫入etcd。

7.informer reflectorwatch api-service 將pod資訊通知node kubelet,kublet通過相應動作策略通過cri指令傳送給容器守護程序,容器程序呼叫cni及oci建立pod(cni及cgroup等分配給pause實現部分資源共享)。

8.kubelet將pod節點資訊上傳給api-service。informer進行監聽同步,通知到controller。