Kubernetes 提供 Taints 和 Tolerations 機制,用於更精細地控制 Pod 排程。Taints 標記節點狀態,例如硬體故障或特定用途,而 Tolerations 則允許 Pod 忽略這些標記並在 Taint 節點上執行。本文將探討如何設定 Taints 和 Tolerations,並探討它們與 Node Affinity 的差異。藉由瞭解這些機制,可以更有效地管理節點資源並確保應用程式穩定執行。這對於維護高用性和彈性 Kubernetes 叢集至關重要,尤其在需要隔離特定工作負載或處理硬體維護的情況下。

Kubernetes 中的 Pod 排程進階技巧:Taints 與 Tolerations

在 Kubernetes 中,排程 Pod 至適當的 Node 是至關重要的任務。除了使用 Node Affinity 之外,Kubernetes 還提供了 Taints 和 Tolerations 機制來控制 Pod 的排程。本篇文章將探討 Taints 和 Tolerations 的使用方法及其與 Node Affinity 的差異。

使用 Taints 和 Tolerations

Taints 和 Tolerations 是 Kubernetes 中用於控制 Pod 排程的另一種機制。Taints 是對 Node 的標記,用於表示該 Node 具有某些限制或問題,而 Tolerations 則是對 Pod 的設定,允許 Pod 在具有特定 Taints 的 Node 上執行。

Taints 的結構

Taints 的結構為 <key>=<value>:<effect>,其中 <key><value> 用於識別 Taint,而 <effect> 則定義了 Taint 的效果。常見的 <effect> 包括:

  • NoSchedule:kube-scheduler 將不會排程 Pod 至此 Node。
  • PreferNoSchedule:kube-scheduler 將盡量避免排程 Pod 至此 Node。
  • NoExecute:kube-scheduler 將不會排程 Pod 至此 Node,並且會驅逐(終止並重新排程)正在執行的 Pod。

Taints 的應用

要為 Node 新增 Taint,可以使用以下命令:

$ kubectl taint node <nodeName> <key>=<value>:<effect>

例如,要為 Node minikube 新增一個 Taint,key 為 machine-check-exception,value 為 memory,effect 為 NoExecute,可以使用以下命令:

$ kubectl taint node minikube machine-check-exception=memory:NoExecute

要移除 Taint,可以使用以下命令:

$ kubectl taint node minikube machine-check-exception=memory:NoExecute-

Tolerations 的設定

要在 Pod 中設定 Tolerations,需要在 Pod 的 YAML 設定檔中新增 tolerations 欄位。例如:

apiVersion: v1
kind: Pod
metadata:
  name: nginx-app
spec:
  tolerations:
  - key: "machine-check-exception"
    operator: "Equal"
    value: "memory"
    effect: "NoExecute"

與 Node Affinity 的差異

Taints 和 Tolerations 與 Node Affinity 都可以用於控制 Pod 的排程,但它們有不同的使用場景和效果。Node Affinity 用於定義 Pod 對 Node 的偏好,而 Taints 和 Tolerations 則用於定義 Node 對 Pod 的限制。

Taints 和 Tolerations 的優勢在於,它們可以實作更細粒度的控制,例如,可以使用 NoExecute effect 來驅逐正在執行的 Pod。

內容解密:

本章節詳細介紹了 Kubernetes 中的 Taints 和 Tolerations 機制,包括其結構、應用和與 Node Affinity 的差異。透過瞭解 Taints 和 Tolerations 的使用方法,可以更好地控制 Pod 的排程和實作更靈活的資源管理。Taints 和 Tolerations 的主要優點在於,它們可以實作更細粒度的控制和更靈活的排程策略,從而提高資源利用率和應用效能。

Taints 和 Tolerations 的工作流程

@startuml
skinparam backgroundColor #FEFEFE
skinparam defaultTextAlignment center
skinparam rectangleBackgroundColor #F5F5F5
skinparam rectangleBorderColor #333333
skinparam arrowColor #333333

title 與 Node Affinity 的差異

rectangle "Tolerations" as node1
rectangle "Taints" as node2
rectangle "排程" as node3
rectangle "驅逐" as node4

node1 --> node2
node2 --> node3
node3 --> node4

@enduml

此圖示展示了 Taints 和 Tolerations 的工作流程。當 Pod 具有與 Node 上的 Taint 相匹配的 Toleration 時,kube-scheduler 將排程 Pod 至該 Node。否則,kube-scheduler 將避免排程 Pod 至該 Node,或驅逐正在執行的 Pod。

內容解密:

