1. 程式人生 > 其它 >Kubernetes學習記錄(四):深入理解Pod

Kubernetes學習記錄(四):深入理解Pod

1. 什麼是Pod

1.1 Pod的基本概念

Pod就是一組共享了某些資源的容器

Pod的設計是為了親密性應用可以共享儲存和網路而設計

什麼是親密性應用場景:

  • 兩個應用之間發生檔案互動
  • 兩個應用需要通過127.0.0.1或者socket通訊
  • 兩個應用需要發生頻繁呼叫

 

1.2 pod的實現機制和設計模式

共享網路

容器實現了namesapce隔離,那麼pod是怎麼打破這種隔離的?

實際上,在k8s中,pod的實現需要一箇中間容器,這個容器叫做Infra容器

在一個pod中,Infra容器永遠都是第一個被建立的容器,使用者定義的其它容器則通過JoinNetworkNamespace的方式與Infra關聯在一起

我們可以在node節點中找到這個容器,就是pause容器

 

在一個pod中共享網路,這意味著對於pod中的兩個容器來說:

  • 它們可以使用localhost進行通訊
  • 它們看到的網路裝置和Infra容器看到的完全一樣
  • 一個pod只有一個IP地址,也就是這個pod的Network Namespace對應的地址
  • Pod的生命週期和Infra容器一致,而與其他業務容器無關

 

共享儲存

pod使用資料卷的方式實現資料共享,k8s只需要把所有的volume定義在pod層級即可

這樣,一個volume對應的宿主機目錄對於pod來說就只有一個,pod內容器只需要宣告掛載這個volume,就可以實現資料共享

我們可以在一個具體的YAML檔案中觀察到這一點

 

在這個例子中,debian和nginx都宣告掛載了shared-data這個資料卷,而shared-data是hostPath型別,所以它在宿主機上對應的目錄就是 /data

從而nginx可以在它的/usr/share/nginx/html目錄中讀取到debian生成的index.html檔案

 

1.3 Pod的狀態

Pod的生命週期主要體現在Pod API物件的Status部分,這是它除了Metadata和Spec外的第三個重要欄位

其中pod.status.phase就是Pod當前的狀態,它有下面五種可能的情況:

  • Pending

    這個狀態意味著Pod的YAML檔案已經提交給了k8s,API物件已經被建立並儲存到etcd中

    但是,這個Pod裡有些容器可能因為某種原因不能夠被順序建立,比如無法排程

  • Running

    這個狀態下,Pod已經被排程成功,跟一個具體節點繫結

    它包含的容器都已經被建立,並且至少有一個在正在執行

  • Succeeded

    Pod裡所有的容器都執行完畢,並且成功退出,常見於一次性任務

  • Failed

    Pod裡至少有一個容器以不正常的狀態退出,遇到這個狀態需要檢視events

  • Unknown

    異常狀態,意味著kubelet不能上報情況,可能是master和node之間的通訊出問題

 

2. Pod的排程策略

k8s的排程策略分為兩個部分:predicates預選策略和priorites優選策略

  • 預選策略:predicates是強制性規則,遍歷所有的node節點,按照具體的預選策略篩選出所有符合要求的node,如果沒有node符合要求,pod將會被掛起
  • 優選擇略:在預選的基礎之上,按照優選策略為待選的node打分,獲取更優者部署pod

 

預選策略必須全部滿足

(1)CheckNodeCondition:檢測node是否正常

(2)GeneralPredicates:普通判斷策略

    HostName: 檢測pod物件是否定義了pod.spec.hostname

    PodFitsHostPorts:檢測pods.spec.containets.ports.hostPort是否定義

    MatchNodeSelector:檢測pod是否設定了pods.spec.nodeSelector

    PodFitsResources:檢測pod的資源需求是否能被節點所滿足

(3)NoDiskConflict:檢測pod依賴的儲存卷是否能滿足需求

(4)PodToleratesNodeTaints: 檢測pod上的spec.tolerations可容忍的汙點是否完全包含節點上的汙點

(5)PodToleratesNodeNoExecuteTaints: 檢測pod上是否啟用了NoExecute級別的汙點

(6)CheckNodeLabelPresence: 檢測node上的標籤的存在與否

(7)CheckServiceAffinity:將相同service pod的物件放到一起

(8)CheckVolumeBinding:檢測節點上已繫結和未繫結的volume

(9)NoVolumeZoneConflict:檢測區域,是否有pod volume的衝突

(10)CheckNodeMemoryPressure:檢測記憶體節點是否存在壓力

(11)CheckNodePIDPressure:檢測pid資源的情況

(12)CheckNodeDiskPressure:檢測disk資源壓力

(13)MatchInterPodAffity:檢測pod的親和性

 

優選擇略

優選函式的評估:如果一個pod過來,會根據啟用的全部函式的得分相加得到評估

(1)LeastRequested:最少請求,與節點的總容量的比值

(2)BalancedResourceAllocation:cpu和記憶體資源被佔用的比率相近程度,越接近,比分越高,平衡節點的資源使用情況

(3)NodePreferAvoidPods:在這個優先順序中,優先順序最高,得分非常高

(4)TaintToleration:將pod物件的spec.tolertions與節點的taints列表項進行匹配度檢測,匹配的條目越多,得分越低

(5)SeletorSpreading:儘可能的把pod分散開,也就是沒有啟動這個pod的node,得分會越高

(6)InterPodAffinity:遍歷pod的親和性,匹配項越多,得分就越多