此 Plantuml 圖表展示了 Taints 和 Tolerations 的工作流程,說明瞭 kube-scheduler 如何根據 Taints 和 Tolerations 排程或驅逐 Pod。這有助於讀者更好地理解 Taints 和 Tolerations 的機制和作用。圖表清晰地呈現了 Pod、Node、kube-scheduler 之間的互動關係,使得讀者能夠更容易地理解相關概念。

高階 Pod 排程技術:汙點(Taint)與容忍度(Toleration)

在 Kubernetes 叢集中,Pod 的排程是一個複雜的過程,涉及多種因素,如節點的資源可用性、Pod 的需求以及叢集的管理策略。其中,汙點(Taint)和容忍度(Toleration)是兩個重要的機制,用於控制 Pod 在節點上的排程和執行。

汙點(Taint)與容忍度(Toleration)的基本概念

汙點是一種標記,可以應用於節點上,用於指示該節點具有某些特殊屬性或限制。當節點被標記為汙點時,Kubernetes 的排程器(kube-scheduler)將不會把 Pod 排程到該節點上,除非該 Pod 具有對應的容忍度。

容忍度是 Pod 對汙點的容忍程度的定義。透過在 Pod 的規格中定義容忍度,可以使 Pod 忽略某些汙點,從而被排程到具有該汙點的節點上。

汙點的結構和型別

汙點的結構通常由三個部分組成:鍵(key)、值(value)和效果(effect)。效果可以是以下三種型別之一:

  • NoSchedule:表示 Kubernetes 不會將 Pod 排程到具有該汙點的節點上。
  • PreferNoSchedule:表示 Kubernetes 盡量避免將 Pod 排程到具有該汙點的節點上,但不是絕對不會排程。
  • NoExecute:表示 Kubernetes 不僅不會將 Pod 排程到具有該汙點的節點上,而且如果該節點已經執行了 Pod,則會將其驅逐。

容忍度的定義和作用

容忍度的定義是在 Pod 的規格中的 .spec.tolerations 欄位下進行的。一個典型的容忍度定義如下所示:

tolerations:
- key: machine-check-exception
  operator: Equal
  value: memory
  effect: NoExecute
  tolerationSeconds: 60

在這個例子中,Pod 定義了一個對 machine-check-exception=memory:NoExecute 汙點的容忍度。這意味著該 Pod 可以被排程到具有該汙點的節點上,並且在該汙點被觸發時,可以容忍該汙點 60 秒後再被驅逐。

內容解密:

  1. keyvalue:指定了汙點的鍵和值。在這個例子中,鍵是 machine-check-exception,值是 memory
  2. operator:指定了比較運算子。在這個例子中,使用的是 Equal,表示鍵和值必須完全匹配。
  3. effect:指定了汙點的效果。在這個例子中,效果是 NoExecute,表示如果節點具有該汙點,則 Pod 將被驅逐。
  4. tolerationSeconds:指定了 Pod 可以容忍該汙點的時間長度。在這個例子中,Pod 可以容忍該汙點 60 秒後再被驅逐。

實踐:使用汙點和容忍度控制 Pod 排程

假設我們有一個名為 nginx-app 的 Deployment,其 Pod 目前正在 minikube 節點上執行。現在,我們想要將 minikube 節點標記為具有 machine-check-exception=memory:NoExecute 汙點,以測試 Pod 的排程行為。

首先,我們對 minikube 節點應用汙點:

$ kubectl taint node minikube machine-check-exception=memory:NoExecute
node/minikube tainted

接著,我們檢查 Pod 的狀態和節點分配:

$ kubectl get pods --namespace default --output=custom-columns="NAME:.metadata.name,STATUS:.status.phase,NODE:.spec.nodeName"
NAME                     STATUS    NODE
nginx-app-7d8c65464c-5j69n   Pending   <none>
nginx-app-7d8c65464c-c8j58   Pending   <none>
nginx-app-7d8c65464c-cnczc   Pending   <none>
nginx-app-7d8c65464c-drpdh   Pending   <none>
nginx-app-7d8c65464c-xss9b   Pending   <none>

可以看到,所有 Pod 都處於 Pending 狀態,因為沒有節點可以滿足其排程需求。

接下來,我們編輯 nginx-deployment.yaml 檔案,移除原有的 Node affinity 規則,並新增對 machine-check-exception=memory:NoExecute 汙點的容忍度定義,如下所示:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-app
spec:
  ...
  template:
    ...
    spec:
      tolerations:
      - key: machine-check-exception
        operator: Equal
        value: memory
        effect: NoExecute
        tolerationSeconds: 60