(7)NodeAffinity:節點親和性,親和性高,得分高

(8)MostRequested:空閒量越少的,得分越高,與LeastRequested不能同時使用,集中一個機器上面跑pod

(9)NodeLabel:根據node上面的標籤來評估得分,有標籤就有分,沒有標籤就沒有分

(10)ImageLocality:一個node的得分高低,是根據node上面是否有映象,有映象就有得分,反之沒有。根據node上已有滿足需求的image的size的大小之和來計算

 

2.1 映象拉取策略

在建立pod時,有三種不同的映象拉取策略

  • IfNotPresent:預設值,映象在宿主機上不存在時才會拉取
  • Always:每次建立pod時都會重新拉取映象
  • Never:Pod永遠不會主動拉取這個映象

關於拉取策略的使用,可以在YAML檔案中看到其使用的位置

 上面也同樣展示了關於一些需要認證的私有倉庫,應該怎麼加認證去訪問,這個和secret有關

 

2.2 資源限制

Pod和Container的資源請求和限制:

  • spec.containers[].resources.limits.cpu:實際使用最大CPU配額
  • spec.containers[].resources.limits.memory:實際使用最大記憶體配額
  • spec.containers[].resources.requests.cpu:排程時請求的CPU配額參考
  • spec.containers[].resources.requests.memory:排程時請求的記憶體配額參考

資源限制有什麼用處?

最重要的一點就是避免某個容器資源利用率異常突發影響其它容器,從而造成雪崩

 

2.3 重啟策略

pod中的容器有三種重啟策略:

  • Always:預設策略,當容器終止退出後,總是重啟
  • OnFailure:當容器異常退出(退出狀態碼非0)時,才會重啟容器
  • Never:當容器終止退出時,從不重啟容器

2.4 健康檢查

Probe有以下兩種型別:

  • livenessProbe(存活檢查):如果檢查失敗,將殺死容器,根據重啟策略來決定是否重啟
  • readinessProbe(就緒檢查):如果檢查失敗,k8s會將Pod從service endpoints中刪除

 

Probe支援以下三種檢查方法:

  • httpGet:傳送HTTP請求,返回200-400範圍狀態碼為成功
  • exec:執行shell命令返回狀態碼是0為成功
  • tcpSocket:發起TCP Socket建立成功

比如在下面這個Pod中,健康檢查的機制就是通過在Pod內建立一個healthy檔案的方式來進行健康檢查

因為sleep了30s後刪除了檔案,所以會執行重啟Pod

同樣可以通過生成一個PID或者UUID來檢查

 

 我們可以觀察到liveness測試Pod已經重啟了一次,說明其因為沒有通過健康檢查而重啟

 

通過 kubectl describe pod liveness-exec 檢視這個容器的Events

可以發現其就是因為沒有通過健康檢查而重啟的,因為healthy檔案被刪除了,cat時返回非0狀態碼

 

2.5 標籤選擇器

為node設定標籤,讓pod排程到指定標籤的node上

為節點打標籤

kubectl label nodes [node] key=value

 

為節點刪除標籤

kubectl label nodes [node] key-

 

在YAML中使用節點選擇器選擇對應標籤的節點即可

 

2.7 節點親和性

節點親和性用於替換節點標籤選擇器,有兩種親和性表達:

  • RequiredDuringSchedulingIgnoredDuringExecution:硬限制,必須滿足條件
  • PreferrefDuringSchedulingIgnoredDuringExecution:軟限制,可以按權重優先

 

2.8 汙點和汙點容忍

首先區分一下汙點是node的汙點,汙點容忍是pod對node上汙點的容忍程度

關於汙點,常見的汙點應用場景為節點獨佔或者有特殊硬體的節點

給一個node設定汙點:

kubectl taint node [node] key=valie[effect]

 

刪除汙點:

kubectl taint node [node] key:[effect]-

 

其中[effect]可取值:

  • NoSchedule:不可能被排程,比如master節點在初始化時已經被打上不可排程標籤
  • PreferNoSchedule:儘量不要被排程
  • NoExecute:不僅不會被排程,還會驅逐Node上已有的Pod

 

汙點容忍是在構建Pod時,YAML檔案中的一個欄位

比如下面這個Pod,它可以忍受NoSchedule汙點的node

 

3. Pod的建立

 

  1. 使用者建立pod的資訊通過API Server儲存到etcd中,etcd記錄pod的元資訊並將結果返回給API Server
  2. API Server告知排程器請求資源排程,排程器通過排程演算法計算,將優先順序高的node與pod繫結並告知API Server
  3. API Server將此資訊寫入etcd,得到etcd回覆後呼叫kubelet建立pod
  4. kubelet使用docker run建立pod內容器,得到反饋後將此資訊告知API Server
  5. API Server將收到的資訊寫入etcd
  6. kubectl get pods 可以查到pod資訊了

 

參考:

【Kubernetes】Pod學習(八)Pod排程:定向排程與親和性排程_刺眼的寶石藍的部落格-CSDN部落格

pod排程策略,一篇就夠_Mr-Liuqx的部落格-CSDN部落格_pod排程策略

kube-scheduler :排程 Pod 流程-江哥架構師筆記 (andblog.cn)

乾貨!K8S之pod建立流程+排程約束_時光慢旅的部落格-CSDN部落格_k8s建立pod的詳細過程

這應該是最全的K8s-Pod排程策略了 - 雲+社群 - 騰訊雲 (tencent.com)

k8s之pod排程 - 路過的柚子廚 - 部落格園 (cnblogs.com)