然後,我們應用該組態到叢集中,並檢查 Pod 的狀態和節點分配:

$ kubectl apply -f 04_taints/nginx-deployment.yaml
$ kubectl get pods --namespace default --output=custom-columns="NAME:.metadata.name,STATUS:.status.phase,NODE:.spec.nodeName"
NAME                     STATUS    NODE
nginx-app-84d755f746-4zkjd   Running   minikube
nginx-app-84d755f746-58qmh   Running   minikube-m02
nginx-app-84d755f746-5h5vk   Running   minikube-m03
nginx-app-84d755f746-psmgf   Running   minikube-m02
nginx-app-84d755f746-zkbc6   Running   minikube-m03

內容解密:

  1. 為什麼 Pod 被排程到具有汙點的節點上?因為我們在 Pod 的規格中定義了對應的容忍度。
  2. 為什麼 Pod 在 minikube 節點上會被反覆驅逐和重新排程?因為我們只定義了 NoExecute 汙點的容忍度,而沒有定義 NoSchedule 汙點的容忍度。
  3. 如何解決這個問題?可以透過新增 NoSchedule 汙點來防止 Pod 被排程到具有 NoExecute 汙點的節點上。

為了修復這個問題,我們可以對 minikube 節點新增 NoSchedule 汙點:

$ kubectl taint node minikube machine-check-exception=memory:NoSchedule
node/minikube tainted

然後,再次檢查 Pod 的狀態和節點分配:

$ kubectl get pods --namespace default --output=custom-columns="NAME:.metadata.name,STATUS:.status.phase,NODE:.spec.nodeName"
NAME                     STATUS    NODE
nginx-app-84d755f746-58qmh   Running   minikube-m02
nginx-app-84d755f746-5h5vk   Running   minikube-m03
nginx-app-84d755f746-psmgf   Running   minikube-m02
nginx-app-84d755f746-sm2cm   Running   minikube-m03
nginx-app-84d755f746-zkbc6   Running   minikube-m03

可以看到,Pod 現在被正確地排程和執行在其他節點上。

Kubernetes 排程機制進階應用

在前面的章節中,我們探討了 Kubernetes 的基本排程機制,包括 Taints 和 Tolerations、Node Affinity 等。本章節將探討更進階的排程技術,包括靜態 Pod、管理排程器組態、節點隔離和排程器效能調優。

靜態 Pod

靜態 Pod 是由 kubelet 直接管理的 Pod,不受 API 伺服器的控制。它們通常用於引導重要的叢集元件,如 API 伺服器或控制器管理器。靜態 Pod 有兩個主要特點:

  • 節點特定:靜態 Pod 與特定節點繫結,無法在叢集中移動。
  • Kubelet 管理:kubelet 負責啟動、停止和重新啟動靜態 Pod。

靜態 Pod 可以透過兩種方式建立:檔案系統託管組態和網頁託管組態。檔案系統託管組態需要將 Pod 定義檔案放置在節點上的特定目錄中,而網頁託管組態則需要將 Pod 定義檔案託管在網頁伺服器上。

靜態 Pod 的建立方法

  1. 檔案系統託管組態:將 Pod 定義檔案以 YAML 或 JSON 格式放置在節點上的特定目錄。kubelet 會定期掃描該目錄並根據檔案內容管理 Pod。
  2. 網頁託管組態:將 Pod 定義檔案託管在網頁伺服器上,並組態 kubelet 使用該檔案的 URL。kubelet 會定期下載該檔案以管理靜態 Pod。

排程器組態

Kubernetes 排程器可以使用組態檔案進行自定義,該檔案定義了排程器如何根據各種標準對節點進行優先排序。主要概念包括:

  • 排程組態檔案:組態檔案可以指定多個排程組態檔案,每個組態檔案都有不同的名稱和外掛集。
  • 排程外掛:外掛是排程過程中的構建塊,用於執行特定任務,如根據資源可用性或硬體相容性篩選節點。
  • 擴充套件點:擴充套件點是排程過程中插入外掛的階段,不同的外掛適用於不同的階段,如篩選不適合的節點或評分適合的節點。

排程器組態的優點

  1. 靈活性:允許根據需求自定義排程行為。
  2. 可擴充套件性:可以開發自定義外掛以處理預設外掛無法滿足的特殊排程需求。
  3. 粒度控制:可以為不同型別的 Pod 分配不同的排程組態檔案。

節點隔離和限制

Kubernetes 允許使用節點標籤隔離特定節點上的 Pod。這些標籤可以定義安全需求或法規遵從性等屬性,確保 Pod 只被排程到符合這些標準的節點上。

節點隔離的實作步驟

  1. 啟用 NodeRestriction 外掛和 Node 授權器
  2. 新增具有受限字首的標籤到節點
  3. 在 Pod 的 nodeSelector 組態中參照這些標籤

排程器效能調優

在大規模 Kubernetes 叢集中,排程器的效能至關重要。其中一個關鍵的調優引數是 percentageOfNodesToScore

percentageOfNodesToScore 的作用

  • 該設定決定了排程器在搜尋合適的 Pod 放置時考慮的節點數量。
  • 較高的值意味著排程器會檢查更多節點,可能找到更好的匹配,但需要更長的時間。
  • 較低的值會導致排程速度更快,但可能會導致次優的放置。

您可以透過調整 percentageOfNodesToScore 的值來平衡排程速度和放置品質。

重大變更:Kubernetes v1.23 及之後版本的排程策略變更

在 Kubernetes v1.23 之前,可以透過 kube-scheduler 標誌或 ConfigMaps 指定排程策略。這些策略使用謂詞(篩選標準)和優先順序(評分函式)定義了排程器如何選擇節點。自 v1.23 起,此功能已被排程器組態取代,提供了更大的靈活性和對排程行為的控制。

Kubernetes Pod 與節點的自動擴充套件技術

在雲端環境中執行應用程式時,具備自動擴充套件(Autoscaling)能力可謂是最佳實踐。簡單來說,自動擴充套件是一種根據終端使用者的需求動態調整計算資源(如 CPU 和 RAM)的方法。其目標是根據活動和需求新增或移除資源,以確保應用程式的高用性並降低營運成本。例如,某個應用程式在白天使用者活躍時可能需要更多的 CPU 和 RAM,而在夜間則需求較低。同樣地,對於電子商務基礎設施來說,在黑色星期五等促銷活動期間可能會出現巨大的需求峰值。透過自動擴充套件,不僅可以為使用者提供更好的服務,還能減少雲端資源的消耗,從而降低成本。

Kubernetes 作為最成熟的容器協調系統,提供了多種內建的自動擴充套件功能。其中一些功能在每個 Kubernetes 叢集中都原生支援,而其他一些則需要安裝或特定的叢集佈署型別。此外,您還可以根據不同的維度進行擴充套件:

Pod 的垂直擴充套件

這涉及到調整 Pod 可用的 CPU 和記憶體資源。Pod 可以在指定的 CPU 和記憶體限制下執行,以防止過度消耗,但這些限制可能需要自動調整,而不是由人工操作員進行猜測。這是由 VerticalPodAutoscaler (VPA) 實作的。

垂直擴充套件的程式碼範例

apiVersion: autoscaling.k8s.io/v1
kind: VerticalPodAutoscaler
metadata:
  name: my-vpa
spec:
  selector:
    matchLabels:
      app: my-app
  updateMode: Auto

內容解密:

  1. apiVersionkind 定義了 VPA 的資源型別。
  2. metadata.name 指定了 VPA 的名稱。
  3. spec.selector.matchLabels 用於選擇要擴充套件的 Pod。
  4. updateMode 設定為 Auto 表示 VPA 將自動調整資源。

Pod 的水平擴充套件

這涉及到動態更改 Deployment 或 StatefulSet 的 Pod 複本數量。這些物件具有不錯的擴充套件功能,但可以使用 HorizontalPodAutoscaler (HPA) 自動調整複本數量。

水平擴充套件的程式碼範例

apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
  name: my-hpa
spec:
  selector:
    matchLabels:
      app: my-app
  minReplicas: 1
  maxReplicas: 10
  metrics:
  - type: Resource
    resource:
      name: cpu
      target:
        type: Utilization
        averageUtilization: 50

內容解密:

  1. apiVersionkind 定義了 HPA 的資源型別。
  2. metadata.name 指定了 HPA 的名稱。
  3. spec.selector.matchLabels 用於選擇要擴充套件的 Pod。
  4. minReplicasmaxReplicas 設定了 Pod 複本數量的範圍。
  5. metrics 設定了根據 CPU 使用率進行擴充套件的規則。

自動擴充套件的優勢與挑戰

自動擴充套件可以根據實際需求動態調整資源,從而提高資源利用率並降低成本。然而,自動擴充套件也面臨著一些挑戰,例如如何選擇合適的指標、如何設定合理的擴充套件策略等。